var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

var mapboxGlUnminified$1 = {exports: {}};

/* Mapbox GL JS is Copyright © 2020 Mapbox and subject to the Mapbox Terms of Service ((https://www.mapbox.com/legal/tos/). */

(function (module, exports) {
	(function (global, factory) {
	module.exports = factory() ;
	})(commonjsGlobal, (function () {
	/* eslint-disable */

	var shared, worker, mapboxgl;
	// define gets called three times: one for each chunk. we rely on the order
	// they're imported to know which is which
	function define(_, chunk) {
	if (!shared) {
	    shared = chunk;
	} else if (!worker) {
	    worker = chunk;
	} else {
	    var workerBundleString = "self.onerror = function() { console.error('An error occurred while parsing the WebWorker bundle. This is most likely due to improper transpilation by Babel; please see https://docs.mapbox.com/mapbox-gl-js/guides/install/#transpiling'); }; var sharedChunk = {}; (" + shared + ")(sharedChunk); (" + worker + ")(sharedChunk); self.onerror = null;";

	    var sharedChunk = {};
	    shared(sharedChunk);
	    mapboxgl = chunk(sharedChunk);
	    if (typeof window !== 'undefined' && window && window.URL && window.URL.createObjectURL) {
	        mapboxgl.workerUrl = window.URL.createObjectURL(new Blob([workerBundleString], { type: 'text/javascript' }));
	    }
	}
	}


	define(['exports'], (function (exports) {
	var window$1 = typeof self !== 'undefined' ? self : {};

	var unitbezier = UnitBezier;
	function UnitBezier(p1x, p1y, p2x, p2y) {
	    this.cx = 3 * p1x;
	    this.bx = 3 * (p2x - p1x) - this.cx;
	    this.ax = 1 - this.cx - this.bx;
	    this.cy = 3 * p1y;
	    this.by = 3 * (p2y - p1y) - this.cy;
	    this.ay = 1 - this.cy - this.by;
	    this.p1x = p1x;
	    this.p1y = p2y;
	    this.p2x = p2x;
	    this.p2y = p2y;
	}
	UnitBezier.prototype.sampleCurveX = function (t) {
	    return ((this.ax * t + this.bx) * t + this.cx) * t;
	};
	UnitBezier.prototype.sampleCurveY = function (t) {
	    return ((this.ay * t + this.by) * t + this.cy) * t;
	};
	UnitBezier.prototype.sampleCurveDerivativeX = function (t) {
	    return (3 * this.ax * t + 2 * this.bx) * t + this.cx;
	};
	UnitBezier.prototype.solveCurveX = function (x, epsilon) {
	    if (typeof epsilon === 'undefined')
	        epsilon = 0.000001;
	    var t0, t1, t2, x2, i;
	    for (t2 = x, i = 0; i < 8; i++) {
	        x2 = this.sampleCurveX(t2) - x;
	        if (Math.abs(x2) < epsilon)
	            return t2;
	        var d2 = this.sampleCurveDerivativeX(t2);
	        if (Math.abs(d2) < 0.000001)
	            break;
	        t2 = t2 - x2 / d2;
	    }
	    t0 = 0;
	    t1 = 1;
	    t2 = x;
	    if (t2 < t0)
	        return t0;
	    if (t2 > t1)
	        return t1;
	    while (t0 < t1) {
	        x2 = this.sampleCurveX(t2);
	        if (Math.abs(x2 - x) < epsilon)
	            return t2;
	        if (x > x2) {
	            t0 = t2;
	        } else {
	            t1 = t2;
	        }
	        t2 = (t1 - t0) * 0.5 + t0;
	    }
	    return t2;
	};
	UnitBezier.prototype.solve = function (x, epsilon) {
	    return this.sampleCurveY(this.solveCurveX(x, epsilon));
	};

	var pointGeometry = Point;
	function Point(x, y) {
	    this.x = x;
	    this.y = y;
	}
	Point.prototype = {
	    clone: function () {
	        return new Point(this.x, this.y);
	    },
	    add: function (p) {
	        return this.clone()._add(p);
	    },
	    sub: function (p) {
	        return this.clone()._sub(p);
	    },
	    multByPoint: function (p) {
	        return this.clone()._multByPoint(p);
	    },
	    divByPoint: function (p) {
	        return this.clone()._divByPoint(p);
	    },
	    mult: function (k) {
	        return this.clone()._mult(k);
	    },
	    div: function (k) {
	        return this.clone()._div(k);
	    },
	    rotate: function (a) {
	        return this.clone()._rotate(a);
	    },
	    rotateAround: function (a, p) {
	        return this.clone()._rotateAround(a, p);
	    },
	    matMult: function (m) {
	        return this.clone()._matMult(m);
	    },
	    unit: function () {
	        return this.clone()._unit();
	    },
	    perp: function () {
	        return this.clone()._perp();
	    },
	    round: function () {
	        return this.clone()._round();
	    },
	    mag: function () {
	        return Math.sqrt(this.x * this.x + this.y * this.y);
	    },
	    equals: function (other) {
	        return this.x === other.x && this.y === other.y;
	    },
	    dist: function (p) {
	        return Math.sqrt(this.distSqr(p));
	    },
	    distSqr: function (p) {
	        var dx = p.x - this.x, dy = p.y - this.y;
	        return dx * dx + dy * dy;
	    },
	    angle: function () {
	        return Math.atan2(this.y, this.x);
	    },
	    angleTo: function (b) {
	        return Math.atan2(this.y - b.y, this.x - b.x);
	    },
	    angleWith: function (b) {
	        return this.angleWithSep(b.x, b.y);
	    },
	    angleWithSep: function (x, y) {
	        return Math.atan2(this.x * y - this.y * x, this.x * x + this.y * y);
	    },
	    _matMult: function (m) {
	        var x = m[0] * this.x + m[1] * this.y, y = m[2] * this.x + m[3] * this.y;
	        this.x = x;
	        this.y = y;
	        return this;
	    },
	    _add: function (p) {
	        this.x += p.x;
	        this.y += p.y;
	        return this;
	    },
	    _sub: function (p) {
	        this.x -= p.x;
	        this.y -= p.y;
	        return this;
	    },
	    _mult: function (k) {
	        this.x *= k;
	        this.y *= k;
	        return this;
	    },
	    _div: function (k) {
	        this.x /= k;
	        this.y /= k;
	        return this;
	    },
	    _multByPoint: function (p) {
	        this.x *= p.x;
	        this.y *= p.y;
	        return this;
	    },
	    _divByPoint: function (p) {
	        this.x /= p.x;
	        this.y /= p.y;
	        return this;
	    },
	    _unit: function () {
	        this._div(this.mag());
	        return this;
	    },
	    _perp: function () {
	        var y = this.y;
	        this.y = this.x;
	        this.x = -y;
	        return this;
	    },
	    _rotate: function (angle) {
	        var cos = Math.cos(angle), sin = Math.sin(angle), x = cos * this.x - sin * this.y, y = sin * this.x + cos * this.y;
	        this.x = x;
	        this.y = y;
	        return this;
	    },
	    _rotateAround: function (angle, p) {
	        var cos = Math.cos(angle), sin = Math.sin(angle), x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y), y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y);
	        this.x = x;
	        this.y = y;
	        return this;
	    },
	    _round: function () {
	        this.x = Math.round(this.x);
	        this.y = Math.round(this.y);
	        return this;
	    }
	};
	Point.convert = function (a) {
	    if (a instanceof Point) {
	        return a;
	    }
	    if (Array.isArray(a)) {
	        return new Point(a[0], a[1]);
	    }
	    return a;
	};

	const DEG_TO_RAD = Math.PI / 180;
	const RAD_TO_DEG = 180 / Math.PI;
	function degToRad(a) {
	    return a * DEG_TO_RAD;
	}
	function radToDeg(a) {
	    return a * RAD_TO_DEG;
	}
	const TILE_CORNERS = [
	    [
	        0,
	        0
	    ],
	    [
	        1,
	        0
	    ],
	    [
	        1,
	        1
	    ],
	    [
	        0,
	        1
	    ]
	];
	function furthestTileCorner(bearing) {
	    const alignedBearing = (bearing + 45 + 360) % 360;
	    const cornerIdx = Math.round(alignedBearing / 90) % 4;
	    return TILE_CORNERS[cornerIdx];
	}
	function easeCubicInOut(t) {
	    if (t <= 0)
	        return 0;
	    if (t >= 1)
	        return 1;
	    const t2 = t * t, t3 = t2 * t;
	    return 4 * (t < 0.5 ? t3 : 3 * (t - t2) + t3 - 0.75);
	}
	function getBounds(points) {
	    let minX = Infinity;
	    let minY = Infinity;
	    let maxX = -Infinity;
	    let maxY = -Infinity;
	    for (const p of points) {
	        minX = Math.min(minX, p.x);
	        minY = Math.min(minY, p.y);
	        maxX = Math.max(maxX, p.x);
	        maxY = Math.max(maxY, p.y);
	    }
	    return {
	        min: new pointGeometry(minX, minY),
	        max: new pointGeometry(maxX, maxY)
	    };
	}
	function getAABBPointSquareDist(min, max, point) {
	    let sqDist = 0;
	    for (let i = 0; i < 2; ++i) {
	        const v = point ? point[i] : 0;
	        if (min[i] > v)
	            sqDist += (min[i] - v) * (min[i] - v);
	        if (max[i] < v)
	            sqDist += (v - max[i]) * (v - max[i]);
	    }
	    return sqDist;
	}
	function polygonizeBounds(min, max, buffer = 0, close = true) {
	    const offset = new pointGeometry(buffer, buffer);
	    const minBuf = min.sub(offset);
	    const maxBuf = max.add(offset);
	    const polygon = [
	        minBuf,
	        new pointGeometry(maxBuf.x, minBuf.y),
	        maxBuf,
	        new pointGeometry(minBuf.x, maxBuf.y)
	    ];
	    if (close) {
	        polygon.push(minBuf.clone());
	    }
	    return polygon;
	}
	function bufferConvexPolygon(ring, buffer) {
	    const output = [];
	    for (let currIdx = 0; currIdx < ring.length; currIdx++) {
	        const prevIdx = wrap(currIdx - 1, -1, ring.length - 1);
	        const nextIdx = wrap(currIdx + 1, -1, ring.length - 1);
	        const prev = ring[prevIdx];
	        const curr = ring[currIdx];
	        const next = ring[nextIdx];
	        const p1 = prev.sub(curr).unit();
	        const p2 = next.sub(curr).unit();
	        const interiorAngle = p2.angleWithSep(p1.x, p1.y);
	        const offset = p1.add(p2).unit().mult(-1 * buffer / Math.sin(interiorAngle / 2));
	        output.push(curr.add(offset));
	    }
	    return output;
	}
	function bezier(p1x, p1y, p2x, p2y) {
	    const bezier = new unitbezier(p1x, p1y, p2x, p2y);
	    return function (t) {
	        return bezier.solve(t);
	    };
	}
	const ease = bezier(0.25, 0.1, 0.25, 1);
	function clamp(n, min, max) {
	    return Math.min(max, Math.max(min, n));
	}
	function smoothstep(e0, e1, x) {
	    x = clamp((x - e0) / (e1 - e0), 0, 1);
	    return x * x * (3 - 2 * x);
	}
	function wrap(n, min, max) {
	    const d = max - min;
	    const w = ((n - min) % d + d) % d + min;
	    return w === min ? max : w;
	}
	function shortestAngle(a, b) {
	    const diff = (b - a + 180) % 360 - 180;
	    return diff < -180 ? diff + 360 : diff;
	}
	function asyncAll(array, fn, callback) {
	    if (!array.length) {
	        return callback(null, []);
	    }
	    let remaining = array.length;
	    const results = new Array(array.length);
	    let error = null;
	    array.forEach((item, i) => {
	        fn(item, (err, result) => {
	            if (err)
	                error = err;
	            results[i] = result;
	            if (--remaining === 0)
	                callback(error, results);
	        });
	    });
	}
	function values(obj) {
	    const result = [];
	    for (const k in obj) {
	        result.push(obj[k]);
	    }
	    return result;
	}
	function keysDifference(obj, other) {
	    const difference = [];
	    for (const i in obj) {
	        if (!(i in other)) {
	            difference.push(i);
	        }
	    }
	    return difference;
	}
	function extend$1(dest, ...sources) {
	    for (const src of sources) {
	        for (const k in src) {
	            dest[k] = src[k];
	        }
	    }
	    return dest;
	}
	function pick(src, properties) {
	    const result = {};
	    for (let i = 0; i < properties.length; i++) {
	        const k = properties[i];
	        if (k in src) {
	            result[k] = src[k];
	        }
	    }
	    return result;
	}
	let id = 1;
	function uniqueId() {
	    return id++;
	}
	function uuid() {
	    function b(a) {
	        return a ? (a ^ Math.random() * (16 >> a / 4)).toString(16) : ([10000000] + -[1000] + -4000 + -8000 + -100000000000).replace(/[018]/g, b);
	    }
	    return b();
	}
	function nextPowerOfTwo(value) {
	    if (value <= 1)
	        return 1;
	    return Math.pow(2, Math.ceil(Math.log(value) / Math.LN2));
	}
	function prevPowerOfTwo(value) {
	    if (value <= 1)
	        return 1;
	    return Math.pow(2, Math.floor(Math.log(value) / Math.LN2));
	}
	function validateUuid(str) {
	    return str ? /^[0-9a-f]{8}-[0-9a-f]{4}-[4][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(str) : false;
	}
	function bindAll(fns, context) {
	    fns.forEach(fn => {
	        if (!context[fn]) {
	            return;
	        }
	        context[fn] = context[fn].bind(context);
	    });
	}
	function endsWith(string, suffix) {
	    return string.indexOf(suffix, string.length - suffix.length) !== -1;
	}
	function mapObject(input, iterator, context) {
	    const output = {};
	    for (const key in input) {
	        output[key] = iterator.call(context || this, input[key], key, input);
	    }
	    return output;
	}
	function filterObject(input, iterator, context) {
	    const output = {};
	    for (const key in input) {
	        if (iterator.call(context || this, input[key], key, input)) {
	            output[key] = input[key];
	        }
	    }
	    return output;
	}
	function clone$2(input) {
	    if (Array.isArray(input)) {
	        return input.map(clone$2);
	    } else if (typeof input === 'object' && input) {
	        return mapObject(input, clone$2);
	    } else {
	        return input;
	    }
	}
	function mapValue(value, min, max, outMin, outMax) {
	    return clamp((value - min) / (max - min) * (outMax - outMin) + outMin, outMin, outMax);
	}
	function arraysIntersect(a, b) {
	    for (let l = 0; l < a.length; l++) {
	        if (b.indexOf(a[l]) >= 0)
	            return true;
	    }
	    return false;
	}
	const warnOnceHistory = {};
	function warnOnce(message) {
	    if (!warnOnceHistory[message]) {
	        if (typeof console !== 'undefined')
	            console.warn(message);
	        warnOnceHistory[message] = true;
	    }
	}
	function isCounterClockwise(a, b, c) {
	    return (c.y - a.y) * (b.x - a.x) > (b.y - a.y) * (c.x - a.x);
	}
	function calculateSignedArea(ring) {
	    let sum = 0;
	    for (let i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
	        p1 = ring[i];
	        p2 = ring[j];
	        sum += (p2.x - p1.x) * (p1.y + p2.y);
	    }
	    return sum;
	}
	function isWorker() {
	    return typeof WorkerGlobalScope !== 'undefined' && typeof self !== 'undefined' && self instanceof WorkerGlobalScope;
	}
	function parseCacheControl(cacheControl) {
	    const re = /(?:^|(?:\s*\,\s*))([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)(?:\=(?:([^\x00-\x20\(\)<>@\,;\:\\"\/\[\]\?\=\{\}\x7F]+)|(?:\"((?:[^"\\]|\\.)*)\")))?/g;
	    const header = {};
	    cacheControl.replace(re, ($0, $1, $2, $3) => {
	        const value = $2 || $3;
	        header[$1] = value ? value.toLowerCase() : true;
	        return '';
	    });
	    if (header['max-age']) {
	        const maxAge = parseInt(header['max-age'], 10);
	        if (isNaN(maxAge))
	            delete header['max-age'];
	        else
	            header['max-age'] = maxAge;
	    }
	    return header;
	}
	let _isSafari = null;
	function isSafari(scope) {
	    if (_isSafari == null) {
	        const userAgent = scope.navigator ? scope.navigator.userAgent : null;
	        _isSafari = !!scope.safari || !!(userAgent && (/\b(iPad|iPhone|iPod)\b/.test(userAgent) || !!userAgent.match('Safari') && !userAgent.match('Chrome')));
	    }
	    return _isSafari;
	}
	function isSafariWithAntialiasingBug(scope) {
	    const userAgent = scope.navigator ? scope.navigator.userAgent : null;
	    if (!isSafari(scope))
	        return false;
	    return userAgent && (userAgent.match('Version/15.4') || userAgent.match('Version/15.5') || userAgent.match(/CPU (OS|iPhone OS) (15_4|15_5) like Mac OS X/));
	}
	function storageAvailable(type) {
	    try {
	        const storage = window$1[type];
	        storage.setItem('_mapbox_test_', 1);
	        storage.removeItem('_mapbox_test_');
	        return true;
	    } catch (e) {
	        return false;
	    }
	}
	function b64EncodeUnicode(str) {
	    return window$1.btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => {
	        return String.fromCharCode(Number('0x' + p1));
	    }));
	}
	function b64DecodeUnicode(str) {
	    return decodeURIComponent(window$1.atob(str).split('').map(c => {
	        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
	    }).join(''));
	}
	function getColumn(matrix, col) {
	    return [
	        matrix[col * 4],
	        matrix[col * 4 + 1],
	        matrix[col * 4 + 2],
	        matrix[col * 4 + 3]
	    ];
	}
	function setColumn(matrix, col, values) {
	    matrix[col * 4 + 0] = values[0];
	    matrix[col * 4 + 1] = values[1];
	    matrix[col * 4 + 2] = values[2];
	    matrix[col * 4 + 3] = values[3];
	}

	const performance = window$1.performance;
	function getPerformanceMeasurement(request) {
	    const url = request ? request.url.toString() : undefined;
	    return performance.getEntriesByName(url);
	}

	var version = "2.9.1";

	let linkEl;
	let reducedMotionQuery;
	let stubTime;
	let canvas;
	const exported$1 = {
	    now() {
	        if (stubTime !== undefined) {
	            return stubTime;
	        }
	        return window$1.performance.now();
	    },
	    setNow(time) {
	        stubTime = time;
	    },
	    restoreNow() {
	        stubTime = undefined;
	    },
	    frame(fn) {
	        const frame = window$1.requestAnimationFrame(fn);
	        return { cancel: () => window$1.cancelAnimationFrame(frame) };
	    },
	    getImageData(img, padding = 0) {
	        const {width, height} = img;
	        if (!canvas) {
	            canvas = window$1.document.createElement('canvas');
	        }
	        const context = canvas.getContext('2d');
	        if (!context) {
	            throw new Error('failed to create canvas 2d context');
	        }
	        if (width > canvas.width || height > canvas.height) {
	            canvas.width = width;
	            canvas.height = height;
	        }
	        context.clearRect(-padding, -padding, width + 2 * padding, height + 2 * padding);
	        context.drawImage(img, 0, 0, width, height);
	        return context.getImageData(-padding, -padding, width + 2 * padding, height + 2 * padding);
	    },
	    resolveURL(path) {
	        if (!linkEl)
	            linkEl = window$1.document.createElement('a');
	        linkEl.href = path;
	        return linkEl.href;
	    },
	    get devicePixelRatio() {
	        return window$1.devicePixelRatio;
	    },
	    get prefersReducedMotion() {
	        if (!window$1.matchMedia)
	            return false;
	        if (reducedMotionQuery == null) {
	            reducedMotionQuery = window$1.matchMedia('(prefers-reduced-motion: reduce)');
	        }
	        return reducedMotionQuery.matches;
	    }
	};

	let mapboxHTTPURLRegex;
	const config = {
	    API_URL: 'https://api.mapbox.com',
	    get API_URL_REGEX() {
	        if (mapboxHTTPURLRegex == null) {
	            const prodMapboxHTTPURLRegex = /^((https?:)?\/\/)?([^\/]+\.)?mapbox\.c(n|om)(\/|\?|$)/i;
	            try {
	                mapboxHTTPURLRegex = process.env.API_URL_REGEX != null ? new RegExp(process.env.API_URL_REGEX) : prodMapboxHTTPURLRegex;
	            } catch (e) {
	                mapboxHTTPURLRegex = prodMapboxHTTPURLRegex;
	            }
	        }
	        return mapboxHTTPURLRegex;
	    },
	    get EVENTS_URL() {
	        if (!this.API_URL) {
	            return null;
	        }
	        if (this.API_URL.indexOf('https://api.mapbox.cn') === 0) {
	            return 'https://events.mapbox.cn/events/v2';
	        } else if (this.API_URL.indexOf('https://api.mapbox.com') === 0) {
	            return 'https://events.mapbox.com/events/v2';
	        } else {
	            return null;
	        }
	    },
	    SESSION_PATH: '/map-sessions/v1',
	    FEEDBACK_URL: 'https://apps.mapbox.com/feedback',
	    TILE_URL_VERSION: 'v4',
	    RASTER_URL_PREFIX: 'raster/v1',
	    REQUIRE_ACCESS_TOKEN: true,
	    ACCESS_TOKEN: null,
	    MAX_PARALLEL_IMAGE_REQUESTS: 16
	};

	const exported = {
	    supported: false,
	    testSupport
	};
	let glForTesting;
	let webpCheckComplete = false;
	let webpImgTest;
	let webpImgTestOnloadComplete = false;
	if (window$1.document) {
	    webpImgTest = window$1.document.createElement('img');
	    webpImgTest.onload = function () {
	        if (glForTesting)
	            testWebpTextureUpload(glForTesting);
	        glForTesting = null;
	        webpImgTestOnloadComplete = true;
	    };
	    webpImgTest.onerror = function () {
	        webpCheckComplete = true;
	        glForTesting = null;
	    };
	    webpImgTest.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAQAAAAfQ//73v/+BiOh/AAA=';
	}
	function testSupport(gl) {
	    if (webpCheckComplete || !webpImgTest)
	        return;
	    if (webpImgTestOnloadComplete) {
	        testWebpTextureUpload(gl);
	    } else {
	        glForTesting = gl;
	    }
	}
	function testWebpTextureUpload(gl) {
	    const texture = gl.createTexture();
	    gl.bindTexture(gl.TEXTURE_2D, texture);
	    try {
	        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, webpImgTest);
	        if (gl.isContextLost())
	            return;
	        exported.supported = true;
	    } catch (e) {
	    }
	    gl.deleteTexture(texture);
	    webpCheckComplete = true;
	}

	const SKU_ID = '01';
	function createSkuToken() {
	    const TOKEN_VERSION = '1';
	    const base62chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
	    let sessionRandomizer = '';
	    for (let i = 0; i < 10; i++) {
	        sessionRandomizer += base62chars[Math.floor(Math.random() * 62)];
	    }
	    const expiration = 12 * 60 * 60 * 1000;
	    const token = [
	        TOKEN_VERSION,
	        SKU_ID,
	        sessionRandomizer
	    ].join('');
	    const tokenExpiresAt = Date.now() + expiration;
	    return {
	        token,
	        tokenExpiresAt
	    };
	}

	const AUTH_ERR_MSG = 'NO_ACCESS_TOKEN';
	class RequestManager {
	    constructor(transformRequestFn, customAccessToken, silenceAuthErrors) {
	        this._transformRequestFn = transformRequestFn;
	        this._customAccessToken = customAccessToken;
	        this._silenceAuthErrors = !!silenceAuthErrors;
	        this._createSkuToken();
	    }
	    _createSkuToken() {
	        const skuToken = createSkuToken();
	        this._skuToken = skuToken.token;
	        this._skuTokenExpiresAt = skuToken.tokenExpiresAt;
	    }
	    _isSkuTokenExpired() {
	        return Date.now() > this._skuTokenExpiresAt;
	    }
	    transformRequest(url, type) {
	        if (this._transformRequestFn) {
	            return this._transformRequestFn(url, type) || { url };
	        }
	        return { url };
	    }
	    normalizeStyleURL(url, accessToken) {
	        if (!isMapboxURL(url))
	            return url;
	        const urlObject = parseUrl(url);
	        urlObject.path = `/styles/v1${ urlObject.path }`;
	        return this._makeAPIURL(urlObject, this._customAccessToken || accessToken);
	    }
	    normalizeGlyphsURL(url, accessToken) {
	        if (!isMapboxURL(url))
	            return url;
	        const urlObject = parseUrl(url);
	        urlObject.path = `/fonts/v1${ urlObject.path }`;
	        return this._makeAPIURL(urlObject, this._customAccessToken || accessToken);
	    }
	    normalizeSourceURL(url, accessToken, language, worldview) {
	        if (!isMapboxURL(url))
	            return url;
	        const urlObject = parseUrl(url);
	        urlObject.path = `/v4/${ urlObject.authority }.json`;
	        urlObject.params.push('secure');
	        if (language) {
	            urlObject.params.push(`language=${ language }`);
	        }
	        if (worldview) {
	            urlObject.params.push(`worldview=${ worldview }`);
	        }
	        return this._makeAPIURL(urlObject, this._customAccessToken || accessToken);
	    }
	    normalizeSpriteURL(url, format, extension, accessToken) {
	        const urlObject = parseUrl(url);
	        if (!isMapboxURL(url)) {
	            urlObject.path += `${ format }${ extension }`;
	            return formatUrl(urlObject);
	        }
	        urlObject.path = `/styles/v1${ urlObject.path }/sprite${ format }${ extension }`;
	        return this._makeAPIURL(urlObject, this._customAccessToken || accessToken);
	    }
	    normalizeTileURL(tileURL, use2x, rasterTileSize) {
	        if (this._isSkuTokenExpired()) {
	            this._createSkuToken();
	        }
	        if (tileURL && !isMapboxURL(tileURL))
	            return tileURL;
	        const urlObject = parseUrl(tileURL);
	        const imageExtensionRe = /(\.(png|jpg)\d*)(?=$)/;
	        const extension = exported.supported ? '.webp' : '$1';
	        const use2xAs512 = rasterTileSize && urlObject.authority !== 'raster' && rasterTileSize === 512;
	        const suffix = use2x || use2xAs512 ? '@2x' : '';
	        urlObject.path = urlObject.path.replace(imageExtensionRe, `${ suffix }${ extension }`);
	        if (urlObject.authority === 'raster') {
	            urlObject.path = `/${ config.RASTER_URL_PREFIX }${ urlObject.path }`;
	        } else {
	            const tileURLAPIPrefixRe = /^.+\/v4\//;
	            urlObject.path = urlObject.path.replace(tileURLAPIPrefixRe, '/');
	            urlObject.path = `/${ config.TILE_URL_VERSION }${ urlObject.path }`;
	        }
	        const accessToken = this._customAccessToken || getAccessToken(urlObject.params) || config.ACCESS_TOKEN;
	        if (config.REQUIRE_ACCESS_TOKEN && accessToken && this._skuToken) {
	            urlObject.params.push(`sku=${ this._skuToken }`);
	        }
	        return this._makeAPIURL(urlObject, accessToken);
	    }
	    canonicalizeTileURL(url, removeAccessToken) {
	        const extensionRe = /\.[\w]+$/;
	        const urlObject = parseUrl(url);
	        if (!urlObject.path.match(/^(\/v4\/|\/raster\/v1\/)/) || !urlObject.path.match(extensionRe)) {
	            return url;
	        }
	        let result = 'mapbox://';
	        if (urlObject.path.match(/^\/raster\/v1\//)) {
	            const rasterPrefix = `/${ config.RASTER_URL_PREFIX }/`;
	            result += `raster/${ urlObject.path.replace(rasterPrefix, '') }`;
	        } else {
	            const tilesPrefix = `/${ config.TILE_URL_VERSION }/`;
	            result += `tiles/${ urlObject.path.replace(tilesPrefix, '') }`;
	        }
	        let params = urlObject.params;
	        if (removeAccessToken) {
	            params = params.filter(p => !p.match(/^access_token=/));
	        }
	        if (params.length)
	            result += `?${ params.join('&') }`;
	        return result;
	    }
	    canonicalizeTileset(tileJSON, sourceURL) {
	        const removeAccessToken = sourceURL ? isMapboxURL(sourceURL) : false;
	        const canonical = [];
	        for (const url of tileJSON.tiles || []) {
	            if (isMapboxHTTPURL(url)) {
	                canonical.push(this.canonicalizeTileURL(url, removeAccessToken));
	            } else {
	                canonical.push(url);
	            }
	        }
	        return canonical;
	    }
	    _makeAPIURL(urlObject, accessToken) {
	        const help = 'See https://www.mapbox.com/api-documentation/#access-tokens-and-token-scopes';
	        const apiUrlObject = parseUrl(config.API_URL);
	        urlObject.protocol = apiUrlObject.protocol;
	        urlObject.authority = apiUrlObject.authority;
	        if (urlObject.protocol === 'http') {
	            const i = urlObject.params.indexOf('secure');
	            if (i >= 0)
	                urlObject.params.splice(i, 1);
	        }
	        if (apiUrlObject.path !== '/') {
	            urlObject.path = `${ apiUrlObject.path }${ urlObject.path }`;
	        }
	        if (!config.REQUIRE_ACCESS_TOKEN)
	            return formatUrl(urlObject);
	        accessToken = accessToken || config.ACCESS_TOKEN;
	        if (!this._silenceAuthErrors) {
	            if (!accessToken)
	                throw new Error(`An API access token is required to use Mapbox GL. ${ help }`);
	            if (accessToken[0] === 's')
	                throw new Error(`Use a public access token (pk.*) with Mapbox GL, not a secret access token (sk.*). ${ help }`);
	        }
	        urlObject.params = urlObject.params.filter(d => d.indexOf('access_token') === -1);
	        urlObject.params.push(`access_token=${ accessToken || '' }`);
	        return formatUrl(urlObject);
	    }
	}
	function isMapboxURL(url) {
	    return url.indexOf('mapbox:') === 0;
	}
	function isMapboxHTTPURL(url) {
	    return config.API_URL_REGEX.test(url);
	}
	function hasCacheDefeatingSku(url) {
	    return url.indexOf('sku=') > 0 && isMapboxHTTPURL(url);
	}
	function getAccessToken(params) {
	    for (const param of params) {
	        const match = param.match(/^access_token=(.*)$/);
	        if (match) {
	            return match[1];
	        }
	    }
	    return null;
	}
	const urlRe = /^(\w+):\/\/([^/?]*)(\/[^?]+)?\??(.+)?/;
	function parseUrl(url) {
	    const parts = url.match(urlRe);
	    if (!parts) {
	        throw new Error('Unable to parse URL object');
	    }
	    return {
	        protocol: parts[1],
	        authority: parts[2],
	        path: parts[3] || '/',
	        params: parts[4] ? parts[4].split('&') : []
	    };
	}
	function formatUrl(obj) {
	    const params = obj.params.length ? `?${ obj.params.join('&') }` : '';
	    return `${ obj.protocol }://${ obj.authority }${ obj.path }${ params }`;
	}
	const telemEventKey = 'mapbox.eventData';
	function parseAccessToken(accessToken) {
	    if (!accessToken) {
	        return null;
	    }
	    const parts = accessToken.split('.');
	    if (!parts || parts.length !== 3) {
	        return null;
	    }
	    try {
	        const jsonData = JSON.parse(b64DecodeUnicode(parts[1]));
	        return jsonData;
	    } catch (e) {
	        return null;
	    }
	}
	class TelemetryEvent {
	    constructor(type) {
	        this.type = type;
	        this.anonId = null;
	        this.eventData = {};
	        this.queue = [];
	        this.pendingRequest = null;
	    }
	    getStorageKey(domain) {
	        const tokenData = parseAccessToken(config.ACCESS_TOKEN);
	        let u = '';
	        if (tokenData && tokenData['u']) {
	            u = b64EncodeUnicode(tokenData['u']);
	        } else {
	            u = config.ACCESS_TOKEN || '';
	        }
	        return domain ? `${ telemEventKey }.${ domain }:${ u }` : `${ telemEventKey }:${ u }`;
	    }
	    fetchEventData() {
	        const isLocalStorageAvailable = storageAvailable('localStorage');
	        const storageKey = this.getStorageKey();
	        const uuidKey = this.getStorageKey('uuid');
	        if (isLocalStorageAvailable) {
	            try {
	                const data = window$1.localStorage.getItem(storageKey);
	                if (data) {
	                    this.eventData = JSON.parse(data);
	                }
	                const uuid = window$1.localStorage.getItem(uuidKey);
	                if (uuid)
	                    this.anonId = uuid;
	            } catch (e) {
	                warnOnce('Unable to read from LocalStorage');
	            }
	        }
	    }
	    saveEventData() {
	        const isLocalStorageAvailable = storageAvailable('localStorage');
	        const storageKey = this.getStorageKey();
	        const uuidKey = this.getStorageKey('uuid');
	        if (isLocalStorageAvailable) {
	            try {
	                window$1.localStorage.setItem(uuidKey, this.anonId);
	                if (Object.keys(this.eventData).length >= 1) {
	                    window$1.localStorage.setItem(storageKey, JSON.stringify(this.eventData));
	                }
	            } catch (e) {
	                warnOnce('Unable to write to LocalStorage');
	            }
	        }
	    }
	    processRequests(_) {
	    }
	    postEvent(timestamp, additionalPayload, callback, customAccessToken) {
	        if (!config.EVENTS_URL)
	            return;
	        const eventsUrlObject = parseUrl(config.EVENTS_URL);
	        eventsUrlObject.params.push(`access_token=${ customAccessToken || config.ACCESS_TOKEN || '' }`);
	        const payload = {
	            event: this.type,
	            created: new Date(timestamp).toISOString(),
	            sdkIdentifier: 'mapbox-gl-js',
	            sdkVersion: version,
	            skuId: SKU_ID,
	            userId: this.anonId
	        };
	        const finalPayload = additionalPayload ? extend$1(payload, additionalPayload) : payload;
	        const request = {
	            url: formatUrl(eventsUrlObject),
	            headers: { 'Content-Type': 'text/plain' },
	            body: JSON.stringify([finalPayload])
	        };
	        this.pendingRequest = postData(request, error => {
	            this.pendingRequest = null;
	            callback(error);
	            this.saveEventData();
	            this.processRequests(customAccessToken);
	        });
	    }
	    queueRequest(event, customAccessToken) {
	        this.queue.push(event);
	        this.processRequests(customAccessToken);
	    }
	}
	class MapLoadEvent extends TelemetryEvent {
	    constructor() {
	        super('map.load');
	        this.success = {};
	        this.skuToken = '';
	    }
	    postMapLoadEvent(mapId, skuToken, customAccessToken, callback) {
	        this.skuToken = skuToken;
	        this.errorCb = callback;
	        if (config.EVENTS_URL) {
	            if (customAccessToken || config.ACCESS_TOKEN) {
	                this.queueRequest({
	                    id: mapId,
	                    timestamp: Date.now()
	                }, customAccessToken);
	            } else {
	                this.errorCb(new Error(AUTH_ERR_MSG));
	            }
	        }
	    }
	    processRequests(customAccessToken) {
	        if (this.pendingRequest || this.queue.length === 0)
	            return;
	        const {id, timestamp} = this.queue.shift();
	        if (id && this.success[id])
	            return;
	        if (!this.anonId) {
	            this.fetchEventData();
	        }
	        if (!validateUuid(this.anonId)) {
	            this.anonId = uuid();
	        }
	        this.postEvent(timestamp, { skuToken: this.skuToken }, err => {
	            if (err) {
	                this.errorCb(err);
	            } else {
	                if (id)
	                    this.success[id] = true;
	            }
	        }, customAccessToken);
	    }
	}
	class MapSessionAPI extends TelemetryEvent {
	    constructor() {
	        super('map.auth');
	        this.success = {};
	        this.skuToken = '';
	    }
	    getSession(timestamp, token, callback, customAccessToken) {
	        if (!config.API_URL || !config.SESSION_PATH)
	            return;
	        const authUrlObject = parseUrl(config.API_URL + config.SESSION_PATH);
	        authUrlObject.params.push(`sku=${ token || '' }`);
	        authUrlObject.params.push(`access_token=${ customAccessToken || config.ACCESS_TOKEN || '' }`);
	        const request = {
	            url: formatUrl(authUrlObject),
	            headers: { 'Content-Type': 'text/plain' }
	        };
	        this.pendingRequest = getData(request, error => {
	            this.pendingRequest = null;
	            callback(error);
	            this.saveEventData();
	            this.processRequests(customAccessToken);
	        });
	    }
	    getSessionAPI(mapId, skuToken, customAccessToken, callback) {
	        this.skuToken = skuToken;
	        this.errorCb = callback;
	        if (config.SESSION_PATH && config.API_URL) {
	            if (customAccessToken || config.ACCESS_TOKEN) {
	                this.queueRequest({
	                    id: mapId,
	                    timestamp: Date.now()
	                }, customAccessToken);
	            } else {
	                this.errorCb(new Error(AUTH_ERR_MSG));
	            }
	        }
	    }
	    processRequests(customAccessToken) {
	        if (this.pendingRequest || this.queue.length === 0)
	            return;
	        const {id, timestamp} = this.queue.shift();
	        if (id && this.success[id])
	            return;
	        this.getSession(timestamp, this.skuToken, err => {
	            if (err) {
	                this.errorCb(err);
	            } else {
	                if (id)
	                    this.success[id] = true;
	            }
	        }, customAccessToken);
	    }
	}
	class TurnstileEvent extends TelemetryEvent {
	    constructor(customAccessToken) {
	        super('appUserTurnstile');
	        this._customAccessToken = customAccessToken;
	    }
	    postTurnstileEvent(tileUrls, customAccessToken) {
	        if (config.EVENTS_URL && config.ACCESS_TOKEN && Array.isArray(tileUrls) && tileUrls.some(url => isMapboxURL(url) || isMapboxHTTPURL(url))) {
	            this.queueRequest(Date.now(), customAccessToken);
	        }
	    }
	    processRequests(customAccessToken) {
	        if (this.pendingRequest || this.queue.length === 0) {
	            return;
	        }
	        if (!this.anonId || !this.eventData.lastSuccess || !this.eventData.tokenU) {
	            this.fetchEventData();
	        }
	        const tokenData = parseAccessToken(config.ACCESS_TOKEN);
	        const tokenU = tokenData ? tokenData['u'] : config.ACCESS_TOKEN;
	        let dueForEvent = tokenU !== this.eventData.tokenU;
	        if (!validateUuid(this.anonId)) {
	            this.anonId = uuid();
	            dueForEvent = true;
	        }
	        const nextUpdate = this.queue.shift();
	        if (this.eventData.lastSuccess) {
	            const lastUpdate = new Date(this.eventData.lastSuccess);
	            const nextDate = new Date(nextUpdate);
	            const daysElapsed = (nextUpdate - this.eventData.lastSuccess) / (24 * 60 * 60 * 1000);
	            dueForEvent = dueForEvent || daysElapsed >= 1 || daysElapsed < -1 || lastUpdate.getDate() !== nextDate.getDate();
	        } else {
	            dueForEvent = true;
	        }
	        if (!dueForEvent) {
	            this.processRequests();
	            return;
	        }
	        this.postEvent(nextUpdate, { 'enabled.telemetry': false }, err => {
	            if (!err) {
	                this.eventData.lastSuccess = nextUpdate;
	                this.eventData.tokenU = tokenU;
	            }
	        }, customAccessToken);
	    }
	}
	const turnstileEvent_ = new TurnstileEvent();
	const postTurnstileEvent = turnstileEvent_.postTurnstileEvent.bind(turnstileEvent_);
	const mapLoadEvent_ = new MapLoadEvent();
	const postMapLoadEvent = mapLoadEvent_.postMapLoadEvent.bind(mapLoadEvent_);
	const mapSessionAPI_ = new MapSessionAPI();
	const getMapSessionAPI = mapSessionAPI_.getSessionAPI.bind(mapSessionAPI_);
	const authenticatedMaps = new Set();
	function storeAuthState(gl, state) {
	    if (state) {
	        authenticatedMaps.add(gl);
	    } else {
	        authenticatedMaps.delete(gl);
	    }
	}
	function isMapAuthenticated(gl) {
	    return authenticatedMaps.has(gl);
	}
	function removeAuthState(gl) {
	    authenticatedMaps.delete(gl);
	}

	const CACHE_NAME = 'mapbox-tiles';
	let cacheLimit = 500;
	let cacheCheckThreshold = 50;
	const MIN_TIME_UNTIL_EXPIRY = 1000 * 60 * 7;
	let sharedCaches = {};
	function getCacheName(url) {
	    const queryParams = getQueryParameters(url);
	    let language;
	    let worldview;
	    if (queryParams) {
	        queryParams.forEach(param => {
	            const entry = param.split('=');
	            if (entry[0] === 'language') {
	                language = entry[1];
	            } else if (entry[0] === 'worldview') {
	                worldview = entry[1];
	            }
	        });
	    }
	    let cacheName = CACHE_NAME;
	    if (language)
	        cacheName += `-${ language }`;
	    if (worldview)
	        cacheName += `-${ worldview }`;
	    return cacheName;
	}
	function cacheOpen(cacheName) {
	    if (window$1.caches && !sharedCaches[cacheName]) {
	        sharedCaches[cacheName] = window$1.caches.open(cacheName);
	    }
	}
	let responseConstructorSupportsReadableStream;
	function prepareBody(response, callback) {
	    if (responseConstructorSupportsReadableStream === undefined) {
	        try {
	            new Response(new ReadableStream());
	            responseConstructorSupportsReadableStream = true;
	        } catch (e) {
	            responseConstructorSupportsReadableStream = false;
	        }
	    }
	    if (responseConstructorSupportsReadableStream) {
	        callback(response.body);
	    } else {
	        response.blob().then(callback);
	    }
	}
	function cachePut(request, response, requestTime) {
	    const cacheName = getCacheName(request.url);
	    cacheOpen(cacheName);
	    if (!sharedCaches[cacheName])
	        return;
	    const options = {
	        status: response.status,
	        statusText: response.statusText,
	        headers: new window$1.Headers()
	    };
	    response.headers.forEach((v, k) => options.headers.set(k, v));
	    const cacheControl = parseCacheControl(response.headers.get('Cache-Control') || '');
	    if (cacheControl['no-store']) {
	        return;
	    }
	    if (cacheControl['max-age']) {
	        options.headers.set('Expires', new Date(requestTime + cacheControl['max-age'] * 1000).toUTCString());
	    }
	    const expires = options.headers.get('Expires');
	    if (!expires)
	        return;
	    const timeUntilExpiry = new Date(expires).getTime() - requestTime;
	    if (timeUntilExpiry < MIN_TIME_UNTIL_EXPIRY)
	        return;
	    prepareBody(response, body => {
	        const clonedResponse = new window$1.Response(body, options);
	        cacheOpen(cacheName);
	        if (!sharedCaches[cacheName])
	            return;
	        sharedCaches[cacheName].then(cache => cache.put(stripQueryParameters(request.url), clonedResponse)).catch(e => warnOnce(e.message));
	    });
	}
	function getQueryParameters(url) {
	    const paramStart = url.indexOf('?');
	    return paramStart > 0 ? url.slice(paramStart + 1).split('&') : [];
	}
	function stripQueryParameters(url) {
	    const start = url.indexOf('?');
	    if (start < 0)
	        return url;
	    const params = getQueryParameters(url);
	    const filteredParams = params.filter(param => {
	        const entry = param.split('=');
	        return entry[0] === 'language' || entry[0] === 'worldview';
	    });
	    if (filteredParams.length) {
	        return `${ url.slice(0, start) }?${ filteredParams.join('&') }`;
	    }
	    return url.slice(0, start);
	}
	function cacheGet(request, callback) {
	    const cacheName = getCacheName(request.url);
	    cacheOpen(cacheName);
	    if (!sharedCaches[cacheName])
	        return callback(null);
	    const strippedURL = stripQueryParameters(request.url);
	    sharedCaches[cacheName].then(cache => {
	        cache.match(strippedURL).then(response => {
	            const fresh = isFresh(response);
	            cache.delete(strippedURL);
	            if (fresh) {
	                cache.put(strippedURL, response.clone());
	            }
	            callback(null, response, fresh);
	        }).catch(callback);
	    }).catch(callback);
	}
	function isFresh(response) {
	    if (!response)
	        return false;
	    const expires = new Date(response.headers.get('Expires') || 0);
	    const cacheControl = parseCacheControl(response.headers.get('Cache-Control') || '');
	    return expires > Date.now() && !cacheControl['no-cache'];
	}
	let globalEntryCounter = Infinity;
	function cacheEntryPossiblyAdded(dispatcher) {
	    globalEntryCounter++;
	    if (globalEntryCounter > cacheCheckThreshold) {
	        dispatcher.getActor().send('enforceCacheSizeLimit', cacheLimit);
	        globalEntryCounter = 0;
	    }
	}
	function enforceCacheSizeLimit(limit) {
	    for (const sharedCache in sharedCaches) {
	        cacheOpen(sharedCache);
	        sharedCaches[sharedCache].then(cache => {
	            cache.keys().then(keys => {
	                for (let i = 0; i < keys.length - limit; i++) {
	                    cache.delete(keys[i]);
	                }
	            });
	        });
	    }
	}
	function clearTileCache(callback) {
	    const promises = [];
	    for (const cache in sharedCaches) {
	        promises.push(window$1.caches.delete(cache));
	        delete sharedCaches[cache];
	    }
	    if (callback) {
	        Promise.all(promises).catch(callback).then(() => callback());
	    }
	}
	function setCacheLimits(limit, checkThreshold) {
	    cacheLimit = limit;
	    cacheCheckThreshold = checkThreshold;
	}

	const ResourceType = {
	    Unknown: 'Unknown',
	    Style: 'Style',
	    Source: 'Source',
	    Tile: 'Tile',
	    Glyphs: 'Glyphs',
	    SpriteImage: 'SpriteImage',
	    SpriteJSON: 'SpriteJSON',
	    Image: 'Image'
	};
	if (typeof Object.freeze == 'function') {
	    Object.freeze(ResourceType);
	}
	class AJAXError extends Error {
	    constructor(message, status, url) {
	        if (status === 401 && isMapboxHTTPURL(url)) {
	            message += ': you may have provided an invalid Mapbox access token. See https://www.mapbox.com/api-documentation/#access-tokens-and-token-scopes';
	        }
	        super(message);
	        this.status = status;
	        this.url = url;
	    }
	    toString() {
	        return `${ this.name }: ${ this.message } (${ this.status }): ${ this.url }`;
	    }
	}
	const getReferrer = isWorker() ? () => self.worker && self.worker.referrer : () => (window$1.location.protocol === 'blob:' ? window$1.parent : window$1).location.href;
	const isFileURL = url => /^file:/.test(url) || /^file:/.test(getReferrer()) && !/^\w+:/.test(url);
	function makeFetchRequest(requestParameters, callback) {
	    const controller = new window$1.AbortController();
	    const request = new window$1.Request(requestParameters.url, {
	        method: requestParameters.method || 'GET',
	        body: requestParameters.body,
	        credentials: requestParameters.credentials,
	        headers: requestParameters.headers,
	        referrer: getReferrer(),
	        signal: controller.signal
	    });
	    let complete = false;
	    let aborted = false;
	    const cacheIgnoringSearch = hasCacheDefeatingSku(request.url);
	    if (requestParameters.type === 'json') {
	        request.headers.set('Accept', 'application/json');
	    }
	    const validateOrFetch = (err, cachedResponse, responseIsFresh) => {
	        if (aborted)
	            return;
	        if (err) {
	            if (err.message !== 'SecurityError') {
	                warnOnce(err);
	            }
	        }
	        if (cachedResponse && responseIsFresh) {
	            return finishRequest(cachedResponse);
	        }
	        const requestTime = Date.now();
	        window$1.fetch(request).then(response => {
	            if (response.ok) {
	                const cacheableResponse = cacheIgnoringSearch ? response.clone() : null;
	                return finishRequest(response, cacheableResponse, requestTime);
	            } else {
	                return callback(new AJAXError(response.statusText, response.status, requestParameters.url));
	            }
	        }).catch(error => {
	            if (error.code === 20) {
	                return;
	            }
	            callback(new Error(error.message));
	        });
	    };
	    const finishRequest = (response, cacheableResponse, requestTime) => {
	        (requestParameters.type === 'arrayBuffer' ? response.arrayBuffer() : requestParameters.type === 'json' ? response.json() : response.text()).then(result => {
	            if (aborted)
	                return;
	            if (cacheableResponse && requestTime) {
	                cachePut(request, cacheableResponse, requestTime);
	            }
	            complete = true;
	            callback(null, result, response.headers.get('Cache-Control'), response.headers.get('Expires'));
	        }).catch(err => {
	            if (!aborted)
	                callback(new Error(err.message));
	        });
	    };
	    if (cacheIgnoringSearch) {
	        cacheGet(request, validateOrFetch);
	    } else {
	        validateOrFetch(null, null);
	    }
	    return {
	        cancel: () => {
	            aborted = true;
	            if (!complete)
	                controller.abort();
	        }
	    };
	}
	function makeXMLHttpRequest(requestParameters, callback) {
	    const xhr = new window$1.XMLHttpRequest();
	    xhr.open(requestParameters.method || 'GET', requestParameters.url, true);
	    if (requestParameters.type === 'arrayBuffer') {
	        xhr.responseType = 'arraybuffer';
	    }
	    for (const k in requestParameters.headers) {
	        xhr.setRequestHeader(k, requestParameters.headers[k]);
	    }
	    if (requestParameters.type === 'json') {
	        xhr.responseType = 'text';
	        xhr.setRequestHeader('Accept', 'application/json');
	    }
	    xhr.withCredentials = requestParameters.credentials === 'include';
	    xhr.onerror = () => {
	        callback(new Error(xhr.statusText));
	    };
	    xhr.onload = () => {
	        if ((xhr.status >= 200 && xhr.status < 300 || xhr.status === 0) && xhr.response !== null) {
	            let data = xhr.response;
	            if (requestParameters.type === 'json') {
	                try {
	                    data = JSON.parse(xhr.response);
	                } catch (err) {
	                    return callback(err);
	                }
	            }
	            callback(null, data, xhr.getResponseHeader('Cache-Control'), xhr.getResponseHeader('Expires'));
	        } else {
	            callback(new AJAXError(xhr.statusText, xhr.status, requestParameters.url));
	        }
	    };
	    xhr.send(requestParameters.body);
	    return { cancel: () => xhr.abort() };
	}
	const makeRequest = function (requestParameters, callback) {
	    if (!isFileURL(requestParameters.url)) {
	        if (window$1.fetch && window$1.Request && window$1.AbortController && window$1.Request.prototype.hasOwnProperty('signal')) {
	            return makeFetchRequest(requestParameters, callback);
	        }
	        if (isWorker() && self.worker && self.worker.actor) {
	            const queueOnMainThread = true;
	            return self.worker.actor.send('getResource', requestParameters, callback, undefined, queueOnMainThread);
	        }
	    }
	    return makeXMLHttpRequest(requestParameters, callback);
	};
	const getJSON = function (requestParameters, callback) {
	    return makeRequest(extend$1(requestParameters, { type: 'json' }), callback);
	};
	const getArrayBuffer = function (requestParameters, callback) {
	    return makeRequest(extend$1(requestParameters, { type: 'arrayBuffer' }), callback);
	};
	const postData = function (requestParameters, callback) {
	    return makeRequest(extend$1(requestParameters, { method: 'POST' }), callback);
	};
	const getData = function (requestParameters, callback) {
	    return makeRequest(extend$1(requestParameters, { method: 'GET' }), callback);
	};
	function sameOrigin(url) {
	    const a = window$1.document.createElement('a');
	    a.href = url;
	    return a.protocol === window$1.document.location.protocol && a.host === window$1.document.location.host;
	}
	const transparentPngUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAC0lEQVQYV2NgAAIAAAUAAarVyFEAAAAASUVORK5CYII=';
	function arrayBufferToImage(data, callback) {
	    const img = new window$1.Image();
	    const URL = window$1.URL;
	    img.onload = () => {
	        callback(null, img);
	        URL.revokeObjectURL(img.src);
	        img.onload = null;
	        window$1.requestAnimationFrame(() => {
	            img.src = transparentPngUrl;
	        });
	    };
	    img.onerror = () => callback(new Error('Could not load image. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.'));
	    const blob = new window$1.Blob([new Uint8Array(data)], { type: 'image/png' });
	    img.src = data.byteLength ? URL.createObjectURL(blob) : transparentPngUrl;
	}
	function arrayBufferToImageBitmap(data, callback) {
	    const blob = new window$1.Blob([new Uint8Array(data)], { type: 'image/png' });
	    window$1.createImageBitmap(blob).then(imgBitmap => {
	        callback(null, imgBitmap);
	    }).catch(e => {
	        callback(new Error(`Could not load image because of ${ e.message }. Please make sure to use a supported image type such as PNG or JPEG. Note that SVGs are not supported.`));
	    });
	}
	let imageQueue, numImageRequests;
	const resetImageRequestQueue = () => {
	    imageQueue = [];
	    numImageRequests = 0;
	};
	resetImageRequestQueue();
	const getImage = function (requestParameters, callback) {
	    if (exported.supported) {
	        if (!requestParameters.headers) {
	            requestParameters.headers = {};
	        }
	        requestParameters.headers.accept = 'image/webp,*/*';
	    }
	    if (numImageRequests >= config.MAX_PARALLEL_IMAGE_REQUESTS) {
	        const queued = {
	            requestParameters,
	            callback,
	            cancelled: false,
	            cancel() {
	                this.cancelled = true;
	            }
	        };
	        imageQueue.push(queued);
	        return queued;
	    }
	    numImageRequests++;
	    let advanced = false;
	    const advanceImageRequestQueue = () => {
	        if (advanced)
	            return;
	        advanced = true;
	        numImageRequests--;
	        while (imageQueue.length && numImageRequests < config.MAX_PARALLEL_IMAGE_REQUESTS) {
	            const request = imageQueue.shift();
	            const {requestParameters, callback, cancelled} = request;
	            if (!cancelled) {
	                request.cancel = getImage(requestParameters, callback).cancel;
	            }
	        }
	    };
	    const request = getArrayBuffer(requestParameters, (err, data, cacheControl, expires) => {
	        advanceImageRequestQueue();
	        if (err) {
	            callback(err);
	        } else if (data) {
	            if (window$1.createImageBitmap) {
	                arrayBufferToImageBitmap(data, (err, imgBitmap) => callback(err, imgBitmap, cacheControl, expires));
	            } else {
	                arrayBufferToImage(data, (err, img) => callback(err, img, cacheControl, expires));
	            }
	        }
	    });
	    return {
	        cancel: () => {
	            request.cancel();
	            advanceImageRequestQueue();
	        }
	    };
	};
	const getVideo = function (urls, callback) {
	    const video = window$1.document.createElement('video');
	    video.muted = true;
	    video.onloadstart = function () {
	        callback(null, video);
	    };
	    for (let i = 0; i < urls.length; i++) {
	        const s = window$1.document.createElement('source');
	        if (!sameOrigin(urls[i])) {
	            video.crossOrigin = 'Anonymous';
	        }
	        s.src = urls[i];
	        video.appendChild(s);
	    }
	    return {
	        cancel: () => {
	        }
	    };
	};

	function _addEventListener(type, listener, listenerList) {
	    const listenerExists = listenerList[type] && listenerList[type].indexOf(listener) !== -1;
	    if (!listenerExists) {
	        listenerList[type] = listenerList[type] || [];
	        listenerList[type].push(listener);
	    }
	}
	function _removeEventListener(type, listener, listenerList) {
	    if (listenerList && listenerList[type]) {
	        const index = listenerList[type].indexOf(listener);
	        if (index !== -1) {
	            listenerList[type].splice(index, 1);
	        }
	    }
	}
	class Event {
	    constructor(type, data = {}) {
	        extend$1(this, data);
	        this.type = type;
	    }
	}
	class ErrorEvent extends Event {
	    constructor(error, data = {}) {
	        super('error', extend$1({ error }, data));
	    }
	}
	class Evented {
	    on(type, listener) {
	        this._listeners = this._listeners || {};
	        _addEventListener(type, listener, this._listeners);
	        return this;
	    }
	    off(type, listener) {
	        _removeEventListener(type, listener, this._listeners);
	        _removeEventListener(type, listener, this._oneTimeListeners);
	        return this;
	    }
	    once(type, listener) {
	        if (!listener) {
	            return new Promise(resolve => this.once(type, resolve));
	        }
	        this._oneTimeListeners = this._oneTimeListeners || {};
	        _addEventListener(type, listener, this._oneTimeListeners);
	        return this;
	    }
	    fire(event, properties) {
	        if (typeof event === 'string') {
	            event = new Event(event, properties || {});
	        }
	        const type = event.type;
	        if (this.listens(type)) {
	            event.target = this;
	            const listeners = this._listeners && this._listeners[type] ? this._listeners[type].slice() : [];
	            for (const listener of listeners) {
	                listener.call(this, event);
	            }
	            const oneTimeListeners = this._oneTimeListeners && this._oneTimeListeners[type] ? this._oneTimeListeners[type].slice() : [];
	            for (const listener of oneTimeListeners) {
	                _removeEventListener(type, listener, this._oneTimeListeners);
	                listener.call(this, event);
	            }
	            const parent = this._eventedParent;
	            if (parent) {
	                extend$1(event, typeof this._eventedParentData === 'function' ? this._eventedParentData() : this._eventedParentData);
	                parent.fire(event);
	            }
	        } else if (event instanceof ErrorEvent) {
	            console.error(event.error);
	        }
	        return this;
	    }
	    listens(type) {
	        return !!(this._listeners && this._listeners[type] && this._listeners[type].length > 0 || this._oneTimeListeners && this._oneTimeListeners[type] && this._oneTimeListeners[type].length > 0 || this._eventedParent && this._eventedParent.listens(type));
	    }
	    setEventedParent(parent, data) {
	        this._eventedParent = parent;
	        this._eventedParentData = data;
	        return this;
	    }
	}

	var spec = JSON.parse('{"$version":8,"$root":{"version":{"required":true,"type":"enum","values":[8]},"name":{"type":"string"},"metadata":{"type":"*"},"center":{"type":"array","value":"number"},"zoom":{"type":"number"},"bearing":{"type":"number","default":0,"period":360,"units":"degrees"},"pitch":{"type":"number","default":0,"units":"degrees"},"light":{"type":"light"},"terrain":{"type":"terrain"},"fog":{"type":"fog"},"sources":{"required":true,"type":"sources"},"sprite":{"type":"string"},"glyphs":{"type":"string"},"transition":{"type":"transition"},"projection":{"type":"projection"},"layers":{"required":true,"type":"array","value":"layer"}},"sources":{"*":{"type":"source"}},"source":["source_vector","source_raster","source_raster_dem","source_geojson","source_video","source_image"],"source_vector":{"type":{"required":true,"type":"enum","values":{"vector":{}}},"url":{"type":"string"},"tiles":{"type":"array","value":"string"},"bounds":{"type":"array","value":"number","length":4,"default":[-180,-85.051129,180,85.051129]},"scheme":{"type":"enum","values":{"xyz":{},"tms":{}},"default":"xyz"},"minzoom":{"type":"number","default":0},"maxzoom":{"type":"number","default":22},"attribution":{"type":"string"},"promoteId":{"type":"promoteId"},"volatile":{"type":"boolean","default":false},"*":{"type":"*"}},"source_raster":{"type":{"required":true,"type":"enum","values":{"raster":{}}},"url":{"type":"string"},"tiles":{"type":"array","value":"string"},"bounds":{"type":"array","value":"number","length":4,"default":[-180,-85.051129,180,85.051129]},"minzoom":{"type":"number","default":0},"maxzoom":{"type":"number","default":22},"tileSize":{"type":"number","default":512,"units":"pixels"},"scheme":{"type":"enum","values":{"xyz":{},"tms":{}},"default":"xyz"},"attribution":{"type":"string"},"volatile":{"type":"boolean","default":false},"*":{"type":"*"}},"source_raster_dem":{"type":{"required":true,"type":"enum","values":{"raster-dem":{}}},"url":{"type":"string"},"tiles":{"type":"array","value":"string"},"bounds":{"type":"array","value":"number","length":4,"default":[-180,-85.051129,180,85.051129]},"minzoom":{"type":"number","default":0},"maxzoom":{"type":"number","default":22},"tileSize":{"type":"number","default":512,"units":"pixels"},"attribution":{"type":"string"},"encoding":{"type":"enum","values":{"terrarium":{},"mapbox":{}},"default":"mapbox"},"volatile":{"type":"boolean","default":false},"*":{"type":"*"}},"source_geojson":{"type":{"required":true,"type":"enum","values":{"geojson":{}}},"data":{"type":"*"},"maxzoom":{"type":"number","default":18},"attribution":{"type":"string"},"buffer":{"type":"number","default":128,"maximum":512,"minimum":0},"filter":{"type":"*"},"tolerance":{"type":"number","default":0.375},"cluster":{"type":"boolean","default":false},"clusterRadius":{"type":"number","default":50,"minimum":0},"clusterMaxZoom":{"type":"number"},"clusterMinPoints":{"type":"number"},"clusterProperties":{"type":"*"},"lineMetrics":{"type":"boolean","default":false},"generateId":{"type":"boolean","default":false},"promoteId":{"type":"promoteId"}},"source_video":{"type":{"required":true,"type":"enum","values":{"video":{}}},"urls":{"required":true,"type":"array","value":"string"},"coordinates":{"required":true,"type":"array","length":4,"value":{"type":"array","length":2,"value":"number"}}},"source_image":{"type":{"required":true,"type":"enum","values":{"image":{}}},"url":{"required":true,"type":"string"},"coordinates":{"required":true,"type":"array","length":4,"value":{"type":"array","length":2,"value":"number"}}},"layer":{"id":{"type":"string","required":true},"type":{"type":"enum","values":{"fill":{},"line":{},"symbol":{},"circle":{},"heatmap":{},"fill-extrusion":{},"raster":{},"hillshade":{},"background":{},"sky":{}},"required":true},"metadata":{"type":"*"},"source":{"type":"string"},"source-layer":{"type":"string"},"minzoom":{"type":"number","minimum":0,"maximum":24},"maxzoom":{"type":"number","minimum":0,"maximum":24},"filter":{"type":"filter"},"layout":{"type":"layout"},"paint":{"type":"paint"}},"layout":["layout_fill","layout_line","layout_circle","layout_heatmap","layout_fill-extrusion","layout_symbol","layout_raster","layout_hillshade","layout_background","layout_sky"],"layout_background":{"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_sky":{"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_fill":{"fill-sort-key":{"type":"number","expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_circle":{"circle-sort-key":{"type":"number","expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_heatmap":{"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_fill-extrusion":{"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_line":{"line-cap":{"type":"enum","values":{"butt":{},"round":{},"square":{}},"default":"butt","expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"line-join":{"type":"enum","values":{"bevel":{},"round":{},"miter":{}},"default":"miter","expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"line-miter-limit":{"type":"number","default":2,"requires":[{"line-join":"miter"}],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"line-round-limit":{"type":"number","default":1.05,"requires":[{"line-join":"round"}],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"line-sort-key":{"type":"number","expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_symbol":{"symbol-placement":{"type":"enum","values":{"point":{},"line":{},"line-center":{}},"default":"point","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"symbol-spacing":{"type":"number","default":250,"minimum":1,"units":"pixels","requires":[{"symbol-placement":"line"}],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"symbol-avoid-edges":{"type":"boolean","default":false,"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"symbol-sort-key":{"type":"number","expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"symbol-z-order":{"type":"enum","values":{"auto":{},"viewport-y":{},"source":{}},"default":"auto","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-allow-overlap":{"type":"boolean","default":false,"requires":["icon-image"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-ignore-placement":{"type":"boolean","default":false,"requires":["icon-image"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-optional":{"type":"boolean","default":false,"requires":["icon-image","text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-rotation-alignment":{"type":"enum","values":{"map":{},"viewport":{},"auto":{}},"default":"auto","requires":["icon-image"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-size":{"type":"number","default":1,"minimum":0,"units":"factor of the original icon size","requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"icon-text-fit":{"type":"enum","values":{"none":{},"width":{},"height":{},"both":{}},"default":"none","requires":["icon-image","text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-text-fit-padding":{"type":"array","value":"number","length":4,"default":[0,0,0,0],"units":"pixels","requires":["icon-image","text-field",{"icon-text-fit":["both","width","height"]}],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"icon-image":{"type":"resolvedImage","tokens":true,"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"icon-rotate":{"type":"number","default":0,"period":360,"units":"degrees","requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"icon-padding":{"type":"number","default":2,"minimum":0,"units":"pixels","requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"icon-keep-upright":{"type":"boolean","default":false,"requires":["icon-image",{"icon-rotation-alignment":"map"},{"symbol-placement":["line","line-center"]}],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"icon-offset":{"type":"array","value":"number","length":2,"default":[0,0],"requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"icon-anchor":{"type":"enum","values":{"center":{},"left":{},"right":{},"top":{},"bottom":{},"top-left":{},"top-right":{},"bottom-left":{},"bottom-right":{}},"default":"center","requires":["icon-image"],"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"icon-pitch-alignment":{"type":"enum","values":{"map":{},"viewport":{},"auto":{}},"default":"auto","requires":["icon-image"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-pitch-alignment":{"type":"enum","values":{"map":{},"viewport":{},"auto":{}},"default":"auto","requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-rotation-alignment":{"type":"enum","values":{"map":{},"viewport":{},"auto":{}},"default":"auto","requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-field":{"type":"formatted","default":"","tokens":true,"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-font":{"type":"array","value":"string","default":["Open Sans Regular","Arial Unicode MS Regular"],"requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-size":{"type":"number","default":16,"minimum":0,"units":"pixels","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-max-width":{"type":"number","default":10,"minimum":0,"units":"ems","requires":["text-field",{"symbol-placement":["point"]}],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-line-height":{"type":"number","default":1.2,"units":"ems","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-letter-spacing":{"type":"number","default":0,"units":"ems","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-justify":{"type":"enum","values":{"auto":{},"left":{},"center":{},"right":{}},"default":"center","requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-radial-offset":{"type":"number","units":"ems","default":0,"requires":["text-field"],"property-type":"data-driven","expression":{"interpolated":true,"parameters":["zoom","feature"]}},"text-variable-anchor":{"type":"array","value":"enum","values":{"center":{},"left":{},"right":{},"top":{},"bottom":{},"top-left":{},"top-right":{},"bottom-left":{},"bottom-right":{}},"requires":["text-field",{"symbol-placement":["point"]}],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-anchor":{"type":"enum","values":{"center":{},"left":{},"right":{},"top":{},"bottom":{},"top-left":{},"top-right":{},"bottom-left":{},"bottom-right":{}},"default":"center","requires":["text-field",{"!":"text-variable-anchor"}],"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-max-angle":{"type":"number","default":45,"units":"degrees","requires":["text-field",{"symbol-placement":["line","line-center"]}],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"text-writing-mode":{"type":"array","value":"enum","values":{"horizontal":{},"vertical":{}},"requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-rotate":{"type":"number","default":0,"period":360,"units":"degrees","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-padding":{"type":"number","default":2,"minimum":0,"units":"pixels","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"text-keep-upright":{"type":"boolean","default":true,"requires":["text-field",{"text-rotation-alignment":"map"},{"symbol-placement":["line","line-center"]}],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-transform":{"type":"enum","values":{"none":{},"uppercase":{},"lowercase":{}},"default":"none","requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-offset":{"type":"array","value":"number","units":"ems","length":2,"default":[0,0],"requires":["text-field",{"!":"text-radial-offset"}],"expression":{"interpolated":true,"parameters":["zoom","feature"]},"property-type":"data-driven"},"text-allow-overlap":{"type":"boolean","default":false,"requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-ignore-placement":{"type":"boolean","default":false,"requires":["text-field"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-optional":{"type":"boolean","default":false,"requires":["text-field","icon-image"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_raster":{"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"layout_hillshade":{"visibility":{"type":"enum","values":{"visible":{},"none":{}},"default":"visible","property-type":"constant"}},"filter":{"type":"array","value":"*"},"filter_symbol":{"type":"boolean","default":false,"transition":false,"property-type":"data-driven","expression":{"interpolated":false,"parameters":["zoom","feature","pitch","distance-from-center"]}},"filter_fill":{"type":"boolean","default":false,"transition":false,"property-type":"data-driven","expression":{"interpolated":false,"parameters":["zoom","feature"]}},"filter_line":{"type":"boolean","default":false,"transition":false,"property-type":"data-driven","expression":{"interpolated":false,"parameters":["zoom","feature"]}},"filter_circle":{"type":"boolean","default":false,"transition":false,"property-type":"data-driven","expression":{"interpolated":false,"parameters":["zoom","feature"]}},"filter_fill-extrusion":{"type":"boolean","default":false,"transition":false,"property-type":"data-driven","expression":{"interpolated":false,"parameters":["zoom","feature"]}},"filter_heatmap":{"type":"boolean","default":false,"transition":false,"property-type":"data-driven","expression":{"interpolated":false,"parameters":["zoom","feature"]}},"filter_operator":{"type":"enum","values":{"==":{},"!=":{},">":{},">=":{},"<":{},"<=":{},"in":{},"!in":{},"all":{},"any":{},"none":{},"has":{},"!has":{},"within":{}}},"geometry_type":{"type":"enum","values":{"Point":{},"LineString":{},"Polygon":{}}},"function":{"expression":{"type":"expression"},"stops":{"type":"array","value":"function_stop"},"base":{"type":"number","default":1,"minimum":0},"property":{"type":"string","default":"$zoom"},"type":{"type":"enum","values":{"identity":{},"exponential":{},"interval":{},"categorical":{}},"default":"exponential"},"colorSpace":{"type":"enum","values":{"rgb":{},"lab":{},"hcl":{}},"default":"rgb"},"default":{"type":"*","required":false}},"function_stop":{"type":"array","minimum":0,"maximum":24,"value":["number","color"],"length":2},"expression":{"type":"array","value":"*","minimum":1},"fog":{"range":{"type":"array","default":[0.5,10],"minimum":-20,"maximum":20,"length":2,"value":"number","property-type":"data-constant","transition":true,"expression":{"interpolated":true,"parameters":["zoom"]}},"color":{"type":"color","property-type":"data-constant","default":"#ffffff","expression":{"interpolated":true,"parameters":["zoom"]},"transition":true},"high-color":{"type":"color","property-type":"data-constant","default":"#245cdf","expression":{"interpolated":true,"parameters":["zoom"]},"transition":true},"space-color":{"type":"color","property-type":"data-constant","default":["interpolate",["linear"],["zoom"],4,"#010b19",7,"#367ab9"],"expression":{"interpolated":true,"parameters":["zoom"]},"transition":true},"horizon-blend":{"type":"number","property-type":"data-constant","default":["interpolate",["linear"],["zoom"],4,0.2,7,0.1],"minimum":0,"maximum":1,"expression":{"interpolated":true,"parameters":["zoom"]},"transition":true},"star-intensity":{"type":"number","property-type":"data-constant","default":["interpolate",["linear"],["zoom"],5,0.35,6,0],"minimum":0,"maximum":1,"expression":{"interpolated":true,"parameters":["zoom"]},"transition":true}},"light":{"anchor":{"type":"enum","default":"viewport","values":{"map":{},"viewport":{}},"property-type":"data-constant","transition":false,"expression":{"interpolated":false,"parameters":["zoom"]}},"position":{"type":"array","default":[1.15,210,30],"length":3,"value":"number","property-type":"data-constant","transition":true,"expression":{"interpolated":true,"parameters":["zoom"]}},"color":{"type":"color","property-type":"data-constant","default":"#ffffff","expression":{"interpolated":true,"parameters":["zoom"]},"transition":true},"intensity":{"type":"number","property-type":"data-constant","default":0.5,"minimum":0,"maximum":1,"expression":{"interpolated":true,"parameters":["zoom"]},"transition":true}},"projection":{"name":{"type":"enum","values":{"albers":{},"equalEarth":{},"equirectangular":{},"lambertConformalConic":{},"mercator":{},"naturalEarth":{},"winkelTripel":{},"globe":{}},"default":"mercator","required":true},"center":{"type":"array","length":2,"value":"number","property-type":"data-constant","minimum":[-180,-90],"maximum":[180,90],"transition":false,"requires":[{"name":["albers","lambertConformalConic"]}]},"parallels":{"type":"array","length":2,"value":"number","property-type":"data-constant","minimum":[-90,-90],"maximum":[90,90],"transition":false,"requires":[{"name":["albers","lambertConformalConic"]}]}},"terrain":{"source":{"type":"string","required":true},"exaggeration":{"type":"number","property-type":"data-constant","default":1,"minimum":0,"maximum":1000,"expression":{"interpolated":true,"parameters":["zoom"]},"transition":true,"requires":["source"]}},"paint":["paint_fill","paint_line","paint_circle","paint_heatmap","paint_fill-extrusion","paint_symbol","paint_raster","paint_hillshade","paint_background","paint_sky"],"paint_fill":{"fill-antialias":{"type":"boolean","default":true,"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"fill-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-color":{"type":"color","default":"#000000","transition":true,"requires":[{"!":"fill-pattern"}],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-outline-color":{"type":"color","transition":true,"requires":[{"!":"fill-pattern"},{"fill-antialias":true}],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-translate":{"type":"array","value":"number","length":2,"default":[0,0],"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"fill-translate-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","requires":["fill-translate"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"fill-pattern":{"type":"resolvedImage","transition":true,"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"cross-faded-data-driven"}},"paint_fill-extrusion":{"fill-extrusion-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"fill-extrusion-color":{"type":"color","default":"#000000","transition":true,"requires":[{"!":"fill-extrusion-pattern"}],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-extrusion-translate":{"type":"array","value":"number","length":2,"default":[0,0],"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"fill-extrusion-translate-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","requires":["fill-extrusion-translate"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"fill-extrusion-pattern":{"type":"resolvedImage","transition":true,"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"cross-faded-data-driven"},"fill-extrusion-height":{"type":"number","default":0,"minimum":0,"units":"meters","transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-extrusion-base":{"type":"number","default":0,"minimum":0,"units":"meters","transition":true,"requires":["fill-extrusion-height"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-extrusion-vertical-gradient":{"type":"boolean","default":true,"transition":false,"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"}},"paint_line":{"line-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-color":{"type":"color","default":"#000000","transition":true,"requires":[{"!":"line-pattern"}],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-translate":{"type":"array","value":"number","length":2,"default":[0,0],"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"line-translate-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","requires":["line-translate"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"line-width":{"type":"number","default":1,"minimum":0,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-gap-width":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-offset":{"type":"number","default":0,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-blur":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-dasharray":{"type":"array","value":"number","minimum":0,"transition":true,"units":"line widths","requires":[{"!":"line-pattern"}],"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"cross-faded-data-driven"},"line-pattern":{"type":"resolvedImage","transition":true,"expression":{"interpolated":false,"parameters":["zoom","feature"]},"property-type":"cross-faded-data-driven"},"line-gradient":{"type":"color","transition":false,"requires":[{"!":"line-pattern"},{"source":"geojson","has":{"lineMetrics":true}}],"expression":{"interpolated":true,"parameters":["line-progress"]},"property-type":"color-ramp"},"line-trim-offset":{"type":"array","value":"number","length":2,"default":[0,0],"minimum":[0,0],"maximum":[1,1],"transition":false,"requires":[{"source":"geojson","has":{"lineMetrics":true}}],"property-type":"constant"}},"paint_circle":{"circle-radius":{"type":"number","default":5,"minimum":0,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-color":{"type":"color","default":"#000000","transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-blur":{"type":"number","default":0,"transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-translate":{"type":"array","value":"number","length":2,"default":[0,0],"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"circle-translate-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","requires":["circle-translate"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"circle-pitch-scale":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"circle-pitch-alignment":{"type":"enum","values":{"map":{},"viewport":{}},"default":"viewport","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"circle-stroke-width":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-stroke-color":{"type":"color","default":"#000000","transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-stroke-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"}},"paint_heatmap":{"heatmap-radius":{"type":"number","default":30,"minimum":1,"transition":true,"units":"pixels","expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"heatmap-weight":{"type":"number","default":1,"minimum":0,"transition":false,"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"heatmap-intensity":{"type":"number","default":1,"minimum":0,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"heatmap-color":{"type":"color","default":["interpolate",["linear"],["heatmap-density"],0,"rgba(0, 0, 255, 0)",0.1,"royalblue",0.3,"cyan",0.5,"lime",0.7,"yellow",1,"red"],"transition":false,"expression":{"interpolated":true,"parameters":["heatmap-density"]},"property-type":"color-ramp"},"heatmap-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"}},"paint_symbol":{"icon-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-color":{"type":"color","default":"#000000","transition":true,"requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-halo-color":{"type":"color","default":"rgba(0, 0, 0, 0)","transition":true,"requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-halo-width":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-halo-blur":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-translate":{"type":"array","value":"number","length":2,"default":[0,0],"transition":true,"units":"pixels","requires":["icon-image"],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"icon-translate-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","requires":["icon-image","icon-translate"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"text-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-color":{"type":"color","default":"#000000","transition":true,"overridable":true,"requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-halo-color":{"type":"color","default":"rgba(0, 0, 0, 0)","transition":true,"requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-halo-width":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-halo-blur":{"type":"number","default":0,"minimum":0,"transition":true,"units":"pixels","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-translate":{"type":"array","value":"number","length":2,"default":[0,0],"transition":true,"units":"pixels","requires":["text-field"],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"text-translate-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"map","requires":["text-field","text-translate"],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"}},"paint_raster":{"raster-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"raster-hue-rotate":{"type":"number","default":0,"period":360,"transition":true,"units":"degrees","expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"raster-brightness-min":{"type":"number","default":0,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"raster-brightness-max":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"raster-saturation":{"type":"number","default":0,"minimum":-1,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"raster-contrast":{"type":"number","default":0,"minimum":-1,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"raster-resampling":{"type":"enum","values":{"linear":{},"nearest":{}},"default":"linear","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"raster-fade-duration":{"type":"number","default":300,"minimum":0,"transition":false,"units":"milliseconds","expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"}},"paint_hillshade":{"hillshade-illumination-direction":{"type":"number","default":335,"minimum":0,"maximum":359,"transition":false,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"hillshade-illumination-anchor":{"type":"enum","values":{"map":{},"viewport":{}},"default":"viewport","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"hillshade-exaggeration":{"type":"number","default":0.5,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"hillshade-shadow-color":{"type":"color","default":"#000000","transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"hillshade-highlight-color":{"type":"color","default":"#FFFFFF","transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"hillshade-accent-color":{"type":"color","default":"#000000","transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"}},"paint_background":{"background-color":{"type":"color","default":"#000000","transition":true,"requires":[{"!":"background-pattern"}],"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"},"background-pattern":{"type":"resolvedImage","transition":true,"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"cross-faded"},"background-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"}},"paint_sky":{"sky-type":{"type":"enum","values":{"gradient":{},"atmosphere":{}},"default":"atmosphere","expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"sky-atmosphere-sun":{"type":"array","value":"number","length":2,"units":"degrees","minimum":[0,0],"maximum":[360,180],"transition":false,"requires":[{"sky-type":"atmosphere"}],"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"sky-atmosphere-sun-intensity":{"type":"number","requires":[{"sky-type":"atmosphere"}],"default":10,"minimum":0,"maximum":100,"transition":false,"property-type":"data-constant"},"sky-gradient-center":{"type":"array","requires":[{"sky-type":"gradient"}],"value":"number","default":[0,0],"length":2,"units":"degrees","minimum":[0,0],"maximum":[360,180],"transition":false,"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"sky-gradient-radius":{"type":"number","requires":[{"sky-type":"gradient"}],"default":90,"minimum":0,"maximum":180,"transition":false,"expression":{"interpolated":false,"parameters":["zoom"]},"property-type":"data-constant"},"sky-gradient":{"type":"color","default":["interpolate",["linear"],["sky-radial-progress"],0.8,"#87ceeb",1,"white"],"transition":false,"requires":[{"sky-type":"gradient"}],"expression":{"interpolated":true,"parameters":["sky-radial-progress"]},"property-type":"color-ramp"},"sky-atmosphere-halo-color":{"type":"color","default":"white","transition":false,"requires":[{"sky-type":"atmosphere"}],"property-type":"data-constant"},"sky-atmosphere-color":{"type":"color","default":"white","transition":false,"requires":[{"sky-type":"atmosphere"}],"property-type":"data-constant"},"sky-opacity":{"type":"number","default":1,"minimum":0,"maximum":1,"transition":true,"expression":{"interpolated":true,"parameters":["zoom"]},"property-type":"data-constant"}},"transition":{"duration":{"type":"number","default":300,"minimum":0,"units":"milliseconds"},"delay":{"type":"number","default":0,"minimum":0,"units":"milliseconds"}},"property-type":{"data-driven":{"type":"property-type"},"cross-faded":{"type":"property-type"},"cross-faded-data-driven":{"type":"property-type"},"color-ramp":{"type":"property-type"},"data-constant":{"type":"property-type"},"constant":{"type":"property-type"}},"promoteId":{"*":{"type":"string"}}}');

	function extend (output, ...inputs) {
	    for (const input of inputs) {
	        for (const k in input) {
	            output[k] = input[k];
	        }
	    }
	    return output;
	}

	function unbundle(value) {
	    if (value instanceof Number || value instanceof String || value instanceof Boolean) {
	        return value.valueOf();
	    } else {
	        return value;
	    }
	}
	function deepUnbundle(value) {
	    if (Array.isArray(value)) {
	        return value.map(deepUnbundle);
	    } else if (value instanceof Object && !(value instanceof Number || value instanceof String || value instanceof Boolean)) {
	        const unbundledValue = {};
	        for (const key in value) {
	            unbundledValue[key] = deepUnbundle(value[key]);
	        }
	        return unbundledValue;
	    }
	    return unbundle(value);
	}

	class ParsingError extends Error {
	    constructor(key, message) {
	        super(message);
	        this.message = message;
	        this.key = key;
	    }
	}
	var ParsingError$1 = ParsingError;

	class Scope {
	    constructor(parent, bindings = []) {
	        this.parent = parent;
	        this.bindings = {};
	        for (const [name, expression] of bindings) {
	            this.bindings[name] = expression;
	        }
	    }
	    concat(bindings) {
	        return new Scope(this, bindings);
	    }
	    get(name) {
	        if (this.bindings[name]) {
	            return this.bindings[name];
	        }
	        if (this.parent) {
	            return this.parent.get(name);
	        }
	        throw new Error(`${ name } not found in scope.`);
	    }
	    has(name) {
	        if (this.bindings[name])
	            return true;
	        return this.parent ? this.parent.has(name) : false;
	    }
	}
	var Scope$1 = Scope;

	const NullType = { kind: 'null' };
	const NumberType = { kind: 'number' };
	const StringType = { kind: 'string' };
	const BooleanType = { kind: 'boolean' };
	const ColorType = { kind: 'color' };
	const ObjectType = { kind: 'object' };
	const ValueType = { kind: 'value' };
	const ErrorType = { kind: 'error' };
	const CollatorType = { kind: 'collator' };
	const FormattedType = { kind: 'formatted' };
	const ResolvedImageType = { kind: 'resolvedImage' };
	function array$1(itemType, N) {
	    return {
	        kind: 'array',
	        itemType,
	        N
	    };
	}
	function toString$1(type) {
	    if (type.kind === 'array') {
	        const itemType = toString$1(type.itemType);
	        return typeof type.N === 'number' ? `array<${ itemType }, ${ type.N }>` : type.itemType.kind === 'value' ? 'array' : `array<${ itemType }>`;
	    } else {
	        return type.kind;
	    }
	}
	const valueMemberTypes = [
	    NullType,
	    NumberType,
	    StringType,
	    BooleanType,
	    ColorType,
	    FormattedType,
	    ObjectType,
	    array$1(ValueType),
	    ResolvedImageType
	];
	function checkSubtype(expected, t) {
	    if (t.kind === 'error') {
	        return null;
	    } else if (expected.kind === 'array') {
	        if (t.kind === 'array' && (t.N === 0 && t.itemType.kind === 'value' || !checkSubtype(expected.itemType, t.itemType)) && (typeof expected.N !== 'number' || expected.N === t.N)) {
	            return null;
	        }
	    } else if (expected.kind === t.kind) {
	        return null;
	    } else if (expected.kind === 'value') {
	        for (const memberType of valueMemberTypes) {
	            if (!checkSubtype(memberType, t)) {
	                return null;
	            }
	        }
	    }
	    return `Expected ${ toString$1(expected) } but found ${ toString$1(t) } instead.`;
	}
	function isValidType(provided, allowedTypes) {
	    return allowedTypes.some(t => t.kind === provided.kind);
	}
	function isValidNativeType(provided, allowedTypes) {
	    return allowedTypes.some(t => {
	        if (t === 'null') {
	            return provided === null;
	        } else if (t === 'array') {
	            return Array.isArray(provided);
	        } else if (t === 'object') {
	            return provided && !Array.isArray(provided) && typeof provided === 'object';
	        } else {
	            return t === typeof provided;
	        }
	    });
	}

	function createCommonjsModule(fn) {
	  var module = { exports: {} };
		return fn(module, module.exports), module.exports;
	}

	var csscolorparser = createCommonjsModule(function (module, exports) {
	var kCSSColorTable = {
	    'transparent': [
	        0,
	        0,
	        0,
	        0
	    ],
	    'aliceblue': [
	        240,
	        248,
	        255,
	        1
	    ],
	    'antiquewhite': [
	        250,
	        235,
	        215,
	        1
	    ],
	    'aqua': [
	        0,
	        255,
	        255,
	        1
	    ],
	    'aquamarine': [
	        127,
	        255,
	        212,
	        1
	    ],
	    'azure': [
	        240,
	        255,
	        255,
	        1
	    ],
	    'beige': [
	        245,
	        245,
	        220,
	        1
	    ],
	    'bisque': [
	        255,
	        228,
	        196,
	        1
	    ],
	    'black': [
	        0,
	        0,
	        0,
	        1
	    ],
	    'blanchedalmond': [
	        255,
	        235,
	        205,
	        1
	    ],
	    'blue': [
	        0,
	        0,
	        255,
	        1
	    ],
	    'blueviolet': [
	        138,
	        43,
	        226,
	        1
	    ],
	    'brown': [
	        165,
	        42,
	        42,
	        1
	    ],
	    'burlywood': [
	        222,
	        184,
	        135,
	        1
	    ],
	    'cadetblue': [
	        95,
	        158,
	        160,
	        1
	    ],
	    'chartreuse': [
	        127,
	        255,
	        0,
	        1
	    ],
	    'chocolate': [
	        210,
	        105,
	        30,
	        1
	    ],
	    'coral': [
	        255,
	        127,
	        80,
	        1
	    ],
	    'cornflowerblue': [
	        100,
	        149,
	        237,
	        1
	    ],
	    'cornsilk': [
	        255,
	        248,
	        220,
	        1
	    ],
	    'crimson': [
	        220,
	        20,
	        60,
	        1
	    ],
	    'cyan': [
	        0,
	        255,
	        255,
	        1
	    ],
	    'darkblue': [
	        0,
	        0,
	        139,
	        1
	    ],
	    'darkcyan': [
	        0,
	        139,
	        139,
	        1
	    ],
	    'darkgoldenrod': [
	        184,
	        134,
	        11,
	        1
	    ],
	    'darkgray': [
	        169,
	        169,
	        169,
	        1
	    ],
	    'darkgreen': [
	        0,
	        100,
	        0,
	        1
	    ],
	    'darkgrey': [
	        169,
	        169,
	        169,
	        1
	    ],
	    'darkkhaki': [
	        189,
	        183,
	        107,
	        1
	    ],
	    'darkmagenta': [
	        139,
	        0,
	        139,
	        1
	    ],
	    'darkolivegreen': [
	        85,
	        107,
	        47,
	        1
	    ],
	    'darkorange': [
	        255,
	        140,
	        0,
	        1
	    ],
	    'darkorchid': [
	        153,
	        50,
	        204,
	        1
	    ],
	    'darkred': [
	        139,
	        0,
	        0,
	        1
	    ],
	    'darksalmon': [
	        233,
	        150,
	        122,
	        1
	    ],
	    'darkseagreen': [
	        143,
	        188,
	        143,
	        1
	    ],
	    'darkslateblue': [
	        72,
	        61,
	        139,
	        1
	    ],
	    'darkslategray': [
	        47,
	        79,
	        79,
	        1
	    ],
	    'darkslategrey': [
	        47,
	        79,
	        79,
	        1
	    ],
	    'darkturquoise': [
	        0,
	        206,
	        209,
	        1
	    ],
	    'darkviolet': [
	        148,
	        0,
	        211,
	        1
	    ],
	    'deeppink': [
	        255,
	        20,
	        147,
	        1
	    ],
	    'deepskyblue': [
	        0,
	        191,
	        255,
	        1
	    ],
	    'dimgray': [
	        105,
	        105,
	        105,
	        1
	    ],
	    'dimgrey': [
	        105,
	        105,
	        105,
	        1
	    ],
	    'dodgerblue': [
	        30,
	        144,
	        255,
	        1
	    ],
	    'firebrick': [
	        178,
	        34,
	        34,
	        1
	    ],
	    'floralwhite': [
	        255,
	        250,
	        240,
	        1
	    ],
	    'forestgreen': [
	        34,
	        139,
	        34,
	        1
	    ],
	    'fuchsia': [
	        255,
	        0,
	        255,
	        1
	    ],
	    'gainsboro': [
	        220,
	        220,
	        220,
	        1
	    ],
	    'ghostwhite': [
	        248,
	        248,
	        255,
	        1
	    ],
	    'gold': [
	        255,
	        215,
	        0,
	        1
	    ],
	    'goldenrod': [
	        218,
	        165,
	        32,
	        1
	    ],
	    'gray': [
	        128,
	        128,
	        128,
	        1
	    ],
	    'green': [
	        0,
	        128,
	        0,
	        1
	    ],
	    'greenyellow': [
	        173,
	        255,
	        47,
	        1
	    ],
	    'grey': [
	        128,
	        128,
	        128,
	        1
	    ],
	    'honeydew': [
	        240,
	        255,
	        240,
	        1
	    ],
	    'hotpink': [
	        255,
	        105,
	        180,
	        1
	    ],
	    'indianred': [
	        205,
	        92,
	        92,
	        1
	    ],
	    'indigo': [
	        75,
	        0,
	        130,
	        1
	    ],
	    'ivory': [
	        255,
	        255,
	        240,
	        1
	    ],
	    'khaki': [
	        240,
	        230,
	        140,
	        1
	    ],
	    'lavender': [
	        230,
	        230,
	        250,
	        1
	    ],
	    'lavenderblush': [
	        255,
	        240,
	        245,
	        1
	    ],
	    'lawngreen': [
	        124,
	        252,
	        0,
	        1
	    ],
	    'lemonchiffon': [
	        255,
	        250,
	        205,
	        1
	    ],
	    'lightblue': [
	        173,
	        216,
	        230,
	        1
	    ],
	    'lightcoral': [
	        240,
	        128,
	        128,
	        1
	    ],
	    'lightcyan': [
	        224,
	        255,
	        255,
	        1
	    ],
	    'lightgoldenrodyellow': [
	        250,
	        250,
	        210,
	        1
	    ],
	    'lightgray': [
	        211,
	        211,
	        211,
	        1
	    ],
	    'lightgreen': [
	        144,
	        238,
	        144,
	        1
	    ],
	    'lightgrey': [
	        211,
	        211,
	        211,
	        1
	    ],
	    'lightpink': [
	        255,
	        182,
	        193,
	        1
	    ],
	    'lightsalmon': [
	        255,
	        160,
	        122,
	        1
	    ],
	    'lightseagreen': [
	        32,
	        178,
	        170,
	        1
	    ],
	    'lightskyblue': [
	        135,
	        206,
	        250,
	        1
	    ],
	    'lightslategray': [
	        119,
	        136,
	        153,
	        1
	    ],
	    'lightslategrey': [
	        119,
	        136,
	        153,
	        1
	    ],
	    'lightsteelblue': [
	        176,
	        196,
	        222,
	        1
	    ],
	    'lightyellow': [
	        255,
	        255,
	        224,
	        1
	    ],
	    'lime': [
	        0,
	        255,
	        0,
	        1
	    ],
	    'limegreen': [
	        50,
	        205,
	        50,
	        1
	    ],
	    'linen': [
	        250,
	        240,
	        230,
	        1
	    ],
	    'magenta': [
	        255,
	        0,
	        255,
	        1
	    ],
	    'maroon': [
	        128,
	        0,
	        0,
	        1
	    ],
	    'mediumaquamarine': [
	        102,
	        205,
	        170,
	        1
	    ],
	    'mediumblue': [
	        0,
	        0,
	        205,
	        1
	    ],
	    'mediumorchid': [
	        186,
	        85,
	        211,
	        1
	    ],
	    'mediumpurple': [
	        147,
	        112,
	        219,
	        1
	    ],
	    'mediumseagreen': [
	        60,
	        179,
	        113,
	        1
	    ],
	    'mediumslateblue': [
	        123,
	        104,
	        238,
	        1
	    ],
	    'mediumspringgreen': [
	        0,
	        250,
	        154,
	        1
	    ],
	    'mediumturquoise': [
	        72,
	        209,
	        204,
	        1
	    ],
	    'mediumvioletred': [
	        199,
	        21,
	        133,
	        1
	    ],
	    'midnightblue': [
	        25,
	        25,
	        112,
	        1
	    ],
	    'mintcream': [
	        245,
	        255,
	        250,
	        1
	    ],
	    'mistyrose': [
	        255,
	        228,
	        225,
	        1
	    ],
	    'moccasin': [
	        255,
	        228,
	        181,
	        1
	    ],
	    'navajowhite': [
	        255,
	        222,
	        173,
	        1
	    ],
	    'navy': [
	        0,
	        0,
	        128,
	        1
	    ],
	    'oldlace': [
	        253,
	        245,
	        230,
	        1
	    ],
	    'olive': [
	        128,
	        128,
	        0,
	        1
	    ],
	    'olivedrab': [
	        107,
	        142,
	        35,
	        1
	    ],
	    'orange': [
	        255,
	        165,
	        0,
	        1
	    ],
	    'orangered': [
	        255,
	        69,
	        0,
	        1
	    ],
	    'orchid': [
	        218,
	        112,
	        214,
	        1
	    ],
	    'palegoldenrod': [
	        238,
	        232,
	        170,
	        1
	    ],
	    'palegreen': [
	        152,
	        251,
	        152,
	        1
	    ],
	    'paleturquoise': [
	        175,
	        238,
	        238,
	        1
	    ],
	    'palevioletred': [
	        219,
	        112,
	        147,
	        1
	    ],
	    'papayawhip': [
	        255,
	        239,
	        213,
	        1
	    ],
	    'peachpuff': [
	        255,
	        218,
	        185,
	        1
	    ],
	    'peru': [
	        205,
	        133,
	        63,
	        1
	    ],
	    'pink': [
	        255,
	        192,
	        203,
	        1
	    ],
	    'plum': [
	        221,
	        160,
	        221,
	        1
	    ],
	    'powderblue': [
	        176,
	        224,
	        230,
	        1
	    ],
	    'purple': [
	        128,
	        0,
	        128,
	        1
	    ],
	    'rebeccapurple': [
	        102,
	        51,
	        153,
	        1
	    ],
	    'red': [
	        255,
	        0,
	        0,
	        1
	    ],
	    'rosybrown': [
	        188,
	        143,
	        143,
	        1
	    ],
	    'royalblue': [
	        65,
	        105,
	        225,
	        1
	    ],
	    'saddlebrown': [
	        139,
	        69,
	        19,
	        1
	    ],
	    'salmon': [
	        250,
	        128,
	        114,
	        1
	    ],
	    'sandybrown': [
	        244,
	        164,
	        96,
	        1
	    ],
	    'seagreen': [
	        46,
	        139,
	        87,
	        1
	    ],
	    'seashell': [
	        255,
	        245,
	        238,
	        1
	    ],
	    'sienna': [
	        160,
	        82,
	        45,
	        1
	    ],
	    'silver': [
	        192,
	        192,
	        192,
	        1
	    ],
	    'skyblue': [
	        135,
	        206,
	        235,
	        1
	    ],
	    'slateblue': [
	        106,
	        90,
	        205,
	        1
	    ],
	    'slategray': [
	        112,
	        128,
	        144,
	        1
	    ],
	    'slategrey': [
	        112,
	        128,
	        144,
	        1
	    ],
	    'snow': [
	        255,
	        250,
	        250,
	        1
	    ],
	    'springgreen': [
	        0,
	        255,
	        127,
	        1
	    ],
	    'steelblue': [
	        70,
	        130,
	        180,
	        1
	    ],
	    'tan': [
	        210,
	        180,
	        140,
	        1
	    ],
	    'teal': [
	        0,
	        128,
	        128,
	        1
	    ],
	    'thistle': [
	        216,
	        191,
	        216,
	        1
	    ],
	    'tomato': [
	        255,
	        99,
	        71,
	        1
	    ],
	    'turquoise': [
	        64,
	        224,
	        208,
	        1
	    ],
	    'violet': [
	        238,
	        130,
	        238,
	        1
	    ],
	    'wheat': [
	        245,
	        222,
	        179,
	        1
	    ],
	    'white': [
	        255,
	        255,
	        255,
	        1
	    ],
	    'whitesmoke': [
	        245,
	        245,
	        245,
	        1
	    ],
	    'yellow': [
	        255,
	        255,
	        0,
	        1
	    ],
	    'yellowgreen': [
	        154,
	        205,
	        50,
	        1
	    ]
	};
	function clamp_css_byte(i) {
	    i = Math.round(i);
	    return i < 0 ? 0 : i > 255 ? 255 : i;
	}
	function clamp_css_float(f) {
	    return f < 0 ? 0 : f > 1 ? 1 : f;
	}
	function parse_css_int(str) {
	    if (str[str.length - 1] === '%')
	        return clamp_css_byte(parseFloat(str) / 100 * 255);
	    return clamp_css_byte(parseInt(str));
	}
	function parse_css_float(str) {
	    if (str[str.length - 1] === '%')
	        return clamp_css_float(parseFloat(str) / 100);
	    return clamp_css_float(parseFloat(str));
	}
	function css_hue_to_rgb(m1, m2, h) {
	    if (h < 0)
	        h += 1;
	    else if (h > 1)
	        h -= 1;
	    if (h * 6 < 1)
	        return m1 + (m2 - m1) * h * 6;
	    if (h * 2 < 1)
	        return m2;
	    if (h * 3 < 2)
	        return m1 + (m2 - m1) * (2 / 3 - h) * 6;
	    return m1;
	}
	function parseCSSColor(css_str) {
	    var str = css_str.replace(/ /g, '').toLowerCase();
	    if (str in kCSSColorTable)
	        return kCSSColorTable[str].slice();
	    if (str[0] === '#') {
	        if (str.length === 4) {
	            var iv = parseInt(str.substr(1), 16);
	            if (!(iv >= 0 && iv <= 4095))
	                return null;
	            return [
	                (iv & 3840) >> 4 | (iv & 3840) >> 8,
	                iv & 240 | (iv & 240) >> 4,
	                iv & 15 | (iv & 15) << 4,
	                1
	            ];
	        } else if (str.length === 7) {
	            var iv = parseInt(str.substr(1), 16);
	            if (!(iv >= 0 && iv <= 16777215))
	                return null;
	            return [
	                (iv & 16711680) >> 16,
	                (iv & 65280) >> 8,
	                iv & 255,
	                1
	            ];
	        }
	        return null;
	    }
	    var op = str.indexOf('('), ep = str.indexOf(')');
	    if (op !== -1 && ep + 1 === str.length) {
	        var fname = str.substr(0, op);
	        var params = str.substr(op + 1, ep - (op + 1)).split(',');
	        var alpha = 1;
	        switch (fname) {
	        case 'rgba':
	            if (params.length !== 4)
	                return null;
	            alpha = parse_css_float(params.pop());
	        case 'rgb':
	            if (params.length !== 3)
	                return null;
	            return [
	                parse_css_int(params[0]),
	                parse_css_int(params[1]),
	                parse_css_int(params[2]),
	                alpha
	            ];
	        case 'hsla':
	            if (params.length !== 4)
	                return null;
	            alpha = parse_css_float(params.pop());
	        case 'hsl':
	            if (params.length !== 3)
	                return null;
	            var h = (parseFloat(params[0]) % 360 + 360) % 360 / 360;
	            var s = parse_css_float(params[1]);
	            var l = parse_css_float(params[2]);
	            var m2 = l <= 0.5 ? l * (s + 1) : l + s - l * s;
	            var m1 = l * 2 - m2;
	            return [
	                clamp_css_byte(css_hue_to_rgb(m1, m2, h + 1 / 3) * 255),
	                clamp_css_byte(css_hue_to_rgb(m1, m2, h) * 255),
	                clamp_css_byte(css_hue_to_rgb(m1, m2, h - 1 / 3) * 255),
	                alpha
	            ];
	        default:
	            return null;
	        }
	    }
	    return null;
	}
	try {
	    exports.parseCSSColor = parseCSSColor;
	} catch (e) {
	}
	});

	class Color {
	    constructor(r, g, b, a = 1) {
	        this.r = r;
	        this.g = g;
	        this.b = b;
	        this.a = a;
	    }
	    static parse(input) {
	        if (!input) {
	            return undefined;
	        }
	        if (input instanceof Color) {
	            return input;
	        }
	        if (typeof input !== 'string') {
	            return undefined;
	        }
	        const rgba = csscolorparser.parseCSSColor(input);
	        if (!rgba) {
	            return undefined;
	        }
	        return new Color(rgba[0] / 255 * rgba[3], rgba[1] / 255 * rgba[3], rgba[2] / 255 * rgba[3], rgba[3]);
	    }
	    toString() {
	        const [r, g, b, a] = this.toArray();
	        return `rgba(${ Math.round(r) },${ Math.round(g) },${ Math.round(b) },${ a })`;
	    }
	    toArray() {
	        const {r, g, b, a} = this;
	        return a === 0 ? [
	            0,
	            0,
	            0,
	            0
	        ] : [
	            r * 255 / a,
	            g * 255 / a,
	            b * 255 / a,
	            a
	        ];
	    }
	    toArray01() {
	        const {r, g, b, a} = this;
	        return a === 0 ? [
	            0,
	            0,
	            0,
	            0
	        ] : [
	            r / a,
	            g / a,
	            b / a,
	            a
	        ];
	    }
	    toArray01PremultipliedAlpha() {
	        const {r, g, b, a} = this;
	        return [
	            r,
	            g,
	            b,
	            a
	        ];
	    }
	}
	Color.black = new Color(0, 0, 0, 1);
	Color.white = new Color(1, 1, 1, 1);
	Color.transparent = new Color(0, 0, 0, 0);
	Color.red = new Color(1, 0, 0, 1);
	Color.blue = new Color(0, 0, 1, 1);
	var Color$1 = Color;

	class Collator {
	    constructor(caseSensitive, diacriticSensitive, locale) {
	        if (caseSensitive)
	            this.sensitivity = diacriticSensitive ? 'variant' : 'case';
	        else
	            this.sensitivity = diacriticSensitive ? 'accent' : 'base';
	        this.locale = locale;
	        this.collator = new Intl.Collator(this.locale ? this.locale : [], {
	            sensitivity: this.sensitivity,
	            usage: 'search'
	        });
	    }
	    compare(lhs, rhs) {
	        return this.collator.compare(lhs, rhs);
	    }
	    resolvedLocale() {
	        return new Intl.Collator(this.locale ? this.locale : []).resolvedOptions().locale;
	    }
	}

	class FormattedSection {
	    constructor(text, image, scale, fontStack, textColor) {
	        this.text = text.normalize ? text.normalize() : text;
	        this.image = image;
	        this.scale = scale;
	        this.fontStack = fontStack;
	        this.textColor = textColor;
	    }
	}
	class Formatted {
	    constructor(sections) {
	        this.sections = sections;
	    }
	    static fromString(unformatted) {
	        return new Formatted([new FormattedSection(unformatted, null, null, null, null)]);
	    }
	    isEmpty() {
	        if (this.sections.length === 0)
	            return true;
	        return !this.sections.some(section => section.text.length !== 0 || section.image && section.image.name.length !== 0);
	    }
	    static factory(text) {
	        if (text instanceof Formatted) {
	            return text;
	        } else {
	            return Formatted.fromString(text);
	        }
	    }
	    toString() {
	        if (this.sections.length === 0)
	            return '';
	        return this.sections.map(section => section.text).join('');
	    }
	    serialize() {
	        const serialized = ['format'];
	        for (const section of this.sections) {
	            if (section.image) {
	                serialized.push([
	                    'image',
	                    section.image.name
	                ]);
	                continue;
	            }
	            serialized.push(section.text);
	            const options = {};
	            if (section.fontStack) {
	                options['text-font'] = [
	                    'literal',
	                    section.fontStack.split(',')
	                ];
	            }
	            if (section.scale) {
	                options['font-scale'] = section.scale;
	            }
	            if (section.textColor) {
	                options['text-color'] = ['rgba'].concat(section.textColor.toArray());
	            }
	            serialized.push(options);
	        }
	        return serialized;
	    }
	}

	class ResolvedImage {
	    constructor(options) {
	        this.name = options.name;
	        this.available = options.available;
	    }
	    toString() {
	        return this.name;
	    }
	    static fromString(name) {
	        if (!name)
	            return null;
	        return new ResolvedImage({
	            name,
	            available: false
	        });
	    }
	    serialize() {
	        return [
	            'image',
	            this.name
	        ];
	    }
	}

	function validateRGBA(r, g, b, a) {
	    if (!(typeof r === 'number' && r >= 0 && r <= 255 && typeof g === 'number' && g >= 0 && g <= 255 && typeof b === 'number' && b >= 0 && b <= 255)) {
	        const value = typeof a === 'number' ? [
	            r,
	            g,
	            b,
	            a
	        ] : [
	            r,
	            g,
	            b
	        ];
	        return `Invalid rgba value [${ value.join(', ') }]: 'r', 'g', and 'b' must be between 0 and 255.`;
	    }
	    if (!(typeof a === 'undefined' || typeof a === 'number' && a >= 0 && a <= 1)) {
	        return `Invalid rgba value [${ [
	            r,
	            g,
	            b,
	            a
	        ].join(', ') }]: 'a' must be between 0 and 1.`;
	    }
	    return null;
	}
	function isValue(mixed) {
	    if (mixed === null) {
	        return true;
	    } else if (typeof mixed === 'string') {
	        return true;
	    } else if (typeof mixed === 'boolean') {
	        return true;
	    } else if (typeof mixed === 'number') {
	        return true;
	    } else if (mixed instanceof Color$1) {
	        return true;
	    } else if (mixed instanceof Collator) {
	        return true;
	    } else if (mixed instanceof Formatted) {
	        return true;
	    } else if (mixed instanceof ResolvedImage) {
	        return true;
	    } else if (Array.isArray(mixed)) {
	        for (const item of mixed) {
	            if (!isValue(item)) {
	                return false;
	            }
	        }
	        return true;
	    } else if (typeof mixed === 'object') {
	        for (const key in mixed) {
	            if (!isValue(mixed[key])) {
	                return false;
	            }
	        }
	        return true;
	    } else {
	        return false;
	    }
	}
	function typeOf(value) {
	    if (value === null) {
	        return NullType;
	    } else if (typeof value === 'string') {
	        return StringType;
	    } else if (typeof value === 'boolean') {
	        return BooleanType;
	    } else if (typeof value === 'number') {
	        return NumberType;
	    } else if (value instanceof Color$1) {
	        return ColorType;
	    } else if (value instanceof Collator) {
	        return CollatorType;
	    } else if (value instanceof Formatted) {
	        return FormattedType;
	    } else if (value instanceof ResolvedImage) {
	        return ResolvedImageType;
	    } else if (Array.isArray(value)) {
	        const length = value.length;
	        let itemType;
	        for (const item of value) {
	            const t = typeOf(item);
	            if (!itemType) {
	                itemType = t;
	            } else if (itemType === t) {
	                continue;
	            } else {
	                itemType = ValueType;
	                break;
	            }
	        }
	        return array$1(itemType || ValueType, length);
	    } else {
	        return ObjectType;
	    }
	}
	function toString(value) {
	    const type = typeof value;
	    if (value === null) {
	        return '';
	    } else if (type === 'string' || type === 'number' || type === 'boolean') {
	        return String(value);
	    } else if (value instanceof Color$1 || value instanceof Formatted || value instanceof ResolvedImage) {
	        return value.toString();
	    } else {
	        return JSON.stringify(value);
	    }
	}

	class Literal {
	    constructor(type, value) {
	        this.type = type;
	        this.value = value;
	    }
	    static parse(args, context) {
	        if (args.length !== 2)
	            return context.error(`'literal' expression requires exactly one argument, but found ${ args.length - 1 } instead.`);
	        if (!isValue(args[1]))
	            return context.error(`invalid value`);
	        const value = args[1];
	        let type = typeOf(value);
	        const expected = context.expectedType;
	        if (type.kind === 'array' && type.N === 0 && expected && expected.kind === 'array' && (typeof expected.N !== 'number' || expected.N === 0)) {
	            type = expected;
	        }
	        return new Literal(type, value);
	    }
	    evaluate() {
	        return this.value;
	    }
	    eachChild() {
	    }
	    outputDefined() {
	        return true;
	    }
	    serialize() {
	        if (this.type.kind === 'array' || this.type.kind === 'object') {
	            return [
	                'literal',
	                this.value
	            ];
	        } else if (this.value instanceof Color$1) {
	            return ['rgba'].concat(this.value.toArray());
	        } else if (this.value instanceof Formatted) {
	            return this.value.serialize();
	        } else {
	            return this.value;
	        }
	    }
	}
	var Literal$1 = Literal;

	class RuntimeError {
	    constructor(message) {
	        this.name = 'ExpressionEvaluationError';
	        this.message = message;
	    }
	    toJSON() {
	        return this.message;
	    }
	}
	var RuntimeError$1 = RuntimeError;

	const types$1 = {
	    string: StringType,
	    number: NumberType,
	    boolean: BooleanType,
	    object: ObjectType
	};
	class Assertion {
	    constructor(type, args) {
	        this.type = type;
	        this.args = args;
	    }
	    static parse(args, context) {
	        if (args.length < 2)
	            return context.error(`Expected at least one argument.`);
	        let i = 1;
	        let type;
	        const name = args[0];
	        if (name === 'array') {
	            let itemType;
	            if (args.length > 2) {
	                const type = args[1];
	                if (typeof type !== 'string' || !(type in types$1) || type === 'object')
	                    return context.error('The item type argument of "array" must be one of string, number, boolean', 1);
	                itemType = types$1[type];
	                i++;
	            } else {
	                itemType = ValueType;
	            }
	            let N;
	            if (args.length > 3) {
	                if (args[2] !== null && (typeof args[2] !== 'number' || args[2] < 0 || args[2] !== Math.floor(args[2]))) {
	                    return context.error('The length argument to "array" must be a positive integer literal', 2);
	                }
	                N = args[2];
	                i++;
	            }
	            type = array$1(itemType, N);
	        } else {
	            type = types$1[name];
	        }
	        const parsed = [];
	        for (; i < args.length; i++) {
	            const input = context.parse(args[i], i, ValueType);
	            if (!input)
	                return null;
	            parsed.push(input);
	        }
	        return new Assertion(type, parsed);
	    }
	    evaluate(ctx) {
	        for (let i = 0; i < this.args.length; i++) {
	            const value = this.args[i].evaluate(ctx);
	            const error = checkSubtype(this.type, typeOf(value));
	            if (!error) {
	                return value;
	            } else if (i === this.args.length - 1) {
	                throw new RuntimeError$1(`Expected value to be of type ${ toString$1(this.type) }, but found ${ toString$1(typeOf(value)) } instead.`);
	            }
	        }
	        return null;
	    }
	    eachChild(fn) {
	        this.args.forEach(fn);
	    }
	    outputDefined() {
	        return this.args.every(arg => arg.outputDefined());
	    }
	    serialize() {
	        const type = this.type;
	        const serialized = [type.kind];
	        if (type.kind === 'array') {
	            const itemType = type.itemType;
	            if (itemType.kind === 'string' || itemType.kind === 'number' || itemType.kind === 'boolean') {
	                serialized.push(itemType.kind);
	                const N = type.N;
	                if (typeof N === 'number' || this.args.length > 1) {
	                    serialized.push(N);
	                }
	            }
	        }
	        return serialized.concat(this.args.map(arg => arg.serialize()));
	    }
	}
	var Assertion$1 = Assertion;

	class FormatExpression {
	    constructor(sections) {
	        this.type = FormattedType;
	        this.sections = sections;
	    }
	    static parse(args, context) {
	        if (args.length < 2) {
	            return context.error(`Expected at least one argument.`);
	        }
	        const firstArg = args[1];
	        if (!Array.isArray(firstArg) && typeof firstArg === 'object') {
	            return context.error(`First argument must be an image or text section.`);
	        }
	        const sections = [];
	        let nextTokenMayBeObject = false;
	        for (let i = 1; i <= args.length - 1; ++i) {
	            const arg = args[i];
	            if (nextTokenMayBeObject && typeof arg === 'object' && !Array.isArray(arg)) {
	                nextTokenMayBeObject = false;
	                let scale = null;
	                if (arg['font-scale']) {
	                    scale = context.parse(arg['font-scale'], 1, NumberType);
	                    if (!scale)
	                        return null;
	                }
	                let font = null;
	                if (arg['text-font']) {
	                    font = context.parse(arg['text-font'], 1, array$1(StringType));
	                    if (!font)
	                        return null;
	                }
	                let textColor = null;
	                if (arg['text-color']) {
	                    textColor = context.parse(arg['text-color'], 1, ColorType);
	                    if (!textColor)
	                        return null;
	                }
	                const lastExpression = sections[sections.length - 1];
	                lastExpression.scale = scale;
	                lastExpression.font = font;
	                lastExpression.textColor = textColor;
	            } else {
	                const content = context.parse(args[i], 1, ValueType);
	                if (!content)
	                    return null;
	                const kind = content.type.kind;
	                if (kind !== 'string' && kind !== 'value' && kind !== 'null' && kind !== 'resolvedImage')
	                    return context.error(`Formatted text type must be 'string', 'value', 'image' or 'null'.`);
	                nextTokenMayBeObject = true;
	                sections.push({
	                    content,
	                    scale: null,
	                    font: null,
	                    textColor: null
	                });
	            }
	        }
	        return new FormatExpression(sections);
	    }
	    evaluate(ctx) {
	        const evaluateSection = section => {
	            const evaluatedContent = section.content.evaluate(ctx);
	            if (typeOf(evaluatedContent) === ResolvedImageType) {
	                return new FormattedSection('', evaluatedContent, null, null, null);
	            }
	            return new FormattedSection(toString(evaluatedContent), null, section.scale ? section.scale.evaluate(ctx) : null, section.font ? section.font.evaluate(ctx).join(',') : null, section.textColor ? section.textColor.evaluate(ctx) : null);
	        };
	        return new Formatted(this.sections.map(evaluateSection));
	    }
	    eachChild(fn) {
	        for (const section of this.sections) {
	            fn(section.content);
	            if (section.scale) {
	                fn(section.scale);
	            }
	            if (section.font) {
	                fn(section.font);
	            }
	            if (section.textColor) {
	                fn(section.textColor);
	            }
	        }
	    }
	    outputDefined() {
	        return false;
	    }
	    serialize() {
	        const serialized = ['format'];
	        for (const section of this.sections) {
	            serialized.push(section.content.serialize());
	            const options = {};
	            if (section.scale) {
	                options['font-scale'] = section.scale.serialize();
	            }
	            if (section.font) {
	                options['text-font'] = section.font.serialize();
	            }
	            if (section.textColor) {
	                options['text-color'] = section.textColor.serialize();
	            }
	            serialized.push(options);
	        }
	        return serialized;
	    }
	}

	class ImageExpression {
	    constructor(input) {
	        this.type = ResolvedImageType;
	        this.input = input;
	    }
	    static parse(args, context) {
	        if (args.length !== 2) {
	            return context.error(`Expected two arguments.`);
	        }
	        const name = context.parse(args[1], 1, StringType);
	        if (!name)
	            return context.error(`No image name provided.`);
	        return new ImageExpression(name);
	    }
	    evaluate(ctx) {
	        const evaluatedImageName = this.input.evaluate(ctx);
	        const value = ResolvedImage.fromString(evaluatedImageName);
	        if (value && ctx.availableImages)
	            value.available = ctx.availableImages.indexOf(evaluatedImageName) > -1;
	        return value;
	    }
	    eachChild(fn) {
	        fn(this.input);
	    }
	    outputDefined() {
	        return false;
	    }
	    serialize() {
	        return [
	            'image',
	            this.input.serialize()
	        ];
	    }
	}

	const types = {
	    'to-boolean': BooleanType,
	    'to-color': ColorType,
	    'to-number': NumberType,
	    'to-string': StringType
	};
	class Coercion {
	    constructor(type, args) {
	        this.type = type;
	        this.args = args;
	    }
	    static parse(args, context) {
	        if (args.length < 2)
	            return context.error(`Expected at least one argument.`);
	        const name = args[0];
	        if ((name === 'to-boolean' || name === 'to-string') && args.length !== 2)
	            return context.error(`Expected one argument.`);
	        const type = types[name];
	        const parsed = [];
	        for (let i = 1; i < args.length; i++) {
	            const input = context.parse(args[i], i, ValueType);
	            if (!input)
	                return null;
	            parsed.push(input);
	        }
	        return new Coercion(type, parsed);
	    }
	    evaluate(ctx) {
	        if (this.type.kind === 'boolean') {
	            return Boolean(this.args[0].evaluate(ctx));
	        } else if (this.type.kind === 'color') {
	            let input;
	            let error;
	            for (const arg of this.args) {
	                input = arg.evaluate(ctx);
	                error = null;
	                if (input instanceof Color$1) {
	                    return input;
	                } else if (typeof input === 'string') {
	                    const c = ctx.parseColor(input);
	                    if (c)
	                        return c;
	                } else if (Array.isArray(input)) {
	                    if (input.length < 3 || input.length > 4) {
	                        error = `Invalid rbga value ${ JSON.stringify(input) }: expected an array containing either three or four numeric values.`;
	                    } else {
	                        error = validateRGBA(input[0], input[1], input[2], input[3]);
	                    }
	                    if (!error) {
	                        return new Color$1(input[0] / 255, input[1] / 255, input[2] / 255, input[3]);
	                    }
	                }
	            }
	            throw new RuntimeError$1(error || `Could not parse color from value '${ typeof input === 'string' ? input : String(JSON.stringify(input)) }'`);
	        } else if (this.type.kind === 'number') {
	            let value = null;
	            for (const arg of this.args) {
	                value = arg.evaluate(ctx);
	                if (value === null)
	                    return 0;
	                const num = Number(value);
	                if (isNaN(num))
	                    continue;
	                return num;
	            }
	            throw new RuntimeError$1(`Could not convert ${ JSON.stringify(value) } to number.`);
	        } else if (this.type.kind === 'formatted') {
	            return Formatted.fromString(toString(this.args[0].evaluate(ctx)));
	        } else if (this.type.kind === 'resolvedImage') {
	            return ResolvedImage.fromString(toString(this.args[0].evaluate(ctx)));
	        } else {
	            return toString(this.args[0].evaluate(ctx));
	        }
	    }
	    eachChild(fn) {
	        this.args.forEach(fn);
	    }
	    outputDefined() {
	        return this.args.every(arg => arg.outputDefined());
	    }
	    serialize() {
	        if (this.type.kind === 'formatted') {
	            return new FormatExpression([{
	                    content: this.args[0],
	                    scale: null,
	                    font: null,
	                    textColor: null
	                }]).serialize();
	        }
	        if (this.type.kind === 'resolvedImage') {
	            return new ImageExpression(this.args[0]).serialize();
	        }
	        const serialized = [`to-${ this.type.kind }`];
	        this.eachChild(child => {
	            serialized.push(child.serialize());
	        });
	        return serialized;
	    }
	}
	var Coercion$1 = Coercion;

	const geometryTypes = [
	    'Unknown',
	    'Point',
	    'LineString',
	    'Polygon'
	];
	class EvaluationContext {
	    constructor() {
	        this.globals = null;
	        this.feature = null;
	        this.featureState = null;
	        this.formattedSection = null;
	        this._parseColorCache = {};
	        this.availableImages = null;
	        this.canonical = null;
	        this.featureTileCoord = null;
	        this.featureDistanceData = null;
	    }
	    id() {
	        return this.feature && 'id' in this.feature && this.feature.id ? this.feature.id : null;
	    }
	    geometryType() {
	        return this.feature ? typeof this.feature.type === 'number' ? geometryTypes[this.feature.type] : this.feature.type : null;
	    }
	    geometry() {
	        return this.feature && 'geometry' in this.feature ? this.feature.geometry : null;
	    }
	    canonicalID() {
	        return this.canonical;
	    }
	    properties() {
	        return this.feature && this.feature.properties || {};
	    }
	    distanceFromCenter() {
	        if (this.featureTileCoord && this.featureDistanceData) {
	            const c = this.featureDistanceData.center;
	            const scale = this.featureDistanceData.scale;
	            const {x, y} = this.featureTileCoord;
	            const dX = x * scale - c[0];
	            const dY = y * scale - c[1];
	            const bX = this.featureDistanceData.bearing[0];
	            const bY = this.featureDistanceData.bearing[1];
	            const dist = bX * dX + bY * dY;
	            return dist;
	        }
	        return 0;
	    }
	    parseColor(input) {
	        let cached = this._parseColorCache[input];
	        if (!cached) {
	            cached = this._parseColorCache[input] = Color$1.parse(input);
	        }
	        return cached;
	    }
	}
	var EvaluationContext$1 = EvaluationContext;

	class CompoundExpression {
	    constructor(name, type, evaluate, args) {
	        this.name = name;
	        this.type = type;
	        this._evaluate = evaluate;
	        this.args = args;
	    }
	    evaluate(ctx) {
	        return this._evaluate(ctx, this.args);
	    }
	    eachChild(fn) {
	        this.args.forEach(fn);
	    }
	    outputDefined() {
	        return false;
	    }
	    serialize() {
	        return [this.name].concat(this.args.map(arg => arg.serialize()));
	    }
	    static parse(args, context) {
	        const op = args[0];
	        const definition = CompoundExpression.definitions[op];
	        if (!definition) {
	            return context.error(`Unknown expression "${ op }". If you wanted a literal array, use ["literal", [...]].`, 0);
	        }
	        const type = Array.isArray(definition) ? definition[0] : definition.type;
	        const availableOverloads = Array.isArray(definition) ? [[
	                definition[1],
	                definition[2]
	            ]] : definition.overloads;
	        const overloads = availableOverloads.filter(([signature]) => !Array.isArray(signature) || signature.length === args.length - 1);
	        let signatureContext = null;
	        for (const [params, evaluate] of overloads) {
	            signatureContext = new ParsingContext$1(context.registry, context.path, null, context.scope);
	            const parsedArgs = [];
	            let argParseFailed = false;
	            for (let i = 1; i < args.length; i++) {
	                const arg = args[i];
	                const expectedType = Array.isArray(params) ? params[i - 1] : params.type;
	                const parsed = signatureContext.parse(arg, 1 + parsedArgs.length, expectedType);
	                if (!parsed) {
	                    argParseFailed = true;
	                    break;
	                }
	                parsedArgs.push(parsed);
	            }
	            if (argParseFailed) {
	                continue;
	            }
	            if (Array.isArray(params)) {
	                if (params.length !== parsedArgs.length) {
	                    signatureContext.error(`Expected ${ params.length } arguments, but found ${ parsedArgs.length } instead.`);
	                    continue;
	                }
	            }
	            for (let i = 0; i < parsedArgs.length; i++) {
	                const expected = Array.isArray(params) ? params[i] : params.type;
	                const arg = parsedArgs[i];
	                signatureContext.concat(i + 1).checkSubtype(expected, arg.type);
	            }
	            if (signatureContext.errors.length === 0) {
	                return new CompoundExpression(op, type, evaluate, parsedArgs);
	            }
	        }
	        if (overloads.length === 1) {
	            context.errors.push(...signatureContext.errors);
	        } else {
	            const expected = overloads.length ? overloads : availableOverloads;
	            const signatures = expected.map(([params]) => stringifySignature(params)).join(' | ');
	            const actualTypes = [];
	            for (let i = 1; i < args.length; i++) {
	                const parsed = context.parse(args[i], 1 + actualTypes.length);
	                if (!parsed)
	                    return null;
	                actualTypes.push(toString$1(parsed.type));
	            }
	            context.error(`Expected arguments of type ${ signatures }, but found (${ actualTypes.join(', ') }) instead.`);
	        }
	        return null;
	    }
	    static register(registry, definitions) {
	        CompoundExpression.definitions = definitions;
	        for (const name in definitions) {
	            registry[name] = CompoundExpression;
	        }
	    }
	}
	function stringifySignature(signature) {
	    if (Array.isArray(signature)) {
	        return `(${ signature.map(toString$1).join(', ') })`;
	    } else {
	        return `(${ toString$1(signature.type) }...)`;
	    }
	}
	var CompoundExpression$1 = CompoundExpression;

	class CollatorExpression {
	    constructor(caseSensitive, diacriticSensitive, locale) {
	        this.type = CollatorType;
	        this.locale = locale;
	        this.caseSensitive = caseSensitive;
	        this.diacriticSensitive = diacriticSensitive;
	    }
	    static parse(args, context) {
	        if (args.length !== 2)
	            return context.error(`Expected one argument.`);
	        const options = args[1];
	        if (typeof options !== 'object' || Array.isArray(options))
	            return context.error(`Collator options argument must be an object.`);
	        const caseSensitive = context.parse(options['case-sensitive'] === undefined ? false : options['case-sensitive'], 1, BooleanType);
	        if (!caseSensitive)
	            return null;
	        const diacriticSensitive = context.parse(options['diacritic-sensitive'] === undefined ? false : options['diacritic-sensitive'], 1, BooleanType);
	        if (!diacriticSensitive)
	            return null;
	        let locale = null;
	        if (options['locale']) {
	            locale = context.parse(options['locale'], 1, StringType);
	            if (!locale)
	                return null;
	        }
	        return new CollatorExpression(caseSensitive, diacriticSensitive, locale);
	    }
	    evaluate(ctx) {
	        return new Collator(this.caseSensitive.evaluate(ctx), this.diacriticSensitive.evaluate(ctx), this.locale ? this.locale.evaluate(ctx) : null);
	    }
	    eachChild(fn) {
	        fn(this.caseSensitive);
	        fn(this.diacriticSensitive);
	        if (this.locale) {
	            fn(this.locale);
	        }
	    }
	    outputDefined() {
	        return false;
	    }
	    serialize() {
	        const options = {};
	        options['case-sensitive'] = this.caseSensitive.serialize();
	        options['diacritic-sensitive'] = this.diacriticSensitive.serialize();
	        if (this.locale) {
	            options['locale'] = this.locale.serialize();
	        }
	        return [
	            'collator',
	            options
	        ];
	    }
	}

	const EXTENT$1 = 8192;
	function updateBBox(bbox, coord) {
	    bbox[0] = Math.min(bbox[0], coord[0]);
	    bbox[1] = Math.min(bbox[1], coord[1]);
	    bbox[2] = Math.max(bbox[2], coord[0]);
	    bbox[3] = Math.max(bbox[3], coord[1]);
	}
	function mercatorXfromLng$1(lng) {
	    return (180 + lng) / 360;
	}
	function mercatorYfromLat$1(lat) {
	    return (180 - 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360))) / 360;
	}
	function boxWithinBox(bbox1, bbox2) {
	    if (bbox1[0] <= bbox2[0])
	        return false;
	    if (bbox1[2] >= bbox2[2])
	        return false;
	    if (bbox1[1] <= bbox2[1])
	        return false;
	    if (bbox1[3] >= bbox2[3])
	        return false;
	    return true;
	}
	function getTileCoordinates(p, canonical) {
	    const x = mercatorXfromLng$1(p[0]);
	    const y = mercatorYfromLat$1(p[1]);
	    const tilesAtZoom = Math.pow(2, canonical.z);
	    return [
	        Math.round(x * tilesAtZoom * EXTENT$1),
	        Math.round(y * tilesAtZoom * EXTENT$1)
	    ];
	}
	function onBoundary(p, p1, p2) {
	    const x1 = p[0] - p1[0];
	    const y1 = p[1] - p1[1];
	    const x2 = p[0] - p2[0];
	    const y2 = p[1] - p2[1];
	    return x1 * y2 - x2 * y1 === 0 && x1 * x2 <= 0 && y1 * y2 <= 0;
	}
	function rayIntersect(p, p1, p2) {
	    return p1[1] > p[1] !== p2[1] > p[1] && p[0] < (p2[0] - p1[0]) * (p[1] - p1[1]) / (p2[1] - p1[1]) + p1[0];
	}
	function pointWithinPolygon(point, rings) {
	    let inside = false;
	    for (let i = 0, len = rings.length; i < len; i++) {
	        const ring = rings[i];
	        for (let j = 0, len2 = ring.length; j < len2 - 1; j++) {
	            if (onBoundary(point, ring[j], ring[j + 1]))
	                return false;
	            if (rayIntersect(point, ring[j], ring[j + 1]))
	                inside = !inside;
	        }
	    }
	    return inside;
	}
	function pointWithinPolygons(point, polygons) {
	    for (let i = 0; i < polygons.length; i++) {
	        if (pointWithinPolygon(point, polygons[i]))
	            return true;
	    }
	    return false;
	}
	function perp(v1, v2) {
	    return v1[0] * v2[1] - v1[1] * v2[0];
	}
	function twoSided(p1, p2, q1, q2) {
	    const x1 = p1[0] - q1[0];
	    const y1 = p1[1] - q1[1];
	    const x2 = p2[0] - q1[0];
	    const y2 = p2[1] - q1[1];
	    const x3 = q2[0] - q1[0];
	    const y3 = q2[1] - q1[1];
	    const det1 = x1 * y3 - x3 * y1;
	    const det2 = x2 * y3 - x3 * y2;
	    if (det1 > 0 && det2 < 0 || det1 < 0 && det2 > 0)
	        return true;
	    return false;
	}
	function lineIntersectLine(a, b, c, d) {
	    const vectorP = [
	        b[0] - a[0],
	        b[1] - a[1]
	    ];
	    const vectorQ = [
	        d[0] - c[0],
	        d[1] - c[1]
	    ];
	    if (perp(vectorQ, vectorP) === 0)
	        return false;
	    if (twoSided(a, b, c, d) && twoSided(c, d, a, b))
	        return true;
	    return false;
	}
	function lineIntersectPolygon(p1, p2, polygon) {
	    for (const ring of polygon) {
	        for (let j = 0; j < ring.length - 1; ++j) {
	            if (lineIntersectLine(p1, p2, ring[j], ring[j + 1])) {
	                return true;
	            }
	        }
	    }
	    return false;
	}
	function lineStringWithinPolygon(line, polygon) {
	    for (let i = 0; i < line.length; ++i) {
	        if (!pointWithinPolygon(line[i], polygon)) {
	            return false;
	        }
	    }
	    for (let i = 0; i < line.length - 1; ++i) {
	        if (lineIntersectPolygon(line[i], line[i + 1], polygon)) {
	            return false;
	        }
	    }
	    return true;
	}
	function lineStringWithinPolygons(line, polygons) {
	    for (let i = 0; i < polygons.length; i++) {
	        if (lineStringWithinPolygon(line, polygons[i]))
	            return true;
	    }
	    return false;
	}
	function getTilePolygon(coordinates, bbox, canonical) {
	    const polygon = [];
	    for (let i = 0; i < coordinates.length; i++) {
	        const ring = [];
	        for (let j = 0; j < coordinates[i].length; j++) {
	            const coord = getTileCoordinates(coordinates[i][j], canonical);
	            updateBBox(bbox, coord);
	            ring.push(coord);
	        }
	        polygon.push(ring);
	    }
	    return polygon;
	}
	function getTilePolygons(coordinates, bbox, canonical) {
	    const polygons = [];
	    for (let i = 0; i < coordinates.length; i++) {
	        const polygon = getTilePolygon(coordinates[i], bbox, canonical);
	        polygons.push(polygon);
	    }
	    return polygons;
	}
	function updatePoint(p, bbox, polyBBox, worldSize) {
	    if (p[0] < polyBBox[0] || p[0] > polyBBox[2]) {
	        const halfWorldSize = worldSize * 0.5;
	        let shift = p[0] - polyBBox[0] > halfWorldSize ? -worldSize : polyBBox[0] - p[0] > halfWorldSize ? worldSize : 0;
	        if (shift === 0) {
	            shift = p[0] - polyBBox[2] > halfWorldSize ? -worldSize : polyBBox[2] - p[0] > halfWorldSize ? worldSize : 0;
	        }
	        p[0] += shift;
	    }
	    updateBBox(bbox, p);
	}
	function resetBBox(bbox) {
	    bbox[0] = bbox[1] = Infinity;
	    bbox[2] = bbox[3] = -Infinity;
	}
	function getTilePoints(geometry, pointBBox, polyBBox, canonical) {
	    const worldSize = Math.pow(2, canonical.z) * EXTENT$1;
	    const shifts = [
	        canonical.x * EXTENT$1,
	        canonical.y * EXTENT$1
	    ];
	    const tilePoints = [];
	    if (!geometry)
	        return tilePoints;
	    for (const points of geometry) {
	        for (const point of points) {
	            const p = [
	                point.x + shifts[0],
	                point.y + shifts[1]
	            ];
	            updatePoint(p, pointBBox, polyBBox, worldSize);
	            tilePoints.push(p);
	        }
	    }
	    return tilePoints;
	}
	function getTileLines(geometry, lineBBox, polyBBox, canonical) {
	    const worldSize = Math.pow(2, canonical.z) * EXTENT$1;
	    const shifts = [
	        canonical.x * EXTENT$1,
	        canonical.y * EXTENT$1
	    ];
	    const tileLines = [];
	    if (!geometry)
	        return tileLines;
	    for (const line of geometry) {
	        const tileLine = [];
	        for (const point of line) {
	            const p = [
	                point.x + shifts[0],
	                point.y + shifts[1]
	            ];
	            updateBBox(lineBBox, p);
	            tileLine.push(p);
	        }
	        tileLines.push(tileLine);
	    }
	    if (lineBBox[2] - lineBBox[0] <= worldSize / 2) {
	        resetBBox(lineBBox);
	        for (const line of tileLines) {
	            for (const p of line) {
	                updatePoint(p, lineBBox, polyBBox, worldSize);
	            }
	        }
	    }
	    return tileLines;
	}
	function pointsWithinPolygons(ctx, polygonGeometry) {
	    const pointBBox = [
	        Infinity,
	        Infinity,
	        -Infinity,
	        -Infinity
	    ];
	    const polyBBox = [
	        Infinity,
	        Infinity,
	        -Infinity,
	        -Infinity
	    ];
	    const canonical = ctx.canonicalID();
	    if (!canonical) {
	        return false;
	    }
	    if (polygonGeometry.type === 'Polygon') {
	        const tilePolygon = getTilePolygon(polygonGeometry.coordinates, polyBBox, canonical);
	        const tilePoints = getTilePoints(ctx.geometry(), pointBBox, polyBBox, canonical);
	        if (!boxWithinBox(pointBBox, polyBBox))
	            return false;
	        for (const point of tilePoints) {
	            if (!pointWithinPolygon(point, tilePolygon))
	                return false;
	        }
	    }
	    if (polygonGeometry.type === 'MultiPolygon') {
	        const tilePolygons = getTilePolygons(polygonGeometry.coordinates, polyBBox, canonical);
	        const tilePoints = getTilePoints(ctx.geometry(), pointBBox, polyBBox, canonical);
	        if (!boxWithinBox(pointBBox, polyBBox))
	            return false;
	        for (const point of tilePoints) {
	            if (!pointWithinPolygons(point, tilePolygons))
	                return false;
	        }
	    }
	    return true;
	}
	function linesWithinPolygons(ctx, polygonGeometry) {
	    const lineBBox = [
	        Infinity,
	        Infinity,
	        -Infinity,
	        -Infinity
	    ];
	    const polyBBox = [
	        Infinity,
	        Infinity,
	        -Infinity,
	        -Infinity
	    ];
	    const canonical = ctx.canonicalID();
	    if (!canonical) {
	        return false;
	    }
	    if (polygonGeometry.type === 'Polygon') {
	        const tilePolygon = getTilePolygon(polygonGeometry.coordinates, polyBBox, canonical);
	        const tileLines = getTileLines(ctx.geometry(), lineBBox, polyBBox, canonical);
	        if (!boxWithinBox(lineBBox, polyBBox))
	            return false;
	        for (const line of tileLines) {
	            if (!lineStringWithinPolygon(line, tilePolygon))
	                return false;
	        }
	    }
	    if (polygonGeometry.type === 'MultiPolygon') {
	        const tilePolygons = getTilePolygons(polygonGeometry.coordinates, polyBBox, canonical);
	        const tileLines = getTileLines(ctx.geometry(), lineBBox, polyBBox, canonical);
	        if (!boxWithinBox(lineBBox, polyBBox))
	            return false;
	        for (const line of tileLines) {
	            if (!lineStringWithinPolygons(line, tilePolygons))
	                return false;
	        }
	    }
	    return true;
	}
	class Within {
	    constructor(geojson, geometries) {
	        this.type = BooleanType;
	        this.geojson = geojson;
	        this.geometries = geometries;
	    }
	    static parse(args, context) {
	        if (args.length !== 2)
	            return context.error(`'within' expression requires exactly one argument, but found ${ args.length - 1 } instead.`);
	        if (isValue(args[1])) {
	            const geojson = args[1];
	            if (geojson.type === 'FeatureCollection') {
	                for (let i = 0; i < geojson.features.length; ++i) {
	                    const type = geojson.features[i].geometry.type;
	                    if (type === 'Polygon' || type === 'MultiPolygon') {
	                        return new Within(geojson, geojson.features[i].geometry);
	                    }
	                }
	            } else if (geojson.type === 'Feature') {
	                const type = geojson.geometry.type;
	                if (type === 'Polygon' || type === 'MultiPolygon') {
	                    return new Within(geojson, geojson.geometry);
	                }
	            } else if (geojson.type === 'Polygon' || geojson.type === 'MultiPolygon') {
	                return new Within(geojson, geojson);
	            }
	        }
	        return context.error(`'within' expression requires valid geojson object that contains polygon geometry type.`);
	    }
	    evaluate(ctx) {
	        if (ctx.geometry() != null && ctx.canonicalID() != null) {
	            if (ctx.geometryType() === 'Point') {
	                return pointsWithinPolygons(ctx, this.geometries);
	            } else if (ctx.geometryType() === 'LineString') {
	                return linesWithinPolygons(ctx, this.geometries);
	            }
	        }
	        return false;
	    }
	    eachChild() {
	    }
	    outputDefined() {
	        return true;
	    }
	    serialize() {
	        return [
	            'within',
	            this.geojson
	        ];
	    }
	}
	var Within$1 = Within;

	function isFeatureConstant(e) {
	    if (e instanceof CompoundExpression$1) {
	        if (e.name === 'get' && e.args.length === 1) {
	            return false;
	        } else if (e.name === 'feature-state') {
	            return false;
	        } else if (e.name === 'has' && e.args.length === 1) {
	            return false;
	        } else if (e.name === 'properties' || e.name === 'geometry-type' || e.name === 'id') {
	            return false;
	        } else if (/^filter-/.test(e.name)) {
	            return false;
	        }
	    }
	    if (e instanceof Within$1) {
	        return false;
	    }
	    let result = true;
	    e.eachChild(arg => {
	        if (result && !isFeatureConstant(arg)) {
	            result = false;
	        }
	    });
	    return result;
	}
	function isStateConstant(e) {
	    if (e instanceof CompoundExpression$1) {
	        if (e.name === 'feature-state') {
	            return false;
	        }
	    }
	    let result = true;
	    e.eachChild(arg => {
	        if (result && !isStateConstant(arg)) {
	            result = false;
	        }
	    });
	    return result;
	}
	function isGlobalPropertyConstant(e, properties) {
	    if (e instanceof CompoundExpression$1 && properties.indexOf(e.name) >= 0) {
	        return false;
	    }
	    let result = true;
	    e.eachChild(arg => {
	        if (result && !isGlobalPropertyConstant(arg, properties)) {
	            result = false;
	        }
	    });
	    return result;
	}

	class Var {
	    constructor(name, boundExpression) {
	        this.type = boundExpression.type;
	        this.name = name;
	        this.boundExpression = boundExpression;
	    }
	    static parse(args, context) {
	        if (args.length !== 2 || typeof args[1] !== 'string')
	            return context.error(`'var' expression requires exactly one string literal argument.`);
	        const name = args[1];
	        if (!context.scope.has(name)) {
	            return context.error(`Unknown variable "${ name }". Make sure "${ name }" has been bound in an enclosing "let" expression before using it.`, 1);
	        }
	        return new Var(name, context.scope.get(name));
	    }
	    evaluate(ctx) {
	        return this.boundExpression.evaluate(ctx);
	    }
	    eachChild() {
	    }
	    outputDefined() {
	        return false;
	    }
	    serialize() {
	        return [
	            'var',
	            this.name
	        ];
	    }
	}
	var Var$1 = Var;

	class ParsingContext {
	    constructor(registry, path = [], expectedType, scope = new Scope$1(), errors = []) {
	        this.registry = registry;
	        this.path = path;
	        this.key = path.map(part => `[${ part }]`).join('');
	        this.scope = scope;
	        this.errors = errors;
	        this.expectedType = expectedType;
	    }
	    parse(expr, index, expectedType, bindings, options = {}) {
	        if (index) {
	            return this.concat(index, expectedType, bindings)._parse(expr, options);
	        }
	        return this._parse(expr, options);
	    }
	    _parse(expr, options) {
	        if (expr === null || typeof expr === 'string' || typeof expr === 'boolean' || typeof expr === 'number') {
	            expr = [
	                'literal',
	                expr
	            ];
	        }
	        function annotate(parsed, type, typeAnnotation) {
	            if (typeAnnotation === 'assert') {
	                return new Assertion$1(type, [parsed]);
	            } else if (typeAnnotation === 'coerce') {
	                return new Coercion$1(type, [parsed]);
	            } else {
	                return parsed;
	            }
	        }
	        if (Array.isArray(expr)) {
	            if (expr.length === 0) {
	                return this.error(`Expected an array with at least one element. If you wanted a literal array, use ["literal", []].`);
	            }
	            const op = expr[0];
	            if (typeof op !== 'string') {
	                this.error(`Expression name must be a string, but found ${ typeof op } instead. If you wanted a literal array, use ["literal", [...]].`, 0);
	                return null;
	            }
	            const Expr = this.registry[op];
	            if (Expr) {
	                let parsed = Expr.parse(expr, this);
	                if (!parsed)
	                    return null;
	                if (this.expectedType) {
	                    const expected = this.expectedType;
	                    const actual = parsed.type;
	                    if ((expected.kind === 'string' || expected.kind === 'number' || expected.kind === 'boolean' || expected.kind === 'object' || expected.kind === 'array') && actual.kind === 'value') {
	                        parsed = annotate(parsed, expected, options.typeAnnotation || 'assert');
	                    } else if ((expected.kind === 'color' || expected.kind === 'formatted' || expected.kind === 'resolvedImage') && (actual.kind === 'value' || actual.kind === 'string')) {
	                        parsed = annotate(parsed, expected, options.typeAnnotation || 'coerce');
	                    } else if (this.checkSubtype(expected, actual)) {
	                        return null;
	                    }
	                }
	                if (!(parsed instanceof Literal$1) && parsed.type.kind !== 'resolvedImage' && isConstant(parsed)) {
	                    const ec = new EvaluationContext$1();
	                    try {
	                        parsed = new Literal$1(parsed.type, parsed.evaluate(ec));
	                    } catch (e) {
	                        this.error(e.message);
	                        return null;
	                    }
	                }
	                return parsed;
	            }
	            return this.error(`Unknown expression "${ op }". If you wanted a literal array, use ["literal", [...]].`, 0);
	        } else if (typeof expr === 'undefined') {
	            return this.error(`'undefined' value invalid. Use null instead.`);
	        } else if (typeof expr === 'object') {
	            return this.error(`Bare objects invalid. Use ["literal", {...}] instead.`);
	        } else {
	            return this.error(`Expected an array, but found ${ typeof expr } instead.`);
	        }
	    }
	    concat(index, expectedType, bindings) {
	        const path = typeof index === 'number' ? this.path.concat(index) : this.path;
	        const scope = bindings ? this.scope.concat(bindings) : this.scope;
	        return new ParsingContext(this.registry, path, expectedType || null, scope, this.errors);
	    }
	    error(error, ...keys) {
	        const key = `${ this.key }${ keys.map(k => `[${ k }]`).join('') }`;
	        this.errors.push(new ParsingError$1(key, error));
	    }
	    checkSubtype(expected, t) {
	        const error = checkSubtype(expected, t);
	        if (error)
	            this.error(error);
	        return error;
	    }
	}
	var ParsingContext$1 = ParsingContext;
	function isConstant(expression) {
	    if (expression instanceof Var$1) {
	        return isConstant(expression.boundExpression);
	    } else if (expression instanceof CompoundExpression$1 && expression.name === 'error') {
	        return false;
	    } else if (expression instanceof CollatorExpression) {
	        return false;
	    } else if (expression instanceof Within$1) {
	        return false;
	    }
	    const isTypeAnnotation = expression instanceof Coercion$1 || expression instanceof Assertion$1;
	    let childrenConstant = true;
	    expression.eachChild(child => {
	        if (isTypeAnnotation) {
	            childrenConstant = childrenConstant && isConstant(child);
	        } else {
	            childrenConstant = childrenConstant && child instanceof Literal$1;
	        }
	    });
	    if (!childrenConstant) {
	        return false;
	    }
	    return isFeatureConstant(expression) && isGlobalPropertyConstant(expression, [
	        'zoom',
	        'heatmap-density',
	        'line-progress',
	        'sky-radial-progress',
	        'accumulated',
	        'is-supported-script',
	        'pitch',
	        'distance-from-center'
	    ]);
	}

	function findStopLessThanOrEqualTo(stops, input) {
	    const lastIndex = stops.length - 1;
	    let lowerIndex = 0;
	    let upperIndex = lastIndex;
	    let currentIndex = 0;
	    let currentValue, nextValue;
	    while (lowerIndex <= upperIndex) {
	        currentIndex = Math.floor((lowerIndex + upperIndex) / 2);
	        currentValue = stops[currentIndex];
	        nextValue = stops[currentIndex + 1];
	        if (currentValue <= input) {
	            if (currentIndex === lastIndex || input < nextValue) {
	                return currentIndex;
	            }
	            lowerIndex = currentIndex + 1;
	        } else if (currentValue > input) {
	            upperIndex = currentIndex - 1;
	        } else {
	            throw new RuntimeError$1('Input is not a number.');
	        }
	    }
	    return 0;
	}

	class Step {
	    constructor(type, input, stops) {
	        this.type = type;
	        this.input = input;
	        this.labels = [];
	        this.outputs = [];
	        for (const [label, expression] of stops) {
	            this.labels.push(label);
	            this.outputs.push(expression);
	        }
	    }
	    static parse(args, context) {
	        if (args.length - 1 < 4) {
	            return context.error(`Expected at least 4 arguments, but found only ${ args.length - 1 }.`);
	        }
	        if ((args.length - 1) % 2 !== 0) {
	            return context.error(`Expected an even number of arguments.`);
	        }
	        const input = context.parse(args[1], 1, NumberType);
	        if (!input)
	            return null;
	        const stops = [];
	        let outputType = null;
	        if (context.expectedType && context.expectedType.kind !== 'value') {
	            outputType = context.expectedType;
	        }
	        for (let i = 1; i < args.length; i += 2) {
	            const label = i === 1 ? -Infinity : args[i];
	            const value = args[i + 1];
	            const labelKey = i;
	            const valueKey = i + 1;
	            if (typeof label !== 'number') {
	                return context.error('Input/output pairs for "step" expressions must be defined using literal numeric values (not computed expressions) for the input values.', labelKey);
	            }
	            if (stops.length && stops[stops.length - 1][0] >= label) {
	                return context.error('Input/output pairs for "step" expressions must be arranged with input values in strictly ascending order.', labelKey);
	            }
	            const parsed = context.parse(value, valueKey, outputType);
	            if (!parsed)
	                return null;
	            outputType = outputType || parsed.type;
	            stops.push([
	                label,
	                parsed
	            ]);
	        }
	        return new Step(outputType, input, stops);
	    }
	    evaluate(ctx) {
	        const labels = this.labels;
	        const outputs = this.outputs;
	        if (labels.length === 1) {
	            return outputs[0].evaluate(ctx);
	        }
	        const value = this.input.evaluate(ctx);
	        if (value <= labels[0]) {
	            return outputs[0].evaluate(ctx);
	        }
	        const stopCount = labels.length;
	        if (value >= labels[stopCount - 1]) {
	            return outputs[stopCount - 1].evaluate(ctx);
	        }
	        const index = findStopLessThanOrEqualTo(labels, value);
	        return outputs[index].evaluate(ctx);
	    }
	    eachChild(fn) {
	        fn(this.input);
	        for (const expression of this.outputs) {
	            fn(expression);
	        }
	    }
	    outputDefined() {
	        return this.outputs.every(out => out.outputDefined());
	    }
	    serialize() {
	        const serialized = [
	            'step',
	            this.input.serialize()
	        ];
	        for (let i = 0; i < this.labels.length; i++) {
	            if (i > 0) {
	                serialized.push(this.labels[i]);
	            }
	            serialized.push(this.outputs[i].serialize());
	        }
	        return serialized;
	    }
	}
	var Step$1 = Step;

	function number(a, b, t) {
	    return a * (1 - t) + b * t;
	}
	function color(from, to, t) {
	    return new Color$1(number(from.r, to.r, t), number(from.g, to.g, t), number(from.b, to.b, t), number(from.a, to.a, t));
	}
	function array(from, to, t) {
	    return from.map((d, i) => {
	        return number(d, to[i], t);
	    });
	}

	var interpolate = /*#__PURE__*/Object.freeze({
	__proto__: null,
	number: number,
	color: color,
	array: array
	});

	const Xn = 0.95047, Yn = 1, Zn = 1.08883, t0 = 4 / 29, t1 = 6 / 29, t2 = 3 * t1 * t1, t3 = t1 * t1 * t1, deg2rad = Math.PI / 180, rad2deg = 180 / Math.PI;
	function xyz2lab(t) {
	    return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
	}
	function lab2xyz(t) {
	    return t > t1 ? t * t * t : t2 * (t - t0);
	}
	function xyz2rgb(x) {
	    return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
	}
	function rgb2xyz(x) {
	    x /= 255;
	    return x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
	}
	function rgbToLab(rgbColor) {
	    const b = rgb2xyz(rgbColor.r), a = rgb2xyz(rgbColor.g), l = rgb2xyz(rgbColor.b), x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn), y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.072175 * l) / Yn), z = xyz2lab((0.0193339 * b + 0.119192 * a + 0.9503041 * l) / Zn);
	    return {
	        l: 116 * y - 16,
	        a: 500 * (x - y),
	        b: 200 * (y - z),
	        alpha: rgbColor.a
	    };
	}
	function labToRgb(labColor) {
	    let y = (labColor.l + 16) / 116, x = isNaN(labColor.a) ? y : y + labColor.a / 500, z = isNaN(labColor.b) ? y : y - labColor.b / 200;
	    y = Yn * lab2xyz(y);
	    x = Xn * lab2xyz(x);
	    z = Zn * lab2xyz(z);
	    return new Color$1(xyz2rgb(3.2404542 * x - 1.5371385 * y - 0.4985314 * z), xyz2rgb(-0.969266 * x + 1.8760108 * y + 0.041556 * z), xyz2rgb(0.0556434 * x - 0.2040259 * y + 1.0572252 * z), labColor.alpha);
	}
	function interpolateLab(from, to, t) {
	    return {
	        l: number(from.l, to.l, t),
	        a: number(from.a, to.a, t),
	        b: number(from.b, to.b, t),
	        alpha: number(from.alpha, to.alpha, t)
	    };
	}
	function rgbToHcl(rgbColor) {
	    const {l, a, b} = rgbToLab(rgbColor);
	    const h = Math.atan2(b, a) * rad2deg;
	    return {
	        h: h < 0 ? h + 360 : h,
	        c: Math.sqrt(a * a + b * b),
	        l,
	        alpha: rgbColor.a
	    };
	}
	function hclToRgb(hclColor) {
	    const h = hclColor.h * deg2rad, c = hclColor.c, l = hclColor.l;
	    return labToRgb({
	        l,
	        a: Math.cos(h) * c,
	        b: Math.sin(h) * c,
	        alpha: hclColor.alpha
	    });
	}
	function interpolateHue(a, b, t) {
	    const d = b - a;
	    return a + t * (d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d);
	}
	function interpolateHcl(from, to, t) {
	    return {
	        h: interpolateHue(from.h, to.h, t),
	        c: number(from.c, to.c, t),
	        l: number(from.l, to.l, t),
	        alpha: number(from.alpha, to.alpha, t)
	    };
	}
	const lab = {
	    forward: rgbToLab,
	    reverse: labToRgb,
	    interpolate: interpolateLab
	};
	const hcl = {
	    forward: rgbToHcl,
	    reverse: hclToRgb,
	    interpolate: interpolateHcl
	};

	var colorSpaces = /*#__PURE__*/Object.freeze({
	__proto__: null,
	lab: lab,
	hcl: hcl
	});

	class Interpolate {
	    constructor(type, operator, interpolation, input, stops) {
	        this.type = type;
	        this.operator = operator;
	        this.interpolation = interpolation;
	        this.input = input;
	        this.labels = [];
	        this.outputs = [];
	        for (const [label, expression] of stops) {
	            this.labels.push(label);
	            this.outputs.push(expression);
	        }
	    }
	    static interpolationFactor(interpolation, input, lower, upper) {
	        let t = 0;
	        if (interpolation.name === 'exponential') {
	            t = exponentialInterpolation(input, interpolation.base, lower, upper);
	        } else if (interpolation.name === 'linear') {
	            t = exponentialInterpolation(input, 1, lower, upper);
	        } else if (interpolation.name === 'cubic-bezier') {
	            const c = interpolation.controlPoints;
	            const ub = new unitbezier(c[0], c[1], c[2], c[3]);
	            t = ub.solve(exponentialInterpolation(input, 1, lower, upper));
	        }
	        return t;
	    }
	    static parse(args, context) {
	        let [operator, interpolation, input, ...rest] = args;
	        if (!Array.isArray(interpolation) || interpolation.length === 0) {
	            return context.error(`Expected an interpolation type expression.`, 1);
	        }
	        if (interpolation[0] === 'linear') {
	            interpolation = { name: 'linear' };
	        } else if (interpolation[0] === 'exponential') {
	            const base = interpolation[1];
	            if (typeof base !== 'number')
	                return context.error(`Exponential interpolation requires a numeric base.`, 1, 1);
	            interpolation = {
	                name: 'exponential',
	                base
	            };
	        } else if (interpolation[0] === 'cubic-bezier') {
	            const controlPoints = interpolation.slice(1);
	            if (controlPoints.length !== 4 || controlPoints.some(t => typeof t !== 'number' || t < 0 || t > 1)) {
	                return context.error('Cubic bezier interpolation requires four numeric arguments with values between 0 and 1.', 1);
	            }
	            interpolation = {
	                name: 'cubic-bezier',
	                controlPoints: controlPoints
	            };
	        } else {
	            return context.error(`Unknown interpolation type ${ String(interpolation[0]) }`, 1, 0);
	        }
	        if (args.length - 1 < 4) {
	            return context.error(`Expected at least 4 arguments, but found only ${ args.length - 1 }.`);
	        }
	        if ((args.length - 1) % 2 !== 0) {
	            return context.error(`Expected an even number of arguments.`);
	        }
	        input = context.parse(input, 2, NumberType);
	        if (!input)
	            return null;
	        const stops = [];
	        let outputType = null;
	        if (operator === 'interpolate-hcl' || operator === 'interpolate-lab') {
	            outputType = ColorType;
	        } else if (context.expectedType && context.expectedType.kind !== 'value') {
	            outputType = context.expectedType;
	        }
	        for (let i = 0; i < rest.length; i += 2) {
	            const label = rest[i];
	            const value = rest[i + 1];
	            const labelKey = i + 3;
	            const valueKey = i + 4;
	            if (typeof label !== 'number') {
	                return context.error('Input/output pairs for "interpolate" expressions must be defined using literal numeric values (not computed expressions) for the input values.', labelKey);
	            }
	            if (stops.length && stops[stops.length - 1][0] >= label) {
	                return context.error('Input/output pairs for "interpolate" expressions must be arranged with input values in strictly ascending order.', labelKey);
	            }
	            const parsed = context.parse(value, valueKey, outputType);
	            if (!parsed)
	                return null;
	            outputType = outputType || parsed.type;
	            stops.push([
	                label,
	                parsed
	            ]);
	        }
	        if (outputType.kind !== 'number' && outputType.kind !== 'color' && !(outputType.kind === 'array' && outputType.itemType.kind === 'number' && typeof outputType.N === 'number')) {
	            return context.error(`Type ${ toString$1(outputType) } is not interpolatable.`);
	        }
	        return new Interpolate(outputType, operator, interpolation, input, stops);
	    }
	    evaluate(ctx) {
	        const labels = this.labels;
	        const outputs = this.outputs;
	        if (labels.length === 1) {
	            return outputs[0].evaluate(ctx);
	        }
	        const value = this.input.evaluate(ctx);
	        if (value <= labels[0]) {
	            return outputs[0].evaluate(ctx);
	        }
	        const stopCount = labels.length;
	        if (value >= labels[stopCount - 1]) {
	            return outputs[stopCount - 1].evaluate(ctx);
	        }
	        const index = findStopLessThanOrEqualTo(labels, value);
	        const lower = labels[index];
	        const upper = labels[index + 1];
	        const t = Interpolate.interpolationFactor(this.interpolation, value, lower, upper);
	        const outputLower = outputs[index].evaluate(ctx);
	        const outputUpper = outputs[index + 1].evaluate(ctx);
	        if (this.operator === 'interpolate') {
	            return interpolate[this.type.kind.toLowerCase()](outputLower, outputUpper, t);
	        } else if (this.operator === 'interpolate-hcl') {
	            return hcl.reverse(hcl.interpolate(hcl.forward(outputLower), hcl.forward(outputUpper), t));
	        } else {
	            return lab.reverse(lab.interpolate(lab.forward(outputLower), lab.forward(outputUpper), t));
	        }
	    }
	    eachChild(fn) {
	        fn(this.input);
	        for (const expression of this.outputs) {
	            fn(expression);
	        }
	    }
	    outputDefined() {
	        return this.outputs.every(out => out.outputDefined());
	    }
	    serialize() {
	        let interpolation;
	        if (this.interpolation.name === 'linear') {
	            interpolation = ['linear'];
	        } else if (this.interpolation.name === 'exponential') {
	            if (this.interpolation.base === 1) {
	                interpolation = ['linear'];
	            } else {
	                interpolation = [
	                    'exponential',
	                    this.interpolation.base
	                ];
	            }
	        } else {
	            interpolation = ['cubic-bezier'].concat(this.interpolation.controlPoints);
	        }
	        const serialized = [
	            this.operator,
	            interpolation,
	            this.input.serialize()
	        ];
	        for (let i = 0; i < this.labels.length; i++) {
	            serialized.push(this.labels[i], this.outputs[i].serialize());
	        }
	        return serialized;
	    }
	}
	function exponentialInterpolation(input, base, lowerValue, upperValue) {
	    const difference = upperValue - lowerValue;
	    const progress = input - lowerValue;
	    if (difference === 0) {
	        return 0;
	    } else if (base === 1) {
	        return progress / difference;
	    } else {
	        return (Math.pow(base, progress) - 1) / (Math.pow(base, difference) - 1);
	    }
	}
	var Interpolate$1 = Interpolate;

	class Coalesce {
	    constructor(type, args) {
	        this.type = type;
	        this.args = args;
	    }
	    static parse(args, context) {
	        if (args.length < 2) {
	            return context.error('Expectected at least one argument.');
	        }
	        let outputType = null;
	        const expectedType = context.expectedType;
	        if (expectedType && expectedType.kind !== 'value') {
	            outputType = expectedType;
	        }
	        const parsedArgs = [];
	        for (const arg of args.slice(1)) {
	            const parsed = context.parse(arg, 1 + parsedArgs.length, outputType, undefined, { typeAnnotation: 'omit' });
	            if (!parsed)
	                return null;
	            outputType = outputType || parsed.type;
	            parsedArgs.push(parsed);
	        }
	        const needsAnnotation = expectedType && parsedArgs.some(arg => checkSubtype(expectedType, arg.type));
	        return needsAnnotation ? new Coalesce(ValueType, parsedArgs) : new Coalesce(outputType, parsedArgs);
	    }
	    evaluate(ctx) {
	        let result = null;
	        let argCount = 0;
	        let firstImage;
	        for (const arg of this.args) {
	            argCount++;
	            result = arg.evaluate(ctx);
	            if (result && result instanceof ResolvedImage && !result.available) {
	                if (!firstImage) {
	                    firstImage = result;
	                }
	                result = null;
	                if (argCount === this.args.length) {
	                    return firstImage;
	                }
	            }
	            if (result !== null)
	                break;
	        }
	        return result;
	    }
	    eachChild(fn) {
	        this.args.forEach(fn);
	    }
	    outputDefined() {
	        return this.args.every(arg => arg.outputDefined());
	    }
	    serialize() {
	        const serialized = ['coalesce'];
	        this.eachChild(child => {
	            serialized.push(child.serialize());
	        });
	        return serialized;
	    }
	}
	var Coalesce$1 = Coalesce;

	class Let {
	    constructor(bindings, result) {
	        this.type = result.type;
	        this.bindings = [].concat(bindings);
	        this.result = result;
	    }
	    evaluate(ctx) {
	        return this.result.evaluate(ctx);
	    }
	    eachChild(fn) {
	        for (const binding of this.bindings) {
	            fn(binding[1]);
	        }
	        fn(this.result);
	    }
	    static parse(args, context) {
	        if (args.length < 4)
	            return context.error(`Expected at least 3 arguments, but found ${ args.length - 1 } instead.`);
	        const bindings = [];
	        for (let i = 1; i < args.length - 1; i += 2) {
	            const name = args[i];
	            if (typeof name !== 'string') {
	                return context.error(`Expected string, but found ${ typeof name } instead.`, i);
	            }
	            if (/[^a-zA-Z0-9_]/.test(name)) {
	                return context.error(`Variable names must contain only alphanumeric characters or '_'.`, i);
	            }
	            const value = context.parse(args[i + 1], i + 1);
	            if (!value)
	                return null;
	            bindings.push([
	                name,
	                value
	            ]);
	        }
	        const result = context.parse(args[args.length - 1], args.length - 1, context.expectedType, bindings);
	        if (!result)
	            return null;
	        return new Let(bindings, result);
	    }
	    outputDefined() {
	        return this.result.outputDefined();
	    }
	    serialize() {
	        const serialized = ['let'];
	        for (const [name, expr] of this.bindings) {
	            serialized.push(name, expr.serialize());
	        }
	        serialized.push(this.result.serialize());
	        return serialized;
	    }
	}
	var Let$1 = Let;

	class At {
	    constructor(type, index, input) {
	        this.type = type;
	        this.index = index;
	        this.input = input;
	    }
	    static parse(args, context) {
	        if (args.length !== 3)
	            return context.error(`Expected 2 arguments, but found ${ args.length - 1 } instead.`);
	        const index = context.parse(args[1], 1, NumberType);
	        const input = context.parse(args[2], 2, array$1(context.expectedType || ValueType));
	        if (!index || !input)
	            return null;
	        const t = input.type;
	        return new At(t.itemType, index, input);
	    }
	    evaluate(ctx) {
	        const index = this.index.evaluate(ctx);
	        const array = this.input.evaluate(ctx);
	        if (index < 0) {
	            throw new RuntimeError$1(`Array index out of bounds: ${ index } < 0.`);
	        }
	        if (index >= array.length) {
	            throw new RuntimeError$1(`Array index out of bounds: ${ index } > ${ array.length - 1 }.`);
	        }
	        if (index !== Math.floor(index)) {
	            throw new RuntimeError$1(`Array index must be an integer, but found ${ index } instead.`);
	        }
	        return array[index];
	    }
	    eachChild(fn) {
	        fn(this.index);
	        fn(this.input);
	    }
	    outputDefined() {
	        return false;
	    }
	    serialize() {
	        return [
	            'at',
	            this.index.serialize(),
	            this.input.serialize()
	        ];
	    }
	}
	var At$1 = At;

	class In {
	    constructor(needle, haystack) {
	        this.type = BooleanType;
	        this.needle = needle;
	        this.haystack = haystack;
	    }
	    static parse(args, context) {
	        if (args.length !== 3) {
	            return context.error(`Expected 2 arguments, but found ${ args.length - 1 } instead.`);
	        }
	        const needle = context.parse(args[1], 1, ValueType);
	        const haystack = context.parse(args[2], 2, ValueType);
	        if (!needle || !haystack)
	            return null;
	        if (!isValidType(needle.type, [
	                BooleanType,
	                StringType,
	                NumberType,
	                NullType,
	                ValueType
	            ])) {
	            return context.error(`Expected first argument to be of type boolean, string, number or null, but found ${ toString$1(needle.type) } instead`);
	        }
	        return new In(needle, haystack);
	    }
	    evaluate(ctx) {
	        const needle = this.needle.evaluate(ctx);
	        const haystack = this.haystack.evaluate(ctx);
	        if (haystack == null)
	            return false;
	        if (!isValidNativeType(needle, [
	                'boolean',
	                'string',
	                'number',
	                'null'
	            ])) {
	            throw new RuntimeError$1(`Expected first argument to be of type boolean, string, number or null, but found ${ toString$1(typeOf(needle)) } instead.`);
	        }
	        if (!isValidNativeType(haystack, [
	                'string',
	                'array'
	            ])) {
	            throw new RuntimeError$1(`Expected second argument to be of type array or string, but found ${ toString$1(typeOf(haystack)) } instead.`);
	        }
	        return haystack.indexOf(needle) >= 0;
	    }
	    eachChild(fn) {
	        fn(this.needle);
	        fn(this.haystack);
	    }
	    outputDefined() {
	        return true;
	    }
	    serialize() {
	        return [
	            'in',
	            this.needle.serialize(),
	            this.haystack.serialize()
	        ];
	    }
	}
	var In$1 = In;

	class IndexOf {
	    constructor(needle, haystack, fromIndex) {
	        this.type = NumberType;
	        this.needle = needle;
	        this.haystack = haystack;
	        this.fromIndex = fromIndex;
	    }
	    static parse(args, context) {
	        if (args.length <= 2 || args.length >= 5) {
	            return context.error(`Expected 3 or 4 arguments, but found ${ args.length - 1 } instead.`);
	        }
	        const needle = context.parse(args[1], 1, ValueType);
	        const haystack = context.parse(args[2], 2, ValueType);
	        if (!needle || !haystack)
	            return null;
	        if (!isValidType(needle.type, [
	                BooleanType,
	                StringType,
	                NumberType,
	                NullType,
	                ValueType
	            ])) {
	            return context.error(`Expected first argument to be of type boolean, string, number or null, but found ${ toString$1(needle.type) } instead`);
	        }
	        if (args.length === 4) {
	            const fromIndex = context.parse(args[3], 3, NumberType);
	            if (!fromIndex)
	                return null;
	            return new IndexOf(needle, haystack, fromIndex);
	        } else {
	            return new IndexOf(needle, haystack);
	        }
	    }
	    evaluate(ctx) {
	        const needle = this.needle.evaluate(ctx);
	        const haystack = this.haystack.evaluate(ctx);
	        if (!isValidNativeType(needle, [
	                'boolean',
	                'string',
	                'number',
	                'null'
	            ])) {
	            throw new RuntimeError$1(`Expected first argument to be of type boolean, string, number or null, but found ${ toString$1(typeOf(needle)) } instead.`);
	        }
	        if (!isValidNativeType(haystack, [
	                'string',
	                'array'
	            ])) {
	            throw new RuntimeError$1(`Expected second argument to be of type array or string, but found ${ toString$1(typeOf(haystack)) } instead.`);
	        }
	        if (this.fromIndex) {
	            const fromIndex = this.fromIndex.evaluate(ctx);
	            return haystack.indexOf(needle, fromIndex);
	        }
	        return haystack.indexOf(needle);
	    }
	    eachChild(fn) {
	        fn(this.needle);
	        fn(this.haystack);
	        if (this.fromIndex) {
	            fn(this.fromIndex);
	        }
	    }
	    outputDefined() {
	        return false;
	    }
	    serialize() {
	        if (this.fromIndex != null && this.fromIndex !== undefined) {
	            const fromIndex = this.fromIndex.serialize();
	            return [
	                'index-of',
	                this.needle.serialize(),
	                this.haystack.serialize(),
	                fromIndex
	            ];
	        }
	        return [
	            'index-of',
	            this.needle.serialize(),
	            this.haystack.serialize()
	        ];
	    }
	}
	var IndexOf$1 = IndexOf;

	class Match {
	    constructor(inputType, outputType, input, cases, outputs, otherwise) {
	        this.inputType = inputType;
	        this.type = outputType;
	        this.input = input;
	        this.cases = cases;
	        this.outputs = outputs;
	        this.otherwise = otherwise;
	    }
	    static parse(args, context) {
	        if (args.length < 5)
	            return context.error(`Expected at least 4 arguments, but found only ${ args.length - 1 }.`);
	        if (args.length % 2 !== 1)
	            return context.error(`Expected an even number of arguments.`);
	        let inputType;
	        let outputType;
	        if (context.expectedType && context.expectedType.kind !== 'value') {
	            outputType = context.expectedType;
	        }
	        const cases = {};
	        const outputs = [];
	        for (let i = 2; i < args.length - 1; i += 2) {
	            let labels = args[i];
	            const value = args[i + 1];
	            if (!Array.isArray(labels)) {
	                labels = [labels];
	            }
	            const labelContext = context.concat(i);
	            if (labels.length === 0) {
	                return labelContext.error('Expected at least one branch label.');
	            }
	            for (const label of labels) {
	                if (typeof label !== 'number' && typeof label !== 'string') {
	                    return labelContext.error(`Branch labels must be numbers or strings.`);
	                } else if (typeof label === 'number' && Math.abs(label) > Number.MAX_SAFE_INTEGER) {
	                    return labelContext.error(`Branch labels must be integers no larger than ${ Number.MAX_SAFE_INTEGER }.`);
	                } else if (typeof label === 'number' && Math.floor(label) !== label) {
	                    return labelContext.error(`Numeric branch labels must be integer values.`);
	                } else if (!inputType) {
	                    inputType = typeOf(label);
	                } else if (labelContext.checkSubtype(inputType, typeOf(label))) {
	                    return null;
	                }
	                if (typeof cases[String(label)] !== 'undefined') {
	                    return labelContext.error('Branch labels must be unique.');
	                }
	                cases[String(label)] = outputs.length;
	            }
	            const result = context.parse(value, i, outputType);
	            if (!result)
	                return null;
	            outputType = outputType || result.type;
	            outputs.push(result);
	        }
	        const input = context.parse(args[1], 1, ValueType);
	        if (!input)
	            return null;
	        const otherwise = context.parse(args[args.length - 1], args.length - 1, outputType);
	        if (!otherwise)
	            return null;
	        if (input.type.kind !== 'value' && context.concat(1).checkSubtype(inputType, input.type)) {
	            return null;
	        }
	        return new Match(inputType, outputType, input, cases, outputs, otherwise);
	    }
	    evaluate(ctx) {
	        const input = this.input.evaluate(ctx);
	        const output = typeOf(input) === this.inputType && this.outputs[this.cases[input]] || this.otherwise;
	        return output.evaluate(ctx);
	    }
	    eachChild(fn) {
	        fn(this.input);
	        this.outputs.forEach(fn);
	        fn(this.otherwise);
	    }
	    outputDefined() {
	        return this.outputs.every(out => out.outputDefined()) && this.otherwise.outputDefined();
	    }
	    serialize() {
	        const serialized = [
	            'match',
	            this.input.serialize()
	        ];
	        const sortedLabels = Object.keys(this.cases).sort();
	        const groupedByOutput = [];
	        const outputLookup = {};
	        for (const label of sortedLabels) {
	            const outputIndex = outputLookup[this.cases[label]];
	            if (outputIndex === undefined) {
	                outputLookup[this.cases[label]] = groupedByOutput.length;
	                groupedByOutput.push([
	                    this.cases[label],
	                    [label]
	                ]);
	            } else {
	                groupedByOutput[outputIndex][1].push(label);
	            }
	        }
	        const coerceLabel = label => this.inputType.kind === 'number' ? Number(label) : label;
	        for (const [outputIndex, labels] of groupedByOutput) {
	            if (labels.length === 1) {
	                serialized.push(coerceLabel(labels[0]));
	            } else {
	                serialized.push(labels.map(coerceLabel));
	            }
	            serialized.push(this.outputs[outputIndex].serialize());
	        }
	        serialized.push(this.otherwise.serialize());
	        return serialized;
	    }
	}
	var Match$1 = Match;

	class Case {
	    constructor(type, branches, otherwise) {
	        this.type = type;
	        this.branches = branches;
	        this.otherwise = otherwise;
	    }
	    static parse(args, context) {
	        if (args.length < 4)
	            return context.error(`Expected at least 3 arguments, but found only ${ args.length - 1 }.`);
	        if (args.length % 2 !== 0)
	            return context.error(`Expected an odd number of arguments.`);
	        let outputType;
	        if (context.expectedType && context.expectedType.kind !== 'value') {
	            outputType = context.expectedType;
	        }
	        const branches = [];
	        for (let i = 1; i < args.length - 1; i += 2) {
	            const test = context.parse(args[i], i, BooleanType);
	            if (!test)
	                return null;
	            const result = context.parse(args[i + 1], i + 1, outputType);
	            if (!result)
	                return null;
	            branches.push([
	                test,
	                result
	            ]);
	            outputType = outputType || result.type;
	        }
	        const otherwise = context.parse(args[args.length - 1], args.length - 1, outputType);
	        if (!otherwise)
	            return null;
	        return new Case(outputType, branches, otherwise);
	    }
	    evaluate(ctx) {
	        for (const [test, expression] of this.branches) {
	            if (test.evaluate(ctx)) {
	                return expression.evaluate(ctx);
	            }
	        }
	        return this.otherwise.evaluate(ctx);
	    }
	    eachChild(fn) {
	        for (const [test, expression] of this.branches) {
	            fn(test);
	            fn(expression);
	        }
	        fn(this.otherwise);
	    }
	    outputDefined() {
	        return this.branches.every(([_, out]) => out.outputDefined()) && this.otherwise.outputDefined();
	    }
	    serialize() {
	        const serialized = ['case'];
	        this.eachChild(child => {
	            serialized.push(child.serialize());
	        });
	        return serialized;
	    }
	}
	var Case$1 = Case;

	class Slice {
	    constructor(type, input, beginIndex, endIndex) {
	        this.type = type;
	        this.input = input;
	        this.beginIndex = beginIndex;
	        this.endIndex = endIndex;
	    }
	    static parse(args, context) {
	        if (args.length <= 2 || args.length >= 5) {
	            return context.error(`Expected 3 or 4 arguments, but found ${ args.length - 1 } instead.`);
	        }
	        const input = context.parse(args[1], 1, ValueType);
	        const beginIndex = context.parse(args[2], 2, NumberType);
	        if (!input || !beginIndex)
	            return null;
	        if (!isValidType(input.type, [
	                array$1(ValueType),
	                StringType,
	                ValueType
	            ])) {
	            return context.error(`Expected first argument to be of type array or string, but found ${ toString$1(input.type) } instead`);
	        }
	        if (args.length === 4) {
	            const endIndex = context.parse(args[3], 3, NumberType);
	            if (!endIndex)
	                return null;
	            return new Slice(input.type, input, beginIndex, endIndex);
	        } else {
	            return new Slice(input.type, input, beginIndex);
	        }
	    }
	    evaluate(ctx) {
	        const input = this.input.evaluate(ctx);
	        const beginIndex = this.beginIndex.evaluate(ctx);
	        if (!isValidNativeType(input, [
	                'string',
	                'array'
	            ])) {
	            throw new RuntimeError$1(`Expected first argument to be of type array or string, but found ${ toString$1(typeOf(input)) } instead.`);
	        }
	        if (this.endIndex) {
	            const endIndex = this.endIndex.evaluate(ctx);
	            return input.slice(beginIndex, endIndex);
	        }
	        return input.slice(beginIndex);
	    }
	    eachChild(fn) {
	        fn(this.input);
	        fn(this.beginIndex);
	        if (this.endIndex) {
	            fn(this.endIndex);
	        }
	    }
	    outputDefined() {
	        return false;
	    }
	    serialize() {
	        if (this.endIndex != null && this.endIndex !== undefined) {
	            const endIndex = this.endIndex.serialize();
	            return [
	                'slice',
	                this.input.serialize(),
	                this.beginIndex.serialize(),
	                endIndex
	            ];
	        }
	        return [
	            'slice',
	            this.input.serialize(),
	            this.beginIndex.serialize()
	        ];
	    }
	}
	var Slice$1 = Slice;

	function isComparableType(op, type) {
	    if (op === '==' || op === '!=') {
	        return type.kind === 'boolean' || type.kind === 'string' || type.kind === 'number' || type.kind === 'null' || type.kind === 'value';
	    } else {
	        return type.kind === 'string' || type.kind === 'number' || type.kind === 'value';
	    }
	}
	function eq(ctx, a, b) {
	    return a === b;
	}
	function neq(ctx, a, b) {
	    return a !== b;
	}
	function lt(ctx, a, b) {
	    return a < b;
	}
	function gt(ctx, a, b) {
	    return a > b;
	}
	function lteq(ctx, a, b) {
	    return a <= b;
	}
	function gteq(ctx, a, b) {
	    return a >= b;
	}
	function eqCollate(ctx, a, b, c) {
	    return c.compare(a, b) === 0;
	}
	function neqCollate(ctx, a, b, c) {
	    return !eqCollate(ctx, a, b, c);
	}
	function ltCollate(ctx, a, b, c) {
	    return c.compare(a, b) < 0;
	}
	function gtCollate(ctx, a, b, c) {
	    return c.compare(a, b) > 0;
	}
	function lteqCollate(ctx, a, b, c) {
	    return c.compare(a, b) <= 0;
	}
	function gteqCollate(ctx, a, b, c) {
	    return c.compare(a, b) >= 0;
	}
	function makeComparison(op, compareBasic, compareWithCollator) {
	    const isOrderComparison = op !== '==' && op !== '!=';
	    return class Comparison {
	        constructor(lhs, rhs, collator) {
	            this.type = BooleanType;
	            this.lhs = lhs;
	            this.rhs = rhs;
	            this.collator = collator;
	            this.hasUntypedArgument = lhs.type.kind === 'value' || rhs.type.kind === 'value';
	        }
	        static parse(args, context) {
	            if (args.length !== 3 && args.length !== 4)
	                return context.error(`Expected two or three arguments.`);
	            const op = args[0];
	            let lhs = context.parse(args[1], 1, ValueType);
	            if (!lhs)
	                return null;
	            if (!isComparableType(op, lhs.type)) {
	                return context.concat(1).error(`"${ op }" comparisons are not supported for type '${ toString$1(lhs.type) }'.`);
	            }
	            let rhs = context.parse(args[2], 2, ValueType);
	            if (!rhs)
	                return null;
	            if (!isComparableType(op, rhs.type)) {
	                return context.concat(2).error(`"${ op }" comparisons are not supported for type '${ toString$1(rhs.type) }'.`);
	            }
	            if (lhs.type.kind !== rhs.type.kind && lhs.type.kind !== 'value' && rhs.type.kind !== 'value') {
	                return context.error(`Cannot compare types '${ toString$1(lhs.type) }' and '${ toString$1(rhs.type) }'.`);
	            }
	            if (isOrderComparison) {
	                if (lhs.type.kind === 'value' && rhs.type.kind !== 'value') {
	                    lhs = new Assertion$1(rhs.type, [lhs]);
	                } else if (lhs.type.kind !== 'value' && rhs.type.kind === 'value') {
	                    rhs = new Assertion$1(lhs.type, [rhs]);
	                }
	            }
	            let collator = null;
	            if (args.length === 4) {
	                if (lhs.type.kind !== 'string' && rhs.type.kind !== 'string' && lhs.type.kind !== 'value' && rhs.type.kind !== 'value') {
	                    return context.error(`Cannot use collator to compare non-string types.`);
	                }
	                collator = context.parse(args[3], 3, CollatorType);
	                if (!collator)
	                    return null;
	            }
	            return new Comparison(lhs, rhs, collator);
	        }
	        evaluate(ctx) {
	            const lhs = this.lhs.evaluate(ctx);
	            const rhs = this.rhs.evaluate(ctx);
	            if (isOrderComparison && this.hasUntypedArgument) {
	                const lt = typeOf(lhs);
	                const rt = typeOf(rhs);
	                if (lt.kind !== rt.kind || !(lt.kind === 'string' || lt.kind === 'number')) {
	                    throw new RuntimeError$1(`Expected arguments for "${ op }" to be (string, string) or (number, number), but found (${ lt.kind }, ${ rt.kind }) instead.`);
	                }
	            }
	            if (this.collator && !isOrderComparison && this.hasUntypedArgument) {
	                const lt = typeOf(lhs);
	                const rt = typeOf(rhs);
	                if (lt.kind !== 'string' || rt.kind !== 'string') {
	                    return compareBasic(ctx, lhs, rhs);
	                }
	            }
	            return this.collator ? compareWithCollator(ctx, lhs, rhs, this.collator.evaluate(ctx)) : compareBasic(ctx, lhs, rhs);
	        }
	        eachChild(fn) {
	            fn(this.lhs);
	            fn(this.rhs);
	            if (this.collator) {
	                fn(this.collator);
	            }
	        }
	        outputDefined() {
	            return true;
	        }
	        serialize() {
	            const serialized = [op];
	            this.eachChild(child => {
	                serialized.push(child.serialize());
	            });
	            return serialized;
	        }
	    };
	}
	const Equals = makeComparison('==', eq, eqCollate);
	const NotEquals = makeComparison('!=', neq, neqCollate);
	const LessThan = makeComparison('<', lt, ltCollate);
	const GreaterThan = makeComparison('>', gt, gtCollate);
	const LessThanOrEqual = makeComparison('<=', lteq, lteqCollate);
	const GreaterThanOrEqual = makeComparison('>=', gteq, gteqCollate);

	class NumberFormat {
	    constructor(number, locale, currency, minFractionDigits, maxFractionDigits) {
	        this.type = StringType;
	        this.number = number;
	        this.locale = locale;
	        this.currency = currency;
	        this.minFractionDigits = minFractionDigits;
	        this.maxFractionDigits = maxFractionDigits;
	    }
	    static parse(args, context) {
	        if (args.length !== 3)
	            return context.error(`Expected two arguments.`);
	        const number = context.parse(args[1], 1, NumberType);
	        if (!number)
	            return null;
	        const options = args[2];
	        if (typeof options !== 'object' || Array.isArray(options))
	            return context.error(`NumberFormat options argument must be an object.`);
	        let locale = null;
	        if (options['locale']) {
	            locale = context.parse(options['locale'], 1, StringType);
	            if (!locale)
	                return null;
	        }
	        let currency = null;
	        if (options['currency']) {
	            currency = context.parse(options['currency'], 1, StringType);
	            if (!currency)
	                return null;
	        }
	        let minFractionDigits = null;
	        if (options['min-fraction-digits']) {
	            minFractionDigits = context.parse(options['min-fraction-digits'], 1, NumberType);
	            if (!minFractionDigits)
	                return null;
	        }
	        let maxFractionDigits = null;
	        if (options['max-fraction-digits']) {
	            maxFractionDigits = context.parse(options['max-fraction-digits'], 1, NumberType);
	            if (!maxFractionDigits)
	                return null;
	        }
	        return new NumberFormat(number, locale, currency, minFractionDigits, maxFractionDigits);
	    }
	    evaluate(ctx) {
	        return new Intl.NumberFormat(this.locale ? this.locale.evaluate(ctx) : [], {
	            style: this.currency ? 'currency' : 'decimal',
	            currency: this.currency ? this.currency.evaluate(ctx) : undefined,
	            minimumFractionDigits: this.minFractionDigits ? this.minFractionDigits.evaluate(ctx) : undefined,
	            maximumFractionDigits: this.maxFractionDigits ? this.maxFractionDigits.evaluate(ctx) : undefined
	        }).format(this.number.evaluate(ctx));
	    }
	    eachChild(fn) {
	        fn(this.number);
	        if (this.locale) {
	            fn(this.locale);
	        }
	        if (this.currency) {
	            fn(this.currency);
	        }
	        if (this.minFractionDigits) {
	            fn(this.minFractionDigits);
	        }
	        if (this.maxFractionDigits) {
	            fn(this.maxFractionDigits);
	        }
	    }
	    outputDefined() {
	        return false;
	    }
	    serialize() {
	        const options = {};
	        if (this.locale) {
	            options['locale'] = this.locale.serialize();
	        }
	        if (this.currency) {
	            options['currency'] = this.currency.serialize();
	        }
	        if (this.minFractionDigits) {
	            options['min-fraction-digits'] = this.minFractionDigits.serialize();
	        }
	        if (this.maxFractionDigits) {
	            options['max-fraction-digits'] = this.maxFractionDigits.serialize();
	        }
	        return [
	            'number-format',
	            this.number.serialize(),
	            options
	        ];
	    }
	}

	class Length {
	    constructor(input) {
	        this.type = NumberType;
	        this.input = input;
	    }
	    static parse(args, context) {
	        if (args.length !== 2)
	            return context.error(`Expected 1 argument, but found ${ args.length - 1 } instead.`);
	        const input = context.parse(args[1], 1);
	        if (!input)
	            return null;
	        if (input.type.kind !== 'array' && input.type.kind !== 'string' && input.type.kind !== 'value')
	            return context.error(`Expected argument of type string or array, but found ${ toString$1(input.type) } instead.`);
	        return new Length(input);
	    }
	    evaluate(ctx) {
	        const input = this.input.evaluate(ctx);
	        if (typeof input === 'string') {
	            return input.length;
	        } else if (Array.isArray(input)) {
	            return input.length;
	        } else {
	            throw new RuntimeError$1(`Expected value to be of type string or array, but found ${ toString$1(typeOf(input)) } instead.`);
	        }
	    }
	    eachChild(fn) {
	        fn(this.input);
	    }
	    outputDefined() {
	        return false;
	    }
	    serialize() {
	        const serialized = ['length'];
	        this.eachChild(child => {
	            serialized.push(child.serialize());
	        });
	        return serialized;
	    }
	}
	var Length$1 = Length;

	const expressions = {
	    '==': Equals,
	    '!=': NotEquals,
	    '>': GreaterThan,
	    '<': LessThan,
	    '>=': GreaterThanOrEqual,
	    '<=': LessThanOrEqual,
	    'array': Assertion$1,
	    'at': At$1,
	    'boolean': Assertion$1,
	    'case': Case$1,
	    'coalesce': Coalesce$1,
	    'collator': CollatorExpression,
	    'format': FormatExpression,
	    'image': ImageExpression,
	    'in': In$1,
	    'index-of': IndexOf$1,
	    'interpolate': Interpolate$1,
	    'interpolate-hcl': Interpolate$1,
	    'interpolate-lab': Interpolate$1,
	    'length': Length$1,
	    'let': Let$1,
	    'literal': Literal$1,
	    'match': Match$1,
	    'number': Assertion$1,
	    'number-format': NumberFormat,
	    'object': Assertion$1,
	    'slice': Slice$1,
	    'step': Step$1,
	    'string': Assertion$1,
	    'to-boolean': Coercion$1,
	    'to-color': Coercion$1,
	    'to-number': Coercion$1,
	    'to-string': Coercion$1,
	    'var': Var$1,
	    'within': Within$1
	};
	function rgba(ctx, [r, g, b, a]) {
	    r = r.evaluate(ctx);
	    g = g.evaluate(ctx);
	    b = b.evaluate(ctx);
	    const alpha = a ? a.evaluate(ctx) : 1;
	    const error = validateRGBA(r, g, b, alpha);
	    if (error)
	        throw new RuntimeError$1(error);
	    return new Color$1(r / 255 * alpha, g / 255 * alpha, b / 255 * alpha, alpha);
	}
	function has(key, obj) {
	    return key in obj;
	}
	function get(key, obj) {
	    const v = obj[key];
	    return typeof v === 'undefined' ? null : v;
	}
	function binarySearch(v, a, i, j) {
	    while (i <= j) {
	        const m = i + j >> 1;
	        if (a[m] === v)
	            return true;
	        if (a[m] > v)
	            j = m - 1;
	        else
	            i = m + 1;
	    }
	    return false;
	}
	function varargs(type) {
	    return { type };
	}
	CompoundExpression$1.register(expressions, {
	    'error': [
	        ErrorType,
	        [StringType],
	        (ctx, [v]) => {
	            throw new RuntimeError$1(v.evaluate(ctx));
	        }
	    ],
	    'typeof': [
	        StringType,
	        [ValueType],
	        (ctx, [v]) => toString$1(typeOf(v.evaluate(ctx)))
	    ],
	    'to-rgba': [
	        array$1(NumberType, 4),
	        [ColorType],
	        (ctx, [v]) => {
	            return v.evaluate(ctx).toArray();
	        }
	    ],
	    'rgb': [
	        ColorType,
	        [
	            NumberType,
	            NumberType,
	            NumberType
	        ],
	        rgba
	    ],
	    'rgba': [
	        ColorType,
	        [
	            NumberType,
	            NumberType,
	            NumberType,
	            NumberType
	        ],
	        rgba
	    ],
	    'has': {
	        type: BooleanType,
	        overloads: [
	            [
	                [StringType],
	                (ctx, [key]) => has(key.evaluate(ctx), ctx.properties())
	            ],
	            [
	                [
	                    StringType,
	                    ObjectType
	                ],
	                (ctx, [key, obj]) => has(key.evaluate(ctx), obj.evaluate(ctx))
	            ]
	        ]
	    },
	    'get': {
	        type: ValueType,
	        overloads: [
	            [
	                [StringType],
	                (ctx, [key]) => get(key.evaluate(ctx), ctx.properties())
	            ],
	            [
	                [
	                    StringType,
	                    ObjectType
	                ],
	                (ctx, [key, obj]) => get(key.evaluate(ctx), obj.evaluate(ctx))
	            ]
	        ]
	    },
	    'feature-state': [
	        ValueType,
	        [StringType],
	        (ctx, [key]) => get(key.evaluate(ctx), ctx.featureState || {})
	    ],
	    'properties': [
	        ObjectType,
	        [],
	        ctx => ctx.properties()
	    ],
	    'geometry-type': [
	        StringType,
	        [],
	        ctx => ctx.geometryType()
	    ],
	    'id': [
	        ValueType,
	        [],
	        ctx => ctx.id()
	    ],
	    'zoom': [
	        NumberType,
	        [],
	        ctx => ctx.globals.zoom
	    ],
	    'pitch': [
	        NumberType,
	        [],
	        ctx => ctx.globals.pitch || 0
	    ],
	    'distance-from-center': [
	        NumberType,
	        [],
	        ctx => ctx.distanceFromCenter()
	    ],
	    'heatmap-density': [
	        NumberType,
	        [],
	        ctx => ctx.globals.heatmapDensity || 0
	    ],
	    'line-progress': [
	        NumberType,
	        [],
	        ctx => ctx.globals.lineProgress || 0
	    ],
	    'sky-radial-progress': [
	        NumberType,
	        [],
	        ctx => ctx.globals.skyRadialProgress || 0
	    ],
	    'accumulated': [
	        ValueType,
	        [],
	        ctx => ctx.globals.accumulated === undefined ? null : ctx.globals.accumulated
	    ],
	    '+': [
	        NumberType,
	        varargs(NumberType),
	        (ctx, args) => {
	            let result = 0;
	            for (const arg of args) {
	                result += arg.evaluate(ctx);
	            }
	            return result;
	        }
	    ],
	    '*': [
	        NumberType,
	        varargs(NumberType),
	        (ctx, args) => {
	            let result = 1;
	            for (const arg of args) {
	                result *= arg.evaluate(ctx);
	            }
	            return result;
	        }
	    ],
	    '-': {
	        type: NumberType,
	        overloads: [
	            [
	                [
	                    NumberType,
	                    NumberType
	                ],
	                (ctx, [a, b]) => a.evaluate(ctx) - b.evaluate(ctx)
	            ],
	            [
	                [NumberType],
	                (ctx, [a]) => -a.evaluate(ctx)
	            ]
	        ]
	    },
	    '/': [
	        NumberType,
	        [
	            NumberType,
	            NumberType
	        ],
	        (ctx, [a, b]) => a.evaluate(ctx) / b.evaluate(ctx)
	    ],
	    '%': [
	        NumberType,
	        [
	            NumberType,
	            NumberType
	        ],
	        (ctx, [a, b]) => a.evaluate(ctx) % b.evaluate(ctx)
	    ],
	    'ln2': [
	        NumberType,
	        [],
	        () => Math.LN2
	    ],
	    'pi': [
	        NumberType,
	        [],
	        () => Math.PI
	    ],
	    'e': [
	        NumberType,
	        [],
	        () => Math.E
	    ],
	    '^': [
	        NumberType,
	        [
	            NumberType,
	            NumberType
	        ],
	        (ctx, [b, e]) => Math.pow(b.evaluate(ctx), e.evaluate(ctx))
	    ],
	    'sqrt': [
	        NumberType,
	        [NumberType],
	        (ctx, [x]) => Math.sqrt(x.evaluate(ctx))
	    ],
	    'log10': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => Math.log(n.evaluate(ctx)) / Math.LN10
	    ],
	    'ln': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => Math.log(n.evaluate(ctx))
	    ],
	    'log2': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => Math.log(n.evaluate(ctx)) / Math.LN2
	    ],
	    'sin': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => Math.sin(n.evaluate(ctx))
	    ],
	    'cos': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => Math.cos(n.evaluate(ctx))
	    ],
	    'tan': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => Math.tan(n.evaluate(ctx))
	    ],
	    'asin': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => Math.asin(n.evaluate(ctx))
	    ],
	    'acos': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => Math.acos(n.evaluate(ctx))
	    ],
	    'atan': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => Math.atan(n.evaluate(ctx))
	    ],
	    'min': [
	        NumberType,
	        varargs(NumberType),
	        (ctx, args) => Math.min(...args.map(arg => arg.evaluate(ctx)))
	    ],
	    'max': [
	        NumberType,
	        varargs(NumberType),
	        (ctx, args) => Math.max(...args.map(arg => arg.evaluate(ctx)))
	    ],
	    'abs': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => Math.abs(n.evaluate(ctx))
	    ],
	    'round': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => {
	            const v = n.evaluate(ctx);
	            return v < 0 ? -Math.round(-v) : Math.round(v);
	        }
	    ],
	    'floor': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => Math.floor(n.evaluate(ctx))
	    ],
	    'ceil': [
	        NumberType,
	        [NumberType],
	        (ctx, [n]) => Math.ceil(n.evaluate(ctx))
	    ],
	    'filter-==': [
	        BooleanType,
	        [
	            StringType,
	            ValueType
	        ],
	        (ctx, [k, v]) => ctx.properties()[k.value] === v.value
	    ],
	    'filter-id-==': [
	        BooleanType,
	        [ValueType],
	        (ctx, [v]) => ctx.id() === v.value
	    ],
	    'filter-type-==': [
	        BooleanType,
	        [StringType],
	        (ctx, [v]) => ctx.geometryType() === v.value
	    ],
	    'filter-<': [
	        BooleanType,
	        [
	            StringType,
	            ValueType
	        ],
	        (ctx, [k, v]) => {
	            const a = ctx.properties()[k.value];
	            const b = v.value;
	            return typeof a === typeof b && a < b;
	        }
	    ],
	    'filter-id-<': [
	        BooleanType,
	        [ValueType],
	        (ctx, [v]) => {
	            const a = ctx.id();
	            const b = v.value;
	            return typeof a === typeof b && a < b;
	        }
	    ],
	    'filter->': [
	        BooleanType,
	        [
	            StringType,
	            ValueType
	        ],
	        (ctx, [k, v]) => {
	            const a = ctx.properties()[k.value];
	            const b = v.value;
	            return typeof a === typeof b && a > b;
	        }
	    ],
	    'filter-id->': [
	        BooleanType,
	        [ValueType],
	        (ctx, [v]) => {
	            const a = ctx.id();
	            const b = v.value;
	            return typeof a === typeof b && a > b;
	        }
	    ],
	    'filter-<=': [
	        BooleanType,
	        [
	            StringType,
	            ValueType
	        ],
	        (ctx, [k, v]) => {
	            const a = ctx.properties()[k.value];
	            const b = v.value;
	            return typeof a === typeof b && a <= b;
	        }
	    ],
	    'filter-id-<=': [
	        BooleanType,
	        [ValueType],
	        (ctx, [v]) => {
	            const a = ctx.id();
	            const b = v.value;
	            return typeof a === typeof b && a <= b;
	        }
	    ],
	    'filter->=': [
	        BooleanType,
	        [
	            StringType,
	            ValueType
	        ],
	        (ctx, [k, v]) => {
	            const a = ctx.properties()[k.value];
	            const b = v.value;
	            return typeof a === typeof b && a >= b;
	        }
	    ],
	    'filter-id->=': [
	        BooleanType,
	        [ValueType],
	        (ctx, [v]) => {
	            const a = ctx.id();
	            const b = v.value;
	            return typeof a === typeof b && a >= b;
	        }
	    ],
	    'filter-has': [
	        BooleanType,
	        [ValueType],
	        (ctx, [k]) => k.value in ctx.properties()
	    ],
	    'filter-has-id': [
	        BooleanType,
	        [],
	        ctx => ctx.id() !== null && ctx.id() !== undefined
	    ],
	    'filter-type-in': [
	        BooleanType,
	        [array$1(StringType)],
	        (ctx, [v]) => v.value.indexOf(ctx.geometryType()) >= 0
	    ],
	    'filter-id-in': [
	        BooleanType,
	        [array$1(ValueType)],
	        (ctx, [v]) => v.value.indexOf(ctx.id()) >= 0
	    ],
	    'filter-in-small': [
	        BooleanType,
	        [
	            StringType,
	            array$1(ValueType)
	        ],
	        (ctx, [k, v]) => v.value.indexOf(ctx.properties()[k.value]) >= 0
	    ],
	    'filter-in-large': [
	        BooleanType,
	        [
	            StringType,
	            array$1(ValueType)
	        ],
	        (ctx, [k, v]) => binarySearch(ctx.properties()[k.value], v.value, 0, v.value.length - 1)
	    ],
	    'all': {
	        type: BooleanType,
	        overloads: [
	            [
	                [
	                    BooleanType,
	                    BooleanType
	                ],
	                (ctx, [a, b]) => a.evaluate(ctx) && b.evaluate(ctx)
	            ],
	            [
	                varargs(BooleanType),
	                (ctx, args) => {
	                    for (const arg of args) {
	                        if (!arg.evaluate(ctx))
	                            return false;
	                    }
	                    return true;
	                }
	            ]
	        ]
	    },
	    'any': {
	        type: BooleanType,
	        overloads: [
	            [
	                [
	                    BooleanType,
	                    BooleanType
	                ],
	                (ctx, [a, b]) => a.evaluate(ctx) || b.evaluate(ctx)
	            ],
	            [
	                varargs(BooleanType),
	                (ctx, args) => {
	                    for (const arg of args) {
	                        if (arg.evaluate(ctx))
	                            return true;
	                    }
	                    return false;
	                }
	            ]
	        ]
	    },
	    '!': [
	        BooleanType,
	        [BooleanType],
	        (ctx, [b]) => !b.evaluate(ctx)
	    ],
	    'is-supported-script': [
	        BooleanType,
	        [StringType],
	        (ctx, [s]) => {
	            const isSupportedScript = ctx.globals && ctx.globals.isSupportedScript;
	            if (isSupportedScript) {
	                return isSupportedScript(s.evaluate(ctx));
	            }
	            return true;
	        }
	    ],
	    'upcase': [
	        StringType,
	        [StringType],
	        (ctx, [s]) => s.evaluate(ctx).toUpperCase()
	    ],
	    'downcase': [
	        StringType,
	        [StringType],
	        (ctx, [s]) => s.evaluate(ctx).toLowerCase()
	    ],
	    'concat': [
	        StringType,
	        varargs(ValueType),
	        (ctx, args) => args.map(arg => toString(arg.evaluate(ctx))).join('')
	    ],
	    'resolved-locale': [
	        StringType,
	        [CollatorType],
	        (ctx, [collator]) => collator.evaluate(ctx).resolvedLocale()
	    ]
	});
	var expressions$1 = expressions;

	function success(value) {
	    return {
	        result: 'success',
	        value
	    };
	}
	function error(value) {
	    return {
	        result: 'error',
	        value
	    };
	}

	function supportsPropertyExpression(spec) {
	    return spec['property-type'] === 'data-driven' || spec['property-type'] === 'cross-faded-data-driven';
	}
	function supportsZoomExpression(spec) {
	    return !!spec.expression && spec.expression.parameters.indexOf('zoom') > -1;
	}
	function supportsInterpolation(spec) {
	    return !!spec.expression && spec.expression.interpolated;
	}

	function getType(val) {
	    if (val instanceof Number) {
	        return 'number';
	    } else if (val instanceof String) {
	        return 'string';
	    } else if (val instanceof Boolean) {
	        return 'boolean';
	    } else if (Array.isArray(val)) {
	        return 'array';
	    } else if (val === null) {
	        return 'null';
	    } else {
	        return typeof val;
	    }
	}

	function isFunction(value) {
	    return typeof value === 'object' && value !== null && !Array.isArray(value);
	}
	function identityFunction(x) {
	    return x;
	}
	function createFunction(parameters, propertySpec) {
	    const isColor = propertySpec.type === 'color';
	    const zoomAndFeatureDependent = parameters.stops && typeof parameters.stops[0][0] === 'object';
	    const featureDependent = zoomAndFeatureDependent || parameters.property !== undefined;
	    const zoomDependent = zoomAndFeatureDependent || !featureDependent;
	    const type = parameters.type || (supportsInterpolation(propertySpec) ? 'exponential' : 'interval');
	    if (isColor) {
	        parameters = extend({}, parameters);
	        if (parameters.stops) {
	            parameters.stops = parameters.stops.map(stop => {
	                return [
	                    stop[0],
	                    Color$1.parse(stop[1])
	                ];
	            });
	        }
	        if (parameters.default) {
	            parameters.default = Color$1.parse(parameters.default);
	        } else {
	            parameters.default = Color$1.parse(propertySpec.default);
	        }
	    }
	    if (parameters.colorSpace && parameters.colorSpace !== 'rgb' && !colorSpaces[parameters.colorSpace]) {
	        throw new Error(`Unknown color space: ${ parameters.colorSpace }`);
	    }
	    let innerFun;
	    let hashedStops;
	    let categoricalKeyType;
	    if (type === 'exponential') {
	        innerFun = evaluateExponentialFunction;
	    } else if (type === 'interval') {
	        innerFun = evaluateIntervalFunction;
	    } else if (type === 'categorical') {
	        innerFun = evaluateCategoricalFunction;
	        hashedStops = Object.create(null);
	        for (const stop of parameters.stops) {
	            hashedStops[stop[0]] = stop[1];
	        }
	        categoricalKeyType = typeof parameters.stops[0][0];
	    } else if (type === 'identity') {
	        innerFun = evaluateIdentityFunction;
	    } else {
	        throw new Error(`Unknown function type "${ type }"`);
	    }
	    if (zoomAndFeatureDependent) {
	        const featureFunctions = {};
	        const zoomStops = [];
	        for (let s = 0; s < parameters.stops.length; s++) {
	            const stop = parameters.stops[s];
	            const zoom = stop[0].zoom;
	            if (featureFunctions[zoom] === undefined) {
	                featureFunctions[zoom] = {
	                    zoom,
	                    type: parameters.type,
	                    property: parameters.property,
	                    default: parameters.default,
	                    stops: []
	                };
	                zoomStops.push(zoom);
	            }
	            featureFunctions[zoom].stops.push([
	                stop[0].value,
	                stop[1]
	            ]);
	        }
	        const featureFunctionStops = [];
	        for (const z of zoomStops) {
	            featureFunctionStops.push([
	                featureFunctions[z].zoom,
	                createFunction(featureFunctions[z], propertySpec)
	            ]);
	        }
	        const interpolationType = { name: 'linear' };
	        return {
	            kind: 'composite',
	            interpolationType,
	            interpolationFactor: Interpolate$1.interpolationFactor.bind(undefined, interpolationType),
	            zoomStops: featureFunctionStops.map(s => s[0]),
	            evaluate({zoom}, properties) {
	                return evaluateExponentialFunction({
	                    stops: featureFunctionStops,
	                    base: parameters.base
	                }, propertySpec, zoom).evaluate(zoom, properties);
	            }
	        };
	    } else if (zoomDependent) {
	        const interpolationType = type === 'exponential' ? {
	            name: 'exponential',
	            base: parameters.base !== undefined ? parameters.base : 1
	        } : null;
	        return {
	            kind: 'camera',
	            interpolationType,
	            interpolationFactor: Interpolate$1.interpolationFactor.bind(undefined, interpolationType),
	            zoomStops: parameters.stops.map(s => s[0]),
	            evaluate: ({zoom}) => innerFun(parameters, propertySpec, zoom, hashedStops, categoricalKeyType)
	        };
	    } else {
	        return {
	            kind: 'source',
	            evaluate(_, feature) {
	                const value = feature && feature.properties ? feature.properties[parameters.property] : undefined;
	                if (value === undefined) {
	                    return coalesce(parameters.default, propertySpec.default);
	                }
	                return innerFun(parameters, propertySpec, value, hashedStops, categoricalKeyType);
	            }
	        };
	    }
	}
	function coalesce(a, b, c) {
	    if (a !== undefined)
	        return a;
	    if (b !== undefined)
	        return b;
	    if (c !== undefined)
	        return c;
	}
	function evaluateCategoricalFunction(parameters, propertySpec, input, hashedStops, keyType) {
	    const evaluated = typeof input === keyType ? hashedStops[input] : undefined;
	    return coalesce(evaluated, parameters.default, propertySpec.default);
	}
	function evaluateIntervalFunction(parameters, propertySpec, input) {
	    if (getType(input) !== 'number')
	        return coalesce(parameters.default, propertySpec.default);
	    const n = parameters.stops.length;
	    if (n === 1)
	        return parameters.stops[0][1];
	    if (input <= parameters.stops[0][0])
	        return parameters.stops[0][1];
	    if (input >= parameters.stops[n - 1][0])
	        return parameters.stops[n - 1][1];
	    const index = findStopLessThanOrEqualTo(parameters.stops.map(stop => stop[0]), input);
	    return parameters.stops[index][1];
	}
	function evaluateExponentialFunction(parameters, propertySpec, input) {
	    const base = parameters.base !== undefined ? parameters.base : 1;
	    if (getType(input) !== 'number')
	        return coalesce(parameters.default, propertySpec.default);
	    const n = parameters.stops.length;
	    if (n === 1)
	        return parameters.stops[0][1];
	    if (input <= parameters.stops[0][0])
	        return parameters.stops[0][1];
	    if (input >= parameters.stops[n - 1][0])
	        return parameters.stops[n - 1][1];
	    const index = findStopLessThanOrEqualTo(parameters.stops.map(stop => stop[0]), input);
	    const t = interpolationFactor(input, base, parameters.stops[index][0], parameters.stops[index + 1][0]);
	    const outputLower = parameters.stops[index][1];
	    const outputUpper = parameters.stops[index + 1][1];
	    let interp = interpolate[propertySpec.type] || identityFunction;
	    if (parameters.colorSpace && parameters.colorSpace !== 'rgb') {
	        const colorspace = colorSpaces[parameters.colorSpace];
	        interp = (a, b) => colorspace.reverse(colorspace.interpolate(colorspace.forward(a), colorspace.forward(b), t));
	    }
	    if (typeof outputLower.evaluate === 'function') {
	        return {
	            evaluate(...args) {
	                const evaluatedLower = outputLower.evaluate.apply(undefined, args);
	                const evaluatedUpper = outputUpper.evaluate.apply(undefined, args);
	                if (evaluatedLower === undefined || evaluatedUpper === undefined) {
	                    return undefined;
	                }
	                return interp(evaluatedLower, evaluatedUpper, t);
	            }
	        };
	    }
	    return interp(outputLower, outputUpper, t);
	}
	function evaluateIdentityFunction(parameters, propertySpec, input) {
	    if (propertySpec.type === 'color') {
	        input = Color$1.parse(input);
	    } else if (propertySpec.type === 'formatted') {
	        input = Formatted.fromString(input.toString());
	    } else if (propertySpec.type === 'resolvedImage') {
	        input = ResolvedImage.fromString(input.toString());
	    } else if (getType(input) !== propertySpec.type && (propertySpec.type !== 'enum' || !propertySpec.values[input])) {
	        input = undefined;
	    }
	    return coalesce(input, parameters.default, propertySpec.default);
	}
	function interpolationFactor(input, base, lowerValue, upperValue) {
	    const difference = upperValue - lowerValue;
	    const progress = input - lowerValue;
	    if (difference === 0) {
	        return 0;
	    } else if (base === 1) {
	        return progress / difference;
	    } else {
	        return (Math.pow(base, progress) - 1) / (Math.pow(base, difference) - 1);
	    }
	}

	class StyleExpression {
	    constructor(expression, propertySpec) {
	        this.expression = expression;
	        this._warningHistory = {};
	        this._evaluator = new EvaluationContext$1();
	        this._defaultValue = propertySpec ? getDefaultValue(propertySpec) : null;
	        this._enumValues = propertySpec && propertySpec.type === 'enum' ? propertySpec.values : null;
	    }
	    evaluateWithoutErrorHandling(globals, feature, featureState, canonical, availableImages, formattedSection, featureTileCoord, featureDistanceData) {
	        this._evaluator.globals = globals;
	        this._evaluator.feature = feature;
	        this._evaluator.featureState = featureState;
	        this._evaluator.canonical = canonical || null;
	        this._evaluator.availableImages = availableImages || null;
	        this._evaluator.formattedSection = formattedSection;
	        this._evaluator.featureTileCoord = featureTileCoord || null;
	        this._evaluator.featureDistanceData = featureDistanceData || null;
	        return this.expression.evaluate(this._evaluator);
	    }
	    evaluate(globals, feature, featureState, canonical, availableImages, formattedSection, featureTileCoord, featureDistanceData) {
	        this._evaluator.globals = globals;
	        this._evaluator.feature = feature || null;
	        this._evaluator.featureState = featureState || null;
	        this._evaluator.canonical = canonical || null;
	        this._evaluator.availableImages = availableImages || null;
	        this._evaluator.formattedSection = formattedSection || null;
	        this._evaluator.featureTileCoord = featureTileCoord || null;
	        this._evaluator.featureDistanceData = featureDistanceData || null;
	        try {
	            const val = this.expression.evaluate(this._evaluator);
	            if (val === null || val === undefined || typeof val === 'number' && val !== val) {
	                return this._defaultValue;
	            }
	            if (this._enumValues && !(val in this._enumValues)) {
	                throw new RuntimeError$1(`Expected value to be one of ${ Object.keys(this._enumValues).map(v => JSON.stringify(v)).join(', ') }, but found ${ JSON.stringify(val) } instead.`);
	            }
	            return val;
	        } catch (e) {
	            if (!this._warningHistory[e.message]) {
	                this._warningHistory[e.message] = true;
	                if (typeof console !== 'undefined') {
	                    console.warn(e.message);
	                }
	            }
	            return this._defaultValue;
	        }
	    }
	}
	function isExpression(expression) {
	    return Array.isArray(expression) && expression.length > 0 && typeof expression[0] === 'string' && expression[0] in expressions$1;
	}
	function createExpression(expression, propertySpec) {
	    const parser = new ParsingContext$1(expressions$1, [], propertySpec ? getExpectedType(propertySpec) : undefined);
	    const parsed = parser.parse(expression, undefined, undefined, undefined, propertySpec && propertySpec.type === 'string' ? { typeAnnotation: 'coerce' } : undefined);
	    if (!parsed) {
	        return error(parser.errors);
	    }
	    return success(new StyleExpression(parsed, propertySpec));
	}
	class ZoomConstantExpression {
	    constructor(kind, expression) {
	        this.kind = kind;
	        this._styleExpression = expression;
	        this.isStateDependent = kind !== 'constant' && !isStateConstant(expression.expression);
	    }
	    evaluateWithoutErrorHandling(globals, feature, featureState, canonical, availableImages, formattedSection) {
	        return this._styleExpression.evaluateWithoutErrorHandling(globals, feature, featureState, canonical, availableImages, formattedSection);
	    }
	    evaluate(globals, feature, featureState, canonical, availableImages, formattedSection) {
	        return this._styleExpression.evaluate(globals, feature, featureState, canonical, availableImages, formattedSection);
	    }
	}
	class ZoomDependentExpression {
	    constructor(kind, expression, zoomStops, interpolationType) {
	        this.kind = kind;
	        this.zoomStops = zoomStops;
	        this._styleExpression = expression;
	        this.isStateDependent = kind !== 'camera' && !isStateConstant(expression.expression);
	        this.interpolationType = interpolationType;
	    }
	    evaluateWithoutErrorHandling(globals, feature, featureState, canonical, availableImages, formattedSection) {
	        return this._styleExpression.evaluateWithoutErrorHandling(globals, feature, featureState, canonical, availableImages, formattedSection);
	    }
	    evaluate(globals, feature, featureState, canonical, availableImages, formattedSection) {
	        return this._styleExpression.evaluate(globals, feature, featureState, canonical, availableImages, formattedSection);
	    }
	    interpolationFactor(input, lower, upper) {
	        if (this.interpolationType) {
	            return Interpolate$1.interpolationFactor(this.interpolationType, input, lower, upper);
	        } else {
	            return 0;
	        }
	    }
	}
	function createPropertyExpression(expression, propertySpec) {
	    expression = createExpression(expression, propertySpec);
	    if (expression.result === 'error') {
	        return expression;
	    }
	    const parsed = expression.value.expression;
	    const isFeatureConstant$1 = isFeatureConstant(parsed);
	    if (!isFeatureConstant$1 && !supportsPropertyExpression(propertySpec)) {
	        return error([new ParsingError$1('', 'data expressions not supported')]);
	    }
	    const isZoomConstant = isGlobalPropertyConstant(parsed, [
	        'zoom',
	        'pitch',
	        'distance-from-center'
	    ]);
	    if (!isZoomConstant && !supportsZoomExpression(propertySpec)) {
	        return error([new ParsingError$1('', 'zoom expressions not supported')]);
	    }
	    const zoomCurve = findZoomCurve(parsed);
	    if (!zoomCurve && !isZoomConstant) {
	        return error([new ParsingError$1('', '"zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.')]);
	    } else if (zoomCurve instanceof ParsingError$1) {
	        return error([zoomCurve]);
	    } else if (zoomCurve instanceof Interpolate$1 && !supportsInterpolation(propertySpec)) {
	        return error([new ParsingError$1('', '"interpolate" expressions cannot be used with this property')]);
	    }
	    if (!zoomCurve) {
	        return success(isFeatureConstant$1 ? new ZoomConstantExpression('constant', expression.value) : new ZoomConstantExpression('source', expression.value));
	    }
	    const interpolationType = zoomCurve instanceof Interpolate$1 ? zoomCurve.interpolation : undefined;
	    return success(isFeatureConstant$1 ? new ZoomDependentExpression('camera', expression.value, zoomCurve.labels, interpolationType) : new ZoomDependentExpression('composite', expression.value, zoomCurve.labels, interpolationType));
	}
	class StylePropertyFunction {
	    constructor(parameters, specification) {
	        this._parameters = parameters;
	        this._specification = specification;
	        extend(this, createFunction(this._parameters, this._specification));
	    }
	    static deserialize(serialized) {
	        return new StylePropertyFunction(serialized._parameters, serialized._specification);
	    }
	    static serialize(input) {
	        return {
	            _parameters: input._parameters,
	            _specification: input._specification
	        };
	    }
	}
	function normalizePropertyExpression(value, specification) {
	    if (isFunction(value)) {
	        return new StylePropertyFunction(value, specification);
	    } else if (isExpression(value)) {
	        const expression = createPropertyExpression(value, specification);
	        if (expression.result === 'error') {
	            throw new Error(expression.value.map(err => `${ err.key }: ${ err.message }`).join(', '));
	        }
	        return expression.value;
	    } else {
	        let constant = value;
	        if (typeof value === 'string' && specification.type === 'color') {
	            constant = Color$1.parse(value);
	        }
	        return {
	            kind: 'constant',
	            evaluate: () => constant
	        };
	    }
	}
	function findZoomCurve(expression) {
	    let result = null;
	    if (expression instanceof Let$1) {
	        result = findZoomCurve(expression.result);
	    } else if (expression instanceof Coalesce$1) {
	        for (const arg of expression.args) {
	            result = findZoomCurve(arg);
	            if (result) {
	                break;
	            }
	        }
	    } else if ((expression instanceof Step$1 || expression instanceof Interpolate$1) && expression.input instanceof CompoundExpression$1 && expression.input.name === 'zoom') {
	        result = expression;
	    }
	    if (result instanceof ParsingError$1) {
	        return result;
	    }
	    expression.eachChild(child => {
	        const childResult = findZoomCurve(child);
	        if (childResult instanceof ParsingError$1) {
	            result = childResult;
	        } else if (!result && childResult) {
	            result = new ParsingError$1('', '"zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.');
	        } else if (result && childResult && result !== childResult) {
	            result = new ParsingError$1('', 'Only one zoom-based "step" or "interpolate" subexpression may be used in an expression.');
	        }
	    });
	    return result;
	}
	function getExpectedType(spec) {
	    const types = {
	        color: ColorType,
	        string: StringType,
	        number: NumberType,
	        enum: StringType,
	        boolean: BooleanType,
	        formatted: FormattedType,
	        resolvedImage: ResolvedImageType
	    };
	    if (spec.type === 'array') {
	        return array$1(types[spec.value] || ValueType, spec.length);
	    }
	    return types[spec.type];
	}
	function getDefaultValue(spec) {
	    if (spec.type === 'color' && (isFunction(spec.default) || Array.isArray(spec.default))) {
	        return new Color$1(0, 0, 0, 0);
	    } else if (spec.type === 'color') {
	        return Color$1.parse(spec.default) || null;
	    } else if (spec.default === undefined) {
	        return null;
	    } else {
	        return spec.default;
	    }
	}

	class ValidationError {
	    constructor(key, value, message, identifier) {
	        this.message = (key ? `${ key }: ` : '') + message;
	        if (identifier)
	            this.identifier = identifier;
	        if (value !== null && value !== undefined && value.__line__) {
	            this.line = value.__line__;
	        }
	    }
	}

	function validateObject(options) {
	    const key = options.key;
	    const object = options.value;
	    const elementSpecs = options.valueSpec || {};
	    const elementValidators = options.objectElementValidators || {};
	    const style = options.style;
	    const styleSpec = options.styleSpec;
	    let errors = [];
	    const type = getType(object);
	    if (type !== 'object') {
	        return [new ValidationError(key, object, `object expected, ${ type } found`)];
	    }
	    for (const objectKey in object) {
	        const elementSpecKey = objectKey.split('.')[0];
	        const elementSpec = elementSpecs[elementSpecKey] || elementSpecs['*'];
	        let validateElement;
	        if (elementValidators[elementSpecKey]) {
	            validateElement = elementValidators[elementSpecKey];
	        } else if (elementSpecs[elementSpecKey]) {
	            validateElement = validate;
	        } else if (elementValidators['*']) {
	            validateElement = elementValidators['*'];
	        } else if (elementSpecs['*']) {
	            validateElement = validate;
	        }
	        if (!validateElement) {
	            errors.push(new ValidationError(key, object[objectKey], `unknown property "${ objectKey }"`));
	            continue;
	        }
	        errors = errors.concat(validateElement({
	            key: (key ? `${ key }.` : key) + objectKey,
	            value: object[objectKey],
	            valueSpec: elementSpec,
	            style,
	            styleSpec,
	            object,
	            objectKey
	        }, object));
	    }
	    for (const elementSpecKey in elementSpecs) {
	        if (elementValidators[elementSpecKey]) {
	            continue;
	        }
	        if (elementSpecs[elementSpecKey].required && elementSpecs[elementSpecKey]['default'] === undefined && object[elementSpecKey] === undefined) {
	            errors.push(new ValidationError(key, object, `missing required property "${ elementSpecKey }"`));
	        }
	    }
	    return errors;
	}

	function validateArray(options) {
	    const array = options.value;
	    const arraySpec = options.valueSpec;
	    const style = options.style;
	    const styleSpec = options.styleSpec;
	    const key = options.key;
	    const validateArrayElement = options.arrayElementValidator || validate;
	    if (getType(array) !== 'array') {
	        return [new ValidationError(key, array, `array expected, ${ getType(array) } found`)];
	    }
	    if (arraySpec.length && array.length !== arraySpec.length) {
	        return [new ValidationError(key, array, `array length ${ arraySpec.length } expected, length ${ array.length } found`)];
	    }
	    if (arraySpec['min-length'] && array.length < arraySpec['min-length']) {
	        return [new ValidationError(key, array, `array length at least ${ arraySpec['min-length'] } expected, length ${ array.length } found`)];
	    }
	    let arrayElementSpec = {
	        'type': arraySpec.value,
	        'values': arraySpec.values,
	        'minimum': arraySpec.minimum,
	        'maximum': arraySpec.maximum,
	        function: undefined
	    };
	    if (styleSpec.$version < 7) {
	        arrayElementSpec.function = arraySpec.function;
	    }
	    if (getType(arraySpec.value) === 'object') {
	        arrayElementSpec = arraySpec.value;
	    }
	    let errors = [];
	    for (let i = 0; i < array.length; i++) {
	        errors = errors.concat(validateArrayElement({
	            array,
	            arrayIndex: i,
	            value: array[i],
	            valueSpec: arrayElementSpec,
	            style,
	            styleSpec,
	            key: `${ key }[${ i }]`
	        }));
	    }
	    return errors;
	}

	function validateNumber(options) {
	    const key = options.key;
	    const value = options.value;
	    const valueSpec = options.valueSpec;
	    let type = getType(value);
	    if (type === 'number' && value !== value) {
	        type = 'NaN';
	    }
	    if (type !== 'number') {
	        return [new ValidationError(key, value, `number expected, ${ type } found`)];
	    }
	    if ('minimum' in valueSpec) {
	        let specMin = valueSpec.minimum;
	        if (getType(valueSpec.minimum) === 'array') {
	            const i = options.arrayIndex;
	            specMin = valueSpec.minimum[i];
	        }
	        if (value < specMin) {
	            return [new ValidationError(key, value, `${ value } is less than the minimum value ${ specMin }`)];
	        }
	    }
	    if ('maximum' in valueSpec) {
	        let specMax = valueSpec.maximum;
	        if (getType(valueSpec.maximum) === 'array') {
	            const i = options.arrayIndex;
	            specMax = valueSpec.maximum[i];
	        }
	        if (value > specMax) {
	            return [new ValidationError(key, value, `${ value } is greater than the maximum value ${ specMax }`)];
	        }
	    }
	    return [];
	}

	function validateFunction(options) {
	    const functionValueSpec = options.valueSpec;
	    const functionType = unbundle(options.value.type);
	    let stopKeyType;
	    let stopDomainValues = {};
	    let previousStopDomainValue;
	    let previousStopDomainZoom;
	    const isZoomFunction = functionType !== 'categorical' && options.value.property === undefined;
	    const isPropertyFunction = !isZoomFunction;
	    const isZoomAndPropertyFunction = getType(options.value.stops) === 'array' && getType(options.value.stops[0]) === 'array' && getType(options.value.stops[0][0]) === 'object';
	    const errors = validateObject({
	        key: options.key,
	        value: options.value,
	        valueSpec: options.styleSpec.function,
	        style: options.style,
	        styleSpec: options.styleSpec,
	        objectElementValidators: {
	            stops: validateFunctionStops,
	            default: validateFunctionDefault
	        }
	    });
	    if (functionType === 'identity' && isZoomFunction) {
	        errors.push(new ValidationError(options.key, options.value, 'missing required property "property"'));
	    }
	    if (functionType !== 'identity' && !options.value.stops) {
	        errors.push(new ValidationError(options.key, options.value, 'missing required property "stops"'));
	    }
	    if (functionType === 'exponential' && options.valueSpec.expression && !supportsInterpolation(options.valueSpec)) {
	        errors.push(new ValidationError(options.key, options.value, 'exponential functions not supported'));
	    }
	    if (options.styleSpec.$version >= 8) {
	        if (isPropertyFunction && !supportsPropertyExpression(options.valueSpec)) {
	            errors.push(new ValidationError(options.key, options.value, 'property functions not supported'));
	        } else if (isZoomFunction && !supportsZoomExpression(options.valueSpec)) {
	            errors.push(new ValidationError(options.key, options.value, 'zoom functions not supported'));
	        }
	    }
	    if ((functionType === 'categorical' || isZoomAndPropertyFunction) && options.value.property === undefined) {
	        errors.push(new ValidationError(options.key, options.value, '"property" property is required'));
	    }
	    return errors;
	    function validateFunctionStops(options) {
	        if (functionType === 'identity') {
	            return [new ValidationError(options.key, options.value, 'identity function may not have a "stops" property')];
	        }
	        let errors = [];
	        const value = options.value;
	        errors = errors.concat(validateArray({
	            key: options.key,
	            value,
	            valueSpec: options.valueSpec,
	            style: options.style,
	            styleSpec: options.styleSpec,
	            arrayElementValidator: validateFunctionStop
	        }));
	        if (getType(value) === 'array' && value.length === 0) {
	            errors.push(new ValidationError(options.key, value, 'array must have at least one stop'));
	        }
	        return errors;
	    }
	    function validateFunctionStop(options) {
	        let errors = [];
	        const value = options.value;
	        const key = options.key;
	        if (getType(value) !== 'array') {
	            return [new ValidationError(key, value, `array expected, ${ getType(value) } found`)];
	        }
	        if (value.length !== 2) {
	            return [new ValidationError(key, value, `array length 2 expected, length ${ value.length } found`)];
	        }
	        if (isZoomAndPropertyFunction) {
	            if (getType(value[0]) !== 'object') {
	                return [new ValidationError(key, value, `object expected, ${ getType(value[0]) } found`)];
	            }
	            if (value[0].zoom === undefined) {
	                return [new ValidationError(key, value, 'object stop key must have zoom')];
	            }
	            if (value[0].value === undefined) {
	                return [new ValidationError(key, value, 'object stop key must have value')];
	            }
	            const nextStopDomainZoom = unbundle(value[0].zoom);
	            if (typeof nextStopDomainZoom !== 'number') {
	                return [new ValidationError(key, value[0].zoom, 'stop zoom values must be numbers')];
	            }
	            if (previousStopDomainZoom && previousStopDomainZoom > nextStopDomainZoom) {
	                return [new ValidationError(key, value[0].zoom, 'stop zoom values must appear in ascending order')];
	            }
	            if (nextStopDomainZoom !== previousStopDomainZoom) {
	                previousStopDomainZoom = nextStopDomainZoom;
	                previousStopDomainValue = undefined;
	                stopDomainValues = {};
	            }
	            errors = errors.concat(validateObject({
	                key: `${ key }[0]`,
	                value: value[0],
	                valueSpec: { zoom: {} },
	                style: options.style,
	                styleSpec: options.styleSpec,
	                objectElementValidators: {
	                    zoom: validateNumber,
	                    value: validateStopDomainValue
	                }
	            }));
	        } else {
	            errors = errors.concat(validateStopDomainValue({
	                key: `${ key }[0]`,
	                value: value[0],
	                valueSpec: {},
	                style: options.style,
	                styleSpec: options.styleSpec
	            }, value));
	        }
	        if (isExpression(deepUnbundle(value[1]))) {
	            return errors.concat([new ValidationError(`${ key }[1]`, value[1], 'expressions are not allowed in function stops.')]);
	        }
	        return errors.concat(validate({
	            key: `${ key }[1]`,
	            value: value[1],
	            valueSpec: functionValueSpec,
	            style: options.style,
	            styleSpec: options.styleSpec
	        }));
	    }
	    function validateStopDomainValue(options, stop) {
	        const type = getType(options.value);
	        const value = unbundle(options.value);
	        const reportValue = options.value !== null ? options.value : stop;
	        if (!stopKeyType) {
	            stopKeyType = type;
	        } else if (type !== stopKeyType) {
	            return [new ValidationError(options.key, reportValue, `${ type } stop domain type must match previous stop domain type ${ stopKeyType }`)];
	        }
	        if (type !== 'number' && type !== 'string' && type !== 'boolean' && typeof value !== 'number' && typeof value !== 'string' && typeof value !== 'boolean') {
	            return [new ValidationError(options.key, reportValue, 'stop domain value must be a number, string, or boolean')];
	        }
	        if (type !== 'number' && functionType !== 'categorical') {
	            let message = `number expected, ${ type } found`;
	            if (supportsPropertyExpression(functionValueSpec) && functionType === undefined) {
	                message += '\nIf you intended to use a categorical function, specify `"type": "categorical"`.';
	            }
	            return [new ValidationError(options.key, reportValue, message)];
	        }
	        if (functionType === 'categorical' && type === 'number' && (typeof value !== 'number' || !isFinite(value) || Math.floor(value) !== value)) {
	            return [new ValidationError(options.key, reportValue, `integer expected, found ${ String(value) }`)];
	        }
	        if (functionType !== 'categorical' && type === 'number' && typeof value === 'number' && typeof previousStopDomainValue === 'number' && previousStopDomainValue !== undefined && value < previousStopDomainValue) {
	            return [new ValidationError(options.key, reportValue, 'stop domain values must appear in ascending order')];
	        } else {
	            previousStopDomainValue = value;
	        }
	        if (functionType === 'categorical' && value in stopDomainValues) {
	            return [new ValidationError(options.key, reportValue, 'stop domain values must be unique')];
	        } else {
	            stopDomainValues[value] = true;
	        }
	        return [];
	    }
	    function validateFunctionDefault(options) {
	        return validate({
	            key: options.key,
	            value: options.value,
	            valueSpec: functionValueSpec,
	            style: options.style,
	            styleSpec: options.styleSpec
	        });
	    }
	}

	function validateExpression(options) {
	    const expression = (options.expressionContext === 'property' ? createPropertyExpression : createExpression)(deepUnbundle(options.value), options.valueSpec);
	    if (expression.result === 'error') {
	        return expression.value.map(error => {
	            return new ValidationError(`${ options.key }${ error.key }`, options.value, error.message);
	        });
	    }
	    const expressionObj = expression.value.expression || expression.value._styleExpression.expression;
	    if (options.expressionContext === 'property' && options.propertyKey === 'text-font' && !expressionObj.outputDefined()) {
	        return [new ValidationError(options.key, options.value, `Invalid data expression for "${ options.propertyKey }". Output values must be contained as literals within the expression.`)];
	    }
	    if (options.expressionContext === 'property' && options.propertyType === 'layout' && !isStateConstant(expressionObj)) {
	        return [new ValidationError(options.key, options.value, '"feature-state" data expressions are not supported with layout properties.')];
	    }
	    if (options.expressionContext === 'filter') {
	        return disallowedFilterParameters(expressionObj, options);
	    }
	    if (options.expressionContext && options.expressionContext.indexOf('cluster') === 0) {
	        if (!isGlobalPropertyConstant(expressionObj, [
	                'zoom',
	                'feature-state'
	            ])) {
	            return [new ValidationError(options.key, options.value, '"zoom" and "feature-state" expressions are not supported with cluster properties.')];
	        }
	        if (options.expressionContext === 'cluster-initial' && !isFeatureConstant(expressionObj)) {
	            return [new ValidationError(options.key, options.value, 'Feature data expressions are not supported with initial expression part of cluster properties.')];
	        }
	    }
	    return [];
	}
	function disallowedFilterParameters(e, options) {
	    const disallowedParameters = new Set([
	        'zoom',
	        'feature-state',
	        'pitch',
	        'distance-from-center'
	    ]);
	    if (options.valueSpec && options.valueSpec.expression) {
	        for (const param of options.valueSpec.expression.parameters) {
	            disallowedParameters.delete(param);
	        }
	    }
	    if (disallowedParameters.size === 0) {
	        return [];
	    }
	    const errors = [];
	    if (e instanceof CompoundExpression$1) {
	        if (disallowedParameters.has(e.name)) {
	            return [new ValidationError(options.key, options.value, `["${ e.name }"] expression is not supported in a filter for a ${ options.object.type } layer with id: ${ options.object.id }`)];
	        }
	    }
	    e.eachChild(arg => {
	        errors.push(...disallowedFilterParameters(arg, options));
	    });
	    return errors;
	}

	function validateBoolean(options) {
	    const value = options.value;
	    const key = options.key;
	    const type = getType(value);
	    if (type !== 'boolean') {
	        return [new ValidationError(key, value, `boolean expected, ${ type } found`)];
	    }
	    return [];
	}

	function validateColor(options) {
	    const key = options.key;
	    const value = options.value;
	    const type = getType(value);
	    if (type !== 'string') {
	        return [new ValidationError(key, value, `color expected, ${ type } found`)];
	    }
	    if (csscolorparser.parseCSSColor(value) === null) {
	        return [new ValidationError(key, value, `color expected, "${ value }" found`)];
	    }
	    return [];
	}

	function validateEnum(options) {
	    const key = options.key;
	    const value = options.value;
	    const valueSpec = options.valueSpec;
	    const errors = [];
	    if (Array.isArray(valueSpec.values)) {
	        if (valueSpec.values.indexOf(unbundle(value)) === -1) {
	            errors.push(new ValidationError(key, value, `expected one of [${ valueSpec.values.join(', ') }], ${ JSON.stringify(value) } found`));
	        }
	    } else {
	        if (Object.keys(valueSpec.values).indexOf(unbundle(value)) === -1) {
	            errors.push(new ValidationError(key, value, `expected one of [${ Object.keys(valueSpec.values).join(', ') }], ${ JSON.stringify(value) } found`));
	        }
	    }
	    return errors;
	}

	function isExpressionFilter(filter) {
	    if (filter === true || filter === false) {
	        return true;
	    }
	    if (!Array.isArray(filter) || filter.length === 0) {
	        return false;
	    }
	    switch (filter[0]) {
	    case 'has':
	        return filter.length >= 2 && filter[1] !== '$id' && filter[1] !== '$type';
	    case 'in':
	        return filter.length >= 3 && (typeof filter[1] !== 'string' || Array.isArray(filter[2]));
	    case '!in':
	    case '!has':
	    case 'none':
	        return false;
	    case '==':
	    case '!=':
	    case '>':
	    case '>=':
	    case '<':
	    case '<=':
	        return filter.length !== 3 || (Array.isArray(filter[1]) || Array.isArray(filter[2]));
	    case 'any':
	    case 'all':
	        for (const f of filter.slice(1)) {
	            if (!isExpressionFilter(f) && typeof f !== 'boolean') {
	                return false;
	            }
	        }
	        return true;
	    default:
	        return true;
	    }
	}
	function createFilter(filter, layerType = 'fill') {
	    if (filter === null || filter === undefined) {
	        return {
	            filter: () => true,
	            needGeometry: false,
	            needFeature: false
	        };
	    }
	    if (!isExpressionFilter(filter)) {
	        filter = convertFilter(filter);
	    }
	    const filterExp = filter;
	    let staticFilter = true;
	    try {
	        staticFilter = extractStaticFilter(filterExp);
	    } catch (e) {
	        console.warn(`Failed to extract static filter. Filter will continue working, but at higher memory usage and slower framerate.
	This is most likely a bug, please report this via https://github.com/mapbox/mapbox-gl-js/issues/new?assignees=&labels=&template=Bug_report.md
	and paste the contents of this message in the report.
	Thank you!
	Filter Expression:
	${ JSON.stringify(filterExp, null, 2) }
	        `);
	    }
	    const filterSpec = spec[`filter_${ layerType }`];
	    const compiledStaticFilter = createExpression(staticFilter, filterSpec);
	    let filterFunc = null;
	    if (compiledStaticFilter.result === 'error') {
	        throw new Error(compiledStaticFilter.value.map(err => `${ err.key }: ${ err.message }`).join(', '));
	    } else {
	        filterFunc = (globalProperties, feature, canonical) => compiledStaticFilter.value.evaluate(globalProperties, feature, {}, canonical);
	    }
	    let dynamicFilterFunc = null;
	    let needFeature = null;
	    if (staticFilter !== filterExp) {
	        const compiledDynamicFilter = createExpression(filterExp, filterSpec);
	        if (compiledDynamicFilter.result === 'error') {
	            throw new Error(compiledDynamicFilter.value.map(err => `${ err.key }: ${ err.message }`).join(', '));
	        } else {
	            dynamicFilterFunc = (globalProperties, feature, canonical, featureTileCoord, featureDistanceData) => compiledDynamicFilter.value.evaluate(globalProperties, feature, {}, canonical, undefined, undefined, featureTileCoord, featureDistanceData);
	            needFeature = !isFeatureConstant(compiledDynamicFilter.value.expression);
	        }
	    }
	    filterFunc = filterFunc;
	    const needGeometry = geometryNeeded(staticFilter);
	    return {
	        filter: filterFunc,
	        dynamicFilter: dynamicFilterFunc ? dynamicFilterFunc : undefined,
	        needGeometry,
	        needFeature: !!needFeature
	    };
	}
	function extractStaticFilter(filter) {
	    if (!isDynamicFilter(filter)) {
	        return filter;
	    }
	    let result = deepUnbundle(filter);
	    unionDynamicBranches(result);
	    result = collapseDynamicBooleanExpressions(result);
	    return result;
	}
	function collapseDynamicBooleanExpressions(expression) {
	    if (!Array.isArray(expression)) {
	        return expression;
	    }
	    const collapsed = collapsedExpression(expression);
	    if (collapsed === true) {
	        return collapsed;
	    } else {
	        return collapsed.map(subExpression => collapseDynamicBooleanExpressions(subExpression));
	    }
	}
	function unionDynamicBranches(filter) {
	    let isBranchingDynamically = false;
	    const branches = [];
	    if (filter[0] === 'case') {
	        for (let i = 1; i < filter.length - 1; i += 2) {
	            isBranchingDynamically = isBranchingDynamically || isDynamicFilter(filter[i]);
	            branches.push(filter[i + 1]);
	        }
	        branches.push(filter[filter.length - 1]);
	    } else if (filter[0] === 'match') {
	        isBranchingDynamically = isBranchingDynamically || isDynamicFilter(filter[1]);
	        for (let i = 2; i < filter.length - 1; i += 2) {
	            branches.push(filter[i + 1]);
	        }
	        branches.push(filter[filter.length - 1]);
	    } else if (filter[0] === 'step') {
	        isBranchingDynamically = isBranchingDynamically || isDynamicFilter(filter[1]);
	        for (let i = 1; i < filter.length - 1; i += 2) {
	            branches.push(filter[i + 1]);
	        }
	    }
	    if (isBranchingDynamically) {
	        filter.length = 0;
	        filter.push('any', ...branches);
	    }
	    for (let i = 1; i < filter.length; i++) {
	        unionDynamicBranches(filter[i]);
	    }
	}
	function isDynamicFilter(filter) {
	    if (!Array.isArray(filter)) {
	        return false;
	    }
	    if (isRootExpressionDynamic(filter[0])) {
	        return true;
	    }
	    for (let i = 1; i < filter.length; i++) {
	        const child = filter[i];
	        if (isDynamicFilter(child)) {
	            return true;
	        }
	    }
	    return false;
	}
	function isRootExpressionDynamic(expression) {
	    return expression === 'pitch' || expression === 'distance-from-center';
	}
	const dynamicConditionExpressions = new Set([
	    'in',
	    '==',
	    '!=',
	    '>',
	    '>=',
	    '<',
	    '<=',
	    'to-boolean'
	]);
	function collapsedExpression(expression) {
	    if (dynamicConditionExpressions.has(expression[0])) {
	        for (let i = 1; i < expression.length; i++) {
	            const param = expression[i];
	            if (isDynamicFilter(param)) {
	                return true;
	            }
	        }
	    }
	    return expression;
	}
	function compare(a, b) {
	    return a < b ? -1 : a > b ? 1 : 0;
	}
	function geometryNeeded(filter) {
	    if (!Array.isArray(filter))
	        return false;
	    if (filter[0] === 'within')
	        return true;
	    for (let index = 1; index < filter.length; index++) {
	        if (geometryNeeded(filter[index]))
	            return true;
	    }
	    return false;
	}
	function convertFilter(filter) {
	    if (!filter)
	        return true;
	    const op = filter[0];
	    if (filter.length <= 1)
	        return op !== 'any';
	    const converted = op === '==' ? convertComparisonOp(filter[1], filter[2], '==') : op === '!=' ? convertNegation(convertComparisonOp(filter[1], filter[2], '==')) : op === '<' || op === '>' || op === '<=' || op === '>=' ? convertComparisonOp(filter[1], filter[2], op) : op === 'any' ? convertDisjunctionOp(filter.slice(1)) : op === 'all' ? ['all'].concat(filter.slice(1).map(convertFilter)) : op === 'none' ? ['all'].concat(filter.slice(1).map(convertFilter).map(convertNegation)) : op === 'in' ? convertInOp(filter[1], filter.slice(2)) : op === '!in' ? convertNegation(convertInOp(filter[1], filter.slice(2))) : op === 'has' ? convertHasOp(filter[1]) : op === '!has' ? convertNegation(convertHasOp(filter[1])) : op === 'within' ? filter : true;
	    return converted;
	}
	function convertComparisonOp(property, value, op) {
	    switch (property) {
	    case '$type':
	        return [
	            `filter-type-${ op }`,
	            value
	        ];
	    case '$id':
	        return [
	            `filter-id-${ op }`,
	            value
	        ];
	    default:
	        return [
	            `filter-${ op }`,
	            property,
	            value
	        ];
	    }
	}
	function convertDisjunctionOp(filters) {
	    return ['any'].concat(filters.map(convertFilter));
	}
	function convertInOp(property, values) {
	    if (values.length === 0) {
	        return false;
	    }
	    switch (property) {
	    case '$type':
	        return [
	            `filter-type-in`,
	            [
	                'literal',
	                values
	            ]
	        ];
	    case '$id':
	        return [
	            `filter-id-in`,
	            [
	                'literal',
	                values
	            ]
	        ];
	    default:
	        if (values.length > 200 && !values.some(v => typeof v !== typeof values[0])) {
	            return [
	                'filter-in-large',
	                property,
	                [
	                    'literal',
	                    values.sort(compare)
	                ]
	            ];
	        } else {
	            return [
	                'filter-in-small',
	                property,
	                [
	                    'literal',
	                    values
	                ]
	            ];
	        }
	    }
	}
	function convertHasOp(property) {
	    switch (property) {
	    case '$type':
	        return true;
	    case '$id':
	        return [`filter-has-id`];
	    default:
	        return [
	            `filter-has`,
	            property
	        ];
	    }
	}
	function convertNegation(filter) {
	    return [
	        '!',
	        filter
	    ];
	}

	function validateFilter$1(options) {
	    if (isExpressionFilter(deepUnbundle(options.value))) {
	        const layerType = options.layerType || 'fill';
	        return validateExpression(extend({}, options, {
	            expressionContext: 'filter',
	            valueSpec: options.styleSpec[`filter_${ layerType }`]
	        }));
	    } else {
	        return validateNonExpressionFilter(options);
	    }
	}
	function validateNonExpressionFilter(options) {
	    const value = options.value;
	    const key = options.key;
	    if (getType(value) !== 'array') {
	        return [new ValidationError(key, value, `array expected, ${ getType(value) } found`)];
	    }
	    const styleSpec = options.styleSpec;
	    let type;
	    let errors = [];
	    if (value.length < 1) {
	        return [new ValidationError(key, value, 'filter array must have at least 1 element')];
	    }
	    errors = errors.concat(validateEnum({
	        key: `${ key }[0]`,
	        value: value[0],
	        valueSpec: styleSpec.filter_operator,
	        style: options.style,
	        styleSpec: options.styleSpec
	    }));
	    switch (unbundle(value[0])) {
	    case '<':
	    case '<=':
	    case '>':
	    case '>=':
	        if (value.length >= 2 && unbundle(value[1]) === '$type') {
	            errors.push(new ValidationError(key, value, `"$type" cannot be use with operator "${ value[0] }"`));
	        }
	    case '==':
	    case '!=':
	        if (value.length !== 3) {
	            errors.push(new ValidationError(key, value, `filter array for operator "${ value[0] }" must have 3 elements`));
	        }
	    case 'in':
	    case '!in':
	        if (value.length >= 2) {
	            type = getType(value[1]);
	            if (type !== 'string') {
	                errors.push(new ValidationError(`${ key }[1]`, value[1], `string expected, ${ type } found`));
	            }
	        }
	        for (let i = 2; i < value.length; i++) {
	            type = getType(value[i]);
	            if (unbundle(value[1]) === '$type') {
	                errors = errors.concat(validateEnum({
	                    key: `${ key }[${ i }]`,
	                    value: value[i],
	                    valueSpec: styleSpec.geometry_type,
	                    style: options.style,
	                    styleSpec: options.styleSpec
	                }));
	            } else if (type !== 'string' && type !== 'number' && type !== 'boolean') {
	                errors.push(new ValidationError(`${ key }[${ i }]`, value[i], `string, number, or boolean expected, ${ type } found`));
	            }
	        }
	        break;
	    case 'any':
	    case 'all':
	    case 'none':
	        for (let i = 1; i < value.length; i++) {
	            errors = errors.concat(validateNonExpressionFilter({
	                key: `${ key }[${ i }]`,
	                value: value[i],
	                style: options.style,
	                styleSpec: options.styleSpec
	            }));
	        }
	        break;
	    case 'has':
	    case '!has':
	        type = getType(value[1]);
	        if (value.length !== 2) {
	            errors.push(new ValidationError(key, value, `filter array for "${ value[0] }" operator must have 2 elements`));
	        } else if (type !== 'string') {
	            errors.push(new ValidationError(`${ key }[1]`, value[1], `string expected, ${ type } found`));
	        }
	        break;
	    case 'within':
	        type = getType(value[1]);
	        if (value.length !== 2) {
	            errors.push(new ValidationError(key, value, `filter array for "${ value[0] }" operator must have 2 elements`));
	        } else if (type !== 'object') {
	            errors.push(new ValidationError(`${ key }[1]`, value[1], `object expected, ${ type } found`));
	        }
	        break;
	    }
	    return errors;
	}

	function validateProperty(options, propertyType) {
	    const key = options.key;
	    const style = options.style;
	    const styleSpec = options.styleSpec;
	    const value = options.value;
	    const propertyKey = options.objectKey;
	    const layerSpec = styleSpec[`${ propertyType }_${ options.layerType }`];
	    if (!layerSpec)
	        return [];
	    const transitionMatch = propertyKey.match(/^(.*)-transition$/);
	    if (propertyType === 'paint' && transitionMatch && layerSpec[transitionMatch[1]] && layerSpec[transitionMatch[1]].transition) {
	        return validate({
	            key,
	            value,
	            valueSpec: styleSpec.transition,
	            style,
	            styleSpec
	        });
	    }
	    const valueSpec = options.valueSpec || layerSpec[propertyKey];
	    if (!valueSpec) {
	        return [new ValidationError(key, value, `unknown property "${ propertyKey }"`)];
	    }
	    let tokenMatch;
	    if (getType(value) === 'string' && supportsPropertyExpression(valueSpec) && !valueSpec.tokens && (tokenMatch = /^{([^}]+)}$/.exec(value))) {
	        return [new ValidationError(key, value, `"${ propertyKey }" does not support interpolation syntax\n` + `Use an identity property function instead: \`{ "type": "identity", "property": ${ JSON.stringify(tokenMatch[1]) } }\`.`)];
	    }
	    const errors = [];
	    if (options.layerType === 'symbol') {
	        if (propertyKey === 'text-field' && style && !style.glyphs) {
	            errors.push(new ValidationError(key, value, 'use of "text-field" requires a style "glyphs" property'));
	        }
	        if (propertyKey === 'text-font' && isFunction(deepUnbundle(value)) && unbundle(value.type) === 'identity') {
	            errors.push(new ValidationError(key, value, '"text-font" does not support identity functions'));
	        }
	    }
	    return errors.concat(validate({
	        key: options.key,
	        value,
	        valueSpec,
	        style,
	        styleSpec,
	        expressionContext: 'property',
	        propertyType,
	        propertyKey
	    }));
	}

	function validatePaintProperty$1(options) {
	    return validateProperty(options, 'paint');
	}

	function validateLayoutProperty$1(options) {
	    return validateProperty(options, 'layout');
	}

	function validateLayer$1(options) {
	    let errors = [];
	    const layer = options.value;
	    const key = options.key;
	    const style = options.style;
	    const styleSpec = options.styleSpec;
	    if (!layer.type && !layer.ref) {
	        errors.push(new ValidationError(key, layer, 'either "type" or "ref" is required'));
	    }
	    let type = unbundle(layer.type);
	    const ref = unbundle(layer.ref);
	    if (layer.id) {
	        const layerId = unbundle(layer.id);
	        for (let i = 0; i < options.arrayIndex; i++) {
	            const otherLayer = style.layers[i];
	            if (unbundle(otherLayer.id) === layerId) {
	                errors.push(new ValidationError(key, layer.id, `duplicate layer id "${ layer.id }", previously used at line ${ otherLayer.id.__line__ }`));
	            }
	        }
	    }
	    if ('ref' in layer) {
	        [
	            'type',
	            'source',
	            'source-layer',
	            'filter',
	            'layout'
	        ].forEach(p => {
	            if (p in layer) {
	                errors.push(new ValidationError(key, layer[p], `"${ p }" is prohibited for ref layers`));
	            }
	        });
	        let parent;
	        style.layers.forEach(layer => {
	            if (unbundle(layer.id) === ref)
	                parent = layer;
	        });
	        if (!parent) {
	            if (typeof ref === 'string')
	                errors.push(new ValidationError(key, layer.ref, `ref layer "${ ref }" not found`));
	        } else if (parent.ref) {
	            errors.push(new ValidationError(key, layer.ref, 'ref cannot reference another ref layer'));
	        } else {
	            type = unbundle(parent.type);
	        }
	    } else if (!(type === 'background' || type === 'sky')) {
	        if (!layer.source) {
	            errors.push(new ValidationError(key, layer, 'missing required property "source"'));
	        } else {
	            const source = style.sources && style.sources[layer.source];
	            const sourceType = source && unbundle(source.type);
	            if (!source) {
	                errors.push(new ValidationError(key, layer.source, `source "${ layer.source }" not found`));
	            } else if (sourceType === 'vector' && type === 'raster') {
	                errors.push(new ValidationError(key, layer.source, `layer "${ layer.id }" requires a raster source`));
	            } else if (sourceType === 'raster' && type !== 'raster') {
	                errors.push(new ValidationError(key, layer.source, `layer "${ layer.id }" requires a vector source`));
	            } else if (sourceType === 'vector' && !layer['source-layer']) {
	                errors.push(new ValidationError(key, layer, `layer "${ layer.id }" must specify a "source-layer"`));
	            } else if (sourceType === 'raster-dem' && type !== 'hillshade') {
	                errors.push(new ValidationError(key, layer.source, 'raster-dem source can only be used with layer type \'hillshade\'.'));
	            } else if (type === 'line' && layer.paint && (layer.paint['line-gradient'] || layer.paint['line-trim-offset']) && (sourceType !== 'geojson' || !source.lineMetrics)) {
	                errors.push(new ValidationError(key, layer, `layer "${ layer.id }" specifies a line-gradient, which requires a GeoJSON source with \`lineMetrics\` enabled.`));
	            }
	        }
	    }
	    errors = errors.concat(validateObject({
	        key,
	        value: layer,
	        valueSpec: styleSpec.layer,
	        style: options.style,
	        styleSpec: options.styleSpec,
	        objectElementValidators: {
	            '*'() {
	                return [];
	            },
	            type() {
	                return validate({
	                    key: `${ key }.type`,
	                    value: layer.type,
	                    valueSpec: styleSpec.layer.type,
	                    style: options.style,
	                    styleSpec: options.styleSpec,
	                    object: layer,
	                    objectKey: 'type'
	                });
	            },
	            filter(options) {
	                return validateFilter$1(extend({ layerType: type }, options));
	            },
	            layout(options) {
	                return validateObject({
	                    layer,
	                    key: options.key,
	                    value: options.value,
	                    valueSpec: {},
	                    style: options.style,
	                    styleSpec: options.styleSpec,
	                    objectElementValidators: {
	                        '*'(options) {
	                            return validateLayoutProperty$1(extend({ layerType: type }, options));
	                        }
	                    }
	                });
	            },
	            paint(options) {
	                return validateObject({
	                    layer,
	                    key: options.key,
	                    value: options.value,
	                    valueSpec: {},
	                    style: options.style,
	                    styleSpec: options.styleSpec,
	                    objectElementValidators: {
	                        '*'(options) {
	                            return validatePaintProperty$1(extend({ layerType: type }, options));
	                        }
	                    }
	                });
	            }
	        }
	    }));
	    return errors;
	}

	function validateString(options) {
	    const value = options.value;
	    const key = options.key;
	    const type = getType(value);
	    if (type !== 'string') {
	        return [new ValidationError(key, value, `string expected, ${ type } found`)];
	    }
	    return [];
	}

	const objectElementValidators = { promoteId: validatePromoteId };
	function validateSource$1(options) {
	    const value = options.value;
	    const key = options.key;
	    const styleSpec = options.styleSpec;
	    const style = options.style;
	    if (!value.type) {
	        return [new ValidationError(key, value, '"type" is required')];
	    }
	    const type = unbundle(value.type);
	    let errors;
	    switch (type) {
	    case 'vector':
	    case 'raster':
	    case 'raster-dem':
	        errors = validateObject({
	            key,
	            value,
	            valueSpec: styleSpec[`source_${ type.replace('-', '_') }`],
	            style: options.style,
	            styleSpec,
	            objectElementValidators
	        });
	        return errors;
	    case 'geojson':
	        errors = validateObject({
	            key,
	            value,
	            valueSpec: styleSpec.source_geojson,
	            style,
	            styleSpec,
	            objectElementValidators
	        });
	        if (value.cluster) {
	            for (const prop in value.clusterProperties) {
	                const [operator, mapExpr] = value.clusterProperties[prop];
	                const reduceExpr = typeof operator === 'string' ? [
	                    operator,
	                    ['accumulated'],
	                    [
	                        'get',
	                        prop
	                    ]
	                ] : operator;
	                errors.push(...validateExpression({
	                    key: `${ key }.${ prop }.map`,
	                    value: mapExpr,
	                    expressionContext: 'cluster-map'
	                }));
	                errors.push(...validateExpression({
	                    key: `${ key }.${ prop }.reduce`,
	                    value: reduceExpr,
	                    expressionContext: 'cluster-reduce'
	                }));
	            }
	        }
	        return errors;
	    case 'video':
	        return validateObject({
	            key,
	            value,
	            valueSpec: styleSpec.source_video,
	            style,
	            styleSpec
	        });
	    case 'image':
	        return validateObject({
	            key,
	            value,
	            valueSpec: styleSpec.source_image,
	            style,
	            styleSpec
	        });
	    case 'canvas':
	        return [new ValidationError(key, null, `Please use runtime APIs to add canvas sources, rather than including them in stylesheets.`, 'source.canvas')];
	    default:
	        return validateEnum({
	            key: `${ key }.type`,
	            value: value.type,
	            valueSpec: {
	                values: [
	                    'vector',
	                    'raster',
	                    'raster-dem',
	                    'geojson',
	                    'video',
	                    'image'
	                ]
	            },
	            style,
	            styleSpec
	        });
	    }
	}
	function validatePromoteId({key, value}) {
	    if (getType(value) === 'string') {
	        return validateString({
	            key,
	            value
	        });
	    } else {
	        const errors = [];
	        for (const prop in value) {
	            errors.push(...validateString({
	                key: `${ key }.${ prop }`,
	                value: value[prop]
	            }));
	        }
	        return errors;
	    }
	}

	function validateLight$1(options) {
	    const light = options.value;
	    const styleSpec = options.styleSpec;
	    const lightSpec = styleSpec.light;
	    const style = options.style;
	    let errors = [];
	    const rootType = getType(light);
	    if (light === undefined) {
	        return errors;
	    } else if (rootType !== 'object') {
	        errors = errors.concat([new ValidationError('light', light, `object expected, ${ rootType } found`)]);
	        return errors;
	    }
	    for (const key in light) {
	        const transitionMatch = key.match(/^(.*)-transition$/);
	        if (transitionMatch && lightSpec[transitionMatch[1]] && lightSpec[transitionMatch[1]].transition) {
	            errors = errors.concat(validate({
	                key,
	                value: light[key],
	                valueSpec: styleSpec.transition,
	                style,
	                styleSpec
	            }));
	        } else if (lightSpec[key]) {
	            errors = errors.concat(validate({
	                key,
	                value: light[key],
	                valueSpec: lightSpec[key],
	                style,
	                styleSpec
	            }));
	        } else {
	            errors = errors.concat([new ValidationError(key, light[key], `unknown property "${ key }"`)]);
	        }
	    }
	    return errors;
	}

	function validateTerrain$1(options) {
	    const terrain = options.value;
	    const key = options.key;
	    const style = options.style;
	    const styleSpec = options.styleSpec;
	    const terrainSpec = styleSpec.terrain;
	    let errors = [];
	    const rootType = getType(terrain);
	    if (terrain === undefined) {
	        return errors;
	    } else if (rootType !== 'object') {
	        errors = errors.concat([new ValidationError('terrain', terrain, `object expected, ${ rootType } found`)]);
	        return errors;
	    }
	    for (const key in terrain) {
	        const transitionMatch = key.match(/^(.*)-transition$/);
	        if (transitionMatch && terrainSpec[transitionMatch[1]] && terrainSpec[transitionMatch[1]].transition) {
	            errors = errors.concat(validate({
	                key,
	                value: terrain[key],
	                valueSpec: styleSpec.transition,
	                style,
	                styleSpec
	            }));
	        } else if (terrainSpec[key]) {
	            errors = errors.concat(validate({
	                key,
	                value: terrain[key],
	                valueSpec: terrainSpec[key],
	                style,
	                styleSpec
	            }));
	        } else {
	            errors = errors.concat([new ValidationError(key, terrain[key], `unknown property "${ key }"`)]);
	        }
	    }
	    if (!terrain.source) {
	        errors.push(new ValidationError(key, terrain, `terrain is missing required property "source"`));
	    } else {
	        const source = style.sources && style.sources[terrain.source];
	        const sourceType = source && unbundle(source.type);
	        if (!source) {
	            errors.push(new ValidationError(key, terrain.source, `source "${ terrain.source }" not found`));
	        } else if (sourceType !== 'raster-dem') {
	            errors.push(new ValidationError(key, terrain.source, `terrain cannot be used with a source of type ${ String(sourceType) }, it only be used with a "raster-dem" source type`));
	        }
	    }
	    return errors;
	}

	function validateFog$1(options) {
	    const fog = options.value;
	    const style = options.style;
	    const styleSpec = options.styleSpec;
	    const fogSpec = styleSpec.fog;
	    let errors = [];
	    const rootType = getType(fog);
	    if (fog === undefined) {
	        return errors;
	    } else if (rootType !== 'object') {
	        errors = errors.concat([new ValidationError('fog', fog, `object expected, ${ rootType } found`)]);
	        return errors;
	    }
	    for (const key in fog) {
	        const transitionMatch = key.match(/^(.*)-transition$/);
	        if (transitionMatch && fogSpec[transitionMatch[1]] && fogSpec[transitionMatch[1]].transition) {
	            errors = errors.concat(validate({
	                key,
	                value: fog[key],
	                valueSpec: styleSpec.transition,
	                style,
	                styleSpec
	            }));
	        } else if (fogSpec[key]) {
	            errors = errors.concat(validate({
	                key,
	                value: fog[key],
	                valueSpec: fogSpec[key],
	                style,
	                styleSpec
	            }));
	        } else {
	            errors = errors.concat([new ValidationError(key, fog[key], `unknown property "${ key }"`)]);
	        }
	    }
	    return errors;
	}

	function validateFormatted(options) {
	    if (validateString(options).length === 0) {
	        return [];
	    }
	    return validateExpression(options);
	}

	function validateImage(options) {
	    if (validateString(options).length === 0) {
	        return [];
	    }
	    return validateExpression(options);
	}

	function validateProjection(options) {
	    const projection = options.value;
	    const styleSpec = options.styleSpec;
	    const projectionSpec = styleSpec.projection;
	    const style = options.style;
	    let errors = [];
	    const rootType = getType(projection);
	    if (rootType === 'object') {
	        for (const key in projection) {
	            errors = errors.concat(validate({
	                key,
	                value: projection[key],
	                valueSpec: projectionSpec[key],
	                style,
	                styleSpec
	            }));
	        }
	    } else if (rootType !== 'string') {
	        errors = errors.concat([new ValidationError('projection', projection, `object or string expected, ${ rootType } found`)]);
	    }
	    return errors;
	}

	const VALIDATORS = {
	    '*'() {
	        return [];
	    },
	    'array': validateArray,
	    'boolean': validateBoolean,
	    'number': validateNumber,
	    'color': validateColor,
	    'enum': validateEnum,
	    'filter': validateFilter$1,
	    'function': validateFunction,
	    'layer': validateLayer$1,
	    'object': validateObject,
	    'source': validateSource$1,
	    'light': validateLight$1,
	    'terrain': validateTerrain$1,
	    'fog': validateFog$1,
	    'string': validateString,
	    'formatted': validateFormatted,
	    'resolvedImage': validateImage,
	    'projection': validateProjection
	};
	function validate(options) {
	    const value = options.value;
	    const valueSpec = options.valueSpec;
	    const styleSpec = options.styleSpec;
	    if (valueSpec.expression && isFunction(unbundle(value))) {
	        return validateFunction(options);
	    } else if (valueSpec.expression && isExpression(deepUnbundle(value))) {
	        return validateExpression(options);
	    } else if (valueSpec.type && VALIDATORS[valueSpec.type]) {
	        return VALIDATORS[valueSpec.type](options);
	    } else {
	        const valid = validateObject(extend({}, options, { valueSpec: valueSpec.type ? styleSpec[valueSpec.type] : valueSpec }));
	        return valid;
	    }
	}

	function validateGlyphsURL (options) {
	    const value = options.value;
	    const key = options.key;
	    const errors = validateString(options);
	    if (errors.length)
	        return errors;
	    if (value.indexOf('{fontstack}') === -1) {
	        errors.push(new ValidationError(key, value, '"glyphs" url must include a "{fontstack}" token'));
	    }
	    if (value.indexOf('{range}') === -1) {
	        errors.push(new ValidationError(key, value, '"glyphs" url must include a "{range}" token'));
	    }
	    return errors;
	}

	function validateStyle(style, styleSpec = spec) {
	    const errors = validate({
	        key: '',
	        value: style,
	        valueSpec: styleSpec.$root,
	        styleSpec,
	        style,
	        objectElementValidators: {
	            glyphs: validateGlyphsURL,
	            '*': () => []
	        }
	    });
	    return sortErrors(errors);
	}
	const validateSource = opts => sortErrors(validateSource$1(opts));
	const validateLight = opts => sortErrors(validateLight$1(opts));
	const validateTerrain = opts => sortErrors(validateTerrain$1(opts));
	const validateFog = opts => sortErrors(validateFog$1(opts));
	const validateLayer = opts => sortErrors(validateLayer$1(opts));
	const validateFilter = opts => sortErrors(validateFilter$1(opts));
	const validatePaintProperty = opts => sortErrors(validatePaintProperty$1(opts));
	const validateLayoutProperty = opts => sortErrors(validateLayoutProperty$1(opts));
	function sortErrors(errors) {
	    return errors.slice().sort((a, b) => a.line && b.line ? a.line - b.line : 0);
	}

	function emitValidationErrors(emitter, errors) {
	    let hasErrors = false;
	    if (errors && errors.length) {
	        for (const error of errors) {
	            emitter.fire(new ErrorEvent(new Error(error.message)));
	            hasErrors = true;
	        }
	    }
	    return hasErrors;
	}

	var gridIndex = GridIndex;
	var NUM_PARAMS = 3;
	function GridIndex(extent, n, padding) {
	    var cells = this.cells = [];
	    if (extent instanceof ArrayBuffer) {
	        this.arrayBuffer = extent;
	        var array = new Int32Array(this.arrayBuffer);
	        extent = array[0];
	        n = array[1];
	        padding = array[2];
	        this.d = n + 2 * padding;
	        for (var k = 0; k < this.d * this.d; k++) {
	            var start = array[NUM_PARAMS + k];
	            var end = array[NUM_PARAMS + k + 1];
	            cells.push(start === end ? null : array.subarray(start, end));
	        }
	        var keysOffset = array[NUM_PARAMS + cells.length];
	        var bboxesOffset = array[NUM_PARAMS + cells.length + 1];
	        this.keys = array.subarray(keysOffset, bboxesOffset);
	        this.bboxes = array.subarray(bboxesOffset);
	        this.insert = this._insertReadonly;
	    } else {
	        this.d = n + 2 * padding;
	        for (var i = 0; i < this.d * this.d; i++) {
	            cells.push([]);
	        }
	        this.keys = [];
	        this.bboxes = [];
	    }
	    this.n = n;
	    this.extent = extent;
	    this.padding = padding;
	    this.scale = n / extent;
	    this.uid = 0;
	    var p = padding / n * extent;
	    this.min = -p;
	    this.max = extent + p;
	}
	GridIndex.prototype.insert = function (key, x1, y1, x2, y2) {
	    this._forEachCell(x1, y1, x2, y2, this._insertCell, this.uid++);
	    this.keys.push(key);
	    this.bboxes.push(x1);
	    this.bboxes.push(y1);
	    this.bboxes.push(x2);
	    this.bboxes.push(y2);
	};
	GridIndex.prototype._insertReadonly = function () {
	    throw 'Cannot insert into a GridIndex created from an ArrayBuffer.';
	};
	GridIndex.prototype._insertCell = function (x1, y1, x2, y2, cellIndex, uid) {
	    this.cells[cellIndex].push(uid);
	};
	GridIndex.prototype.query = function (x1, y1, x2, y2, intersectionTest) {
	    var min = this.min;
	    var max = this.max;
	    if (x1 <= min && y1 <= min && max <= x2 && max <= y2 && !intersectionTest) {
	        return Array.prototype.slice.call(this.keys);
	    } else {
	        var result = [];
	        var seenUids = {};
	        this._forEachCell(x1, y1, x2, y2, this._queryCell, result, seenUids, intersectionTest);
	        return result;
	    }
	};
	GridIndex.prototype._queryCell = function (x1, y1, x2, y2, cellIndex, result, seenUids, intersectionTest) {
	    var cell = this.cells[cellIndex];
	    if (cell !== null) {
	        var keys = this.keys;
	        var bboxes = this.bboxes;
	        for (var u = 0; u < cell.length; u++) {
	            var uid = cell[u];
	            if (seenUids[uid] === undefined) {
	                var offset = uid * 4;
	                if (intersectionTest ? intersectionTest(bboxes[offset + 0], bboxes[offset + 1], bboxes[offset + 2], bboxes[offset + 3]) : x1 <= bboxes[offset + 2] && y1 <= bboxes[offset + 3] && x2 >= bboxes[offset + 0] && y2 >= bboxes[offset + 1]) {
	                    seenUids[uid] = true;
	                    result.push(keys[uid]);
	                } else {
	                    seenUids[uid] = false;
	                }
	            }
	        }
	    }
	};
	GridIndex.prototype._forEachCell = function (x1, y1, x2, y2, fn, arg1, arg2, intersectionTest) {
	    var cx1 = this._convertToCellCoord(x1);
	    var cy1 = this._convertToCellCoord(y1);
	    var cx2 = this._convertToCellCoord(x2);
	    var cy2 = this._convertToCellCoord(y2);
	    for (var x = cx1; x <= cx2; x++) {
	        for (var y = cy1; y <= cy2; y++) {
	            var cellIndex = this.d * y + x;
	            if (intersectionTest && !intersectionTest(this._convertFromCellCoord(x), this._convertFromCellCoord(y), this._convertFromCellCoord(x + 1), this._convertFromCellCoord(y + 1)))
	                continue;
	            if (fn.call(this, x1, y1, x2, y2, cellIndex, arg1, arg2, intersectionTest))
	                return;
	        }
	    }
	};
	GridIndex.prototype._convertFromCellCoord = function (x) {
	    return (x - this.padding) / this.scale;
	};
	GridIndex.prototype._convertToCellCoord = function (x) {
	    return Math.max(0, Math.min(this.d - 1, Math.floor(x * this.scale) + this.padding));
	};
	GridIndex.prototype.toArrayBuffer = function () {
	    if (this.arrayBuffer)
	        return this.arrayBuffer;
	    var cells = this.cells;
	    var metadataLength = NUM_PARAMS + this.cells.length + 1 + 1;
	    var totalCellLength = 0;
	    for (var i = 0; i < this.cells.length; i++) {
	        totalCellLength += this.cells[i].length;
	    }
	    var array = new Int32Array(metadataLength + totalCellLength + this.keys.length + this.bboxes.length);
	    array[0] = this.extent;
	    array[1] = this.n;
	    array[2] = this.padding;
	    var offset = metadataLength;
	    for (var k = 0; k < cells.length; k++) {
	        var cell = cells[k];
	        array[NUM_PARAMS + k] = offset;
	        array.set(cell, offset);
	        offset += cell.length;
	    }
	    array[NUM_PARAMS + cells.length] = offset;
	    array.set(this.keys, offset);
	    offset += this.keys.length;
	    array[NUM_PARAMS + cells.length + 1] = offset;
	    array.set(this.bboxes, offset);
	    offset += this.bboxes.length;
	    return array.buffer;
	};

	const registry = {};
	function register(klass, name, options = {}) {
	    Object.defineProperty(klass, '_classRegistryKey', {
	        value: name,
	        writeable: false
	    });
	    registry[name] = {
	        klass,
	        omit: options.omit || []
	    };
	}
	register(Object, 'Object');
	gridIndex.serialize = function serialize(grid, transferables) {
	    const buffer = grid.toArrayBuffer();
	    if (transferables) {
	        transferables.push(buffer);
	    }
	    return { buffer };
	};
	gridIndex.deserialize = function deserialize(serialized) {
	    return new gridIndex(serialized.buffer);
	};
	Object.defineProperty(gridIndex, 'name', { value: 'Grid' });
	register(gridIndex, 'Grid');
	register(Color$1, 'Color');
	register(Error, 'Error');
	register(AJAXError, 'AJAXError');
	register(ResolvedImage, 'ResolvedImage');
	register(StylePropertyFunction, 'StylePropertyFunction');
	register(StyleExpression, 'StyleExpression', { omit: ['_evaluator'] });
	register(ZoomDependentExpression, 'ZoomDependentExpression');
	register(ZoomConstantExpression, 'ZoomConstantExpression');
	register(CompoundExpression$1, 'CompoundExpression', { omit: ['_evaluate'] });
	for (const name in expressions$1) {
	    if (!registry[expressions$1[name]._classRegistryKey])
	        register(expressions$1[name], `Expression${ name }`);
	}
	function isArrayBuffer(val) {
	    return val && typeof ArrayBuffer !== 'undefined' && (val instanceof ArrayBuffer || val.constructor && val.constructor.name === 'ArrayBuffer');
	}
	function isImageBitmap(val) {
	    return window$1.ImageBitmap && val instanceof window$1.ImageBitmap;
	}
	function serialize(input, transferables) {
	    if (input === null || input === undefined || typeof input === 'boolean' || typeof input === 'number' || typeof input === 'string' || input instanceof Boolean || input instanceof Number || input instanceof String || input instanceof Date || input instanceof RegExp) {
	        return input;
	    }
	    if (isArrayBuffer(input) || isImageBitmap(input)) {
	        if (transferables) {
	            transferables.push(input);
	        }
	        return input;
	    }
	    if (ArrayBuffer.isView(input)) {
	        const view = input;
	        if (transferables) {
	            transferables.push(view.buffer);
	        }
	        return view;
	    }
	    if (input instanceof window$1.ImageData) {
	        if (transferables) {
	            transferables.push(input.data.buffer);
	        }
	        return input;
	    }
	    if (Array.isArray(input)) {
	        const serialized = [];
	        for (const item of input) {
	            serialized.push(serialize(item, transferables));
	        }
	        return serialized;
	    }
	    if (typeof input === 'object') {
	        const klass = input.constructor;
	        const name = klass._classRegistryKey;
	        if (!name) {
	            throw new Error(`can't serialize object of unregistered class ${ name }`);
	        }
	        const properties = klass.serialize ? klass.serialize(input, transferables) : {};
	        if (!klass.serialize) {
	            for (const key in input) {
	                if (!input.hasOwnProperty(key))
	                    continue;
	                if (registry[name].omit.indexOf(key) >= 0)
	                    continue;
	                const property = input[key];
	                properties[key] = serialize(property, transferables);
	            }
	            if (input instanceof Error) {
	                properties.message = input.message;
	            }
	        }
	        if (properties.$name) {
	            throw new Error('$name property is reserved for worker serialization logic.');
	        }
	        if (name !== 'Object') {
	            properties.$name = name;
	        }
	        return properties;
	    }
	    throw new Error(`can't serialize object of type ${ typeof input }`);
	}
	function deserialize$1(input) {
	    if (input === null || input === undefined || typeof input === 'boolean' || typeof input === 'number' || typeof input === 'string' || input instanceof Boolean || input instanceof Number || input instanceof String || input instanceof Date || input instanceof RegExp || isArrayBuffer(input) || isImageBitmap(input) || ArrayBuffer.isView(input) || input instanceof window$1.ImageData) {
	        return input;
	    }
	    if (Array.isArray(input)) {
	        return input.map(deserialize$1);
	    }
	    if (typeof input === 'object') {
	        const name = input.$name || 'Object';
	        const {klass} = registry[name];
	        if (!klass) {
	            throw new Error(`can't deserialize unregistered class ${ name }`);
	        }
	        if (klass.deserialize) {
	            return klass.deserialize(input);
	        }
	        const result = Object.create(klass.prototype);
	        for (const key of Object.keys(input)) {
	            if (key === '$name')
	                continue;
	            const value = input[key];
	            result[key] = deserialize$1(value);
	        }
	        return result;
	    }
	    throw new Error(`can't deserialize object of type ${ typeof input }`);
	}

	class ZoomHistory {
	    constructor() {
	        this.first = true;
	    }
	    update(z, now) {
	        const floorZ = Math.floor(z);
	        if (this.first) {
	            this.first = false;
	            this.lastIntegerZoom = floorZ;
	            this.lastIntegerZoomTime = 0;
	            this.lastZoom = z;
	            this.lastFloorZoom = floorZ;
	            return true;
	        }
	        if (this.lastFloorZoom > floorZ) {
	            this.lastIntegerZoom = floorZ + 1;
	            this.lastIntegerZoomTime = now;
	        } else if (this.lastFloorZoom < floorZ) {
	            this.lastIntegerZoom = floorZ;
	            this.lastIntegerZoomTime = now;
	        }
	        if (z !== this.lastZoom) {
	            this.lastZoom = z;
	            this.lastFloorZoom = floorZ;
	            return true;
	        }
	        return false;
	    }
	}

	const unicodeBlockLookup = {
	    'Latin-1 Supplement': char => char >= 128 && char <= 255,
	    'Arabic': char => char >= 1536 && char <= 1791,
	    'Arabic Supplement': char => char >= 1872 && char <= 1919,
	    'Arabic Extended-A': char => char >= 2208 && char <= 2303,
	    'Hangul Jamo': char => char >= 4352 && char <= 4607,
	    'Unified Canadian Aboriginal Syllabics': char => char >= 5120 && char <= 5759,
	    'Khmer': char => char >= 6016 && char <= 6143,
	    'Unified Canadian Aboriginal Syllabics Extended': char => char >= 6320 && char <= 6399,
	    'General Punctuation': char => char >= 8192 && char <= 8303,
	    'Letterlike Symbols': char => char >= 8448 && char <= 8527,
	    'Number Forms': char => char >= 8528 && char <= 8591,
	    'Miscellaneous Technical': char => char >= 8960 && char <= 9215,
	    'Control Pictures': char => char >= 9216 && char <= 9279,
	    'Optical Character Recognition': char => char >= 9280 && char <= 9311,
	    'Enclosed Alphanumerics': char => char >= 9312 && char <= 9471,
	    'Geometric Shapes': char => char >= 9632 && char <= 9727,
	    'Miscellaneous Symbols': char => char >= 9728 && char <= 9983,
	    'Miscellaneous Symbols and Arrows': char => char >= 11008 && char <= 11263,
	    'CJK Radicals Supplement': char => char >= 11904 && char <= 12031,
	    'Kangxi Radicals': char => char >= 12032 && char <= 12255,
	    'Ideographic Description Characters': char => char >= 12272 && char <= 12287,
	    'CJK Symbols and Punctuation': char => char >= 12288 && char <= 12351,
	    'Hiragana': char => char >= 12352 && char <= 12447,
	    'Katakana': char => char >= 12448 && char <= 12543,
	    'Bopomofo': char => char >= 12544 && char <= 12591,
	    'Hangul Compatibility Jamo': char => char >= 12592 && char <= 12687,
	    'Kanbun': char => char >= 12688 && char <= 12703,
	    'Bopomofo Extended': char => char >= 12704 && char <= 12735,
	    'CJK Strokes': char => char >= 12736 && char <= 12783,
	    'Katakana Phonetic Extensions': char => char >= 12784 && char <= 12799,
	    'Enclosed CJK Letters and Months': char => char >= 12800 && char <= 13055,
	    'CJK Compatibility': char => char >= 13056 && char <= 13311,
	    'CJK Unified Ideographs Extension A': char => char >= 13312 && char <= 19903,
	    'Yijing Hexagram Symbols': char => char >= 19904 && char <= 19967,
	    'CJK Unified Ideographs': char => char >= 19968 && char <= 40959,
	    'Yi Syllables': char => char >= 40960 && char <= 42127,
	    'Yi Radicals': char => char >= 42128 && char <= 42191,
	    'Hangul Jamo Extended-A': char => char >= 43360 && char <= 43391,
	    'Hangul Syllables': char => char >= 44032 && char <= 55215,
	    'Hangul Jamo Extended-B': char => char >= 55216 && char <= 55295,
	    'Private Use Area': char => char >= 57344 && char <= 63743,
	    'CJK Compatibility Ideographs': char => char >= 63744 && char <= 64255,
	    'Arabic Presentation Forms-A': char => char >= 64336 && char <= 65023,
	    'Vertical Forms': char => char >= 65040 && char <= 65055,
	    'CJK Compatibility Forms': char => char >= 65072 && char <= 65103,
	    'Small Form Variants': char => char >= 65104 && char <= 65135,
	    'Arabic Presentation Forms-B': char => char >= 65136 && char <= 65279,
	    'Halfwidth and Fullwidth Forms': char => char >= 65280 && char <= 65519
	};

	function allowsVerticalWritingMode(chars) {
	    for (const char of chars) {
	        if (charHasUprightVerticalOrientation(char.charCodeAt(0)))
	            return true;
	    }
	    return false;
	}
	function allowsLetterSpacing(chars) {
	    for (const char of chars) {
	        if (!charAllowsLetterSpacing(char.charCodeAt(0)))
	            return false;
	    }
	    return true;
	}
	function charAllowsLetterSpacing(char) {
	    if (unicodeBlockLookup['Arabic'](char))
	        return false;
	    if (unicodeBlockLookup['Arabic Supplement'](char))
	        return false;
	    if (unicodeBlockLookup['Arabic Extended-A'](char))
	        return false;
	    if (unicodeBlockLookup['Arabic Presentation Forms-A'](char))
	        return false;
	    if (unicodeBlockLookup['Arabic Presentation Forms-B'](char))
	        return false;
	    return true;
	}
	function charAllowsIdeographicBreaking(char) {
	    if (char < 11904)
	        return false;
	    if (unicodeBlockLookup['Bopomofo Extended'](char))
	        return true;
	    if (unicodeBlockLookup['Bopomofo'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Compatibility Forms'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Compatibility Ideographs'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Compatibility'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Radicals Supplement'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Strokes'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Symbols and Punctuation'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Unified Ideographs Extension A'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Unified Ideographs'](char))
	        return true;
	    if (unicodeBlockLookup['Enclosed CJK Letters and Months'](char))
	        return true;
	    if (unicodeBlockLookup['Halfwidth and Fullwidth Forms'](char))
	        return true;
	    if (unicodeBlockLookup['Hiragana'](char))
	        return true;
	    if (unicodeBlockLookup['Ideographic Description Characters'](char))
	        return true;
	    if (unicodeBlockLookup['Kangxi Radicals'](char))
	        return true;
	    if (unicodeBlockLookup['Katakana Phonetic Extensions'](char))
	        return true;
	    if (unicodeBlockLookup['Katakana'](char))
	        return true;
	    if (unicodeBlockLookup['Vertical Forms'](char))
	        return true;
	    if (unicodeBlockLookup['Yi Radicals'](char))
	        return true;
	    if (unicodeBlockLookup['Yi Syllables'](char))
	        return true;
	    return false;
	}
	function charHasUprightVerticalOrientation(char) {
	    if (char === 746 || char === 747) {
	        return true;
	    }
	    if (char < 4352)
	        return false;
	    if (unicodeBlockLookup['Bopomofo Extended'](char))
	        return true;
	    if (unicodeBlockLookup['Bopomofo'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Compatibility Forms'](char)) {
	        if (!(char >= 65097 && char <= 65103)) {
	            return true;
	        }
	    }
	    if (unicodeBlockLookup['CJK Compatibility Ideographs'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Compatibility'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Radicals Supplement'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Strokes'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Symbols and Punctuation'](char)) {
	        if (!(char >= 12296 && char <= 12305) && !(char >= 12308 && char <= 12319) && char !== 12336) {
	            return true;
	        }
	    }
	    if (unicodeBlockLookup['CJK Unified Ideographs Extension A'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Unified Ideographs'](char))
	        return true;
	    if (unicodeBlockLookup['Enclosed CJK Letters and Months'](char))
	        return true;
	    if (unicodeBlockLookup['Hangul Compatibility Jamo'](char))
	        return true;
	    if (unicodeBlockLookup['Hangul Jamo Extended-A'](char))
	        return true;
	    if (unicodeBlockLookup['Hangul Jamo Extended-B'](char))
	        return true;
	    if (unicodeBlockLookup['Hangul Jamo'](char))
	        return true;
	    if (unicodeBlockLookup['Hangul Syllables'](char))
	        return true;
	    if (unicodeBlockLookup['Hiragana'](char))
	        return true;
	    if (unicodeBlockLookup['Ideographic Description Characters'](char))
	        return true;
	    if (unicodeBlockLookup['Kanbun'](char))
	        return true;
	    if (unicodeBlockLookup['Kangxi Radicals'](char))
	        return true;
	    if (unicodeBlockLookup['Katakana Phonetic Extensions'](char))
	        return true;
	    if (unicodeBlockLookup['Katakana'](char)) {
	        if (char !== 12540) {
	            return true;
	        }
	    }
	    if (unicodeBlockLookup['Halfwidth and Fullwidth Forms'](char)) {
	        if (char !== 65288 && char !== 65289 && char !== 65293 && !(char >= 65306 && char <= 65310) && char !== 65339 && char !== 65341 && char !== 65343 && !(char >= 65371 && char <= 65503) && char !== 65507 && !(char >= 65512 && char <= 65519)) {
	            return true;
	        }
	    }
	    if (unicodeBlockLookup['Small Form Variants'](char)) {
	        if (!(char >= 65112 && char <= 65118) && !(char >= 65123 && char <= 65126)) {
	            return true;
	        }
	    }
	    if (unicodeBlockLookup['Unified Canadian Aboriginal Syllabics'](char))
	        return true;
	    if (unicodeBlockLookup['Unified Canadian Aboriginal Syllabics Extended'](char))
	        return true;
	    if (unicodeBlockLookup['Vertical Forms'](char))
	        return true;
	    if (unicodeBlockLookup['Yijing Hexagram Symbols'](char))
	        return true;
	    if (unicodeBlockLookup['Yi Syllables'](char))
	        return true;
	    if (unicodeBlockLookup['Yi Radicals'](char))
	        return true;
	    return false;
	}
	function charHasNeutralVerticalOrientation(char) {
	    if (unicodeBlockLookup['Latin-1 Supplement'](char)) {
	        if (char === 167 || char === 169 || char === 174 || char === 177 || char === 188 || char === 189 || char === 190 || char === 215 || char === 247) {
	            return true;
	        }
	    }
	    if (unicodeBlockLookup['General Punctuation'](char)) {
	        if (char === 8214 || char === 8224 || char === 8225 || char === 8240 || char === 8241 || char === 8251 || char === 8252 || char === 8258 || char === 8263 || char === 8264 || char === 8265 || char === 8273) {
	            return true;
	        }
	    }
	    if (unicodeBlockLookup['Letterlike Symbols'](char))
	        return true;
	    if (unicodeBlockLookup['Number Forms'](char))
	        return true;
	    if (unicodeBlockLookup['Miscellaneous Technical'](char)) {
	        if (char >= 8960 && char <= 8967 || char >= 8972 && char <= 8991 || char >= 8996 && char <= 9000 || char === 9003 || char >= 9085 && char <= 9114 || char >= 9150 && char <= 9165 || char === 9167 || char >= 9169 && char <= 9179 || char >= 9186 && char <= 9215) {
	            return true;
	        }
	    }
	    if (unicodeBlockLookup['Control Pictures'](char) && char !== 9251)
	        return true;
	    if (unicodeBlockLookup['Optical Character Recognition'](char))
	        return true;
	    if (unicodeBlockLookup['Enclosed Alphanumerics'](char))
	        return true;
	    if (unicodeBlockLookup['Geometric Shapes'](char))
	        return true;
	    if (unicodeBlockLookup['Miscellaneous Symbols'](char)) {
	        if (!(char >= 9754 && char <= 9759)) {
	            return true;
	        }
	    }
	    if (unicodeBlockLookup['Miscellaneous Symbols and Arrows'](char)) {
	        if (char >= 11026 && char <= 11055 || char >= 11088 && char <= 11097 || char >= 11192 && char <= 11243) {
	            return true;
	        }
	    }
	    if (unicodeBlockLookup['CJK Symbols and Punctuation'](char))
	        return true;
	    if (unicodeBlockLookup['Katakana'](char))
	        return true;
	    if (unicodeBlockLookup['Private Use Area'](char))
	        return true;
	    if (unicodeBlockLookup['CJK Compatibility Forms'](char))
	        return true;
	    if (unicodeBlockLookup['Small Form Variants'](char))
	        return true;
	    if (unicodeBlockLookup['Halfwidth and Fullwidth Forms'](char))
	        return true;
	    if (char === 8734 || char === 8756 || char === 8757 || char >= 9984 && char <= 10087 || char >= 10102 && char <= 10131 || char === 65532 || char === 65533) {
	        return true;
	    }
	    return false;
	}
	function charHasRotatedVerticalOrientation(char) {
	    return !(charHasUprightVerticalOrientation(char) || charHasNeutralVerticalOrientation(char));
	}
	function charInComplexShapingScript(char) {
	    return unicodeBlockLookup['Arabic'](char) || unicodeBlockLookup['Arabic Supplement'](char) || unicodeBlockLookup['Arabic Extended-A'](char) || unicodeBlockLookup['Arabic Presentation Forms-A'](char) || unicodeBlockLookup['Arabic Presentation Forms-B'](char);
	}
	function charInRTLScript(char) {
	    return char >= 1424 && char <= 2303 || unicodeBlockLookup['Arabic Presentation Forms-A'](char) || unicodeBlockLookup['Arabic Presentation Forms-B'](char);
	}
	function charInSupportedScript(char, canRenderRTL) {
	    if (!canRenderRTL && charInRTLScript(char)) {
	        return false;
	    }
	    if (char >= 2304 && char <= 3583 || char >= 3840 && char <= 4255 || unicodeBlockLookup['Khmer'](char)) {
	        return false;
	    }
	    return true;
	}
	function stringContainsRTLText(chars) {
	    for (const char of chars) {
	        if (charInRTLScript(char.charCodeAt(0))) {
	            return true;
	        }
	    }
	    return false;
	}
	function isStringInSupportedScript(chars, canRenderRTL) {
	    for (const char of chars) {
	        if (!charInSupportedScript(char.charCodeAt(0), canRenderRTL)) {
	            return false;
	        }
	    }
	    return true;
	}

	const status = {
	    unavailable: 'unavailable',
	    deferred: 'deferred',
	    loading: 'loading',
	    loaded: 'loaded',
	    error: 'error'
	};
	let _completionCallback = null;
	let pluginStatus = status.unavailable;
	let pluginURL = null;
	const triggerPluginCompletionEvent = function (error) {
	    if (error && typeof error === 'string' && error.indexOf('NetworkError') > -1) {
	        pluginStatus = status.error;
	    }
	    if (_completionCallback) {
	        _completionCallback(error);
	    }
	};
	function sendPluginStateToWorker() {
	    evented.fire(new Event('pluginStateChange', {
	        pluginStatus,
	        pluginURL
	    }));
	}
	const evented = new Evented();
	const getRTLTextPluginStatus = function () {
	    return pluginStatus;
	};
	const registerForPluginStateChange = function (callback) {
	    callback({
	        pluginStatus,
	        pluginURL
	    });
	    evented.on('pluginStateChange', callback);
	    return callback;
	};
	const setRTLTextPlugin = function (url, callback, deferred = false) {
	    if (pluginStatus === status.deferred || pluginStatus === status.loading || pluginStatus === status.loaded) {
	        throw new Error('setRTLTextPlugin cannot be called multiple times.');
	    }
	    pluginURL = exported$1.resolveURL(url);
	    pluginStatus = status.deferred;
	    _completionCallback = callback;
	    sendPluginStateToWorker();
	    if (!deferred) {
	        downloadRTLTextPlugin();
	    }
	};
	const downloadRTLTextPlugin = function () {
	    if (pluginStatus !== status.deferred || !pluginURL) {
	        throw new Error('rtl-text-plugin cannot be downloaded unless a pluginURL is specified');
	    }
	    pluginStatus = status.loading;
	    sendPluginStateToWorker();
	    if (pluginURL) {
	        getArrayBuffer({ url: pluginURL }, error => {
	            if (error) {
	                triggerPluginCompletionEvent(error);
	            } else {
	                pluginStatus = status.loaded;
	                sendPluginStateToWorker();
	            }
	        });
	    }
	};
	const plugin = {
	    applyArabicShaping: null,
	    processBidirectionalText: null,
	    processStyledBidirectionalText: null,
	    isLoaded() {
	        return pluginStatus === status.loaded || plugin.applyArabicShaping != null;
	    },
	    isLoading() {
	        return pluginStatus === status.loading;
	    },
	    setState(state) {
	        pluginStatus = state.pluginStatus;
	        pluginURL = state.pluginURL;
	    },
	    isParsed() {
	        return plugin.applyArabicShaping != null && plugin.processBidirectionalText != null && plugin.processStyledBidirectionalText != null;
	    },
	    getPluginURL() {
	        return pluginURL;
	    }
	};
	const lazyLoadRTLTextPlugin = function () {
	    if (!plugin.isLoading() && !plugin.isLoaded() && getRTLTextPluginStatus() === 'deferred') {
	        downloadRTLTextPlugin();
	    }
	};

	class EvaluationParameters {
	    constructor(zoom, options) {
	        this.zoom = zoom;
	        if (options) {
	            this.now = options.now;
	            this.fadeDuration = options.fadeDuration;
	            this.zoomHistory = options.zoomHistory;
	            this.transition = options.transition;
	            this.pitch = options.pitch;
	        } else {
	            this.now = 0;
	            this.fadeDuration = 0;
	            this.zoomHistory = new ZoomHistory();
	            this.transition = {};
	            this.pitch = 0;
	        }
	    }
	    isSupportedScript(str) {
	        return isStringInSupportedScript(str, plugin.isLoaded());
	    }
	    crossFadingFactor() {
	        if (this.fadeDuration === 0) {
	            return 1;
	        } else {
	            return Math.min((this.now - this.zoomHistory.lastIntegerZoomTime) / this.fadeDuration, 1);
	        }
	    }
	    getCrossfadeParameters() {
	        const z = this.zoom;
	        const fraction = z - Math.floor(z);
	        const t = this.crossFadingFactor();
	        return z > this.zoomHistory.lastIntegerZoom ? {
	            fromScale: 2,
	            toScale: 1,
	            t: fraction + (1 - fraction) * t
	        } : {
	            fromScale: 0.5,
	            toScale: 1,
	            t: 1 - (1 - t) * fraction
	        };
	    }
	}

	class PropertyValue {
	    constructor(property, value) {
	        this.property = property;
	        this.value = value;
	        this.expression = normalizePropertyExpression(value === undefined ? property.specification.default : value, property.specification);
	    }
	    isDataDriven() {
	        return this.expression.kind === 'source' || this.expression.kind === 'composite';
	    }
	    possiblyEvaluate(parameters, canonical, availableImages) {
	        return this.property.possiblyEvaluate(this, parameters, canonical, availableImages);
	    }
	}
	class TransitionablePropertyValue {
	    constructor(property) {
	        this.property = property;
	        this.value = new PropertyValue(property, undefined);
	    }
	    transitioned(parameters, prior) {
	        return new TransitioningPropertyValue(this.property, this.value, prior, extend$1({}, parameters.transition, this.transition), parameters.now);
	    }
	    untransitioned() {
	        return new TransitioningPropertyValue(this.property, this.value, null, {}, 0);
	    }
	}
	class Transitionable {
	    constructor(properties) {
	        this._properties = properties;
	        this._values = Object.create(properties.defaultTransitionablePropertyValues);
	    }
	    getValue(name) {
	        return clone$2(this._values[name].value.value);
	    }
	    setValue(name, value) {
	        if (!this._values.hasOwnProperty(name)) {
	            this._values[name] = new TransitionablePropertyValue(this._values[name].property);
	        }
	        this._values[name].value = new PropertyValue(this._values[name].property, value === null ? undefined : clone$2(value));
	    }
	    getTransition(name) {
	        return clone$2(this._values[name].transition);
	    }
	    setTransition(name, value) {
	        if (!this._values.hasOwnProperty(name)) {
	            this._values[name] = new TransitionablePropertyValue(this._values[name].property);
	        }
	        this._values[name].transition = clone$2(value) || undefined;
	    }
	    serialize() {
	        const result = {};
	        for (const property of Object.keys(this._values)) {
	            const value = this.getValue(property);
	            if (value !== undefined) {
	                result[property] = value;
	            }
	            const transition = this.getTransition(property);
	            if (transition !== undefined) {
	                result[`${ property }-transition`] = transition;
	            }
	        }
	        return result;
	    }
	    transitioned(parameters, prior) {
	        const result = new Transitioning(this._properties);
	        for (const property of Object.keys(this._values)) {
	            result._values[property] = this._values[property].transitioned(parameters, prior._values[property]);
	        }
	        return result;
	    }
	    untransitioned() {
	        const result = new Transitioning(this._properties);
	        for (const property of Object.keys(this._values)) {
	            result._values[property] = this._values[property].untransitioned();
	        }
	        return result;
	    }
	}
	class TransitioningPropertyValue {
	    constructor(property, value, prior, transition, now) {
	        const delay = transition.delay || 0;
	        const duration = transition.duration || 0;
	        now = now || 0;
	        this.property = property;
	        this.value = value;
	        this.begin = now + delay;
	        this.end = this.begin + duration;
	        if (property.specification.transition && (transition.delay || transition.duration)) {
	            this.prior = prior;
	        }
	    }
	    possiblyEvaluate(parameters, canonical, availableImages) {
	        const now = parameters.now || 0;
	        const finalValue = this.value.possiblyEvaluate(parameters, canonical, availableImages);
	        const prior = this.prior;
	        if (!prior) {
	            return finalValue;
	        } else if (now > this.end) {
	            this.prior = null;
	            return finalValue;
	        } else if (this.value.isDataDriven()) {
	            this.prior = null;
	            return finalValue;
	        } else if (now < this.begin) {
	            return prior.possiblyEvaluate(parameters, canonical, availableImages);
	        } else {
	            const t = (now - this.begin) / (this.end - this.begin);
	            return this.property.interpolate(prior.possiblyEvaluate(parameters, canonical, availableImages), finalValue, easeCubicInOut(t));
	        }
	    }
	}
	class Transitioning {
	    constructor(properties) {
	        this._properties = properties;
	        this._values = Object.create(properties.defaultTransitioningPropertyValues);
	    }
	    possiblyEvaluate(parameters, canonical, availableImages) {
	        const result = new PossiblyEvaluated(this._properties);
	        for (const property of Object.keys(this._values)) {
	            result._values[property] = this._values[property].possiblyEvaluate(parameters, canonical, availableImages);
	        }
	        return result;
	    }
	    hasTransition() {
	        for (const property of Object.keys(this._values)) {
	            if (this._values[property].prior) {
	                return true;
	            }
	        }
	        return false;
	    }
	}
	class Layout {
	    constructor(properties) {
	        this._properties = properties;
	        this._values = Object.create(properties.defaultPropertyValues);
	    }
	    getValue(name) {
	        return clone$2(this._values[name].value);
	    }
	    setValue(name, value) {
	        this._values[name] = new PropertyValue(this._values[name].property, value === null ? undefined : clone$2(value));
	    }
	    serialize() {
	        const result = {};
	        for (const property of Object.keys(this._values)) {
	            const value = this.getValue(property);
	            if (value !== undefined) {
	                result[property] = value;
	            }
	        }
	        return result;
	    }
	    possiblyEvaluate(parameters, canonical, availableImages) {
	        const result = new PossiblyEvaluated(this._properties);
	        for (const property of Object.keys(this._values)) {
	            result._values[property] = this._values[property].possiblyEvaluate(parameters, canonical, availableImages);
	        }
	        return result;
	    }
	}
	class PossiblyEvaluatedPropertyValue {
	    constructor(property, value, parameters) {
	        this.property = property;
	        this.value = value;
	        this.parameters = parameters;
	    }
	    isConstant() {
	        return this.value.kind === 'constant';
	    }
	    constantOr(value) {
	        if (this.value.kind === 'constant') {
	            return this.value.value;
	        } else {
	            return value;
	        }
	    }
	    evaluate(feature, featureState, canonical, availableImages) {
	        return this.property.evaluate(this.value, this.parameters, feature, featureState, canonical, availableImages);
	    }
	}
	class PossiblyEvaluated {
	    constructor(properties) {
	        this._properties = properties;
	        this._values = Object.create(properties.defaultPossiblyEvaluatedValues);
	    }
	    get(name) {
	        return this._values[name];
	    }
	}
	class DataConstantProperty {
	    constructor(specification) {
	        this.specification = specification;
	    }
	    possiblyEvaluate(value, parameters) {
	        return value.expression.evaluate(parameters);
	    }
	    interpolate(a, b, t) {
	        const interp = interpolate[this.specification.type];
	        if (interp) {
	            return interp(a, b, t);
	        } else {
	            return a;
	        }
	    }
	}
	class DataDrivenProperty {
	    constructor(specification, overrides) {
	        this.specification = specification;
	        this.overrides = overrides;
	    }
	    possiblyEvaluate(value, parameters, canonical, availableImages) {
	        if (value.expression.kind === 'constant' || value.expression.kind === 'camera') {
	            return new PossiblyEvaluatedPropertyValue(this, {
	                kind: 'constant',
	                value: value.expression.evaluate(parameters, null, {}, canonical, availableImages)
	            }, parameters);
	        } else {
	            return new PossiblyEvaluatedPropertyValue(this, value.expression, parameters);
	        }
	    }
	    interpolate(a, b, t) {
	        if (a.value.kind !== 'constant' || b.value.kind !== 'constant') {
	            return a;
	        }
	        if (a.value.value === undefined || b.value.value === undefined) {
	            return new PossiblyEvaluatedPropertyValue(this, {
	                kind: 'constant',
	                value: undefined
	            }, a.parameters);
	        }
	        const interp = interpolate[this.specification.type];
	        if (interp) {
	            return new PossiblyEvaluatedPropertyValue(this, {
	                kind: 'constant',
	                value: interp(a.value.value, b.value.value, t)
	            }, a.parameters);
	        } else {
	            return a;
	        }
	    }
	    evaluate(value, parameters, feature, featureState, canonical, availableImages) {
	        if (value.kind === 'constant') {
	            return value.value;
	        } else {
	            return value.evaluate(parameters, feature, featureState, canonical, availableImages);
	        }
	    }
	}
	class CrossFadedDataDrivenProperty extends DataDrivenProperty {
	    possiblyEvaluate(value, parameters, canonical, availableImages) {
	        if (value.value === undefined) {
	            return new PossiblyEvaluatedPropertyValue(this, {
	                kind: 'constant',
	                value: undefined
	            }, parameters);
	        } else if (value.expression.kind === 'constant') {
	            const evaluatedValue = value.expression.evaluate(parameters, null, {}, canonical, availableImages);
	            const isImageExpression = value.property.specification.type === 'resolvedImage';
	            const constantValue = isImageExpression && typeof evaluatedValue !== 'string' ? evaluatedValue.name : evaluatedValue;
	            const constant = this._calculate(constantValue, constantValue, constantValue, parameters);
	            return new PossiblyEvaluatedPropertyValue(this, {
	                kind: 'constant',
	                value: constant
	            }, parameters);
	        } else if (value.expression.kind === 'camera') {
	            const cameraVal = this._calculate(value.expression.evaluate({ zoom: parameters.zoom - 1 }), value.expression.evaluate({ zoom: parameters.zoom }), value.expression.evaluate({ zoom: parameters.zoom + 1 }), parameters);
	            return new PossiblyEvaluatedPropertyValue(this, {
	                kind: 'constant',
	                value: cameraVal
	            }, parameters);
	        } else {
	            return new PossiblyEvaluatedPropertyValue(this, value.expression, parameters);
	        }
	    }
	    evaluate(value, globals, feature, featureState, canonical, availableImages) {
	        if (value.kind === 'source') {
	            const constant = value.evaluate(globals, feature, featureState, canonical, availableImages);
	            return this._calculate(constant, constant, constant, globals);
	        } else if (value.kind === 'composite') {
	            return this._calculate(value.evaluate({ zoom: Math.floor(globals.zoom) - 1 }, feature, featureState), value.evaluate({ zoom: Math.floor(globals.zoom) }, feature, featureState), value.evaluate({ zoom: Math.floor(globals.zoom) + 1 }, feature, featureState), globals);
	        } else {
	            return value.value;
	        }
	    }
	    _calculate(min, mid, max, parameters) {
	        const z = parameters.zoom;
	        return z > parameters.zoomHistory.lastIntegerZoom ? {
	            from: min,
	            to: mid,
	            other: max
	        } : {
	            from: max,
	            to: mid,
	            other: min
	        };
	    }
	    interpolate(a) {
	        return a;
	    }
	}
	class CrossFadedProperty {
	    constructor(specification) {
	        this.specification = specification;
	    }
	    possiblyEvaluate(value, parameters, canonical, availableImages) {
	        if (value.value === undefined) {
	            return undefined;
	        } else if (value.expression.kind === 'constant') {
	            const constant = value.expression.evaluate(parameters, null, {}, canonical, availableImages);
	            return this._calculate(constant, constant, constant, parameters);
	        } else {
	            return this._calculate(value.expression.evaluate(new EvaluationParameters(Math.floor(parameters.zoom - 1), parameters)), value.expression.evaluate(new EvaluationParameters(Math.floor(parameters.zoom), parameters)), value.expression.evaluate(new EvaluationParameters(Math.floor(parameters.zoom + 1), parameters)), parameters);
	        }
	    }
	    _calculate(min, mid, max, parameters) {
	        const z = parameters.zoom;
	        return z > parameters.zoomHistory.lastIntegerZoom ? {
	            from: min,
	            to: mid
	        } : {
	            from: max,
	            to: mid
	        };
	    }
	    interpolate(a) {
	        return a;
	    }
	}
	class ColorRampProperty {
	    constructor(specification) {
	        this.specification = specification;
	    }
	    possiblyEvaluate(value, parameters, canonical, availableImages) {
	        return !!value.expression.evaluate(parameters, null, {}, canonical, availableImages);
	    }
	    interpolate() {
	        return false;
	    }
	}
	class Properties {
	    constructor(properties) {
	        this.properties = properties;
	        this.defaultPropertyValues = {};
	        this.defaultTransitionablePropertyValues = {};
	        this.defaultTransitioningPropertyValues = {};
	        this.defaultPossiblyEvaluatedValues = {};
	        this.overridableProperties = [];
	        const defaultParameters = new EvaluationParameters(0, {});
	        for (const property in properties) {
	            const prop = properties[property];
	            if (prop.specification.overridable) {
	                this.overridableProperties.push(property);
	            }
	            const defaultPropertyValue = this.defaultPropertyValues[property] = new PropertyValue(prop, undefined);
	            const defaultTransitionablePropertyValue = this.defaultTransitionablePropertyValues[property] = new TransitionablePropertyValue(prop);
	            this.defaultTransitioningPropertyValues[property] = defaultTransitionablePropertyValue.untransitioned();
	            this.defaultPossiblyEvaluatedValues[property] = defaultPropertyValue.possiblyEvaluate(defaultParameters);
	        }
	    }
	}
	register(DataDrivenProperty, 'DataDrivenProperty');
	register(DataConstantProperty, 'DataConstantProperty');
	register(CrossFadedDataDrivenProperty, 'CrossFadedDataDrivenProperty');
	register(CrossFadedProperty, 'CrossFadedProperty');
	register(ColorRampProperty, 'ColorRampProperty');

	function packUint8ToFloat(a, b) {
	    a = clamp(Math.floor(a), 0, 255);
	    b = clamp(Math.floor(b), 0, 255);
	    return 256 * a + b;
	}

	const viewTypes = {
	    'Int8': Int8Array,
	    'Uint8': Uint8Array,
	    'Int16': Int16Array,
	    'Uint16': Uint16Array,
	    'Int32': Int32Array,
	    'Uint32': Uint32Array,
	    'Float32': Float32Array
	};
	class Struct {
	    constructor(structArray, index) {
	        this._structArray = structArray;
	        this._pos1 = index * this.size;
	        this._pos2 = this._pos1 / 2;
	        this._pos4 = this._pos1 / 4;
	        this._pos8 = this._pos1 / 8;
	    }
	}
	const DEFAULT_CAPACITY = 128;
	const RESIZE_MULTIPLIER = 5;
	class StructArray {
	    constructor() {
	        this.isTransferred = false;
	        this.capacity = -1;
	        this.resize(0);
	    }
	    static serialize(array, transferables) {
	        array._trim();
	        if (transferables) {
	            array.isTransferred = true;
	            transferables.push(array.arrayBuffer);
	        }
	        return {
	            length: array.length,
	            arrayBuffer: array.arrayBuffer
	        };
	    }
	    static deserialize(input) {
	        const structArray = Object.create(this.prototype);
	        structArray.arrayBuffer = input.arrayBuffer;
	        structArray.length = input.length;
	        structArray.capacity = input.arrayBuffer.byteLength / structArray.bytesPerElement;
	        structArray._refreshViews();
	        return structArray;
	    }
	    _trim() {
	        if (this.length !== this.capacity) {
	            this.capacity = this.length;
	            this.arrayBuffer = this.arrayBuffer.slice(0, this.length * this.bytesPerElement);
	            this._refreshViews();
	        }
	    }
	    clear() {
	        this.length = 0;
	    }
	    resize(n) {
	        this.reserve(n);
	        this.length = n;
	    }
	    reserve(n) {
	        if (n > this.capacity) {
	            this.capacity = Math.max(n, Math.floor(this.capacity * RESIZE_MULTIPLIER), DEFAULT_CAPACITY);
	            this.arrayBuffer = new ArrayBuffer(this.capacity * this.bytesPerElement);
	            const oldUint8Array = this.uint8;
	            this._refreshViews();
	            if (oldUint8Array)
	                this.uint8.set(oldUint8Array);
	        }
	    }
	    _refreshViews() {
	        throw new Error('_refreshViews() must be implemented by each concrete StructArray layout');
	    }
	    destroy() {
	        this.int8 = this.uint8 = this.int16 = this.uint16 = this.int32 = this.uint32 = this.float32 = null;
	        this.arrayBuffer = null;
	    }
	}
	function createLayout(members, alignment = 1) {
	    let offset = 0;
	    let maxSize = 0;
	    const layoutMembers = members.map(member => {
	        const typeSize = sizeOf(member.type);
	        const memberOffset = offset = align$1(offset, Math.max(alignment, typeSize));
	        const components = member.components || 1;
	        maxSize = Math.max(maxSize, typeSize);
	        offset += typeSize * components;
	        return {
	            name: member.name,
	            type: member.type,
	            components,
	            offset: memberOffset
	        };
	    });
	    const size = align$1(offset, Math.max(maxSize, alignment));
	    return {
	        members: layoutMembers,
	        size,
	        alignment
	    };
	}
	function sizeOf(type) {
	    return viewTypes[type].BYTES_PER_ELEMENT;
	}
	function align$1(offset, size) {
	    return Math.ceil(offset / size) * size;
	}

	class StructArrayLayout2i4 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.int16 = new Int16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1);
	    }
	    emplace(i, v0, v1) {
	        const o2 = i * 2;
	        this.int16[o2 + 0] = v0;
	        this.int16[o2 + 1] = v1;
	        return i;
	    }
	}
	StructArrayLayout2i4.prototype.bytesPerElement = 4;
	register(StructArrayLayout2i4, 'StructArrayLayout2i4');
	class StructArrayLayout3i6 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.int16 = new Int16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2);
	    }
	    emplace(i, v0, v1, v2) {
	        const o2 = i * 3;
	        this.int16[o2 + 0] = v0;
	        this.int16[o2 + 1] = v1;
	        this.int16[o2 + 2] = v2;
	        return i;
	    }
	}
	StructArrayLayout3i6.prototype.bytesPerElement = 6;
	register(StructArrayLayout3i6, 'StructArrayLayout3i6');
	class StructArrayLayout4i8 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.int16 = new Int16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3);
	    }
	    emplace(i, v0, v1, v2, v3) {
	        const o2 = i * 4;
	        this.int16[o2 + 0] = v0;
	        this.int16[o2 + 1] = v1;
	        this.int16[o2 + 2] = v2;
	        this.int16[o2 + 3] = v3;
	        return i;
	    }
	}
	StructArrayLayout4i8.prototype.bytesPerElement = 8;
	register(StructArrayLayout4i8, 'StructArrayLayout4i8');
	class StructArrayLayout2i4ub1f12 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.int16 = new Int16Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4, v5, v6) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4, v5, v6);
	    }
	    emplace(i, v0, v1, v2, v3, v4, v5, v6) {
	        const o2 = i * 6;
	        const o1 = i * 12;
	        const o4 = i * 3;
	        this.int16[o2 + 0] = v0;
	        this.int16[o2 + 1] = v1;
	        this.uint8[o1 + 4] = v2;
	        this.uint8[o1 + 5] = v3;
	        this.uint8[o1 + 6] = v4;
	        this.uint8[o1 + 7] = v5;
	        this.float32[o4 + 2] = v6;
	        return i;
	    }
	}
	StructArrayLayout2i4ub1f12.prototype.bytesPerElement = 12;
	register(StructArrayLayout2i4ub1f12, 'StructArrayLayout2i4ub1f12');
	class StructArrayLayout4f16 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3);
	    }
	    emplace(i, v0, v1, v2, v3) {
	        const o4 = i * 4;
	        this.float32[o4 + 0] = v0;
	        this.float32[o4 + 1] = v1;
	        this.float32[o4 + 2] = v2;
	        this.float32[o4 + 3] = v3;
	        return i;
	    }
	}
	StructArrayLayout4f16.prototype.bytesPerElement = 16;
	register(StructArrayLayout4f16, 'StructArrayLayout4f16');
	class StructArrayLayout10ui20 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.uint16 = new Uint16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
	    }
	    emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9) {
	        const o2 = i * 10;
	        this.uint16[o2 + 0] = v0;
	        this.uint16[o2 + 1] = v1;
	        this.uint16[o2 + 2] = v2;
	        this.uint16[o2 + 3] = v3;
	        this.uint16[o2 + 4] = v4;
	        this.uint16[o2 + 5] = v5;
	        this.uint16[o2 + 6] = v6;
	        this.uint16[o2 + 7] = v7;
	        this.uint16[o2 + 8] = v8;
	        this.uint16[o2 + 9] = v9;
	        return i;
	    }
	}
	StructArrayLayout10ui20.prototype.bytesPerElement = 20;
	register(StructArrayLayout10ui20, 'StructArrayLayout10ui20');
	class StructArrayLayout8ui16 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.uint16 = new Uint16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4, v5, v6, v7) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7);
	    }
	    emplace(i, v0, v1, v2, v3, v4, v5, v6, v7) {
	        const o2 = i * 8;
	        this.uint16[o2 + 0] = v0;
	        this.uint16[o2 + 1] = v1;
	        this.uint16[o2 + 2] = v2;
	        this.uint16[o2 + 3] = v3;
	        this.uint16[o2 + 4] = v4;
	        this.uint16[o2 + 5] = v5;
	        this.uint16[o2 + 6] = v6;
	        this.uint16[o2 + 7] = v7;
	        return i;
	    }
	}
	StructArrayLayout8ui16.prototype.bytesPerElement = 16;
	register(StructArrayLayout8ui16, 'StructArrayLayout8ui16');
	class StructArrayLayout6i12 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.int16 = new Int16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4, v5) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4, v5);
	    }
	    emplace(i, v0, v1, v2, v3, v4, v5) {
	        const o2 = i * 6;
	        this.int16[o2 + 0] = v0;
	        this.int16[o2 + 1] = v1;
	        this.int16[o2 + 2] = v2;
	        this.int16[o2 + 3] = v3;
	        this.int16[o2 + 4] = v4;
	        this.int16[o2 + 5] = v5;
	        return i;
	    }
	}
	StructArrayLayout6i12.prototype.bytesPerElement = 12;
	register(StructArrayLayout6i12, 'StructArrayLayout6i12');
	class StructArrayLayout4i4ui4i24 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.int16 = new Int16Array(this.arrayBuffer);
	        this.uint16 = new Uint16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11);
	    }
	    emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11) {
	        const o2 = i * 12;
	        this.int16[o2 + 0] = v0;
	        this.int16[o2 + 1] = v1;
	        this.int16[o2 + 2] = v2;
	        this.int16[o2 + 3] = v3;
	        this.uint16[o2 + 4] = v4;
	        this.uint16[o2 + 5] = v5;
	        this.uint16[o2 + 6] = v6;
	        this.uint16[o2 + 7] = v7;
	        this.int16[o2 + 8] = v8;
	        this.int16[o2 + 9] = v9;
	        this.int16[o2 + 10] = v10;
	        this.int16[o2 + 11] = v11;
	        return i;
	    }
	}
	StructArrayLayout4i4ui4i24.prototype.bytesPerElement = 24;
	register(StructArrayLayout4i4ui4i24, 'StructArrayLayout4i4ui4i24');
	class StructArrayLayout3i3f20 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.int16 = new Int16Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4, v5) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4, v5);
	    }
	    emplace(i, v0, v1, v2, v3, v4, v5) {
	        const o2 = i * 10;
	        const o4 = i * 5;
	        this.int16[o2 + 0] = v0;
	        this.int16[o2 + 1] = v1;
	        this.int16[o2 + 2] = v2;
	        this.float32[o4 + 2] = v3;
	        this.float32[o4 + 3] = v4;
	        this.float32[o4 + 4] = v5;
	        return i;
	    }
	}
	StructArrayLayout3i3f20.prototype.bytesPerElement = 20;
	register(StructArrayLayout3i3f20, 'StructArrayLayout3i3f20');
	class StructArrayLayout1ul4 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.uint32 = new Uint32Array(this.arrayBuffer);
	    }
	    emplaceBack(v0) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0);
	    }
	    emplace(i, v0) {
	        const o4 = i * 1;
	        this.uint32[o4 + 0] = v0;
	        return i;
	    }
	}
	StructArrayLayout1ul4.prototype.bytesPerElement = 4;
	register(StructArrayLayout1ul4, 'StructArrayLayout1ul4');
	class StructArrayLayout5i4f1i1ul2ui40 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.int16 = new Int16Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	        this.uint32 = new Uint32Array(this.arrayBuffer);
	        this.uint16 = new Uint16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12);
	    }
	    emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12) {
	        const o2 = i * 20;
	        const o4 = i * 10;
	        this.int16[o2 + 0] = v0;
	        this.int16[o2 + 1] = v1;
	        this.int16[o2 + 2] = v2;
	        this.int16[o2 + 3] = v3;
	        this.int16[o2 + 4] = v4;
	        this.float32[o4 + 3] = v5;
	        this.float32[o4 + 4] = v6;
	        this.float32[o4 + 5] = v7;
	        this.float32[o4 + 6] = v8;
	        this.int16[o2 + 14] = v9;
	        this.uint32[o4 + 8] = v10;
	        this.uint16[o2 + 18] = v11;
	        this.uint16[o2 + 19] = v12;
	        return i;
	    }
	}
	StructArrayLayout5i4f1i1ul2ui40.prototype.bytesPerElement = 40;
	register(StructArrayLayout5i4f1i1ul2ui40, 'StructArrayLayout5i4f1i1ul2ui40');
	class StructArrayLayout3i2i2i16 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.int16 = new Int16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4, v5, v6) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4, v5, v6);
	    }
	    emplace(i, v0, v1, v2, v3, v4, v5, v6) {
	        const o2 = i * 8;
	        this.int16[o2 + 0] = v0;
	        this.int16[o2 + 1] = v1;
	        this.int16[o2 + 2] = v2;
	        this.int16[o2 + 4] = v3;
	        this.int16[o2 + 5] = v4;
	        this.int16[o2 + 6] = v5;
	        this.int16[o2 + 7] = v6;
	        return i;
	    }
	}
	StructArrayLayout3i2i2i16.prototype.bytesPerElement = 16;
	register(StructArrayLayout3i2i2i16, 'StructArrayLayout3i2i2i16');
	class StructArrayLayout2f1f2i16 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	        this.int16 = new Int16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4);
	    }
	    emplace(i, v0, v1, v2, v3, v4) {
	        const o4 = i * 4;
	        const o2 = i * 8;
	        this.float32[o4 + 0] = v0;
	        this.float32[o4 + 1] = v1;
	        this.float32[o4 + 2] = v2;
	        this.int16[o2 + 6] = v3;
	        this.int16[o2 + 7] = v4;
	        return i;
	    }
	}
	StructArrayLayout2f1f2i16.prototype.bytesPerElement = 16;
	register(StructArrayLayout2f1f2i16, 'StructArrayLayout2f1f2i16');
	class StructArrayLayout2ub2f12 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3);
	    }
	    emplace(i, v0, v1, v2, v3) {
	        const o1 = i * 12;
	        const o4 = i * 3;
	        this.uint8[o1 + 0] = v0;
	        this.uint8[o1 + 1] = v1;
	        this.float32[o4 + 1] = v2;
	        this.float32[o4 + 2] = v3;
	        return i;
	    }
	}
	StructArrayLayout2ub2f12.prototype.bytesPerElement = 12;
	register(StructArrayLayout2ub2f12, 'StructArrayLayout2ub2f12');
	class StructArrayLayout3f12 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2);
	    }
	    emplace(i, v0, v1, v2) {
	        const o4 = i * 3;
	        this.float32[o4 + 0] = v0;
	        this.float32[o4 + 1] = v1;
	        this.float32[o4 + 2] = v2;
	        return i;
	    }
	}
	StructArrayLayout3f12.prototype.bytesPerElement = 12;
	register(StructArrayLayout3f12, 'StructArrayLayout3f12');
	class StructArrayLayout3ui6 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.uint16 = new Uint16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2);
	    }
	    emplace(i, v0, v1, v2) {
	        const o2 = i * 3;
	        this.uint16[o2 + 0] = v0;
	        this.uint16[o2 + 1] = v1;
	        this.uint16[o2 + 2] = v2;
	        return i;
	    }
	}
	StructArrayLayout3ui6.prototype.bytesPerElement = 6;
	register(StructArrayLayout3ui6, 'StructArrayLayout3ui6');
	class StructArrayLayout3i2f2ui3ul3ui2f3ub1ul1i1ub60 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.int16 = new Int16Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	        this.uint16 = new Uint16Array(this.arrayBuffer);
	        this.uint32 = new Uint32Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20);
	    }
	    emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) {
	        const o2 = i * 30;
	        const o4 = i * 15;
	        const o1 = i * 60;
	        this.int16[o2 + 0] = v0;
	        this.int16[o2 + 1] = v1;
	        this.int16[o2 + 2] = v2;
	        this.float32[o4 + 2] = v3;
	        this.float32[o4 + 3] = v4;
	        this.uint16[o2 + 8] = v5;
	        this.uint16[o2 + 9] = v6;
	        this.uint32[o4 + 5] = v7;
	        this.uint32[o4 + 6] = v8;
	        this.uint32[o4 + 7] = v9;
	        this.uint16[o2 + 16] = v10;
	        this.uint16[o2 + 17] = v11;
	        this.uint16[o2 + 18] = v12;
	        this.float32[o4 + 10] = v13;
	        this.float32[o4 + 11] = v14;
	        this.uint8[o1 + 48] = v15;
	        this.uint8[o1 + 49] = v16;
	        this.uint8[o1 + 50] = v17;
	        this.uint32[o4 + 13] = v18;
	        this.int16[o2 + 28] = v19;
	        this.uint8[o1 + 58] = v20;
	        return i;
	    }
	}
	StructArrayLayout3i2f2ui3ul3ui2f3ub1ul1i1ub60.prototype.bytesPerElement = 60;
	register(StructArrayLayout3i2f2ui3ul3ui2f3ub1ul1i1ub60, 'StructArrayLayout3i2f2ui3ul3ui2f3ub1ul1i1ub60');
	class StructArrayLayout3i2f6i15ui1ul3f76 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.int16 = new Int16Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	        this.uint16 = new Uint16Array(this.arrayBuffer);
	        this.uint32 = new Uint32Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29);
	    }
	    emplace(i, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29) {
	        const o2 = i * 38;
	        const o4 = i * 19;
	        this.int16[o2 + 0] = v0;
	        this.int16[o2 + 1] = v1;
	        this.int16[o2 + 2] = v2;
	        this.float32[o4 + 2] = v3;
	        this.float32[o4 + 3] = v4;
	        this.int16[o2 + 8] = v5;
	        this.int16[o2 + 9] = v6;
	        this.int16[o2 + 10] = v7;
	        this.int16[o2 + 11] = v8;
	        this.int16[o2 + 12] = v9;
	        this.int16[o2 + 13] = v10;
	        this.uint16[o2 + 14] = v11;
	        this.uint16[o2 + 15] = v12;
	        this.uint16[o2 + 16] = v13;
	        this.uint16[o2 + 17] = v14;
	        this.uint16[o2 + 18] = v15;
	        this.uint16[o2 + 19] = v16;
	        this.uint16[o2 + 20] = v17;
	        this.uint16[o2 + 21] = v18;
	        this.uint16[o2 + 22] = v19;
	        this.uint16[o2 + 23] = v20;
	        this.uint16[o2 + 24] = v21;
	        this.uint16[o2 + 25] = v22;
	        this.uint16[o2 + 26] = v23;
	        this.uint16[o2 + 27] = v24;
	        this.uint16[o2 + 28] = v25;
	        this.uint32[o4 + 15] = v26;
	        this.float32[o4 + 16] = v27;
	        this.float32[o4 + 17] = v28;
	        this.float32[o4 + 18] = v29;
	        return i;
	    }
	}
	StructArrayLayout3i2f6i15ui1ul3f76.prototype.bytesPerElement = 76;
	register(StructArrayLayout3i2f6i15ui1ul3f76, 'StructArrayLayout3i2f6i15ui1ul3f76');
	class StructArrayLayout1f4 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	    }
	    emplaceBack(v0) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0);
	    }
	    emplace(i, v0) {
	        const o4 = i * 1;
	        this.float32[o4 + 0] = v0;
	        return i;
	    }
	}
	StructArrayLayout1f4.prototype.bytesPerElement = 4;
	register(StructArrayLayout1f4, 'StructArrayLayout1f4');
	class StructArrayLayout7f28 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4, v5, v6) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4, v5, v6);
	    }
	    emplace(i, v0, v1, v2, v3, v4, v5, v6) {
	        const o4 = i * 7;
	        this.float32[o4 + 0] = v0;
	        this.float32[o4 + 1] = v1;
	        this.float32[o4 + 2] = v2;
	        this.float32[o4 + 3] = v3;
	        this.float32[o4 + 4] = v4;
	        this.float32[o4 + 5] = v5;
	        this.float32[o4 + 6] = v6;
	        return i;
	    }
	}
	StructArrayLayout7f28.prototype.bytesPerElement = 28;
	register(StructArrayLayout7f28, 'StructArrayLayout7f28');
	class StructArrayLayout5f20 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3, v4) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3, v4);
	    }
	    emplace(i, v0, v1, v2, v3, v4) {
	        const o4 = i * 5;
	        this.float32[o4 + 0] = v0;
	        this.float32[o4 + 1] = v1;
	        this.float32[o4 + 2] = v2;
	        this.float32[o4 + 3] = v3;
	        this.float32[o4 + 4] = v4;
	        return i;
	    }
	}
	StructArrayLayout5f20.prototype.bytesPerElement = 20;
	register(StructArrayLayout5f20, 'StructArrayLayout5f20');
	class StructArrayLayout1ul3ui12 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.uint32 = new Uint32Array(this.arrayBuffer);
	        this.uint16 = new Uint16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1, v2, v3) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1, v2, v3);
	    }
	    emplace(i, v0, v1, v2, v3) {
	        const o4 = i * 3;
	        const o2 = i * 6;
	        this.uint32[o4 + 0] = v0;
	        this.uint16[o2 + 2] = v1;
	        this.uint16[o2 + 3] = v2;
	        this.uint16[o2 + 4] = v3;
	        return i;
	    }
	}
	StructArrayLayout1ul3ui12.prototype.bytesPerElement = 12;
	register(StructArrayLayout1ul3ui12, 'StructArrayLayout1ul3ui12');
	class StructArrayLayout2ui4 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.uint16 = new Uint16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1);
	    }
	    emplace(i, v0, v1) {
	        const o2 = i * 2;
	        this.uint16[o2 + 0] = v0;
	        this.uint16[o2 + 1] = v1;
	        return i;
	    }
	}
	StructArrayLayout2ui4.prototype.bytesPerElement = 4;
	register(StructArrayLayout2ui4, 'StructArrayLayout2ui4');
	class StructArrayLayout1ui2 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.uint16 = new Uint16Array(this.arrayBuffer);
	    }
	    emplaceBack(v0) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0);
	    }
	    emplace(i, v0) {
	        const o2 = i * 1;
	        this.uint16[o2 + 0] = v0;
	        return i;
	    }
	}
	StructArrayLayout1ui2.prototype.bytesPerElement = 2;
	register(StructArrayLayout1ui2, 'StructArrayLayout1ui2');
	class StructArrayLayout2f8 extends StructArray {
	    _refreshViews() {
	        this.uint8 = new Uint8Array(this.arrayBuffer);
	        this.float32 = new Float32Array(this.arrayBuffer);
	    }
	    emplaceBack(v0, v1) {
	        const i = this.length;
	        this.resize(i + 1);
	        return this.emplace(i, v0, v1);
	    }
	    emplace(i, v0, v1) {
	        const o4 = i * 2;
	        this.float32[o4 + 0] = v0;
	        this.float32[o4 + 1] = v1;
	        return i;
	    }
	}
	StructArrayLayout2f8.prototype.bytesPerElement = 8;
	register(StructArrayLayout2f8, 'StructArrayLayout2f8');
	class FillExtrusionExtStruct extends Struct {
	    get a_pos_30() {
	        return this._structArray.int16[this._pos2 + 0];
	    }
	    get a_pos_31() {
	        return this._structArray.int16[this._pos2 + 1];
	    }
	    get a_pos_32() {
	        return this._structArray.int16[this._pos2 + 2];
	    }
	    get a_pos_normal_30() {
	        return this._structArray.int16[this._pos2 + 3];
	    }
	    get a_pos_normal_31() {
	        return this._structArray.int16[this._pos2 + 4];
	    }
	    get a_pos_normal_32() {
	        return this._structArray.int16[this._pos2 + 5];
	    }
	}
	FillExtrusionExtStruct.prototype.size = 12;
	class FillExtrusionExtArray extends StructArrayLayout6i12 {
	    get(index) {
	        return new FillExtrusionExtStruct(this, index);
	    }
	}
	register(FillExtrusionExtArray, 'FillExtrusionExtArray');
	class CollisionBoxStruct extends Struct {
	    get projectedAnchorX() {
	        return this._structArray.int16[this._pos2 + 0];
	    }
	    get projectedAnchorY() {
	        return this._structArray.int16[this._pos2 + 1];
	    }
	    get projectedAnchorZ() {
	        return this._structArray.int16[this._pos2 + 2];
	    }
	    get tileAnchorX() {
	        return this._structArray.int16[this._pos2 + 3];
	    }
	    get tileAnchorY() {
	        return this._structArray.int16[this._pos2 + 4];
	    }
	    get x1() {
	        return this._structArray.float32[this._pos4 + 3];
	    }
	    get y1() {
	        return this._structArray.float32[this._pos4 + 4];
	    }
	    get x2() {
	        return this._structArray.float32[this._pos4 + 5];
	    }
	    get y2() {
	        return this._structArray.float32[this._pos4 + 6];
	    }
	    get padding() {
	        return this._structArray.int16[this._pos2 + 14];
	    }
	    get featureIndex() {
	        return this._structArray.uint32[this._pos4 + 8];
	    }
	    get sourceLayerIndex() {
	        return this._structArray.uint16[this._pos2 + 18];
	    }
	    get bucketIndex() {
	        return this._structArray.uint16[this._pos2 + 19];
	    }
	}
	CollisionBoxStruct.prototype.size = 40;
	class CollisionBoxArray extends StructArrayLayout5i4f1i1ul2ui40 {
	    get(index) {
	        return new CollisionBoxStruct(this, index);
	    }
	}
	register(CollisionBoxArray, 'CollisionBoxArray');
	class PlacedSymbolStruct extends Struct {
	    get projectedAnchorX() {
	        return this._structArray.int16[this._pos2 + 0];
	    }
	    get projectedAnchorY() {
	        return this._structArray.int16[this._pos2 + 1];
	    }
	    get projectedAnchorZ() {
	        return this._structArray.int16[this._pos2 + 2];
	    }
	    get tileAnchorX() {
	        return this._structArray.float32[this._pos4 + 2];
	    }
	    get tileAnchorY() {
	        return this._structArray.float32[this._pos4 + 3];
	    }
	    get glyphStartIndex() {
	        return this._structArray.uint16[this._pos2 + 8];
	    }
	    get numGlyphs() {
	        return this._structArray.uint16[this._pos2 + 9];
	    }
	    get vertexStartIndex() {
	        return this._structArray.uint32[this._pos4 + 5];
	    }
	    get lineStartIndex() {
	        return this._structArray.uint32[this._pos4 + 6];
	    }
	    get lineLength() {
	        return this._structArray.uint32[this._pos4 + 7];
	    }
	    get segment() {
	        return this._structArray.uint16[this._pos2 + 16];
	    }
	    get lowerSize() {
	        return this._structArray.uint16[this._pos2 + 17];
	    }
	    get upperSize() {
	        return this._structArray.uint16[this._pos2 + 18];
	    }
	    get lineOffsetX() {
	        return this._structArray.float32[this._pos4 + 10];
	    }
	    get lineOffsetY() {
	        return this._structArray.float32[this._pos4 + 11];
	    }
	    get writingMode() {
	        return this._structArray.uint8[this._pos1 + 48];
	    }
	    get placedOrientation() {
	        return this._structArray.uint8[this._pos1 + 49];
	    }
	    set placedOrientation(x) {
	        this._structArray.uint8[this._pos1 + 49] = x;
	    }
	    get hidden() {
	        return this._structArray.uint8[this._pos1 + 50];
	    }
	    set hidden(x) {
	        this._structArray.uint8[this._pos1 + 50] = x;
	    }
	    get crossTileID() {
	        return this._structArray.uint32[this._pos4 + 13];
	    }
	    set crossTileID(x) {
	        this._structArray.uint32[this._pos4 + 13] = x;
	    }
	    get associatedIconIndex() {
	        return this._structArray.int16[this._pos2 + 28];
	    }
	    get flipState() {
	        return this._structArray.uint8[this._pos1 + 58];
	    }
	    set flipState(x) {
	        this._structArray.uint8[this._pos1 + 58] = x;
	    }
	}
	PlacedSymbolStruct.prototype.size = 60;
	class PlacedSymbolArray extends StructArrayLayout3i2f2ui3ul3ui2f3ub1ul1i1ub60 {
	    get(index) {
	        return new PlacedSymbolStruct(this, index);
	    }
	}
	register(PlacedSymbolArray, 'PlacedSymbolArray');
	class SymbolInstanceStruct extends Struct {
	    get projectedAnchorX() {
	        return this._structArray.int16[this._pos2 + 0];
	    }
	    get projectedAnchorY() {
	        return this._structArray.int16[this._pos2 + 1];
	    }
	    get projectedAnchorZ() {
	        return this._structArray.int16[this._pos2 + 2];
	    }
	    get tileAnchorX() {
	        return this._structArray.float32[this._pos4 + 2];
	    }
	    get tileAnchorY() {
	        return this._structArray.float32[this._pos4 + 3];
	    }
	    get rightJustifiedTextSymbolIndex() {
	        return this._structArray.int16[this._pos2 + 8];
	    }
	    get centerJustifiedTextSymbolIndex() {
	        return this._structArray.int16[this._pos2 + 9];
	    }
	    get leftJustifiedTextSymbolIndex() {
	        return this._structArray.int16[this._pos2 + 10];
	    }
	    get verticalPlacedTextSymbolIndex() {
	        return this._structArray.int16[this._pos2 + 11];
	    }
	    get placedIconSymbolIndex() {
	        return this._structArray.int16[this._pos2 + 12];
	    }
	    get verticalPlacedIconSymbolIndex() {
	        return this._structArray.int16[this._pos2 + 13];
	    }
	    get key() {
	        return this._structArray.uint16[this._pos2 + 14];
	    }
	    get textBoxStartIndex() {
	        return this._structArray.uint16[this._pos2 + 15];
	    }
	    get textBoxEndIndex() {
	        return this._structArray.uint16[this._pos2 + 16];
	    }
	    get verticalTextBoxStartIndex() {
	        return this._structArray.uint16[this._pos2 + 17];
	    }
	    get verticalTextBoxEndIndex() {
	        return this._structArray.uint16[this._pos2 + 18];
	    }
	    get iconBoxStartIndex() {
	        return this._structArray.uint16[this._pos2 + 19];
	    }
	    get iconBoxEndIndex() {
	        return this._structArray.uint16[this._pos2 + 20];
	    }
	    get verticalIconBoxStartIndex() {
	        return this._structArray.uint16[this._pos2 + 21];
	    }
	    get verticalIconBoxEndIndex() {
	        return this._structArray.uint16[this._pos2 + 22];
	    }
	    get featureIndex() {
	        return this._structArray.uint16[this._pos2 + 23];
	    }
	    get numHorizontalGlyphVertices() {
	        return this._structArray.uint16[this._pos2 + 24];
	    }
	    get numVerticalGlyphVertices() {
	        return this._structArray.uint16[this._pos2 + 25];
	    }
	    get numIconVertices() {
	        return this._structArray.uint16[this._pos2 + 26];
	    }
	    get numVerticalIconVertices() {
	        return this._structArray.uint16[this._pos2 + 27];
	    }
	    get useRuntimeCollisionCircles() {
	        return this._structArray.uint16[this._pos2 + 28];
	    }
	    get crossTileID() {
	        return this._structArray.uint32[this._pos4 + 15];
	    }
	    set crossTileID(x) {
	        this._structArray.uint32[this._pos4 + 15] = x;
	    }
	    get textOffset0() {
	        return this._structArray.float32[this._pos4 + 16];
	    }
	    get textOffset1() {
	        return this._structArray.float32[this._pos4 + 17];
	    }
	    get collisionCircleDiameter() {
	        return this._structArray.float32[this._pos4 + 18];
	    }
	}
	SymbolInstanceStruct.prototype.size = 76;
	class SymbolInstanceArray extends StructArrayLayout3i2f6i15ui1ul3f76 {
	    get(index) {
	        return new SymbolInstanceStruct(this, index);
	    }
	}
	register(SymbolInstanceArray, 'SymbolInstanceArray');
	class GlyphOffsetArray extends StructArrayLayout1f4 {
	    getoffsetX(index) {
	        return this.float32[index * 1 + 0];
	    }
	}
	register(GlyphOffsetArray, 'GlyphOffsetArray');
	class SymbolLineVertexArray extends StructArrayLayout3i6 {
	    getx(index) {
	        return this.int16[index * 3 + 0];
	    }
	    gety(index) {
	        return this.int16[index * 3 + 1];
	    }
	    gettileUnitDistanceFromAnchor(index) {
	        return this.int16[index * 3 + 2];
	    }
	}
	register(SymbolLineVertexArray, 'SymbolLineVertexArray');
	class FeatureIndexStruct extends Struct {
	    get featureIndex() {
	        return this._structArray.uint32[this._pos4 + 0];
	    }
	    get sourceLayerIndex() {
	        return this._structArray.uint16[this._pos2 + 2];
	    }
	    get bucketIndex() {
	        return this._structArray.uint16[this._pos2 + 3];
	    }
	    get layoutVertexArrayOffset() {
	        return this._structArray.uint16[this._pos2 + 4];
	    }
	}
	FeatureIndexStruct.prototype.size = 12;
	class FeatureIndexArray extends StructArrayLayout1ul3ui12 {
	    get(index) {
	        return new FeatureIndexStruct(this, index);
	    }
	}
	register(FeatureIndexArray, 'FeatureIndexArray');
	class FillExtrusionCentroidStruct extends Struct {
	    get a_centroid_pos0() {
	        return this._structArray.uint16[this._pos2 + 0];
	    }
	    get a_centroid_pos1() {
	        return this._structArray.uint16[this._pos2 + 1];
	    }
	}
	FillExtrusionCentroidStruct.prototype.size = 4;
	class FillExtrusionCentroidArray extends StructArrayLayout2ui4 {
	    get(index) {
	        return new FillExtrusionCentroidStruct(this, index);
	    }
	}
	register(FillExtrusionCentroidArray, 'FillExtrusionCentroidArray');
	class CircleGlobeExtStruct extends Struct {
	    get a_pos_30() {
	        return this._structArray.int16[this._pos2 + 0];
	    }
	    get a_pos_31() {
	        return this._structArray.int16[this._pos2 + 1];
	    }
	    get a_pos_32() {
	        return this._structArray.int16[this._pos2 + 2];
	    }
	    get a_pos_normal_30() {
	        return this._structArray.int16[this._pos2 + 3];
	    }
	    get a_pos_normal_31() {
	        return this._structArray.int16[this._pos2 + 4];
	    }
	    get a_pos_normal_32() {
	        return this._structArray.int16[this._pos2 + 5];
	    }
	}
	CircleGlobeExtStruct.prototype.size = 12;
	class CircleGlobeExtArray extends StructArrayLayout6i12 {
	    get(index) {
	        return new CircleGlobeExtStruct(this, index);
	    }
	}
	register(CircleGlobeExtArray, 'CircleGlobeExtArray');

	const patternAttributes = createLayout([
	    {
	        name: 'a_pattern_to',
	        components: 4,
	        type: 'Uint16'
	    },
	    {
	        name: 'a_pattern_from',
	        components: 4,
	        type: 'Uint16'
	    },
	    {
	        name: 'a_pixel_ratio_to',
	        components: 1,
	        type: 'Uint16'
	    },
	    {
	        name: 'a_pixel_ratio_from',
	        components: 1,
	        type: 'Uint16'
	    }
	]);

	const dashAttributes = createLayout([
	    {
	        name: 'a_dash_to',
	        components: 4,
	        type: 'Uint16'
	    },
	    {
	        name: 'a_dash_from',
	        components: 4,
	        type: 'Uint16'
	    }
	]);

	var murmurhash3_gc = createCommonjsModule(function (module) {
	function murmurhash3_32_gc(key, seed) {
	    var remainder, bytes, h1, h1b, c1, c2, k1, i;
	    remainder = key.length & 3;
	    bytes = key.length - remainder;
	    h1 = seed;
	    c1 = 3432918353;
	    c2 = 461845907;
	    i = 0;
	    while (i < bytes) {
	        k1 = key.charCodeAt(i) & 255 | (key.charCodeAt(++i) & 255) << 8 | (key.charCodeAt(++i) & 255) << 16 | (key.charCodeAt(++i) & 255) << 24;
	        ++i;
	        k1 = (k1 & 65535) * c1 + (((k1 >>> 16) * c1 & 65535) << 16) & 4294967295;
	        k1 = k1 << 15 | k1 >>> 17;
	        k1 = (k1 & 65535) * c2 + (((k1 >>> 16) * c2 & 65535) << 16) & 4294967295;
	        h1 ^= k1;
	        h1 = h1 << 13 | h1 >>> 19;
	        h1b = (h1 & 65535) * 5 + (((h1 >>> 16) * 5 & 65535) << 16) & 4294967295;
	        h1 = (h1b & 65535) + 27492 + (((h1b >>> 16) + 58964 & 65535) << 16);
	    }
	    k1 = 0;
	    switch (remainder) {
	    case 3:
	        k1 ^= (key.charCodeAt(i + 2) & 255) << 16;
	    case 2:
	        k1 ^= (key.charCodeAt(i + 1) & 255) << 8;
	    case 1:
	        k1 ^= key.charCodeAt(i) & 255;
	        k1 = (k1 & 65535) * c1 + (((k1 >>> 16) * c1 & 65535) << 16) & 4294967295;
	        k1 = k1 << 15 | k1 >>> 17;
	        k1 = (k1 & 65535) * c2 + (((k1 >>> 16) * c2 & 65535) << 16) & 4294967295;
	        h1 ^= k1;
	    }
	    h1 ^= key.length;
	    h1 ^= h1 >>> 16;
	    h1 = (h1 & 65535) * 2246822507 + (((h1 >>> 16) * 2246822507 & 65535) << 16) & 4294967295;
	    h1 ^= h1 >>> 13;
	    h1 = (h1 & 65535) * 3266489909 + (((h1 >>> 16) * 3266489909 & 65535) << 16) & 4294967295;
	    h1 ^= h1 >>> 16;
	    return h1 >>> 0;
	}
	{
	    module.exports = murmurhash3_32_gc;
	}
	});

	var murmurhash2_gc = createCommonjsModule(function (module) {
	function murmurhash2_32_gc(str, seed) {
	    var l = str.length, h = seed ^ l, i = 0, k;
	    while (l >= 4) {
	        k = str.charCodeAt(i) & 255 | (str.charCodeAt(++i) & 255) << 8 | (str.charCodeAt(++i) & 255) << 16 | (str.charCodeAt(++i) & 255) << 24;
	        k = (k & 65535) * 1540483477 + (((k >>> 16) * 1540483477 & 65535) << 16);
	        k ^= k >>> 24;
	        k = (k & 65535) * 1540483477 + (((k >>> 16) * 1540483477 & 65535) << 16);
	        h = (h & 65535) * 1540483477 + (((h >>> 16) * 1540483477 & 65535) << 16) ^ k;
	        l -= 4;
	        ++i;
	    }
	    switch (l) {
	    case 3:
	        h ^= (str.charCodeAt(i + 2) & 255) << 16;
	    case 2:
	        h ^= (str.charCodeAt(i + 1) & 255) << 8;
	    case 1:
	        h ^= str.charCodeAt(i) & 255;
	        h = (h & 65535) * 1540483477 + (((h >>> 16) * 1540483477 & 65535) << 16);
	    }
	    h ^= h >>> 13;
	    h = (h & 65535) * 1540483477 + (((h >>> 16) * 1540483477 & 65535) << 16);
	    h ^= h >>> 15;
	    return h >>> 0;
	}
	{
	    module.exports = murmurhash2_32_gc;
	}
	});

	var murmurhashJs = murmurhash3_gc;
	var murmur3_1 = murmurhash3_gc;
	var murmur2_1 = murmurhash2_gc;
	murmurhashJs.murmur3 = murmur3_1;
	murmurhashJs.murmur2 = murmur2_1;

	class FeaturePositionMap {
	    constructor() {
	        this.ids = [];
	        this.positions = [];
	        this.indexed = false;
	    }
	    add(id, index, start, end) {
	        this.ids.push(getNumericId(id));
	        this.positions.push(index, start, end);
	    }
	    getPositions(id) {
	        const intId = getNumericId(id);
	        let i = 0;
	        let j = this.ids.length - 1;
	        while (i < j) {
	            const m = i + j >> 1;
	            if (this.ids[m] >= intId) {
	                j = m;
	            } else {
	                i = m + 1;
	            }
	        }
	        const positions = [];
	        while (this.ids[i] === intId) {
	            const index = this.positions[3 * i];
	            const start = this.positions[3 * i + 1];
	            const end = this.positions[3 * i + 2];
	            positions.push({
	                index,
	                start,
	                end
	            });
	            i++;
	        }
	        return positions;
	    }
	    static serialize(map, transferables) {
	        const ids = new Float64Array(map.ids);
	        const positions = new Uint32Array(map.positions);
	        sort(ids, positions, 0, ids.length - 1);
	        if (transferables) {
	            transferables.push(ids.buffer, positions.buffer);
	        }
	        return {
	            ids,
	            positions
	        };
	    }
	    static deserialize(obj) {
	        const map = new FeaturePositionMap();
	        map.ids = obj.ids;
	        map.positions = obj.positions;
	        map.indexed = true;
	        return map;
	    }
	}
	function getNumericId(value) {
	    const numValue = +value;
	    if (!isNaN(numValue) && Number.MIN_SAFE_INTEGER <= numValue && numValue <= Number.MAX_SAFE_INTEGER) {
	        return numValue;
	    }
	    return murmurhashJs(String(value));
	}
	function sort(ids, positions, left, right) {
	    while (left < right) {
	        const pivot = ids[left + right >> 1];
	        let i = left - 1;
	        let j = right + 1;
	        while (true) {
	            do
	                i++;
	            while (ids[i] < pivot);
	            do
	                j--;
	            while (ids[j] > pivot);
	            if (i >= j)
	                break;
	            swap$1(ids, i, j);
	            swap$1(positions, 3 * i, 3 * j);
	            swap$1(positions, 3 * i + 1, 3 * j + 1);
	            swap$1(positions, 3 * i + 2, 3 * j + 2);
	        }
	        if (j - left < right - j) {
	            sort(ids, positions, left, j);
	            left = j + 1;
	        } else {
	            sort(ids, positions, j + 1, right);
	            right = j;
	        }
	    }
	}
	function swap$1(arr, i, j) {
	    const tmp = arr[i];
	    arr[i] = arr[j];
	    arr[j] = tmp;
	}
	register(FeaturePositionMap, 'FeaturePositionMap');

	class Uniform {
	    constructor(context, location) {
	        this.gl = context.gl;
	        this.location = location;
	    }
	}
	class Uniform1i extends Uniform {
	    constructor(context, location) {
	        super(context, location);
	        this.current = 0;
	    }
	    set(v) {
	        if (this.current !== v) {
	            this.current = v;
	            this.gl.uniform1i(this.location, v);
	        }
	    }
	}
	class Uniform1f extends Uniform {
	    constructor(context, location) {
	        super(context, location);
	        this.current = 0;
	    }
	    set(v) {
	        if (this.current !== v) {
	            this.current = v;
	            this.gl.uniform1f(this.location, v);
	        }
	    }
	}
	class Uniform2f extends Uniform {
	    constructor(context, location) {
	        super(context, location);
	        this.current = [
	            0,
	            0
	        ];
	    }
	    set(v) {
	        if (v[0] !== this.current[0] || v[1] !== this.current[1]) {
	            this.current = v;
	            this.gl.uniform2f(this.location, v[0], v[1]);
	        }
	    }
	}
	class Uniform3f extends Uniform {
	    constructor(context, location) {
	        super(context, location);
	        this.current = [
	            0,
	            0,
	            0
	        ];
	    }
	    set(v) {
	        if (v[0] !== this.current[0] || v[1] !== this.current[1] || v[2] !== this.current[2]) {
	            this.current = v;
	            this.gl.uniform3f(this.location, v[0], v[1], v[2]);
	        }
	    }
	}
	class Uniform4f extends Uniform {
	    constructor(context, location) {
	        super(context, location);
	        this.current = [
	            0,
	            0,
	            0,
	            0
	        ];
	    }
	    set(v) {
	        if (v[0] !== this.current[0] || v[1] !== this.current[1] || v[2] !== this.current[2] || v[3] !== this.current[3]) {
	            this.current = v;
	            this.gl.uniform4f(this.location, v[0], v[1], v[2], v[3]);
	        }
	    }
	}
	class UniformColor extends Uniform {
	    constructor(context, location) {
	        super(context, location);
	        this.current = Color$1.transparent;
	    }
	    set(v) {
	        if (v.r !== this.current.r || v.g !== this.current.g || v.b !== this.current.b || v.a !== this.current.a) {
	            this.current = v;
	            this.gl.uniform4f(this.location, v.r, v.g, v.b, v.a);
	        }
	    }
	}
	const emptyMat4 = new Float32Array(16);
	class UniformMatrix4f extends Uniform {
	    constructor(context, location) {
	        super(context, location);
	        this.current = emptyMat4;
	    }
	    set(v) {
	        if (v[12] !== this.current[12] || v[0] !== this.current[0]) {
	            this.current = v;
	            this.gl.uniformMatrix4fv(this.location, false, v);
	            return;
	        }
	        for (let i = 1; i < 16; i++) {
	            if (v[i] !== this.current[i]) {
	                this.current = v;
	                this.gl.uniformMatrix4fv(this.location, false, v);
	                break;
	            }
	        }
	    }
	}
	const emptyMat3 = new Float32Array(9);
	class UniformMatrix3f extends Uniform {
	    constructor(context, location) {
	        super(context, location);
	        this.current = emptyMat3;
	    }
	    set(v) {
	        for (let i = 0; i < 9; i++) {
	            if (v[i] !== this.current[i]) {
	                this.current = v;
	                this.gl.uniformMatrix3fv(this.location, false, v);
	                break;
	            }
	        }
	    }
	}
	const emptyMat2 = new Float32Array(4);
	class UniformMatrix2f extends Uniform {
	    constructor(context, location) {
	        super(context, location);
	        this.current = emptyMat2;
	    }
	    set(v) {
	        for (let i = 0; i < 4; i++) {
	            if (v[i] !== this.current[i]) {
	                this.current = v;
	                this.gl.uniformMatrix2fv(this.location, false, v);
	                break;
	            }
	        }
	    }
	}

	function packColor(color) {
	    return [
	        packUint8ToFloat(255 * color.r, 255 * color.g),
	        packUint8ToFloat(255 * color.b, 255 * color.a)
	    ];
	}
	class ConstantBinder {
	    constructor(value, names, type) {
	        this.value = value;
	        this.uniformNames = names.map(name => `u_${ name }`);
	        this.type = type;
	    }
	    setUniform(uniform, globals, currentValue) {
	        uniform.set(currentValue.constantOr(this.value));
	    }
	    getBinding(context, location, _) {
	        return this.type === 'color' ? new UniformColor(context, location) : new Uniform1f(context, location);
	    }
	}
	class CrossFadedConstantBinder {
	    constructor(value, names) {
	        this.uniformNames = names.map(name => `u_${ name }`);
	        this.patternFrom = null;
	        this.patternTo = null;
	        this.pixelRatioFrom = 1;
	        this.pixelRatioTo = 1;
	    }
	    setConstantPatternPositions(posTo, posFrom) {
	        this.pixelRatioFrom = posFrom.pixelRatio || 1;
	        this.pixelRatioTo = posTo.pixelRatio || 1;
	        this.patternFrom = posFrom.tl.concat(posFrom.br);
	        this.patternTo = posTo.tl.concat(posTo.br);
	    }
	    setUniform(uniform, globals, currentValue, uniformName) {
	        const pos = uniformName === 'u_pattern_to' || uniformName === 'u_dash_to' ? this.patternTo : uniformName === 'u_pattern_from' || uniformName === 'u_dash_from' ? this.patternFrom : uniformName === 'u_pixel_ratio_to' ? this.pixelRatioTo : uniformName === 'u_pixel_ratio_from' ? this.pixelRatioFrom : null;
	        if (pos)
	            uniform.set(pos);
	    }
	    getBinding(context, location, name) {
	        return name === 'u_pattern_from' || name === 'u_pattern_to' || name === 'u_dash_from' || name === 'u_dash_to' ? new Uniform4f(context, location) : new Uniform1f(context, location);
	    }
	}
	class SourceExpressionBinder {
	    constructor(expression, names, type, PaintVertexArray) {
	        this.expression = expression;
	        this.type = type;
	        this.maxValue = 0;
	        this.paintVertexAttributes = names.map(name => ({
	            name: `a_${ name }`,
	            type: 'Float32',
	            components: type === 'color' ? 2 : 1,
	            offset: 0
	        }));
	        this.paintVertexArray = new PaintVertexArray();
	    }
	    populatePaintArray(newLength, feature, imagePositions, availableImages, canonical, formattedSection) {
	        const start = this.paintVertexArray.length;
	        const value = this.expression.evaluate(new EvaluationParameters(0), feature, {}, canonical, availableImages, formattedSection);
	        this.paintVertexArray.resize(newLength);
	        this._setPaintValue(start, newLength, value);
	    }
	    updatePaintArray(start, end, feature, featureState, availableImages) {
	        const value = this.expression.evaluate({ zoom: 0 }, feature, featureState, undefined, availableImages);
	        this._setPaintValue(start, end, value);
	    }
	    _setPaintValue(start, end, value) {
	        if (this.type === 'color') {
	            const color = packColor(value);
	            for (let i = start; i < end; i++) {
	                this.paintVertexArray.emplace(i, color[0], color[1]);
	            }
	        } else {
	            for (let i = start; i < end; i++) {
	                this.paintVertexArray.emplace(i, value);
	            }
	            this.maxValue = Math.max(this.maxValue, Math.abs(value));
	        }
	    }
	    upload(context) {
	        if (this.paintVertexArray && this.paintVertexArray.arrayBuffer) {
	            if (this.paintVertexBuffer && this.paintVertexBuffer.buffer) {
	                this.paintVertexBuffer.updateData(this.paintVertexArray);
	            } else {
	                this.paintVertexBuffer = context.createVertexBuffer(this.paintVertexArray, this.paintVertexAttributes, this.expression.isStateDependent);
	            }
	        }
	    }
	    destroy() {
	        if (this.paintVertexBuffer) {
	            this.paintVertexBuffer.destroy();
	        }
	    }
	}
	class CompositeExpressionBinder {
	    constructor(expression, names, type, useIntegerZoom, zoom, PaintVertexArray) {
	        this.expression = expression;
	        this.uniformNames = names.map(name => `u_${ name }_t`);
	        this.type = type;
	        this.useIntegerZoom = useIntegerZoom;
	        this.zoom = zoom;
	        this.maxValue = 0;
	        this.paintVertexAttributes = names.map(name => ({
	            name: `a_${ name }`,
	            type: 'Float32',
	            components: type === 'color' ? 4 : 2,
	            offset: 0
	        }));
	        this.paintVertexArray = new PaintVertexArray();
	    }
	    populatePaintArray(newLength, feature, imagePositions, availableImages, canonical, formattedSection) {
	        const min = this.expression.evaluate(new EvaluationParameters(this.zoom), feature, {}, canonical, availableImages, formattedSection);
	        const max = this.expression.evaluate(new EvaluationParameters(this.zoom + 1), feature, {}, canonical, availableImages, formattedSection);
	        const start = this.paintVertexArray.length;
	        this.paintVertexArray.resize(newLength);
	        this._setPaintValue(start, newLength, min, max);
	    }
	    updatePaintArray(start, end, feature, featureState, availableImages) {
	        const min = this.expression.evaluate({ zoom: this.zoom }, feature, featureState, undefined, availableImages);
	        const max = this.expression.evaluate({ zoom: this.zoom + 1 }, feature, featureState, undefined, availableImages);
	        this._setPaintValue(start, end, min, max);
	    }
	    _setPaintValue(start, end, min, max) {
	        if (this.type === 'color') {
	            const minColor = packColor(min);
	            const maxColor = packColor(max);
	            for (let i = start; i < end; i++) {
	                this.paintVertexArray.emplace(i, minColor[0], minColor[1], maxColor[0], maxColor[1]);
	            }
	        } else {
	            for (let i = start; i < end; i++) {
	                this.paintVertexArray.emplace(i, min, max);
	            }
	            this.maxValue = Math.max(this.maxValue, Math.abs(min), Math.abs(max));
	        }
	    }
	    upload(context) {
	        if (this.paintVertexArray && this.paintVertexArray.arrayBuffer) {
	            if (this.paintVertexBuffer && this.paintVertexBuffer.buffer) {
	                this.paintVertexBuffer.updateData(this.paintVertexArray);
	            } else {
	                this.paintVertexBuffer = context.createVertexBuffer(this.paintVertexArray, this.paintVertexAttributes, this.expression.isStateDependent);
	            }
	        }
	    }
	    destroy() {
	        if (this.paintVertexBuffer) {
	            this.paintVertexBuffer.destroy();
	        }
	    }
	    setUniform(uniform, globals) {
	        const currentZoom = this.useIntegerZoom ? Math.floor(globals.zoom) : globals.zoom;
	        const factor = clamp(this.expression.interpolationFactor(currentZoom, this.zoom, this.zoom + 1), 0, 1);
	        uniform.set(factor);
	    }
	    getBinding(context, location, _) {
	        return new Uniform1f(context, location);
	    }
	}
	class CrossFadedCompositeBinder {
	    constructor(expression, names, type, useIntegerZoom, zoom, PaintVertexArray, layerId) {
	        this.expression = expression;
	        this.type = type;
	        this.useIntegerZoom = useIntegerZoom;
	        this.zoom = zoom;
	        this.layerId = layerId;
	        this.paintVertexAttributes = (type === 'array' ? dashAttributes : patternAttributes).members;
	        for (let i = 0; i < names.length; ++i) {
	        }
	        this.zoomInPaintVertexArray = new PaintVertexArray();
	        this.zoomOutPaintVertexArray = new PaintVertexArray();
	    }
	    populatePaintArray(length, feature, imagePositions) {
	        const start = this.zoomInPaintVertexArray.length;
	        this.zoomInPaintVertexArray.resize(length);
	        this.zoomOutPaintVertexArray.resize(length);
	        this._setPaintValues(start, length, feature.patterns && feature.patterns[this.layerId], imagePositions);
	    }
	    updatePaintArray(start, end, feature, featureState, availableImages, imagePositions) {
	        this._setPaintValues(start, end, feature.patterns && feature.patterns[this.layerId], imagePositions);
	    }
	    _setPaintValues(start, end, patterns, positions) {
	        if (!positions || !patterns)
	            return;
	        const {min, mid, max} = patterns;
	        const imageMin = positions[min];
	        const imageMid = positions[mid];
	        const imageMax = positions[max];
	        if (!imageMin || !imageMid || !imageMax)
	            return;
	        for (let i = start; i < end; i++) {
	            this._setPaintValue(this.zoomInPaintVertexArray, i, imageMid, imageMin);
	            this._setPaintValue(this.zoomOutPaintVertexArray, i, imageMid, imageMax);
	        }
	    }
	    _setPaintValue(array, i, posA, posB) {
	        array.emplace(i, posA.tl[0], posA.tl[1], posA.br[0], posA.br[1], posB.tl[0], posB.tl[1], posB.br[0], posB.br[1], posA.pixelRatio, posB.pixelRatio);
	    }
	    upload(context) {
	        if (this.zoomInPaintVertexArray && this.zoomInPaintVertexArray.arrayBuffer && this.zoomOutPaintVertexArray && this.zoomOutPaintVertexArray.arrayBuffer) {
	            this.zoomInPaintVertexBuffer = context.createVertexBuffer(this.zoomInPaintVertexArray, this.paintVertexAttributes, this.expression.isStateDependent);
	            this.zoomOutPaintVertexBuffer = context.createVertexBuffer(this.zoomOutPaintVertexArray, this.paintVertexAttributes, this.expression.isStateDependent);
	        }
	    }
	    destroy() {
	        if (this.zoomOutPaintVertexBuffer)
	            this.zoomOutPaintVertexBuffer.destroy();
	        if (this.zoomInPaintVertexBuffer)
	            this.zoomInPaintVertexBuffer.destroy();
	    }
	}
	class ProgramConfiguration {
	    constructor(layer, zoom, filterProperties = () => true) {
	        this.binders = {};
	        this._buffers = [];
	        const keys = [];
	        for (const property in layer.paint._values) {
	            if (!filterProperties(property))
	                continue;
	            const value = layer.paint.get(property);
	            if (!(value instanceof PossiblyEvaluatedPropertyValue) || !supportsPropertyExpression(value.property.specification)) {
	                continue;
	            }
	            const names = paintAttributeNames(property, layer.type);
	            const expression = value.value;
	            const type = value.property.specification.type;
	            const useIntegerZoom = value.property.useIntegerZoom;
	            const propType = value.property.specification['property-type'];
	            const isCrossFaded = propType === 'cross-faded' || propType === 'cross-faded-data-driven';
	            const sourceException = String(property) === 'line-dasharray' && layer.layout.get('line-cap').value.kind !== 'constant';
	            if (expression.kind === 'constant' && !sourceException) {
	                this.binders[property] = isCrossFaded ? new CrossFadedConstantBinder(expression.value, names) : new ConstantBinder(expression.value, names, type);
	                keys.push(`/u_${ property }`);
	            } else if (expression.kind === 'source' || sourceException || isCrossFaded) {
	                const StructArrayLayout = layoutType(property, type, 'source');
	                this.binders[property] = isCrossFaded ? new CrossFadedCompositeBinder(expression, names, type, useIntegerZoom, zoom, StructArrayLayout, layer.id) : new SourceExpressionBinder(expression, names, type, StructArrayLayout);
	                keys.push(`/a_${ property }`);
	            } else {
	                const StructArrayLayout = layoutType(property, type, 'composite');
	                this.binders[property] = new CompositeExpressionBinder(expression, names, type, useIntegerZoom, zoom, StructArrayLayout);
	                keys.push(`/z_${ property }`);
	            }
	        }
	        this.cacheKey = keys.sort().join('');
	    }
	    getMaxValue(property) {
	        const binder = this.binders[property];
	        return binder instanceof SourceExpressionBinder || binder instanceof CompositeExpressionBinder ? binder.maxValue : 0;
	    }
	    populatePaintArrays(newLength, feature, imagePositions, availableImages, canonical, formattedSection) {
	        for (const property in this.binders) {
	            const binder = this.binders[property];
	            if (binder instanceof SourceExpressionBinder || binder instanceof CompositeExpressionBinder || binder instanceof CrossFadedCompositeBinder)
	                binder.populatePaintArray(newLength, feature, imagePositions, availableImages, canonical, formattedSection);
	        }
	    }
	    setConstantPatternPositions(posTo, posFrom) {
	        for (const property in this.binders) {
	            const binder = this.binders[property];
	            if (binder instanceof CrossFadedConstantBinder)
	                binder.setConstantPatternPositions(posTo, posFrom);
	        }
	    }
	    updatePaintArrays(featureStates, featureMap, vtLayer, layer, availableImages, imagePositions) {
	        let dirty = false;
	        for (const id in featureStates) {
	            const positions = featureMap.getPositions(id);
	            for (const pos of positions) {
	                const feature = vtLayer.feature(pos.index);
	                for (const property in this.binders) {
	                    const binder = this.binders[property];
	                    if ((binder instanceof SourceExpressionBinder || binder instanceof CompositeExpressionBinder || binder instanceof CrossFadedCompositeBinder) && binder.expression.isStateDependent === true) {
	                        const value = layer.paint.get(property);
	                        binder.expression = value.value;
	                        binder.updatePaintArray(pos.start, pos.end, feature, featureStates[id], availableImages, imagePositions);
	                        dirty = true;
	                    }
	                }
	            }
	        }
	        return dirty;
	    }
	    defines() {
	        const result = [];
	        for (const property in this.binders) {
	            const binder = this.binders[property];
	            if (binder instanceof ConstantBinder || binder instanceof CrossFadedConstantBinder) {
	                result.push(...binder.uniformNames.map(name => `#define HAS_UNIFORM_${ name }`));
	            }
	        }
	        return result;
	    }
	    getBinderAttributes() {
	        const result = [];
	        for (const property in this.binders) {
	            const binder = this.binders[property];
	            if (binder instanceof SourceExpressionBinder || binder instanceof CompositeExpressionBinder || binder instanceof CrossFadedCompositeBinder) {
	                for (let i = 0; i < binder.paintVertexAttributes.length; i++) {
	                    result.push(binder.paintVertexAttributes[i].name);
	                }
	            }
	        }
	        return result;
	    }
	    getBinderUniforms() {
	        const uniforms = [];
	        for (const property in this.binders) {
	            const binder = this.binders[property];
	            if (binder instanceof ConstantBinder || binder instanceof CrossFadedConstantBinder || binder instanceof CompositeExpressionBinder) {
	                for (const uniformName of binder.uniformNames) {
	                    uniforms.push(uniformName);
	                }
	            }
	        }
	        return uniforms;
	    }
	    getPaintVertexBuffers() {
	        return this._buffers;
	    }
	    getUniforms(context, locations) {
	        const uniforms = [];
	        for (const property in this.binders) {
	            const binder = this.binders[property];
	            if (binder instanceof ConstantBinder || binder instanceof CrossFadedConstantBinder || binder instanceof CompositeExpressionBinder) {
	                for (const name of binder.uniformNames) {
	                    if (locations[name]) {
	                        const binding = binder.getBinding(context, locations[name], name);
	                        uniforms.push({
	                            name,
	                            property,
	                            binding
	                        });
	                    }
	                }
	            }
	        }
	        return uniforms;
	    }
	    setUniforms(context, binderUniforms, properties, globals) {
	        for (const {name, property, binding} of binderUniforms) {
	            this.binders[property].setUniform(binding, globals, properties.get(property), name);
	        }
	    }
	    updatePaintBuffers(crossfade) {
	        this._buffers = [];
	        for (const property in this.binders) {
	            const binder = this.binders[property];
	            if (crossfade && binder instanceof CrossFadedCompositeBinder) {
	                const patternVertexBuffer = crossfade.fromScale === 2 ? binder.zoomInPaintVertexBuffer : binder.zoomOutPaintVertexBuffer;
	                if (patternVertexBuffer)
	                    this._buffers.push(patternVertexBuffer);
	            } else if ((binder instanceof SourceExpressionBinder || binder instanceof CompositeExpressionBinder) && binder.paintVertexBuffer) {
	                this._buffers.push(binder.paintVertexBuffer);
	            }
	        }
	    }
	    upload(context) {
	        for (const property in this.binders) {
	            const binder = this.binders[property];
	            if (binder instanceof SourceExpressionBinder || binder instanceof CompositeExpressionBinder || binder instanceof CrossFadedCompositeBinder)
	                binder.upload(context);
	        }
	        this.updatePaintBuffers();
	    }
	    destroy() {
	        for (const property in this.binders) {
	            const binder = this.binders[property];
	            if (binder instanceof SourceExpressionBinder || binder instanceof CompositeExpressionBinder || binder instanceof CrossFadedCompositeBinder)
	                binder.destroy();
	        }
	    }
	}
	class ProgramConfigurationSet {
	    constructor(layers, zoom, filterProperties = () => true) {
	        this.programConfigurations = {};
	        for (const layer of layers) {
	            this.programConfigurations[layer.id] = new ProgramConfiguration(layer, zoom, filterProperties);
	        }
	        this.needsUpload = false;
	        this._featureMap = new FeaturePositionMap();
	        this._bufferOffset = 0;
	    }
	    populatePaintArrays(length, feature, index, imagePositions, availableImages, canonical, formattedSection) {
	        for (const key in this.programConfigurations) {
	            this.programConfigurations[key].populatePaintArrays(length, feature, imagePositions, availableImages, canonical, formattedSection);
	        }
	        if (feature.id !== undefined) {
	            this._featureMap.add(feature.id, index, this._bufferOffset, length);
	        }
	        this._bufferOffset = length;
	        this.needsUpload = true;
	    }
	    updatePaintArrays(featureStates, vtLayer, layers, availableImages, imagePositions) {
	        for (const layer of layers) {
	            this.needsUpload = this.programConfigurations[layer.id].updatePaintArrays(featureStates, this._featureMap, vtLayer, layer, availableImages, imagePositions) || this.needsUpload;
	        }
	    }
	    get(layerId) {
	        return this.programConfigurations[layerId];
	    }
	    upload(context) {
	        if (!this.needsUpload)
	            return;
	        for (const layerId in this.programConfigurations) {
	            this.programConfigurations[layerId].upload(context);
	        }
	        this.needsUpload = false;
	    }
	    destroy() {
	        for (const layerId in this.programConfigurations) {
	            this.programConfigurations[layerId].destroy();
	        }
	    }
	}
	const attributeNameExceptions = {
	    'text-opacity': ['opacity'],
	    'icon-opacity': ['opacity'],
	    'text-color': ['fill_color'],
	    'icon-color': ['fill_color'],
	    'text-halo-color': ['halo_color'],
	    'icon-halo-color': ['halo_color'],
	    'text-halo-blur': ['halo_blur'],
	    'icon-halo-blur': ['halo_blur'],
	    'text-halo-width': ['halo_width'],
	    'icon-halo-width': ['halo_width'],
	    'line-gap-width': ['gapwidth'],
	    'line-pattern': [
	        'pattern_to',
	        'pattern_from',
	        'pixel_ratio_to',
	        'pixel_ratio_from'
	    ],
	    'fill-pattern': [
	        'pattern_to',
	        'pattern_from',
	        'pixel_ratio_to',
	        'pixel_ratio_from'
	    ],
	    'fill-extrusion-pattern': [
	        'pattern_to',
	        'pattern_from',
	        'pixel_ratio_to',
	        'pixel_ratio_from'
	    ],
	    'line-dasharray': [
	        'dash_to',
	        'dash_from'
	    ]
	};
	function paintAttributeNames(property, type) {
	    return attributeNameExceptions[property] || [property.replace(`${ type }-`, '').replace(/-/g, '_')];
	}
	const propertyExceptions = {
	    'line-pattern': {
	        'source': StructArrayLayout10ui20,
	        'composite': StructArrayLayout10ui20
	    },
	    'fill-pattern': {
	        'source': StructArrayLayout10ui20,
	        'composite': StructArrayLayout10ui20
	    },
	    'fill-extrusion-pattern': {
	        'source': StructArrayLayout10ui20,
	        'composite': StructArrayLayout10ui20
	    },
	    'line-dasharray': {
	        'source': StructArrayLayout8ui16,
	        'composite': StructArrayLayout8ui16
	    }
	};
	const defaultLayouts = {
	    'color': {
	        'source': StructArrayLayout2f8,
	        'composite': StructArrayLayout4f16
	    },
	    'number': {
	        'source': StructArrayLayout1f4,
	        'composite': StructArrayLayout2f8
	    }
	};
	function layoutType(property, type, binderType) {
	    const layoutException = propertyExceptions[property];
	    return layoutException && layoutException[binderType] || defaultLayouts[type][binderType];
	}
	register(ConstantBinder, 'ConstantBinder');
	register(CrossFadedConstantBinder, 'CrossFadedConstantBinder');
	register(SourceExpressionBinder, 'SourceExpressionBinder');
	register(CrossFadedCompositeBinder, 'CrossFadedCompositeBinder');
	register(CompositeExpressionBinder, 'CompositeExpressionBinder');
	register(ProgramConfiguration, 'ProgramConfiguration', { omit: ['_buffers'] });
	register(ProgramConfigurationSet, 'ProgramConfigurationSet');

	const TRANSITION_SUFFIX = '-transition';
	class StyleLayer extends Evented {
	    constructor(layer, properties) {
	        super();
	        this.id = layer.id;
	        this.type = layer.type;
	        this._featureFilter = {
	            filter: () => true,
	            needGeometry: false,
	            needFeature: false
	        };
	        this._filterCompiled = false;
	        if (layer.type === 'custom')
	            return;
	        layer = layer;
	        this.metadata = layer.metadata;
	        this.minzoom = layer.minzoom;
	        this.maxzoom = layer.maxzoom;
	        if (layer.type !== 'background' && layer.type !== 'sky') {
	            this.source = layer.source;
	            this.sourceLayer = layer['source-layer'];
	            this.filter = layer.filter;
	        }
	        if (properties.layout) {
	            this._unevaluatedLayout = new Layout(properties.layout);
	        }
	        if (properties.paint) {
	            this._transitionablePaint = new Transitionable(properties.paint);
	            for (const property in layer.paint) {
	                this.setPaintProperty(property, layer.paint[property], { validate: false });
	            }
	            for (const property in layer.layout) {
	                this.setLayoutProperty(property, layer.layout[property], { validate: false });
	            }
	            this._transitioningPaint = this._transitionablePaint.untransitioned();
	            this.paint = new PossiblyEvaluated(properties.paint);
	        }
	    }
	    getCrossfadeParameters() {
	        return this._crossfadeParameters;
	    }
	    getLayoutProperty(name) {
	        if (name === 'visibility') {
	            return this.visibility;
	        }
	        return this._unevaluatedLayout.getValue(name);
	    }
	    setLayoutProperty(name, value, options = {}) {
	        if (value !== null && value !== undefined) {
	            const key = `layers.${ this.id }.layout.${ name }`;
	            if (this._validate(validateLayoutProperty, key, name, value, options)) {
	                return;
	            }
	        }
	        if (name === 'visibility') {
	            this.visibility = value;
	            return;
	        }
	        this._unevaluatedLayout.setValue(name, value);
	    }
	    getPaintProperty(name) {
	        if (endsWith(name, TRANSITION_SUFFIX)) {
	            return this._transitionablePaint.getTransition(name.slice(0, -TRANSITION_SUFFIX.length));
	        } else {
	            return this._transitionablePaint.getValue(name);
	        }
	    }
	    setPaintProperty(name, value, options = {}) {
	        if (value !== null && value !== undefined) {
	            const key = `layers.${ this.id }.paint.${ name }`;
	            if (this._validate(validatePaintProperty, key, name, value, options)) {
	                return false;
	            }
	        }
	        if (endsWith(name, TRANSITION_SUFFIX)) {
	            this._transitionablePaint.setTransition(name.slice(0, -TRANSITION_SUFFIX.length), value || undefined);
	            return false;
	        } else {
	            const transitionable = this._transitionablePaint._values[name];
	            const isCrossFadedProperty = transitionable.property.specification['property-type'] === 'cross-faded-data-driven';
	            const wasDataDriven = transitionable.value.isDataDriven();
	            const oldValue = transitionable.value;
	            this._transitionablePaint.setValue(name, value);
	            this._handleSpecialPaintPropertyUpdate(name);
	            const newValue = this._transitionablePaint._values[name].value;
	            const isDataDriven = newValue.isDataDriven();
	            return isDataDriven || wasDataDriven || isCrossFadedProperty || this._handleOverridablePaintPropertyUpdate(name, oldValue, newValue);
	        }
	    }
	    _handleSpecialPaintPropertyUpdate(_) {
	    }
	    getProgramIds() {
	        return null;
	    }
	    getProgramConfiguration(_) {
	        return null;
	    }
	    _handleOverridablePaintPropertyUpdate(name, oldValue, newValue) {
	        return false;
	    }
	    isHidden(zoom) {
	        if (this.minzoom && zoom < this.minzoom)
	            return true;
	        if (this.maxzoom && zoom >= this.maxzoom)
	            return true;
	        return this.visibility === 'none';
	    }
	    updateTransitions(parameters) {
	        this._transitioningPaint = this._transitionablePaint.transitioned(parameters, this._transitioningPaint);
	    }
	    hasTransition() {
	        return this._transitioningPaint.hasTransition();
	    }
	    recalculate(parameters, availableImages) {
	        if (parameters.getCrossfadeParameters) {
	            this._crossfadeParameters = parameters.getCrossfadeParameters();
	        }
	        if (this._unevaluatedLayout) {
	            this.layout = this._unevaluatedLayout.possiblyEvaluate(parameters, undefined, availableImages);
	        }
	        this.paint = this._transitioningPaint.possiblyEvaluate(parameters, undefined, availableImages);
	    }
	    serialize() {
	        const output = {
	            'id': this.id,
	            'type': this.type,
	            'source': this.source,
	            'source-layer': this.sourceLayer,
	            'metadata': this.metadata,
	            'minzoom': this.minzoom,
	            'maxzoom': this.maxzoom,
	            'filter': this.filter,
	            'layout': this._unevaluatedLayout && this._unevaluatedLayout.serialize(),
	            'paint': this._transitionablePaint && this._transitionablePaint.serialize()
	        };
	        if (this.visibility) {
	            output.layout = output.layout || {};
	            output.layout.visibility = this.visibility;
	        }
	        return filterObject(output, (value, key) => {
	            return value !== undefined && !(key === 'layout' && !Object.keys(value).length) && !(key === 'paint' && !Object.keys(value).length);
	        });
	    }
	    _validate(validate, key, name, value, options = {}) {
	        if (options && options.validate === false) {
	            return false;
	        }
	        return emitValidationErrors(this, validate.call(validateStyle, {
	            key,
	            layerType: this.type,
	            objectKey: name,
	            value,
	            styleSpec: spec,
	            style: {
	                glyphs: true,
	                sprite: true
	            }
	        }));
	    }
	    is3D() {
	        return false;
	    }
	    isSky() {
	        return false;
	    }
	    isTileClipped() {
	        return false;
	    }
	    hasOffscreenPass() {
	        return false;
	    }
	    resize() {
	    }
	    isStateDependent() {
	        for (const property in this.paint._values) {
	            const value = this.paint.get(property);
	            if (!(value instanceof PossiblyEvaluatedPropertyValue) || !supportsPropertyExpression(value.property.specification)) {
	                continue;
	            }
	            if ((value.value.kind === 'source' || value.value.kind === 'composite') && value.value.isStateDependent) {
	                return true;
	            }
	        }
	        return false;
	    }
	    compileFilter() {
	        if (!this._filterCompiled) {
	            this._featureFilter = createFilter(this.filter);
	            this._filterCompiled = true;
	        }
	    }
	    invalidateCompiledFilter() {
	        this._filterCompiled = false;
	    }
	    dynamicFilter() {
	        return this._featureFilter.dynamicFilter;
	    }
	    dynamicFilterNeedsFeature() {
	        return this._featureFilter.needFeature;
	    }
	}

	const circleAttributes = createLayout([{
	        name: 'a_pos',
	        components: 2,
	        type: 'Int16'
	    }], 4);
	const circleGlobeAttributesExt = createLayout([
	    {
	        name: 'a_pos_3',
	        components: 3,
	        type: 'Int16'
	    },
	    {
	        name: 'a_pos_normal_3',
	        components: 3,
	        type: 'Int16'
	    }
	]);

	class SegmentVector {
	    constructor(segments = []) {
	        this.segments = segments;
	    }
	    prepareSegment(numVertices, layoutVertexArray, indexArray, sortKey) {
	        let segment = this.segments[this.segments.length - 1];
	        if (numVertices > SegmentVector.MAX_VERTEX_ARRAY_LENGTH)
	            warnOnce(`Max vertices per segment is ${ SegmentVector.MAX_VERTEX_ARRAY_LENGTH }: bucket requested ${ numVertices }`);
	        if (!segment || segment.vertexLength + numVertices > SegmentVector.MAX_VERTEX_ARRAY_LENGTH || segment.sortKey !== sortKey) {
	            segment = {
	                vertexOffset: layoutVertexArray.length,
	                primitiveOffset: indexArray.length,
	                vertexLength: 0,
	                primitiveLength: 0
	            };
	            if (sortKey !== undefined)
	                segment.sortKey = sortKey;
	            this.segments.push(segment);
	        }
	        return segment;
	    }
	    get() {
	        return this.segments;
	    }
	    destroy() {
	        for (const segment of this.segments) {
	            for (const k in segment.vaos) {
	                segment.vaos[k].destroy();
	            }
	        }
	    }
	    static simpleSegment(vertexOffset, primitiveOffset, vertexLength, primitiveLength) {
	        return new SegmentVector([{
	                vertexOffset,
	                primitiveOffset,
	                vertexLength,
	                primitiveLength,
	                vaos: {},
	                sortKey: 0
	            }]);
	    }
	}
	SegmentVector.MAX_VERTEX_ARRAY_LENGTH = Math.pow(2, 16) - 1;
	register(SegmentVector, 'SegmentVector');

	var EXTENT = 8192;

	class LngLatBounds {
	    constructor(sw, ne) {
	        if (!sw) ; else if (ne) {
	            this.setSouthWest(sw).setNorthEast(ne);
	        } else if (sw.length === 4) {
	            this.setSouthWest([
	                sw[0],
	                sw[1]
	            ]).setNorthEast([
	                sw[2],
	                sw[3]
	            ]);
	        } else {
	            this.setSouthWest(sw[0]).setNorthEast(sw[1]);
	        }
	    }
	    setNorthEast(ne) {
	        this._ne = ne instanceof LngLat ? new LngLat(ne.lng, ne.lat) : LngLat.convert(ne);
	        return this;
	    }
	    setSouthWest(sw) {
	        this._sw = sw instanceof LngLat ? new LngLat(sw.lng, sw.lat) : LngLat.convert(sw);
	        return this;
	    }
	    extend(obj) {
	        const sw = this._sw, ne = this._ne;
	        let sw2, ne2;
	        if (obj instanceof LngLat) {
	            sw2 = obj;
	            ne2 = obj;
	        } else if (obj instanceof LngLatBounds) {
	            sw2 = obj._sw;
	            ne2 = obj._ne;
	            if (!sw2 || !ne2)
	                return this;
	        } else {
	            if (Array.isArray(obj)) {
	                if (obj.length === 4 || obj.every(Array.isArray)) {
	                    const lngLatBoundsObj = obj;
	                    return this.extend(LngLatBounds.convert(lngLatBoundsObj));
	                } else {
	                    const lngLatObj = obj;
	                    return this.extend(LngLat.convert(lngLatObj));
	                }
	            }
	            return this;
	        }
	        if (!sw && !ne) {
	            this._sw = new LngLat(sw2.lng, sw2.lat);
	            this._ne = new LngLat(ne2.lng, ne2.lat);
	        } else {
	            sw.lng = Math.min(sw2.lng, sw.lng);
	            sw.lat = Math.min(sw2.lat, sw.lat);
	            ne.lng = Math.max(ne2.lng, ne.lng);
	            ne.lat = Math.max(ne2.lat, ne.lat);
	        }
	        return this;
	    }
	    getCenter() {
	        return new LngLat((this._sw.lng + this._ne.lng) / 2, (this._sw.lat + this._ne.lat) / 2);
	    }
	    getSouthWest() {
	        return this._sw;
	    }
	    getNorthEast() {
	        return this._ne;
	    }
	    getNorthWest() {
	        return new LngLat(this.getWest(), this.getNorth());
	    }
	    getSouthEast() {
	        return new LngLat(this.getEast(), this.getSouth());
	    }
	    getWest() {
	        return this._sw.lng;
	    }
	    getSouth() {
	        return this._sw.lat;
	    }
	    getEast() {
	        return this._ne.lng;
	    }
	    getNorth() {
	        return this._ne.lat;
	    }
	    toArray() {
	        return [
	            this._sw.toArray(),
	            this._ne.toArray()
	        ];
	    }
	    toString() {
	        return `LngLatBounds(${ this._sw.toString() }, ${ this._ne.toString() })`;
	    }
	    isEmpty() {
	        return !(this._sw && this._ne);
	    }
	    contains(lnglat) {
	        const {lng, lat} = LngLat.convert(lnglat);
	        const containsLatitude = this._sw.lat <= lat && lat <= this._ne.lat;
	        let containsLongitude = this._sw.lng <= lng && lng <= this._ne.lng;
	        if (this._sw.lng > this._ne.lng) {
	            containsLongitude = this._sw.lng >= lng && lng >= this._ne.lng;
	        }
	        return containsLatitude && containsLongitude;
	    }
	    static convert(input) {
	        if (!input || input instanceof LngLatBounds)
	            return input;
	        return new LngLatBounds(input);
	    }
	}

	const earthRadius = 6371008.8;
	class LngLat {
	    constructor(lng, lat) {
	        if (isNaN(lng) || isNaN(lat)) {
	            throw new Error(`Invalid LngLat object: (${ lng }, ${ lat })`);
	        }
	        this.lng = +lng;
	        this.lat = +lat;
	        if (this.lat > 90 || this.lat < -90) {
	            throw new Error('Invalid LngLat latitude value: must be between -90 and 90');
	        }
	    }
	    wrap() {
	        return new LngLat(wrap(this.lng, -180, 180), this.lat);
	    }
	    toArray() {
	        return [
	            this.lng,
	            this.lat
	        ];
	    }
	    toString() {
	        return `LngLat(${ this.lng }, ${ this.lat })`;
	    }
	    distanceTo(lngLat) {
	        const rad = Math.PI / 180;
	        const lat1 = this.lat * rad;
	        const lat2 = lngLat.lat * rad;
	        const a = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos((lngLat.lng - this.lng) * rad);
	        const maxMeters = earthRadius * Math.acos(Math.min(a, 1));
	        return maxMeters;
	    }
	    toBounds(radius = 0) {
	        const earthCircumferenceInMetersAtEquator = 40075017;
	        const latAccuracy = 360 * radius / earthCircumferenceInMetersAtEquator, lngAccuracy = latAccuracy / Math.cos(Math.PI / 180 * this.lat);
	        return new LngLatBounds(new LngLat(this.lng - lngAccuracy, this.lat - latAccuracy), new LngLat(this.lng + lngAccuracy, this.lat + latAccuracy));
	    }
	    static convert(input) {
	        if (input instanceof LngLat) {
	            return input;
	        }
	        if (Array.isArray(input) && (input.length === 2 || input.length === 3)) {
	            return new LngLat(Number(input[0]), Number(input[1]));
	        }
	        if (!Array.isArray(input) && typeof input === 'object' && input !== null) {
	            return new LngLat(Number('lng' in input ? input.lng : input.lon), Number(input.lat));
	        }
	        throw new Error('`LngLatLike` argument must be specified as a LngLat instance, an object {lng: <lng>, lat: <lat>}, an object {lon: <lng>, lat: <lat>}, or an array of [<lng>, <lat>]');
	    }
	}

	const earthCircumference = 2 * Math.PI * earthRadius;
	function circumferenceAtLatitude(latitude) {
	    return earthCircumference * Math.cos(latitude * Math.PI / 180);
	}
	function mercatorXfromLng(lng) {
	    return (180 + lng) / 360;
	}
	function mercatorYfromLat(lat) {
	    return (180 - 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + lat * Math.PI / 360))) / 360;
	}
	function mercatorZfromAltitude(altitude, lat) {
	    return altitude / circumferenceAtLatitude(lat);
	}
	function lngFromMercatorX(x) {
	    return x * 360 - 180;
	}
	function latFromMercatorY(y) {
	    const y2 = 180 - y * 360;
	    return 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90;
	}
	function altitudeFromMercatorZ(z, y) {
	    return z * circumferenceAtLatitude(latFromMercatorY(y));
	}
	const MAX_MERCATOR_LATITUDE = 85.051129;
	function mercatorScale(lat) {
	    return 1 / Math.cos(lat * Math.PI / 180);
	}
	class MercatorCoordinate {
	    constructor(x, y, z = 0) {
	        this.x = +x;
	        this.y = +y;
	        this.z = +z;
	    }
	    static fromLngLat(lngLatLike, altitude = 0) {
	        const lngLat = LngLat.convert(lngLatLike);
	        return new MercatorCoordinate(mercatorXfromLng(lngLat.lng), mercatorYfromLat(lngLat.lat), mercatorZfromAltitude(altitude, lngLat.lat));
	    }
	    toLngLat() {
	        return new LngLat(lngFromMercatorX(this.x), latFromMercatorY(this.y));
	    }
	    toAltitude() {
	        return altitudeFromMercatorZ(this.z, this.y);
	    }
	    meterInMercatorCoordinateUnits() {
	        return 1 / earthCircumference * mercatorScale(latFromMercatorY(this.y));
	    }
	}

	function pointToLineDist(px, py, ax, ay, bx, by) {
	    const dx = ax - bx;
	    const dy = ay - by;
	    return Math.abs((ay - py) * dx - (ax - px) * dy) / Math.hypot(dx, dy);
	}
	function addResampled(resampled, mx0, my0, mx2, my2, start, end, reproject, tolerance) {
	    const mx1 = (mx0 + mx2) / 2;
	    const my1 = (my0 + my2) / 2;
	    const mid = new pointGeometry(mx1, my1);
	    reproject(mid);
	    const err = pointToLineDist(mid.x, mid.y, start.x, start.y, end.x, end.y);
	    if (err >= tolerance) {
	        addResampled(resampled, mx0, my0, mx1, my1, start, mid, reproject, tolerance);
	        addResampled(resampled, mx1, my1, mx2, my2, mid, end, reproject, tolerance);
	    } else {
	        resampled.push(end);
	    }
	}
	function resample$1(line, reproject, tolerance) {
	    let prev = line[0];
	    let mx0 = prev.x;
	    let my0 = prev.y;
	    reproject(prev);
	    const resampled = [prev];
	    for (let i = 1; i < line.length; i++) {
	        const point = line[i];
	        const {x, y} = point;
	        reproject(point);
	        addResampled(resampled, mx0, my0, x, y, prev, point, reproject, tolerance);
	        mx0 = x;
	        my0 = y;
	        prev = point;
	    }
	    return resampled;
	}
	function addResampledPred(resampled, a, b, reproject, pred) {
	    const split = pred(a, b);
	    if (split) {
	        const mid = a.add(b).mult(0.5);
	        reproject(mid);
	        addResampledPred(resampled, a, mid, reproject, pred);
	        addResampledPred(resampled, mid, b, reproject, pred);
	    } else {
	        resampled.push(b);
	    }
	}
	function resamplePred(line, reproject, predicate) {
	    let prev = line[0];
	    reproject(prev);
	    const resampled = [prev];
	    for (let i = 1; i < line.length; i++) {
	        const point = line[i];
	        reproject(point);
	        addResampledPred(resampled, prev, point, reproject, predicate);
	        prev = point;
	    }
	    return resampled;
	}

	const BITS = 15;
	const MAX = Math.pow(2, BITS - 1) - 1;
	const MIN = -MAX - 1;
	function preparePoint(point, scale) {
	    const x = Math.round(point.x * scale);
	    const y = Math.round(point.y * scale);
	    point.x = clamp(x, MIN, MAX);
	    point.y = clamp(y, MIN, MAX);
	    if (x < point.x || x > point.x + 1 || y < point.y || y > point.y + 1) {
	        warnOnce('Geometry exceeds allowed extent, reduce your vector tile buffer size');
	    }
	    return point;
	}
	function loadGeometry(feature, canonical, tileTransform) {
	    const geometry = feature.loadGeometry();
	    const extent = feature.extent;
	    const extentScale = EXTENT / extent;
	    if (canonical && tileTransform && tileTransform.projection.isReprojectedInTileSpace) {
	        const z2 = 1 << canonical.z;
	        const {scale, x, y, projection} = tileTransform;
	        const reproject = p => {
	            const lng = lngFromMercatorX((canonical.x + p.x / extent) / z2);
	            const lat = latFromMercatorY((canonical.y + p.y / extent) / z2);
	            const p2 = projection.project(lng, lat);
	            p.x = (p2.x * scale - x) * extent;
	            p.y = (p2.y * scale - y) * extent;
	        };
	        for (let i = 0; i < geometry.length; i++) {
	            if (feature.type !== 1) {
	                geometry[i] = resample$1(geometry[i], reproject, 1);
	            } else {
	                const line = [];
	                for (const p of geometry[i]) {
	                    if (p.x < 0 || p.x >= extent || p.y < 0 || p.y >= extent)
	                        continue;
	                    reproject(p);
	                    line.push(p);
	                }
	                geometry[i] = line;
	            }
	        }
	    }
	    for (const line of geometry) {
	        for (const p of line) {
	            preparePoint(p, extentScale);
	        }
	    }
	    return geometry;
	}

	function toEvaluationFeature(feature, needGeometry) {
	    return {
	        type: feature.type,
	        id: feature.id,
	        properties: feature.properties,
	        geometry: needGeometry ? loadGeometry(feature) : []
	    };
	}

	function addCircleVertex(layoutVertexArray, x, y, extrudeX, extrudeY) {
	    layoutVertexArray.emplaceBack(x * 2 + (extrudeX + 1) / 2, y * 2 + (extrudeY + 1) / 2);
	}
	function addGlobeExtVertex$1(vertexArray, pos, normal) {
	    const encode = 1 << 14;
	    vertexArray.emplaceBack(pos.x, pos.y, pos.z, normal[0] * encode, normal[1] * encode, normal[2] * encode);
	}
	class CircleBucket {
	    constructor(options) {
	        this.zoom = options.zoom;
	        this.overscaling = options.overscaling;
	        this.layers = options.layers;
	        this.layerIds = this.layers.map(layer => layer.id);
	        this.index = options.index;
	        this.hasPattern = false;
	        this.projection = options.projection;
	        this.layoutVertexArray = new StructArrayLayout2i4();
	        this.indexArray = new StructArrayLayout3ui6();
	        this.segments = new SegmentVector();
	        this.programConfigurations = new ProgramConfigurationSet(options.layers, options.zoom);
	        this.stateDependentLayerIds = this.layers.filter(l => l.isStateDependent()).map(l => l.id);
	    }
	    populate(features, options, canonical, tileTransform) {
	        const styleLayer = this.layers[0];
	        const bucketFeatures = [];
	        let circleSortKey = null;
	        if (styleLayer.type === 'circle') {
	            circleSortKey = styleLayer.layout.get('circle-sort-key');
	        }
	        for (const {feature, id, index, sourceLayerIndex} of features) {
	            const needGeometry = this.layers[0]._featureFilter.needGeometry;
	            const evaluationFeature = toEvaluationFeature(feature, needGeometry);
	            if (!this.layers[0]._featureFilter.filter(new EvaluationParameters(this.zoom), evaluationFeature, canonical))
	                continue;
	            const sortKey = circleSortKey ? circleSortKey.evaluate(evaluationFeature, {}, canonical) : undefined;
	            const bucketFeature = {
	                id,
	                properties: feature.properties,
	                type: feature.type,
	                sourceLayerIndex,
	                index,
	                geometry: needGeometry ? evaluationFeature.geometry : loadGeometry(feature, canonical, tileTransform),
	                patterns: {},
	                sortKey
	            };
	            bucketFeatures.push(bucketFeature);
	        }
	        if (circleSortKey) {
	            bucketFeatures.sort((a, b) => {
	                return a.sortKey - b.sortKey;
	            });
	        }
	        let globeProjection = null;
	        if (tileTransform.projection.name === 'globe') {
	            this.globeExtVertexArray = new CircleGlobeExtArray();
	            globeProjection = tileTransform.projection;
	        }
	        for (const bucketFeature of bucketFeatures) {
	            const {geometry, index, sourceLayerIndex} = bucketFeature;
	            const feature = features[index].feature;
	            this.addFeature(bucketFeature, geometry, index, options.availableImages, canonical, globeProjection);
	            options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
	        }
	    }
	    update(states, vtLayer, availableImages, imagePositions) {
	        if (!this.stateDependentLayers.length)
	            return;
	        this.programConfigurations.updatePaintArrays(states, vtLayer, this.stateDependentLayers, availableImages, imagePositions);
	    }
	    isEmpty() {
	        return this.layoutVertexArray.length === 0;
	    }
	    uploadPending() {
	        return !this.uploaded || this.programConfigurations.needsUpload;
	    }
	    upload(context) {
	        if (!this.uploaded) {
	            this.layoutVertexBuffer = context.createVertexBuffer(this.layoutVertexArray, circleAttributes.members);
	            this.indexBuffer = context.createIndexBuffer(this.indexArray);
	            if (this.globeExtVertexArray) {
	                this.globeExtVertexBuffer = context.createVertexBuffer(this.globeExtVertexArray, circleGlobeAttributesExt.members);
	            }
	        }
	        this.programConfigurations.upload(context);
	        this.uploaded = true;
	    }
	    destroy() {
	        if (!this.layoutVertexBuffer)
	            return;
	        this.layoutVertexBuffer.destroy();
	        this.indexBuffer.destroy();
	        this.programConfigurations.destroy();
	        this.segments.destroy();
	        if (this.globeExtVertexBuffer) {
	            this.globeExtVertexBuffer.destroy();
	        }
	    }
	    addFeature(feature, geometry, index, availableImages, canonical, projection) {
	        for (const ring of geometry) {
	            for (const point of ring) {
	                const x = point.x;
	                const y = point.y;
	                if (x < 0 || x >= EXTENT || y < 0 || y >= EXTENT)
	                    continue;
	                if (projection) {
	                    const projectedPoint = projection.projectTilePoint(x, y, canonical);
	                    const normal = projection.upVector(canonical, x, y);
	                    const array = this.globeExtVertexArray;
	                    addGlobeExtVertex$1(array, projectedPoint, normal);
	                    addGlobeExtVertex$1(array, projectedPoint, normal);
	                    addGlobeExtVertex$1(array, projectedPoint, normal);
	                    addGlobeExtVertex$1(array, projectedPoint, normal);
	                }
	                const segment = this.segments.prepareSegment(4, this.layoutVertexArray, this.indexArray, feature.sortKey);
	                const index = segment.vertexLength;
	                addCircleVertex(this.layoutVertexArray, x, y, -1, -1);
	                addCircleVertex(this.layoutVertexArray, x, y, 1, -1);
	                addCircleVertex(this.layoutVertexArray, x, y, 1, 1);
	                addCircleVertex(this.layoutVertexArray, x, y, -1, 1);
	                this.indexArray.emplaceBack(index, index + 1, index + 2);
	                this.indexArray.emplaceBack(index, index + 2, index + 3);
	                segment.vertexLength += 4;
	                segment.primitiveLength += 2;
	            }
	        }
	        this.programConfigurations.populatePaintArrays(this.layoutVertexArray.length, feature, index, {}, availableImages, canonical);
	    }
	}
	register(CircleBucket, 'CircleBucket', { omit: ['layers'] });

	function polygonIntersectsPolygon(polygonA, polygonB) {
	    for (let i = 0; i < polygonA.length; i++) {
	        if (polygonContainsPoint(polygonB, polygonA[i]))
	            return true;
	    }
	    for (let i = 0; i < polygonB.length; i++) {
	        if (polygonContainsPoint(polygonA, polygonB[i]))
	            return true;
	    }
	    if (lineIntersectsLine(polygonA, polygonB))
	        return true;
	    return false;
	}
	function polygonIntersectsBufferedPoint(polygon, point, radius) {
	    if (polygonContainsPoint(polygon, point))
	        return true;
	    if (pointIntersectsBufferedLine(point, polygon, radius))
	        return true;
	    return false;
	}
	function polygonIntersectsMultiPolygon(polygon, multiPolygon) {
	    if (polygon.length === 1) {
	        return multiPolygonContainsPoint(multiPolygon, polygon[0]);
	    }
	    for (let m = 0; m < multiPolygon.length; m++) {
	        const ring = multiPolygon[m];
	        for (let n = 0; n < ring.length; n++) {
	            if (polygonContainsPoint(polygon, ring[n]))
	                return true;
	        }
	    }
	    for (let i = 0; i < polygon.length; i++) {
	        if (multiPolygonContainsPoint(multiPolygon, polygon[i]))
	            return true;
	    }
	    for (let k = 0; k < multiPolygon.length; k++) {
	        if (lineIntersectsLine(polygon, multiPolygon[k]))
	            return true;
	    }
	    return false;
	}
	function polygonIntersectsBufferedMultiLine(polygon, multiLine, radius) {
	    for (let i = 0; i < multiLine.length; i++) {
	        const line = multiLine[i];
	        if (polygon.length >= 3) {
	            for (let k = 0; k < line.length; k++) {
	                if (polygonContainsPoint(polygon, line[k]))
	                    return true;
	            }
	        }
	        if (lineIntersectsBufferedLine(polygon, line, radius))
	            return true;
	    }
	    return false;
	}
	function lineIntersectsBufferedLine(lineA, lineB, radius) {
	    if (lineA.length > 1) {
	        if (lineIntersectsLine(lineA, lineB))
	            return true;
	        for (let j = 0; j < lineB.length; j++) {
	            if (pointIntersectsBufferedLine(lineB[j], lineA, radius))
	                return true;
	        }
	    }
	    for (let k = 0; k < lineA.length; k++) {
	        if (pointIntersectsBufferedLine(lineA[k], lineB, radius))
	            return true;
	    }
	    return false;
	}
	function lineIntersectsLine(lineA, lineB) {
	    if (lineA.length === 0 || lineB.length === 0)
	        return false;
	    for (let i = 0; i < lineA.length - 1; i++) {
	        const a0 = lineA[i];
	        const a1 = lineA[i + 1];
	        for (let j = 0; j < lineB.length - 1; j++) {
	            const b0 = lineB[j];
	            const b1 = lineB[j + 1];
	            if (lineSegmentIntersectsLineSegment(a0, a1, b0, b1))
	                return true;
	        }
	    }
	    return false;
	}
	function lineSegmentIntersectsLineSegment(a0, a1, b0, b1) {
	    return isCounterClockwise(a0, b0, b1) !== isCounterClockwise(a1, b0, b1) && isCounterClockwise(a0, a1, b0) !== isCounterClockwise(a0, a1, b1);
	}
	function pointIntersectsBufferedLine(p, line, radius) {
	    const radiusSquared = radius * radius;
	    if (line.length === 1)
	        return p.distSqr(line[0]) < radiusSquared;
	    for (let i = 1; i < line.length; i++) {
	        const v = line[i - 1], w = line[i];
	        if (distToSegmentSquared(p, v, w) < radiusSquared)
	            return true;
	    }
	    return false;
	}
	function distToSegmentSquared(p, v, w) {
	    const l2 = v.distSqr(w);
	    if (l2 === 0)
	        return p.distSqr(v);
	    const t = ((p.x - v.x) * (w.x - v.x) + (p.y - v.y) * (w.y - v.y)) / l2;
	    if (t < 0)
	        return p.distSqr(v);
	    if (t > 1)
	        return p.distSqr(w);
	    return p.distSqr(w.sub(v)._mult(t)._add(v));
	}
	function multiPolygonContainsPoint(rings, p) {
	    let c = false, ring, p1, p2;
	    for (let k = 0; k < rings.length; k++) {
	        ring = rings[k];
	        for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
	            p1 = ring[i];
	            p2 = ring[j];
	            if (p1.y > p.y !== p2.y > p.y && p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x) {
	                c = !c;
	            }
	        }
	    }
	    return c;
	}
	function polygonContainsPoint(ring, p) {
	    let c = false;
	    for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
	        const p1 = ring[i];
	        const p2 = ring[j];
	        if (p1.y > p.y !== p2.y > p.y && p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x) {
	            c = !c;
	        }
	    }
	    return c;
	}
	function polygonIntersectsBox(ring, boxX1, boxY1, boxX2, boxY2) {
	    for (const p of ring) {
	        if (boxX1 <= p.x && boxY1 <= p.y && boxX2 >= p.x && boxY2 >= p.y)
	            return true;
	    }
	    const corners = [
	        new pointGeometry(boxX1, boxY1),
	        new pointGeometry(boxX1, boxY2),
	        new pointGeometry(boxX2, boxY2),
	        new pointGeometry(boxX2, boxY1)
	    ];
	    if (ring.length > 2) {
	        for (const corner of corners) {
	            if (polygonContainsPoint(ring, corner))
	                return true;
	        }
	    }
	    for (let i = 0; i < ring.length - 1; i++) {
	        const p1 = ring[i];
	        const p2 = ring[i + 1];
	        if (edgeIntersectsBox(p1, p2, corners))
	            return true;
	    }
	    return false;
	}
	function edgeIntersectsBox(e1, e2, corners) {
	    const tl = corners[0];
	    const br = corners[2];
	    if (e1.x < tl.x && e2.x < tl.x || e1.x > br.x && e2.x > br.x || e1.y < tl.y && e2.y < tl.y || e1.y > br.y && e2.y > br.y)
	        return false;
	    const dir = isCounterClockwise(e1, e2, corners[0]);
	    return dir !== isCounterClockwise(e1, e2, corners[1]) || dir !== isCounterClockwise(e1, e2, corners[2]) || dir !== isCounterClockwise(e1, e2, corners[3]);
	}

	function getMaximumPaintValue(property, layer, bucket) {
	    const value = layer.paint.get(property).value;
	    if (value.kind === 'constant') {
	        return value.value;
	    } else {
	        return bucket.programConfigurations.get(layer.id).getMaxValue(property);
	    }
	}
	function translateDistance(translate) {
	    return Math.sqrt(translate[0] * translate[0] + translate[1] * translate[1]);
	}
	function translate$1(queryGeometry, translate, translateAnchor, bearing, pixelsToTileUnits) {
	    if (!translate[0] && !translate[1]) {
	        return queryGeometry;
	    }
	    const pt = pointGeometry.convert(translate)._mult(pixelsToTileUnits);
	    if (translateAnchor === 'viewport') {
	        pt._rotate(-bearing);
	    }
	    const translated = [];
	    for (let i = 0; i < queryGeometry.length; i++) {
	        const point = queryGeometry[i];
	        translated.push(point.sub(pt));
	    }
	    return translated;
	}
	function tilespaceTranslate(translate, translateAnchor, bearing, pixelsToTileUnits) {
	    const pt = pointGeometry.convert(translate)._mult(pixelsToTileUnits);
	    if (translateAnchor === 'viewport') {
	        pt._rotate(-bearing);
	    }
	    return pt;
	}

	const layout$5 = new Properties({ 'circle-sort-key': new DataDrivenProperty(spec['layout_circle']['circle-sort-key']) });
	const paint$9 = new Properties({
	    'circle-radius': new DataDrivenProperty(spec['paint_circle']['circle-radius']),
	    'circle-color': new DataDrivenProperty(spec['paint_circle']['circle-color']),
	    'circle-blur': new DataDrivenProperty(spec['paint_circle']['circle-blur']),
	    'circle-opacity': new DataDrivenProperty(spec['paint_circle']['circle-opacity']),
	    'circle-translate': new DataConstantProperty(spec['paint_circle']['circle-translate']),
	    'circle-translate-anchor': new DataConstantProperty(spec['paint_circle']['circle-translate-anchor']),
	    'circle-pitch-scale': new DataConstantProperty(spec['paint_circle']['circle-pitch-scale']),
	    'circle-pitch-alignment': new DataConstantProperty(spec['paint_circle']['circle-pitch-alignment']),
	    'circle-stroke-width': new DataDrivenProperty(spec['paint_circle']['circle-stroke-width']),
	    'circle-stroke-color': new DataDrivenProperty(spec['paint_circle']['circle-stroke-color']),
	    'circle-stroke-opacity': new DataDrivenProperty(spec['paint_circle']['circle-stroke-opacity'])
	});
	var properties$9 = {
	    paint: paint$9,
	    layout: layout$5
	};

	var EPSILON = 0.000001;
	var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
	if (!Math.hypot)
	    Math.hypot = function () {
	        var y = 0, i = arguments.length;
	        while (i--) {
	            y += arguments[i] * arguments[i];
	        }
	        return Math.sqrt(y);
	    };

	function create$4() {
	    var out = new ARRAY_TYPE(9);
	    if (ARRAY_TYPE != Float32Array) {
	        out[1] = 0;
	        out[2] = 0;
	        out[3] = 0;
	        out[5] = 0;
	        out[6] = 0;
	        out[7] = 0;
	    }
	    out[0] = 1;
	    out[4] = 1;
	    out[8] = 1;
	    return out;
	}
	function fromMat4(out, a) {
	    out[0] = a[0];
	    out[1] = a[1];
	    out[2] = a[2];
	    out[3] = a[4];
	    out[4] = a[5];
	    out[5] = a[6];
	    out[6] = a[8];
	    out[7] = a[9];
	    out[8] = a[10];
	    return out;
	}
	function transpose(out, a) {
	    if (out === a) {
	        var a01 = a[1], a02 = a[2], a12 = a[5];
	        out[1] = a[3];
	        out[2] = a[6];
	        out[3] = a01;
	        out[5] = a[7];
	        out[6] = a02;
	        out[7] = a12;
	    } else {
	        out[0] = a[0];
	        out[1] = a[3];
	        out[2] = a[6];
	        out[3] = a[1];
	        out[4] = a[4];
	        out[5] = a[7];
	        out[6] = a[2];
	        out[7] = a[5];
	        out[8] = a[8];
	    }
	    return out;
	}
	function adjoint(out, a) {
	    var a00 = a[0], a01 = a[1], a02 = a[2];
	    var a10 = a[3], a11 = a[4], a12 = a[5];
	    var a20 = a[6], a21 = a[7], a22 = a[8];
	    out[0] = a11 * a22 - a12 * a21;
	    out[1] = a02 * a21 - a01 * a22;
	    out[2] = a01 * a12 - a02 * a11;
	    out[3] = a12 * a20 - a10 * a22;
	    out[4] = a00 * a22 - a02 * a20;
	    out[5] = a02 * a10 - a00 * a12;
	    out[6] = a10 * a21 - a11 * a20;
	    out[7] = a01 * a20 - a00 * a21;
	    out[8] = a00 * a11 - a01 * a10;
	    return out;
	}
	function multiply$3(out, a, b) {
	    var a00 = a[0], a01 = a[1], a02 = a[2];
	    var a10 = a[3], a11 = a[4], a12 = a[5];
	    var a20 = a[6], a21 = a[7], a22 = a[8];
	    var b00 = b[0], b01 = b[1], b02 = b[2];
	    var b10 = b[3], b11 = b[4], b12 = b[5];
	    var b20 = b[6], b21 = b[7], b22 = b[8];
	    out[0] = b00 * a00 + b01 * a10 + b02 * a20;
	    out[1] = b00 * a01 + b01 * a11 + b02 * a21;
	    out[2] = b00 * a02 + b01 * a12 + b02 * a22;
	    out[3] = b10 * a00 + b11 * a10 + b12 * a20;
	    out[4] = b10 * a01 + b11 * a11 + b12 * a21;
	    out[5] = b10 * a02 + b11 * a12 + b12 * a22;
	    out[6] = b20 * a00 + b21 * a10 + b22 * a20;
	    out[7] = b20 * a01 + b21 * a11 + b22 * a21;
	    out[8] = b20 * a02 + b21 * a12 + b22 * a22;
	    return out;
	}
	function fromRotation$1(out, rad) {
	    var s = Math.sin(rad), c = Math.cos(rad);
	    out[0] = c;
	    out[1] = s;
	    out[2] = 0;
	    out[3] = -s;
	    out[4] = c;
	    out[5] = 0;
	    out[6] = 0;
	    out[7] = 0;
	    out[8] = 1;
	    return out;
	}

	function create$3() {
	    var out = new ARRAY_TYPE(16);
	    if (ARRAY_TYPE != Float32Array) {
	        out[1] = 0;
	        out[2] = 0;
	        out[3] = 0;
	        out[4] = 0;
	        out[6] = 0;
	        out[7] = 0;
	        out[8] = 0;
	        out[9] = 0;
	        out[11] = 0;
	        out[12] = 0;
	        out[13] = 0;
	        out[14] = 0;
	    }
	    out[0] = 1;
	    out[5] = 1;
	    out[10] = 1;
	    out[15] = 1;
	    return out;
	}
	function clone$1(a) {
	    var out = new ARRAY_TYPE(16);
	    out[0] = a[0];
	    out[1] = a[1];
	    out[2] = a[2];
	    out[3] = a[3];
	    out[4] = a[4];
	    out[5] = a[5];
	    out[6] = a[6];
	    out[7] = a[7];
	    out[8] = a[8];
	    out[9] = a[9];
	    out[10] = a[10];
	    out[11] = a[11];
	    out[12] = a[12];
	    out[13] = a[13];
	    out[14] = a[14];
	    out[15] = a[15];
	    return out;
	}
	function identity$2(out) {
	    out[0] = 1;
	    out[1] = 0;
	    out[2] = 0;
	    out[3] = 0;
	    out[4] = 0;
	    out[5] = 1;
	    out[6] = 0;
	    out[7] = 0;
	    out[8] = 0;
	    out[9] = 0;
	    out[10] = 1;
	    out[11] = 0;
	    out[12] = 0;
	    out[13] = 0;
	    out[14] = 0;
	    out[15] = 1;
	    return out;
	}
	function invert(out, a) {
	    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
	    var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
	    var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
	    var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
	    var b00 = a00 * a11 - a01 * a10;
	    var b01 = a00 * a12 - a02 * a10;
	    var b02 = a00 * a13 - a03 * a10;
	    var b03 = a01 * a12 - a02 * a11;
	    var b04 = a01 * a13 - a03 * a11;
	    var b05 = a02 * a13 - a03 * a12;
	    var b06 = a20 * a31 - a21 * a30;
	    var b07 = a20 * a32 - a22 * a30;
	    var b08 = a20 * a33 - a23 * a30;
	    var b09 = a21 * a32 - a22 * a31;
	    var b10 = a21 * a33 - a23 * a31;
	    var b11 = a22 * a33 - a23 * a32;
	    var det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
	    if (!det) {
	        return null;
	    }
	    det = 1 / det;
	    out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
	    out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
	    out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
	    out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
	    out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
	    out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
	    out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
	    out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
	    out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
	    out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
	    out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
	    out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
	    out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
	    out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
	    out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
	    out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
	    return out;
	}
	function multiply$2(out, a, b) {
	    var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3];
	    var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7];
	    var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11];
	    var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
	    var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
	    out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
	    out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
	    out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
	    out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
	    b0 = b[4];
	    b1 = b[5];
	    b2 = b[6];
	    b3 = b[7];
	    out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
	    out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
	    out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
	    out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
	    b0 = b[8];
	    b1 = b[9];
	    b2 = b[10];
	    b3 = b[11];
	    out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
	    out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
	    out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
	    out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
	    b0 = b[12];
	    b1 = b[13];
	    b2 = b[14];
	    b3 = b[15];
	    out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30;
	    out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31;
	    out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32;
	    out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33;
	    return out;
	}
	function translate(out, a, v) {
	    var x = v[0], y = v[1], z = v[2];
	    var a00, a01, a02, a03;
	    var a10, a11, a12, a13;
	    var a20, a21, a22, a23;
	    if (a === out) {
	        out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
	        out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
	        out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
	        out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
	    } else {
	        a00 = a[0];
	        a01 = a[1];
	        a02 = a[2];
	        a03 = a[3];
	        a10 = a[4];
	        a11 = a[5];
	        a12 = a[6];
	        a13 = a[7];
	        a20 = a[8];
	        a21 = a[9];
	        a22 = a[10];
	        a23 = a[11];
	        out[0] = a00;
	        out[1] = a01;
	        out[2] = a02;
	        out[3] = a03;
	        out[4] = a10;
	        out[5] = a11;
	        out[6] = a12;
	        out[7] = a13;
	        out[8] = a20;
	        out[9] = a21;
	        out[10] = a22;
	        out[11] = a23;
	        out[12] = a00 * x + a10 * y + a20 * z + a[12];
	        out[13] = a01 * x + a11 * y + a21 * z + a[13];
	        out[14] = a02 * x + a12 * y + a22 * z + a[14];
	        out[15] = a03 * x + a13 * y + a23 * z + a[15];
	    }
	    return out;
	}
	function scale$2(out, a, v) {
	    var x = v[0], y = v[1], z = v[2];
	    out[0] = a[0] * x;
	    out[1] = a[1] * x;
	    out[2] = a[2] * x;
	    out[3] = a[3] * x;
	    out[4] = a[4] * y;
	    out[5] = a[5] * y;
	    out[6] = a[6] * y;
	    out[7] = a[7] * y;
	    out[8] = a[8] * z;
	    out[9] = a[9] * z;
	    out[10] = a[10] * z;
	    out[11] = a[11] * z;
	    out[12] = a[12];
	    out[13] = a[13];
	    out[14] = a[14];
	    out[15] = a[15];
	    return out;
	}
	function rotateX$1(out, a, rad) {
	    var s = Math.sin(rad);
	    var c = Math.cos(rad);
	    var a10 = a[4];
	    var a11 = a[5];
	    var a12 = a[6];
	    var a13 = a[7];
	    var a20 = a[8];
	    var a21 = a[9];
	    var a22 = a[10];
	    var a23 = a[11];
	    if (a !== out) {
	        out[0] = a[0];
	        out[1] = a[1];
	        out[2] = a[2];
	        out[3] = a[3];
	        out[12] = a[12];
	        out[13] = a[13];
	        out[14] = a[14];
	        out[15] = a[15];
	    }
	    out[4] = a10 * c + a20 * s;
	    out[5] = a11 * c + a21 * s;
	    out[6] = a12 * c + a22 * s;
	    out[7] = a13 * c + a23 * s;
	    out[8] = a20 * c - a10 * s;
	    out[9] = a21 * c - a11 * s;
	    out[10] = a22 * c - a12 * s;
	    out[11] = a23 * c - a13 * s;
	    return out;
	}
	function rotateY$1(out, a, rad) {
	    var s = Math.sin(rad);
	    var c = Math.cos(rad);
	    var a00 = a[0];
	    var a01 = a[1];
	    var a02 = a[2];
	    var a03 = a[3];
	    var a20 = a[8];
	    var a21 = a[9];
	    var a22 = a[10];
	    var a23 = a[11];
	    if (a !== out) {
	        out[4] = a[4];
	        out[5] = a[5];
	        out[6] = a[6];
	        out[7] = a[7];
	        out[12] = a[12];
	        out[13] = a[13];
	        out[14] = a[14];
	        out[15] = a[15];
	    }
	    out[0] = a00 * c - a20 * s;
	    out[1] = a01 * c - a21 * s;
	    out[2] = a02 * c - a22 * s;
	    out[3] = a03 * c - a23 * s;
	    out[8] = a00 * s + a20 * c;
	    out[9] = a01 * s + a21 * c;
	    out[10] = a02 * s + a22 * c;
	    out[11] = a03 * s + a23 * c;
	    return out;
	}
	function rotateZ$1(out, a, rad) {
	    var s = Math.sin(rad);
	    var c = Math.cos(rad);
	    var a00 = a[0];
	    var a01 = a[1];
	    var a02 = a[2];
	    var a03 = a[3];
	    var a10 = a[4];
	    var a11 = a[5];
	    var a12 = a[6];
	    var a13 = a[7];
	    if (a !== out) {
	        out[8] = a[8];
	        out[9] = a[9];
	        out[10] = a[10];
	        out[11] = a[11];
	        out[12] = a[12];
	        out[13] = a[13];
	        out[14] = a[14];
	        out[15] = a[15];
	    }
	    out[0] = a00 * c + a10 * s;
	    out[1] = a01 * c + a11 * s;
	    out[2] = a02 * c + a12 * s;
	    out[3] = a03 * c + a13 * s;
	    out[4] = a10 * c - a00 * s;
	    out[5] = a11 * c - a01 * s;
	    out[6] = a12 * c - a02 * s;
	    out[7] = a13 * c - a03 * s;
	    return out;
	}
	function fromScaling(out, v) {
	    out[0] = v[0];
	    out[1] = 0;
	    out[2] = 0;
	    out[3] = 0;
	    out[4] = 0;
	    out[5] = v[1];
	    out[6] = 0;
	    out[7] = 0;
	    out[8] = 0;
	    out[9] = 0;
	    out[10] = v[2];
	    out[11] = 0;
	    out[12] = 0;
	    out[13] = 0;
	    out[14] = 0;
	    out[15] = 1;
	    return out;
	}
	function fromRotation(out, rad, axis) {
	    var x = axis[0], y = axis[1], z = axis[2];
	    var len = Math.hypot(x, y, z);
	    var s, c, t;
	    if (len < EPSILON) {
	        return null;
	    }
	    len = 1 / len;
	    x *= len;
	    y *= len;
	    z *= len;
	    s = Math.sin(rad);
	    c = Math.cos(rad);
	    t = 1 - c;
	    out[0] = x * x * t + c;
	    out[1] = y * x * t + z * s;
	    out[2] = z * x * t - y * s;
	    out[3] = 0;
	    out[4] = x * y * t - z * s;
	    out[5] = y * y * t + c;
	    out[6] = z * y * t + x * s;
	    out[7] = 0;
	    out[8] = x * z * t + y * s;
	    out[9] = y * z * t - x * s;
	    out[10] = z * z * t + c;
	    out[11] = 0;
	    out[12] = 0;
	    out[13] = 0;
	    out[14] = 0;
	    out[15] = 1;
	    return out;
	}
	function fromQuat(out, q) {
	    var x = q[0], y = q[1], z = q[2], w = q[3];
	    var x2 = x + x;
	    var y2 = y + y;
	    var z2 = z + z;
	    var xx = x * x2;
	    var yx = y * x2;
	    var yy = y * y2;
	    var zx = z * x2;
	    var zy = z * y2;
	    var zz = z * z2;
	    var wx = w * x2;
	    var wy = w * y2;
	    var wz = w * z2;
	    out[0] = 1 - yy - zz;
	    out[1] = yx + wz;
	    out[2] = zx - wy;
	    out[3] = 0;
	    out[4] = yx - wz;
	    out[5] = 1 - xx - zz;
	    out[6] = zy + wx;
	    out[7] = 0;
	    out[8] = zx + wy;
	    out[9] = zy - wx;
	    out[10] = 1 - xx - yy;
	    out[11] = 0;
	    out[12] = 0;
	    out[13] = 0;
	    out[14] = 0;
	    out[15] = 1;
	    return out;
	}
	function perspectiveNO(out, fovy, aspect, near, far) {
	    var f = 1 / Math.tan(fovy / 2), nf;
	    out[0] = f / aspect;
	    out[1] = 0;
	    out[2] = 0;
	    out[3] = 0;
	    out[4] = 0;
	    out[5] = f;
	    out[6] = 0;
	    out[7] = 0;
	    out[8] = 0;
	    out[9] = 0;
	    out[11] = -1;
	    out[12] = 0;
	    out[13] = 0;
	    out[15] = 0;
	    if (far != null && far !== Infinity) {
	        nf = 1 / (near - far);
	        out[10] = (far + near) * nf;
	        out[14] = 2 * far * near * nf;
	    } else {
	        out[10] = -1;
	        out[14] = -2 * near;
	    }
	    return out;
	}
	var perspective = perspectiveNO;
	function orthoNO(out, left, right, bottom, top, near, far) {
	    var lr = 1 / (left - right);
	    var bt = 1 / (bottom - top);
	    var nf = 1 / (near - far);
	    out[0] = -2 * lr;
	    out[1] = 0;
	    out[2] = 0;
	    out[3] = 0;
	    out[4] = 0;
	    out[5] = -2 * bt;
	    out[6] = 0;
	    out[7] = 0;
	    out[8] = 0;
	    out[9] = 0;
	    out[10] = 2 * nf;
	    out[11] = 0;
	    out[12] = (left + right) * lr;
	    out[13] = (top + bottom) * bt;
	    out[14] = (far + near) * nf;
	    out[15] = 1;
	    return out;
	}
	var ortho = orthoNO;
	var mul$2 = multiply$2;

	function create$2() {
	    var out = new ARRAY_TYPE(3);
	    if (ARRAY_TYPE != Float32Array) {
	        out[0] = 0;
	        out[1] = 0;
	        out[2] = 0;
	    }
	    return out;
	}
	function clone(a) {
	    var out = new ARRAY_TYPE(3);
	    out[0] = a[0];
	    out[1] = a[1];
	    out[2] = a[2];
	    return out;
	}
	function length$2(a) {
	    var x = a[0];
	    var y = a[1];
	    var z = a[2];
	    return Math.hypot(x, y, z);
	}
	function fromValues(x, y, z) {
	    var out = new ARRAY_TYPE(3);
	    out[0] = x;
	    out[1] = y;
	    out[2] = z;
	    return out;
	}
	function add(out, a, b) {
	    out[0] = a[0] + b[0];
	    out[1] = a[1] + b[1];
	    out[2] = a[2] + b[2];
	    return out;
	}
	function subtract(out, a, b) {
	    out[0] = a[0] - b[0];
	    out[1] = a[1] - b[1];
	    out[2] = a[2] - b[2];
	    return out;
	}
	function multiply$1(out, a, b) {
	    out[0] = a[0] * b[0];
	    out[1] = a[1] * b[1];
	    out[2] = a[2] * b[2];
	    return out;
	}
	function divide(out, a, b) {
	    out[0] = a[0] / b[0];
	    out[1] = a[1] / b[1];
	    out[2] = a[2] / b[2];
	    return out;
	}
	function min(out, a, b) {
	    out[0] = Math.min(a[0], b[0]);
	    out[1] = Math.min(a[1], b[1]);
	    out[2] = Math.min(a[2], b[2]);
	    return out;
	}
	function max(out, a, b) {
	    out[0] = Math.max(a[0], b[0]);
	    out[1] = Math.max(a[1], b[1]);
	    out[2] = Math.max(a[2], b[2]);
	    return out;
	}
	function scale$1(out, a, b) {
	    out[0] = a[0] * b;
	    out[1] = a[1] * b;
	    out[2] = a[2] * b;
	    return out;
	}
	function scaleAndAdd(out, a, b, scale) {
	    out[0] = a[0] + b[0] * scale;
	    out[1] = a[1] + b[1] * scale;
	    out[2] = a[2] + b[2] * scale;
	    return out;
	}
	function distance(a, b) {
	    var x = b[0] - a[0];
	    var y = b[1] - a[1];
	    var z = b[2] - a[2];
	    return Math.hypot(x, y, z);
	}
	function negate(out, a) {
	    out[0] = -a[0];
	    out[1] = -a[1];
	    out[2] = -a[2];
	    return out;
	}
	function normalize$2(out, a) {
	    var x = a[0];
	    var y = a[1];
	    var z = a[2];
	    var len = x * x + y * y + z * z;
	    if (len > 0) {
	        len = 1 / Math.sqrt(len);
	    }
	    out[0] = a[0] * len;
	    out[1] = a[1] * len;
	    out[2] = a[2] * len;
	    return out;
	}
	function dot$1(a, b) {
	    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
	}
	function cross(out, a, b) {
	    var ax = a[0], ay = a[1], az = a[2];
	    var bx = b[0], by = b[1], bz = b[2];
	    out[0] = ay * bz - az * by;
	    out[1] = az * bx - ax * bz;
	    out[2] = ax * by - ay * bx;
	    return out;
	}
	function transformMat4$1(out, a, m) {
	    var x = a[0], y = a[1], z = a[2];
	    var w = m[3] * x + m[7] * y + m[11] * z + m[15];
	    w = w || 1;
	    out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w;
	    out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w;
	    out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w;
	    return out;
	}
	function transformMat3(out, a, m) {
	    var x = a[0], y = a[1], z = a[2];
	    out[0] = x * m[0] + y * m[3] + z * m[6];
	    out[1] = x * m[1] + y * m[4] + z * m[7];
	    out[2] = x * m[2] + y * m[5] + z * m[8];
	    return out;
	}
	function transformQuat(out, a, q) {
	    var qx = q[0], qy = q[1], qz = q[2], qw = q[3];
	    var x = a[0], y = a[1], z = a[2];
	    var uvx = qy * z - qz * y, uvy = qz * x - qx * z, uvz = qx * y - qy * x;
	    var uuvx = qy * uvz - qz * uvy, uuvy = qz * uvx - qx * uvz, uuvz = qx * uvy - qy * uvx;
	    var w2 = qw * 2;
	    uvx *= w2;
	    uvy *= w2;
	    uvz *= w2;
	    uuvx *= 2;
	    uuvy *= 2;
	    uuvz *= 2;
	    out[0] = x + uvx + uuvx;
	    out[1] = y + uvy + uuvy;
	    out[2] = z + uvz + uuvz;
	    return out;
	}
	function angle(a, b) {
	    var ax = a[0], ay = a[1], az = a[2], bx = b[0], by = b[1], bz = b[2], mag1 = Math.sqrt(ax * ax + ay * ay + az * az), mag2 = Math.sqrt(bx * bx + by * by + bz * bz), mag = mag1 * mag2, cosine = mag && dot$1(a, b) / mag;
	    return Math.acos(Math.min(Math.max(cosine, -1), 1));
	}
	function exactEquals$2(a, b) {
	    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
	}
	function equals$1(a, b) {
	    var a0 = a[0], a1 = a[1], a2 = a[2];
	    var b0 = b[0], b1 = b[1], b2 = b[2];
	    return Math.abs(a0 - b0) <= EPSILON * Math.max(1, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= EPSILON * Math.max(1, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= EPSILON * Math.max(1, Math.abs(a2), Math.abs(b2));
	}
	var sub = subtract;
	var mul$1 = multiply$1;
	var div = divide;
	var len = length$2;
	(function () {
	    var vec = create$2();
	    return function (a, stride, offset, count, fn, arg) {
	        var i, l;
	        if (!stride) {
	            stride = 3;
	        }
	        if (!offset) {
	            offset = 0;
	        }
	        if (count) {
	            l = Math.min(count * stride + offset, a.length);
	        } else {
	            l = a.length;
	        }
	        for (i = offset; i < l; i += stride) {
	            vec[0] = a[i];
	            vec[1] = a[i + 1];
	            vec[2] = a[i + 2];
	            fn(vec, vec, arg);
	            a[i] = vec[0];
	            a[i + 1] = vec[1];
	            a[i + 2] = vec[2];
	        }
	        return a;
	    };
	})();

	function create$1() {
	    var out = new ARRAY_TYPE(4);
	    if (ARRAY_TYPE != Float32Array) {
	        out[0] = 0;
	        out[1] = 0;
	        out[2] = 0;
	        out[3] = 0;
	    }
	    return out;
	}
	function multiply(out, a, b) {
	    out[0] = a[0] * b[0];
	    out[1] = a[1] * b[1];
	    out[2] = a[2] * b[2];
	    out[3] = a[3] * b[3];
	    return out;
	}
	function scale(out, a, b) {
	    out[0] = a[0] * b;
	    out[1] = a[1] * b;
	    out[2] = a[2] * b;
	    out[3] = a[3] * b;
	    return out;
	}
	function length$1(a) {
	    var x = a[0];
	    var y = a[1];
	    var z = a[2];
	    var w = a[3];
	    return Math.hypot(x, y, z, w);
	}
	function normalize$1(out, a) {
	    var x = a[0];
	    var y = a[1];
	    var z = a[2];
	    var w = a[3];
	    var len = x * x + y * y + z * z + w * w;
	    if (len > 0) {
	        len = 1 / Math.sqrt(len);
	    }
	    out[0] = x * len;
	    out[1] = y * len;
	    out[2] = z * len;
	    out[3] = w * len;
	    return out;
	}
	function transformMat4(out, a, m) {
	    var x = a[0], y = a[1], z = a[2], w = a[3];
	    out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
	    out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
	    out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
	    out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
	    return out;
	}
	function exactEquals$1(a, b) {
	    return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
	}
	var mul = multiply;
	(function () {
	    var vec = create$1();
	    return function (a, stride, offset, count, fn, arg) {
	        var i, l;
	        if (!stride) {
	            stride = 4;
	        }
	        if (!offset) {
	            offset = 0;
	        }
	        if (count) {
	            l = Math.min(count * stride + offset, a.length);
	        } else {
	            l = a.length;
	        }
	        for (i = offset; i < l; i += stride) {
	            vec[0] = a[i];
	            vec[1] = a[i + 1];
	            vec[2] = a[i + 2];
	            vec[3] = a[i + 3];
	            fn(vec, vec, arg);
	            a[i] = vec[0];
	            a[i + 1] = vec[1];
	            a[i + 2] = vec[2];
	            a[i + 3] = vec[3];
	        }
	        return a;
	    };
	})();

	function create() {
	    var out = new ARRAY_TYPE(4);
	    if (ARRAY_TYPE != Float32Array) {
	        out[0] = 0;
	        out[1] = 0;
	        out[2] = 0;
	    }
	    out[3] = 1;
	    return out;
	}
	function identity$1(out) {
	    out[0] = 0;
	    out[1] = 0;
	    out[2] = 0;
	    out[3] = 1;
	    return out;
	}
	function setAxisAngle(out, axis, rad) {
	    rad = rad * 0.5;
	    var s = Math.sin(rad);
	    out[0] = s * axis[0];
	    out[1] = s * axis[1];
	    out[2] = s * axis[2];
	    out[3] = Math.cos(rad);
	    return out;
	}
	function rotateX(out, a, rad) {
	    rad *= 0.5;
	    var ax = a[0], ay = a[1], az = a[2], aw = a[3];
	    var bx = Math.sin(rad), bw = Math.cos(rad);
	    out[0] = ax * bw + aw * bx;
	    out[1] = ay * bw + az * bx;
	    out[2] = az * bw - ay * bx;
	    out[3] = aw * bw - ax * bx;
	    return out;
	}
	function rotateY(out, a, rad) {
	    rad *= 0.5;
	    var ax = a[0], ay = a[1], az = a[2], aw = a[3];
	    var by = Math.sin(rad), bw = Math.cos(rad);
	    out[0] = ax * bw - az * by;
	    out[1] = ay * bw + aw * by;
	    out[2] = az * bw + ax * by;
	    out[3] = aw * bw - ay * by;
	    return out;
	}
	function rotateZ(out, a, rad) {
	    rad *= 0.5;
	    var ax = a[0], ay = a[1], az = a[2], aw = a[3];
	    var bz = Math.sin(rad), bw = Math.cos(rad);
	    out[0] = ax * bw + ay * bz;
	    out[1] = ay * bw - ax * bz;
	    out[2] = az * bw + aw * bz;
	    out[3] = aw * bw - az * bz;
	    return out;
	}
	function slerp$1(out, a, b, t) {
	    var ax = a[0], ay = a[1], az = a[2], aw = a[3];
	    var bx = b[0], by = b[1], bz = b[2], bw = b[3];
	    var omega, cosom, sinom, scale0, scale1;
	    cosom = ax * bx + ay * by + az * bz + aw * bw;
	    if (cosom < 0) {
	        cosom = -cosom;
	        bx = -bx;
	        by = -by;
	        bz = -bz;
	        bw = -bw;
	    }
	    if (1 - cosom > EPSILON) {
	        omega = Math.acos(cosom);
	        sinom = Math.sin(omega);
	        scale0 = Math.sin((1 - t) * omega) / sinom;
	        scale1 = Math.sin(t * omega) / sinom;
	    } else {
	        scale0 = 1 - t;
	        scale1 = t;
	    }
	    out[0] = scale0 * ax + scale1 * bx;
	    out[1] = scale0 * ay + scale1 * by;
	    out[2] = scale0 * az + scale1 * bz;
	    out[3] = scale0 * aw + scale1 * bw;
	    return out;
	}
	function conjugate(out, a) {
	    out[0] = -a[0];
	    out[1] = -a[1];
	    out[2] = -a[2];
	    out[3] = a[3];
	    return out;
	}
	function fromMat3(out, m) {
	    var fTrace = m[0] + m[4] + m[8];
	    var fRoot;
	    if (fTrace > 0) {
	        fRoot = Math.sqrt(fTrace + 1);
	        out[3] = 0.5 * fRoot;
	        fRoot = 0.5 / fRoot;
	        out[0] = (m[5] - m[7]) * fRoot;
	        out[1] = (m[6] - m[2]) * fRoot;
	        out[2] = (m[1] - m[3]) * fRoot;
	    } else {
	        var i = 0;
	        if (m[4] > m[0])
	            i = 1;
	        if (m[8] > m[i * 3 + i])
	            i = 2;
	        var j = (i + 1) % 3;
	        var k = (i + 2) % 3;
	        fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1);
	        out[i] = 0.5 * fRoot;
	        fRoot = 0.5 / fRoot;
	        out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot;
	        out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot;
	        out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot;
	    }
	    return out;
	}
	var length = length$1;
	var normalize = normalize$1;
	var exactEquals = exactEquals$1;
	(function () {
	    var tmpvec3 = create$2();
	    var xUnitVec3 = fromValues(1, 0, 0);
	    var yUnitVec3 = fromValues(0, 1, 0);
	    return function (out, a, b) {
	        var dot = dot$1(a, b);
	        if (dot < -0.999999) {
	            cross(tmpvec3, xUnitVec3, a);
	            if (len(tmpvec3) < 0.000001)
	                cross(tmpvec3, yUnitVec3, a);
	            normalize$2(tmpvec3, tmpvec3);
	            setAxisAngle(out, tmpvec3, Math.PI);
	            return out;
	        } else if (dot > 0.999999) {
	            out[0] = 0;
	            out[1] = 0;
	            out[2] = 0;
	            out[3] = 1;
	            return out;
	        } else {
	            cross(tmpvec3, a, b);
	            out[0] = tmpvec3[0];
	            out[1] = tmpvec3[1];
	            out[2] = tmpvec3[2];
	            out[3] = 1 + dot;
	            return normalize(out, out);
	        }
	    };
	})();
	(function () {
	    var temp1 = create();
	    var temp2 = create();
	    return function (out, a, b, c, d, t) {
	        slerp$1(temp1, a, d, t);
	        slerp$1(temp2, b, c, t);
	        slerp$1(out, temp1, temp2, 2 * t * (1 - t));
	        return out;
	    };
	})();
	(function () {
	    var matr = create$4();
	    return function (out, view, right, up) {
	        matr[0] = right[0];
	        matr[3] = right[1];
	        matr[6] = right[2];
	        matr[1] = up[0];
	        matr[4] = up[1];
	        matr[7] = up[2];
	        matr[2] = -view[0];
	        matr[5] = -view[1];
	        matr[8] = -view[2];
	        return normalize(out, fromMat3(out, matr));
	    };
	})();

	class Ray {
	    constructor(pos_, dir_) {
	        this.pos = pos_;
	        this.dir = dir_;
	    }
	    intersectsPlane(pt, normal, out) {
	        const D = dot$1(normal, this.dir);
	        if (Math.abs(D) < 0.000001) {
	            return false;
	        }
	        const t = ((pt[0] - this.pos[0]) * normal[0] + (pt[1] - this.pos[1]) * normal[1] + (pt[2] - this.pos[2]) * normal[2]) / D;
	        out[0] = this.pos[0] + this.dir[0] * t;
	        out[1] = this.pos[1] + this.dir[1] * t;
	        out[2] = this.pos[2] + this.dir[2] * t;
	        return true;
	    }
	    closestPointOnSphere(center, r, out) {
	        if (equals$1(this.pos, center) || r === 0) {
	            out[0] = out[1] = out[2] = 0;
	            return false;
	        }
	        const [dx, dy, dz] = this.dir;
	        const px = this.pos[0] - center[0];
	        const py = this.pos[1] - center[1];
	        const pz = this.pos[2] - center[2];
	        const a = dx * dx + dy * dy + dz * dz;
	        const b = 2 * (px * dx + py * dy + pz * dz);
	        const c = px * px + py * py + pz * pz - r * r;
	        const d = b * b - 4 * a * c;
	        if (d < 0) {
	            const t = Math.max(-b / 2, 0);
	            const gx = px + dx * t;
	            const gy = py + dy * t;
	            const gz = pz + dz * t;
	            const glen = Math.hypot(gx, gy, gz);
	            out[0] = gx * r / glen;
	            out[1] = gy * r / glen;
	            out[2] = gz * r / glen;
	            return false;
	        } else {
	            const t = (-b - Math.sqrt(d)) / (2 * a);
	            if (t < 0) {
	                const plen = Math.hypot(px, py, pz);
	                out[0] = px * r / plen;
	                out[1] = py * r / plen;
	                out[2] = pz * r / plen;
	                return false;
	            } else {
	                out[0] = px + dx * t;
	                out[1] = py + dy * t;
	                out[2] = pz + dz * t;
	                return true;
	            }
	        }
	    }
	}
	class FrustumCorners {
	    constructor(TL_, TR_, BR_, BL_, horizon_) {
	        this.TL = TL_;
	        this.TR = TR_;
	        this.BR = BR_;
	        this.BL = BL_;
	        this.horizon = horizon_;
	    }
	    static fromInvProjectionMatrix(invProj, horizonFromTop, viewportHeight) {
	        const TLClip = [
	            -1,
	            1,
	            1
	        ];
	        const TRClip = [
	            1,
	            1,
	            1
	        ];
	        const BRClip = [
	            1,
	            -1,
	            1
	        ];
	        const BLClip = [
	            -1,
	            -1,
	            1
	        ];
	        const TL = transformMat4$1(TLClip, TLClip, invProj);
	        const TR = transformMat4$1(TRClip, TRClip, invProj);
	        const BR = transformMat4$1(BRClip, BRClip, invProj);
	        const BL = transformMat4$1(BLClip, BLClip, invProj);
	        return new FrustumCorners(TL, TR, BR, BL, horizonFromTop / viewportHeight);
	    }
	}
	class Frustum {
	    constructor(points_, planes_) {
	        this.points = points_;
	        this.planes = planes_;
	    }
	    static fromInvProjectionMatrix(invProj, worldSize, zoom, zInMeters) {
	        const clipSpaceCorners = [
	            [
	                -1,
	                1,
	                -1,
	                1
	            ],
	            [
	                1,
	                1,
	                -1,
	                1
	            ],
	            [
	                1,
	                -1,
	                -1,
	                1
	            ],
	            [
	                -1,
	                -1,
	                -1,
	                1
	            ],
	            [
	                -1,
	                1,
	                1,
	                1
	            ],
	            [
	                1,
	                1,
	                1,
	                1
	            ],
	            [
	                1,
	                -1,
	                1,
	                1
	            ],
	            [
	                -1,
	                -1,
	                1,
	                1
	            ]
	        ];
	        const scale = Math.pow(2, zoom);
	        const frustumCoords = clipSpaceCorners.map(v => {
	            const s = transformMat4([], v, invProj);
	            const k = 1 / s[3] / worldSize * scale;
	            return mul(s, s, [
	                k,
	                k,
	                zInMeters ? 1 / s[3] : k,
	                k
	            ]);
	        });
	        const frustumPlanePointIndices = [
	            [
	                0,
	                1,
	                2
	            ],
	            [
	                6,
	                5,
	                4
	            ],
	            [
	                0,
	                3,
	                7
	            ],
	            [
	                2,
	                1,
	                5
	            ],
	            [
	                3,
	                2,
	                6
	            ],
	            [
	                0,
	                4,
	                5
	            ]
	        ];
	        const frustumPlanes = frustumPlanePointIndices.map(p => {
	            const a = sub([], frustumCoords[p[0]], frustumCoords[p[1]]);
	            const b = sub([], frustumCoords[p[2]], frustumCoords[p[1]]);
	            const n = normalize$2([], cross([], a, b));
	            const d = -dot$1(n, frustumCoords[p[1]]);
	            return n.concat(d);
	        });
	        return new Frustum(frustumCoords, frustumPlanes);
	    }
	}
	class Aabb {
	    constructor(min_, max_) {
	        this.min = min_;
	        this.max = max_;
	        this.center = scale$1([], add([], this.min, this.max), 0.5);
	    }
	    quadrant(index) {
	        const split = [
	            index % 2 === 0,
	            index < 2
	        ];
	        const qMin = clone(this.min);
	        const qMax = clone(this.max);
	        for (let axis = 0; axis < split.length; axis++) {
	            qMin[axis] = split[axis] ? this.min[axis] : this.center[axis];
	            qMax[axis] = split[axis] ? this.center[axis] : this.max[axis];
	        }
	        qMax[2] = this.max[2];
	        return new Aabb(qMin, qMax);
	    }
	    distanceX(point) {
	        const pointOnAabb = Math.max(Math.min(this.max[0], point[0]), this.min[0]);
	        return pointOnAabb - point[0];
	    }
	    distanceY(point) {
	        const pointOnAabb = Math.max(Math.min(this.max[1], point[1]), this.min[1]);
	        return pointOnAabb - point[1];
	    }
	    distanceZ(point) {
	        const pointOnAabb = Math.max(Math.min(this.max[2], point[2]), this.min[2]);
	        return pointOnAabb - point[2];
	    }
	    getCorners() {
	        const mn = this.min;
	        const mx = this.max;
	        return [
	            [
	                mn[0],
	                mn[1],
	                mn[2]
	            ],
	            [
	                mx[0],
	                mn[1],
	                mn[2]
	            ],
	            [
	                mx[0],
	                mx[1],
	                mn[2]
	            ],
	            [
	                mn[0],
	                mx[1],
	                mn[2]
	            ],
	            [
	                mn[0],
	                mn[1],
	                mx[2]
	            ],
	            [
	                mx[0],
	                mn[1],
	                mx[2]
	            ],
	            [
	                mx[0],
	                mx[1],
	                mx[2]
	            ],
	            [
	                mn[0],
	                mx[1],
	                mx[2]
	            ]
	        ];
	    }
	    intersects(frustum) {
	        const aabbPoints = this.getCorners();
	        let fullyInside = true;
	        for (let p = 0; p < frustum.planes.length; p++) {
	            const plane = frustum.planes[p];
	            let pointsInside = 0;
	            for (let i = 0; i < aabbPoints.length; i++) {
	                pointsInside += dot$1(plane, aabbPoints[i]) + plane[3] >= 0;
	            }
	            if (pointsInside === 0)
	                return 0;
	            if (pointsInside !== aabbPoints.length)
	                fullyInside = false;
	        }
	        if (fullyInside)
	            return 2;
	        for (let axis = 0; axis < 3; axis++) {
	            let projMin = Number.MAX_VALUE;
	            let projMax = -Number.MAX_VALUE;
	            for (let p = 0; p < frustum.points.length; p++) {
	                const projectedPoint = frustum.points[p][axis] - this.min[axis];
	                projMin = Math.min(projMin, projectedPoint);
	                projMax = Math.max(projMax, projectedPoint);
	            }
	            if (projMax < 0 || projMin > this.max[axis] - this.min[axis])
	                return 0;
	        }
	        return 1;
	    }
	}

	class CircleStyleLayer extends StyleLayer {
	    constructor(layer) {
	        super(layer, properties$9);
	    }
	    createBucket(parameters) {
	        return new CircleBucket(parameters);
	    }
	    queryRadius(bucket) {
	        const circleBucket = bucket;
	        return getMaximumPaintValue('circle-radius', this, circleBucket) + getMaximumPaintValue('circle-stroke-width', this, circleBucket) + translateDistance(this.paint.get('circle-translate'));
	    }
	    queryIntersectsFeature(queryGeometry, feature, featureState, geometry, zoom, transform, pixelPosMatrix, elevationHelper) {
	        const translation = tilespaceTranslate(this.paint.get('circle-translate'), this.paint.get('circle-translate-anchor'), transform.angle, queryGeometry.pixelToTileUnitsFactor);
	        const size = this.paint.get('circle-radius').evaluate(feature, featureState) + this.paint.get('circle-stroke-width').evaluate(feature, featureState);
	        return queryIntersectsCircle(queryGeometry, geometry, transform, pixelPosMatrix, elevationHelper, this.paint.get('circle-pitch-alignment') === 'map', this.paint.get('circle-pitch-scale') === 'map', translation, size);
	    }
	    getProgramIds() {
	        return ['circle'];
	    }
	    getProgramConfiguration(zoom) {
	        return new ProgramConfiguration(this, zoom);
	    }
	}
	function queryIntersectsCircle(queryGeometry, geometry, transform, pixelPosMatrix, elevationHelper, alignWithMap, scaleWithMap, translation, size) {
	    if (alignWithMap && queryGeometry.queryGeometry.isAboveHorizon)
	        return false;
	    if (alignWithMap)
	        size *= queryGeometry.pixelToTileUnitsFactor;
	    const tileId = queryGeometry.tileID.canonical;
	    const elevationScale = transform.projection.upVectorScale(tileId, transform.center.lat, transform.worldSize).metersToTile;
	    for (const ring of geometry) {
	        for (const point of ring) {
	            const translatedPoint = point.add(translation);
	            const z = elevationHelper && transform.elevation ? transform.elevation.exaggeration() * elevationHelper.getElevationAt(translatedPoint.x, translatedPoint.y, true) : 0;
	            const reproj = transform.projection.projectTilePoint(translatedPoint.x, translatedPoint.y, tileId);
	            if (z > 0) {
	                const dir = transform.projection.upVector(tileId, translatedPoint.x, translatedPoint.y);
	                reproj.x += dir[0] * elevationScale * z;
	                reproj.y += dir[1] * elevationScale * z;
	                reproj.z += dir[2] * elevationScale * z;
	            }
	            const transformedPoint = alignWithMap ? translatedPoint : projectPoint(reproj.x, reproj.y, reproj.z, pixelPosMatrix);
	            const transformedPolygon = alignWithMap ? queryGeometry.tilespaceRays.map(r => intersectAtHeight(r, z)) : queryGeometry.queryGeometry.screenGeometry;
	            const projectedCenter = transformMat4([], [
	                reproj.x,
	                reproj.y,
	                reproj.z,
	                1
	            ], pixelPosMatrix);
	            if (!scaleWithMap && alignWithMap) {
	                size *= projectedCenter[3] / transform.cameraToCenterDistance;
	            } else if (scaleWithMap && !alignWithMap) {
	                size *= transform.cameraToCenterDistance / projectedCenter[3];
	            }
	            if (alignWithMap) {
	                const lat = latFromMercatorY((point.y / EXTENT + tileId.y) / (1 << tileId.z));
	                const scale = transform.projection.pixelsPerMeter(lat, 1) / mercatorZfromAltitude(1, lat);
	                size /= scale;
	            }
	            if (polygonIntersectsBufferedPoint(transformedPolygon, transformedPoint, size))
	                return true;
	        }
	    }
	    return false;
	}
	function projectPoint(x, y, z, pixelPosMatrix) {
	    const point = transformMat4([], [
	        x,
	        y,
	        z,
	        1
	    ], pixelPosMatrix);
	    return new pointGeometry(point[0] / point[3], point[1] / point[3]);
	}
	const origin = fromValues(0, 0, 0);
	const up = fromValues(0, 0, 1);
	function intersectAtHeight(r, z) {
	    const intersectionPt = create$2();
	    origin[2] = z;
	    r.intersectsPlane(origin, up, intersectionPt);
	    return new pointGeometry(intersectionPt[0], intersectionPt[1]);
	}

	class HeatmapBucket extends CircleBucket {
	}
	register(HeatmapBucket, 'HeatmapBucket', { omit: ['layers'] });

	function createImage(image, {width, height}, channels, data) {
	    if (!data) {
	        data = new Uint8Array(width * height * channels);
	    } else if (data instanceof Uint8ClampedArray) {
	        data = new Uint8Array(data.buffer);
	    } else if (data.length !== width * height * channels) {
	        throw new RangeError('mismatched image size');
	    }
	    image.width = width;
	    image.height = height;
	    image.data = data;
	    return image;
	}
	function resizeImage(image, newImage, channels) {
	    const {width, height} = newImage;
	    if (width === image.width && height === image.height) {
	        return;
	    }
	    copyImage(image, newImage, {
	        x: 0,
	        y: 0
	    }, {
	        x: 0,
	        y: 0
	    }, {
	        width: Math.min(image.width, width),
	        height: Math.min(image.height, height)
	    }, channels);
	    image.width = width;
	    image.height = height;
	    image.data = newImage.data;
	}
	function copyImage(srcImg, dstImg, srcPt, dstPt, size, channels) {
	    if (size.width === 0 || size.height === 0) {
	        return dstImg;
	    }
	    if (size.width > srcImg.width || size.height > srcImg.height || srcPt.x > srcImg.width - size.width || srcPt.y > srcImg.height - size.height) {
	        throw new RangeError('out of range source coordinates for image copy');
	    }
	    if (size.width > dstImg.width || size.height > dstImg.height || dstPt.x > dstImg.width - size.width || dstPt.y > dstImg.height - size.height) {
	        throw new RangeError('out of range destination coordinates for image copy');
	    }
	    const srcData = srcImg.data;
	    const dstData = dstImg.data;
	    for (let y = 0; y < size.height; y++) {
	        const srcOffset = ((srcPt.y + y) * srcImg.width + srcPt.x) * channels;
	        const dstOffset = ((dstPt.y + y) * dstImg.width + dstPt.x) * channels;
	        for (let i = 0; i < size.width * channels; i++) {
	            dstData[dstOffset + i] = srcData[srcOffset + i];
	        }
	    }
	    return dstImg;
	}
	class AlphaImage {
	    constructor(size, data) {
	        createImage(this, size, 1, data);
	    }
	    resize(size) {
	        resizeImage(this, new AlphaImage(size), 1);
	    }
	    clone() {
	        return new AlphaImage({
	            width: this.width,
	            height: this.height
	        }, new Uint8Array(this.data));
	    }
	    static copy(srcImg, dstImg, srcPt, dstPt, size) {
	        copyImage(srcImg, dstImg, srcPt, dstPt, size, 1);
	    }
	}
	class RGBAImage {
	    constructor(size, data) {
	        createImage(this, size, 4, data);
	    }
	    resize(size) {
	        resizeImage(this, new RGBAImage(size), 4);
	    }
	    replace(data, copy) {
	        if (copy) {
	            this.data.set(data);
	        } else if (data instanceof Uint8ClampedArray) {
	            this.data = new Uint8Array(data.buffer);
	        } else {
	            this.data = data;
	        }
	    }
	    clone() {
	        return new RGBAImage({
	            width: this.width,
	            height: this.height
	        }, new Uint8Array(this.data));
	    }
	    static copy(srcImg, dstImg, srcPt, dstPt, size) {
	        copyImage(srcImg, dstImg, srcPt, dstPt, size, 4);
	    }
	}
	register(AlphaImage, 'AlphaImage');
	register(RGBAImage, 'RGBAImage');

	const paint$8 = new Properties({
	    'heatmap-radius': new DataDrivenProperty(spec['paint_heatmap']['heatmap-radius']),
	    'heatmap-weight': new DataDrivenProperty(spec['paint_heatmap']['heatmap-weight']),
	    'heatmap-intensity': new DataConstantProperty(spec['paint_heatmap']['heatmap-intensity']),
	    'heatmap-color': new ColorRampProperty(spec['paint_heatmap']['heatmap-color']),
	    'heatmap-opacity': new DataConstantProperty(spec['paint_heatmap']['heatmap-opacity'])
	});
	var properties$8 = { paint: paint$8 };

	function renderColorRamp(params) {
	    const evaluationGlobals = {};
	    const width = params.resolution || 256;
	    const height = params.clips ? params.clips.length : 1;
	    const image = params.image || new RGBAImage({
	        width,
	        height
	    });
	    const renderPixel = (stride, index, progress) => {
	        evaluationGlobals[params.evaluationKey] = progress;
	        const pxColor = params.expression.evaluate(evaluationGlobals);
	        image.data[stride + index + 0] = Math.floor(pxColor.r * 255 / pxColor.a);
	        image.data[stride + index + 1] = Math.floor(pxColor.g * 255 / pxColor.a);
	        image.data[stride + index + 2] = Math.floor(pxColor.b * 255 / pxColor.a);
	        image.data[stride + index + 3] = Math.floor(pxColor.a * 255);
	    };
	    if (!params.clips) {
	        for (let i = 0, j = 0; i < width; i++, j += 4) {
	            const progress = i / (width - 1);
	            renderPixel(0, j, progress);
	        }
	    } else {
	        for (let clip = 0, stride = 0; clip < height; ++clip, stride += width * 4) {
	            for (let i = 0, j = 0; i < width; i++, j += 4) {
	                const progress = i / (width - 1);
	                const {start, end} = params.clips[clip];
	                const evaluationProgress = start * (1 - progress) + end * progress;
	                renderPixel(stride, j, evaluationProgress);
	            }
	        }
	    }
	    return image;
	}

	class HeatmapStyleLayer extends StyleLayer {
	    createBucket(parameters) {
	        return new HeatmapBucket(parameters);
	    }
	    constructor(layer) {
	        super(layer, properties$8);
	        this._updateColorRamp();
	    }
	    _handleSpecialPaintPropertyUpdate(name) {
	        if (name === 'heatmap-color') {
	            this._updateColorRamp();
	        }
	    }
	    _updateColorRamp() {
	        const expression = this._transitionablePaint._values['heatmap-color'].value.expression;
	        this.colorRamp = renderColorRamp({
	            expression,
	            evaluationKey: 'heatmapDensity',
	            image: this.colorRamp
	        });
	        this.colorRampTexture = null;
	    }
	    resize() {
	        if (this.heatmapFbo) {
	            this.heatmapFbo.destroy();
	            this.heatmapFbo = null;
	        }
	    }
	    queryRadius(bucket) {
	        return getMaximumPaintValue('heatmap-radius', this, bucket);
	    }
	    queryIntersectsFeature(queryGeometry, feature, featureState, geometry, zoom, transform, pixelPosMatrix, elevationHelper) {
	        const size = this.paint.get('heatmap-radius').evaluate(feature, featureState);
	        return queryIntersectsCircle(queryGeometry, geometry, transform, pixelPosMatrix, elevationHelper, true, true, new pointGeometry(0, 0), size);
	    }
	    hasOffscreenPass() {
	        return this.paint.get('heatmap-opacity') !== 0 && this.visibility !== 'none';
	    }
	    getProgramIds() {
	        return [
	            'heatmap',
	            'heatmapTexture'
	        ];
	    }
	    getProgramConfiguration(zoom) {
	        return new ProgramConfiguration(this, zoom);
	    }
	}

	const paint$7 = new Properties({
	    'hillshade-illumination-direction': new DataConstantProperty(spec['paint_hillshade']['hillshade-illumination-direction']),
	    'hillshade-illumination-anchor': new DataConstantProperty(spec['paint_hillshade']['hillshade-illumination-anchor']),
	    'hillshade-exaggeration': new DataConstantProperty(spec['paint_hillshade']['hillshade-exaggeration']),
	    'hillshade-shadow-color': new DataConstantProperty(spec['paint_hillshade']['hillshade-shadow-color']),
	    'hillshade-highlight-color': new DataConstantProperty(spec['paint_hillshade']['hillshade-highlight-color']),
	    'hillshade-accent-color': new DataConstantProperty(spec['paint_hillshade']['hillshade-accent-color'])
	});
	var properties$7 = { paint: paint$7 };

	class HillshadeStyleLayer extends StyleLayer {
	    constructor(layer) {
	        super(layer, properties$7);
	    }
	    hasOffscreenPass() {
	        return this.paint.get('hillshade-exaggeration') !== 0 && this.visibility !== 'none';
	    }
	    getProgramIds() {
	        return [
	            'hillshade',
	            'hillshadePrepare'
	        ];
	    }
	}

	const layout$4 = createLayout([{
	        name: 'a_pos',
	        components: 2,
	        type: 'Int16'
	    }], 4);
	const {members: members$4, size: size$4, alignment: alignment$4} = layout$4;

	var earcut_1 = earcut;
	var _default = earcut;
	function earcut(data, holeIndices, dim) {
	    dim = dim || 2;
	    var hasHoles = holeIndices && holeIndices.length, outerLen = hasHoles ? holeIndices[0] * dim : data.length, outerNode = linkedList(data, 0, outerLen, dim, true), triangles = [];
	    if (!outerNode || outerNode.next === outerNode.prev)
	        return triangles;
	    var minX, minY, maxX, maxY, x, y, invSize;
	    if (hasHoles)
	        outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
	    if (data.length > 80 * dim) {
	        minX = maxX = data[0];
	        minY = maxY = data[1];
	        for (var i = dim; i < outerLen; i += dim) {
	            x = data[i];
	            y = data[i + 1];
	            if (x < minX)
	                minX = x;
	            if (y < minY)
	                minY = y;
	            if (x > maxX)
	                maxX = x;
	            if (y > maxY)
	                maxY = y;
	        }
	        invSize = Math.max(maxX - minX, maxY - minY);
	        invSize = invSize !== 0 ? 1 / invSize : 0;
	    }
	    earcutLinked(outerNode, triangles, dim, minX, minY, invSize);
	    return triangles;
	}
	function linkedList(data, start, end, dim, clockwise) {
	    var i, last;
	    if (clockwise === signedArea$1(data, start, end, dim) > 0) {
	        for (i = start; i < end; i += dim)
	            last = insertNode(i, data[i], data[i + 1], last);
	    } else {
	        for (i = end - dim; i >= start; i -= dim)
	            last = insertNode(i, data[i], data[i + 1], last);
	    }
	    if (last && equals(last, last.next)) {
	        removeNode(last);
	        last = last.next;
	    }
	    return last;
	}
	function filterPoints(start, end) {
	    if (!start)
	        return start;
	    if (!end)
	        end = start;
	    var p = start, again;
	    do {
	        again = false;
	        if (!p.steiner && (equals(p, p.next) || area(p.prev, p, p.next) === 0)) {
	            removeNode(p);
	            p = end = p.prev;
	            if (p === p.next)
	                break;
	            again = true;
	        } else {
	            p = p.next;
	        }
	    } while (again || p !== end);
	    return end;
	}
	function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
	    if (!ear)
	        return;
	    if (!pass && invSize)
	        indexCurve(ear, minX, minY, invSize);
	    var stop = ear, prev, next;
	    while (ear.prev !== ear.next) {
	        prev = ear.prev;
	        next = ear.next;
	        if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
	            triangles.push(prev.i / dim);
	            triangles.push(ear.i / dim);
	            triangles.push(next.i / dim);
	            removeNode(ear);
	            ear = next.next;
	            stop = next.next;
	            continue;
	        }
	        ear = next;
	        if (ear === stop) {
	            if (!pass) {
	                earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
	            } else if (pass === 1) {
	                ear = cureLocalIntersections(filterPoints(ear), triangles, dim);
	                earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
	            } else if (pass === 2) {
	                splitEarcut(ear, triangles, dim, minX, minY, invSize);
	            }
	            break;
	        }
	    }
	}
	function isEar(ear) {
	    var a = ear.prev, b = ear, c = ear.next;
	    if (area(a, b, c) >= 0)
	        return false;
	    var p = ear.next.next;
	    while (p !== ear.prev) {
	        if (pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0)
	            return false;
	        p = p.next;
	    }
	    return true;
	}
	function isEarHashed(ear, minX, minY, invSize) {
	    var a = ear.prev, b = ear, c = ear.next;
	    if (area(a, b, c) >= 0)
	        return false;
	    var minTX = a.x < b.x ? a.x < c.x ? a.x : c.x : b.x < c.x ? b.x : c.x, minTY = a.y < b.y ? a.y < c.y ? a.y : c.y : b.y < c.y ? b.y : c.y, maxTX = a.x > b.x ? a.x > c.x ? a.x : c.x : b.x > c.x ? b.x : c.x, maxTY = a.y > b.y ? a.y > c.y ? a.y : c.y : b.y > c.y ? b.y : c.y;
	    var minZ = zOrder(minTX, minTY, minX, minY, invSize), maxZ = zOrder(maxTX, maxTY, minX, minY, invSize);
	    var p = ear.prevZ, n = ear.nextZ;
	    while (p && p.z >= minZ && n && n.z <= maxZ) {
	        if (p !== ear.prev && p !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0)
	            return false;
	        p = p.prevZ;
	        if (n !== ear.prev && n !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) && area(n.prev, n, n.next) >= 0)
	            return false;
	        n = n.nextZ;
	    }
	    while (p && p.z >= minZ) {
	        if (p !== ear.prev && p !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, p.x, p.y) && area(p.prev, p, p.next) >= 0)
	            return false;
	        p = p.prevZ;
	    }
	    while (n && n.z <= maxZ) {
	        if (n !== ear.prev && n !== ear.next && pointInTriangle(a.x, a.y, b.x, b.y, c.x, c.y, n.x, n.y) && area(n.prev, n, n.next) >= 0)
	            return false;
	        n = n.nextZ;
	    }
	    return true;
	}
	function cureLocalIntersections(start, triangles, dim) {
	    var p = start;
	    do {
	        var a = p.prev, b = p.next.next;
	        if (!equals(a, b) && intersects(a, p, p.next, b) && locallyInside(a, b) && locallyInside(b, a)) {
	            triangles.push(a.i / dim);
	            triangles.push(p.i / dim);
	            triangles.push(b.i / dim);
	            removeNode(p);
	            removeNode(p.next);
	            p = start = b;
	        }
	        p = p.next;
	    } while (p !== start);
	    return filterPoints(p);
	}
	function splitEarcut(start, triangles, dim, minX, minY, invSize) {
	    var a = start;
	    do {
	        var b = a.next.next;
	        while (b !== a.prev) {
	            if (a.i !== b.i && isValidDiagonal(a, b)) {
	                var c = splitPolygon(a, b);
	                a = filterPoints(a, a.next);
	                c = filterPoints(c, c.next);
	                earcutLinked(a, triangles, dim, minX, minY, invSize);
	                earcutLinked(c, triangles, dim, minX, minY, invSize);
	                return;
	            }
	            b = b.next;
	        }
	        a = a.next;
	    } while (a !== start);
	}
	function eliminateHoles(data, holeIndices, outerNode, dim) {
	    var queue = [], i, len, start, end, list;
	    for (i = 0, len = holeIndices.length; i < len; i++) {
	        start = holeIndices[i] * dim;
	        end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
	        list = linkedList(data, start, end, dim, false);
	        if (list === list.next)
	            list.steiner = true;
	        queue.push(getLeftmost(list));
	    }
	    queue.sort(compareX);
	    for (i = 0; i < queue.length; i++) {
	        outerNode = eliminateHole(queue[i], outerNode);
	        outerNode = filterPoints(outerNode, outerNode.next);
	    }
	    return outerNode;
	}
	function compareX(a, b) {
	    return a.x - b.x;
	}
	function eliminateHole(hole, outerNode) {
	    var bridge = findHoleBridge(hole, outerNode);
	    if (!bridge) {
	        return outerNode;
	    }
	    var bridgeReverse = splitPolygon(bridge, hole);
	    var filteredBridge = filterPoints(bridge, bridge.next);
	    filterPoints(bridgeReverse, bridgeReverse.next);
	    return outerNode === bridge ? filteredBridge : outerNode;
	}
	function findHoleBridge(hole, outerNode) {
	    var p = outerNode, hx = hole.x, hy = hole.y, qx = -Infinity, m;
	    do {
	        if (hy <= p.y && hy >= p.next.y && p.next.y !== p.y) {
	            var x = p.x + (hy - p.y) * (p.next.x - p.x) / (p.next.y - p.y);
	            if (x <= hx && x > qx) {
	                qx = x;
	                if (x === hx) {
	                    if (hy === p.y)
	                        return p;
	                    if (hy === p.next.y)
	                        return p.next;
	                }
	                m = p.x < p.next.x ? p : p.next;
	            }
	        }
	        p = p.next;
	    } while (p !== outerNode);
	    if (!m)
	        return null;
	    if (hx === qx)
	        return m;
	    var stop = m, mx = m.x, my = m.y, tanMin = Infinity, tan;
	    p = m;
	    do {
	        if (hx >= p.x && p.x >= mx && hx !== p.x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y)) {
	            tan = Math.abs(hy - p.y) / (hx - p.x);
	            if (locallyInside(p, hole) && (tan < tanMin || tan === tanMin && (p.x > m.x || p.x === m.x && sectorContainsSector(m, p)))) {
	                m = p;
	                tanMin = tan;
	            }
	        }
	        p = p.next;
	    } while (p !== stop);
	    return m;
	}
	function sectorContainsSector(m, p) {
	    return area(m.prev, m, p.prev) < 0 && area(p.next, m, m.next) < 0;
	}
	function indexCurve(start, minX, minY, invSize) {
	    var p = start;
	    do {
	        if (p.z === null)
	            p.z = zOrder(p.x, p.y, minX, minY, invSize);
	        p.prevZ = p.prev;
	        p.nextZ = p.next;
	        p = p.next;
	    } while (p !== start);
	    p.prevZ.nextZ = null;
	    p.prevZ = null;
	    sortLinked(p);
	}
	function sortLinked(list) {
	    var i, p, q, e, tail, numMerges, pSize, qSize, inSize = 1;
	    do {
	        p = list;
	        list = null;
	        tail = null;
	        numMerges = 0;
	        while (p) {
	            numMerges++;
	            q = p;
	            pSize = 0;
	            for (i = 0; i < inSize; i++) {
	                pSize++;
	                q = q.nextZ;
	                if (!q)
	                    break;
	            }
	            qSize = inSize;
	            while (pSize > 0 || qSize > 0 && q) {
	                if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
	                    e = p;
	                    p = p.nextZ;
	                    pSize--;
	                } else {
	                    e = q;
	                    q = q.nextZ;
	                    qSize--;
	                }
	                if (tail)
	                    tail.nextZ = e;
	                else
	                    list = e;
	                e.prevZ = tail;
	                tail = e;
	            }
	            p = q;
	        }
	        tail.nextZ = null;
	        inSize *= 2;
	    } while (numMerges > 1);
	    return list;
	}
	function zOrder(x, y, minX, minY, invSize) {
	    x = 32767 * (x - minX) * invSize;
	    y = 32767 * (y - minY) * invSize;
	    x = (x | x << 8) & 16711935;
	    x = (x | x << 4) & 252645135;
	    x = (x | x << 2) & 858993459;
	    x = (x | x << 1) & 1431655765;
	    y = (y | y << 8) & 16711935;
	    y = (y | y << 4) & 252645135;
	    y = (y | y << 2) & 858993459;
	    y = (y | y << 1) & 1431655765;
	    return x | y << 1;
	}
	function getLeftmost(start) {
	    var p = start, leftmost = start;
	    do {
	        if (p.x < leftmost.x || p.x === leftmost.x && p.y < leftmost.y)
	            leftmost = p;
	        p = p.next;
	    } while (p !== start);
	    return leftmost;
	}
	function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
	    return (cx - px) * (ay - py) - (ax - px) * (cy - py) >= 0 && (ax - px) * (by - py) - (bx - px) * (ay - py) >= 0 && (bx - px) * (cy - py) - (cx - px) * (by - py) >= 0;
	}
	function isValidDiagonal(a, b) {
	    return a.next.i !== b.i && a.prev.i !== b.i && !intersectsPolygon(a, b) && (locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && (area(a.prev, a, b.prev) || area(a, b.prev, b)) || equals(a, b) && area(a.prev, a, a.next) > 0 && area(b.prev, b, b.next) > 0);
	}
	function area(p, q, r) {
	    return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
	}
	function equals(p1, p2) {
	    return p1.x === p2.x && p1.y === p2.y;
	}
	function intersects(p1, q1, p2, q2) {
	    var o1 = sign(area(p1, q1, p2));
	    var o2 = sign(area(p1, q1, q2));
	    var o3 = sign(area(p2, q2, p1));
	    var o4 = sign(area(p2, q2, q1));
	    if (o1 !== o2 && o3 !== o4)
	        return true;
	    if (o1 === 0 && onSegment(p1, p2, q1))
	        return true;
	    if (o2 === 0 && onSegment(p1, q2, q1))
	        return true;
	    if (o3 === 0 && onSegment(p2, p1, q2))
	        return true;
	    if (o4 === 0 && onSegment(p2, q1, q2))
	        return true;
	    return false;
	}
	function onSegment(p, q, r) {
	    return q.x <= Math.max(p.x, r.x) && q.x >= Math.min(p.x, r.x) && q.y <= Math.max(p.y, r.y) && q.y >= Math.min(p.y, r.y);
	}
	function sign(num) {
	    return num > 0 ? 1 : num < 0 ? -1 : 0;
	}
	function intersectsPolygon(a, b) {
	    var p = a;
	    do {
	        if (p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i && intersects(p, p.next, a, b))
	            return true;
	        p = p.next;
	    } while (p !== a);
	    return false;
	}
	function locallyInside(a, b) {
	    return area(a.prev, a, a.next) < 0 ? area(a, b, a.next) >= 0 && area(a, a.prev, b) >= 0 : area(a, b, a.prev) < 0 || area(a, a.next, b) < 0;
	}
	function middleInside(a, b) {
	    var p = a, inside = false, px = (a.x + b.x) / 2, py = (a.y + b.y) / 2;
	    do {
	        if (p.y > py !== p.next.y > py && p.next.y !== p.y && px < (p.next.x - p.x) * (py - p.y) / (p.next.y - p.y) + p.x)
	            inside = !inside;
	        p = p.next;
	    } while (p !== a);
	    return inside;
	}
	function splitPolygon(a, b) {
	    var a2 = new Node(a.i, a.x, a.y), b2 = new Node(b.i, b.x, b.y), an = a.next, bp = b.prev;
	    a.next = b;
	    b.prev = a;
	    a2.next = an;
	    an.prev = a2;
	    b2.next = a2;
	    a2.prev = b2;
	    bp.next = b2;
	    b2.prev = bp;
	    return b2;
	}
	function insertNode(i, x, y, last) {
	    var p = new Node(i, x, y);
	    if (!last) {
	        p.prev = p;
	        p.next = p;
	    } else {
	        p.next = last.next;
	        p.prev = last;
	        last.next.prev = p;
	        last.next = p;
	    }
	    return p;
	}
	function removeNode(p) {
	    p.next.prev = p.prev;
	    p.prev.next = p.next;
	    if (p.prevZ)
	        p.prevZ.nextZ = p.nextZ;
	    if (p.nextZ)
	        p.nextZ.prevZ = p.prevZ;
	}
	function Node(i, x, y) {
	    this.i = i;
	    this.x = x;
	    this.y = y;
	    this.prev = null;
	    this.next = null;
	    this.z = null;
	    this.prevZ = null;
	    this.nextZ = null;
	    this.steiner = false;
	}
	earcut.deviation = function (data, holeIndices, dim, triangles) {
	    var hasHoles = holeIndices && holeIndices.length;
	    var outerLen = hasHoles ? holeIndices[0] * dim : data.length;
	    var polygonArea = Math.abs(signedArea$1(data, 0, outerLen, dim));
	    if (hasHoles) {
	        for (var i = 0, len = holeIndices.length; i < len; i++) {
	            var start = holeIndices[i] * dim;
	            var end = i < len - 1 ? holeIndices[i + 1] * dim : data.length;
	            polygonArea -= Math.abs(signedArea$1(data, start, end, dim));
	        }
	    }
	    var trianglesArea = 0;
	    for (i = 0; i < triangles.length; i += 3) {
	        var a = triangles[i] * dim;
	        var b = triangles[i + 1] * dim;
	        var c = triangles[i + 2] * dim;
	        trianglesArea += Math.abs((data[a] - data[c]) * (data[b + 1] - data[a + 1]) - (data[a] - data[b]) * (data[c + 1] - data[a + 1]));
	    }
	    return polygonArea === 0 && trianglesArea === 0 ? 0 : Math.abs((trianglesArea - polygonArea) / polygonArea);
	};
	function signedArea$1(data, start, end, dim) {
	    var sum = 0;
	    for (var i = start, j = end - dim; i < end; i += dim) {
	        sum += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
	        j = i;
	    }
	    return sum;
	}
	earcut.flatten = function (data) {
	    var dim = data[0][0].length, result = {
	            vertices: [],
	            holes: [],
	            dimensions: dim
	        }, holeIndex = 0;
	    for (var i = 0; i < data.length; i++) {
	        for (var j = 0; j < data[i].length; j++) {
	            for (var d = 0; d < dim; d++)
	                result.vertices.push(data[i][j][d]);
	        }
	        if (i > 0) {
	            holeIndex += data[i - 1].length;
	            result.holes.push(holeIndex);
	        }
	    }
	    return result;
	};
	earcut_1.default = _default;

	function quickselect(arr, k, left, right, compare) {
	    quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare$1);
	}
	function quickselectStep(arr, k, left, right, compare) {
	    while (right > left) {
	        if (right - left > 600) {
	            var n = right - left + 1;
	            var m = k - left + 1;
	            var z = Math.log(n);
	            var s = 0.5 * Math.exp(2 * z / 3);
	            var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
	            var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
	            var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
	            quickselectStep(arr, k, newLeft, newRight, compare);
	        }
	        var t = arr[k];
	        var i = left;
	        var j = right;
	        swap(arr, left, k);
	        if (compare(arr[right], t) > 0)
	            swap(arr, left, right);
	        while (i < j) {
	            swap(arr, i, j);
	            i++;
	            j--;
	            while (compare(arr[i], t) < 0)
	                i++;
	            while (compare(arr[j], t) > 0)
	                j--;
	        }
	        if (compare(arr[left], t) === 0)
	            swap(arr, left, j);
	        else {
	            j++;
	            swap(arr, j, right);
	        }
	        if (j <= k)
	            left = j + 1;
	        if (k <= j)
	            right = j - 1;
	    }
	}
	function swap(arr, i, j) {
	    var tmp = arr[i];
	    arr[i] = arr[j];
	    arr[j] = tmp;
	}
	function defaultCompare$1(a, b) {
	    return a < b ? -1 : a > b ? 1 : 0;
	}

	function classifyRings$1(rings, maxRings) {
	    const len = rings.length;
	    if (len <= 1)
	        return [rings];
	    const polygons = [];
	    let polygon, ccw;
	    for (let i = 0; i < len; i++) {
	        const area = calculateSignedArea(rings[i]);
	        if (area === 0)
	            continue;
	        rings[i].area = Math.abs(area);
	        if (ccw === undefined)
	            ccw = area < 0;
	        if (ccw === area < 0) {
	            if (polygon)
	                polygons.push(polygon);
	            polygon = [rings[i]];
	        } else {
	            polygon.push(rings[i]);
	        }
	    }
	    if (polygon)
	        polygons.push(polygon);
	    if (maxRings > 1) {
	        for (let j = 0; j < polygons.length; j++) {
	            if (polygons[j].length <= maxRings)
	                continue;
	            quickselect(polygons[j], maxRings, 1, polygons[j].length - 1, compareAreas);
	            polygons[j] = polygons[j].slice(0, maxRings);
	        }
	    }
	    return polygons;
	}
	function compareAreas(a, b) {
	    return b.area - a.area;
	}

	function hasPattern(type, layers, options) {
	    const patterns = options.patternDependencies;
	    let hasPattern = false;
	    for (const layer of layers) {
	        const patternProperty = layer.paint.get(`${ type }-pattern`);
	        if (!patternProperty.isConstant()) {
	            hasPattern = true;
	        }
	        const constantPattern = patternProperty.constantOr(null);
	        if (constantPattern) {
	            hasPattern = true;
	            patterns[constantPattern.to] = true;
	            patterns[constantPattern.from] = true;
	        }
	    }
	    return hasPattern;
	}
	function addPatternDependencies(type, layers, patternFeature, zoom, options) {
	    const patterns = options.patternDependencies;
	    for (const layer of layers) {
	        const patternProperty = layer.paint.get(`${ type }-pattern`);
	        const patternPropertyValue = patternProperty.value;
	        if (patternPropertyValue.kind !== 'constant') {
	            let min = patternPropertyValue.evaluate({ zoom: zoom - 1 }, patternFeature, {}, options.availableImages);
	            let mid = patternPropertyValue.evaluate({ zoom }, patternFeature, {}, options.availableImages);
	            let max = patternPropertyValue.evaluate({ zoom: zoom + 1 }, patternFeature, {}, options.availableImages);
	            min = min && min.name ? min.name : min;
	            mid = mid && mid.name ? mid.name : mid;
	            max = max && max.name ? max.name : max;
	            patterns[min] = true;
	            patterns[mid] = true;
	            patterns[max] = true;
	            patternFeature.patterns[layer.id] = {
	                min,
	                mid,
	                max
	            };
	        }
	    }
	    return patternFeature;
	}

	const EARCUT_MAX_RINGS$1 = 500;
	class FillBucket {
	    constructor(options) {
	        this.zoom = options.zoom;
	        this.overscaling = options.overscaling;
	        this.layers = options.layers;
	        this.layerIds = this.layers.map(layer => layer.id);
	        this.index = options.index;
	        this.hasPattern = false;
	        this.patternFeatures = [];
	        this.layoutVertexArray = new StructArrayLayout2i4();
	        this.indexArray = new StructArrayLayout3ui6();
	        this.indexArray2 = new StructArrayLayout2ui4();
	        this.programConfigurations = new ProgramConfigurationSet(options.layers, options.zoom);
	        this.segments = new SegmentVector();
	        this.segments2 = new SegmentVector();
	        this.stateDependentLayerIds = this.layers.filter(l => l.isStateDependent()).map(l => l.id);
	        this.projection = options.projection;
	    }
	    populate(features, options, canonical, tileTransform) {
	        this.hasPattern = hasPattern('fill', this.layers, options);
	        const fillSortKey = this.layers[0].layout.get('fill-sort-key');
	        const bucketFeatures = [];
	        for (const {feature, id, index, sourceLayerIndex} of features) {
	            const needGeometry = this.layers[0]._featureFilter.needGeometry;
	            const evaluationFeature = toEvaluationFeature(feature, needGeometry);
	            if (!this.layers[0]._featureFilter.filter(new EvaluationParameters(this.zoom), evaluationFeature, canonical))
	                continue;
	            const sortKey = fillSortKey ? fillSortKey.evaluate(evaluationFeature, {}, canonical, options.availableImages) : undefined;
	            const bucketFeature = {
	                id,
	                properties: feature.properties,
	                type: feature.type,
	                sourceLayerIndex,
	                index,
	                geometry: needGeometry ? evaluationFeature.geometry : loadGeometry(feature, canonical, tileTransform),
	                patterns: {},
	                sortKey
	            };
	            bucketFeatures.push(bucketFeature);
	        }
	        if (fillSortKey) {
	            bucketFeatures.sort((a, b) => {
	                return a.sortKey - b.sortKey;
	            });
	        }
	        for (const bucketFeature of bucketFeatures) {
	            const {geometry, index, sourceLayerIndex} = bucketFeature;
	            if (this.hasPattern) {
	                const patternFeature = addPatternDependencies('fill', this.layers, bucketFeature, this.zoom, options);
	                this.patternFeatures.push(patternFeature);
	            } else {
	                this.addFeature(bucketFeature, geometry, index, canonical, {}, options.availableImages);
	            }
	            const feature = features[index].feature;
	            options.featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
	        }
	    }
	    update(states, vtLayer, availableImages, imagePositions) {
	        if (!this.stateDependentLayers.length)
	            return;
	        this.programConfigurations.updatePaintArrays(states, vtLayer, this.stateDependentLayers, availableImages, imagePositions);
	    }
	    addFeatures(options, canonical, imagePositions, availableImages, _) {
	        for (const feature of this.patternFeatures) {
	            this.addFeature(feature, feature.geometry, feature.index, canonical, imagePositions, availableImages);
	        }
	    }
	    isEmpty() {
	        return this.layoutVertexArray.length === 0;
	    }
	    uploadPending() {
	        return !this.uploaded || this.programConfigurations.needsUpload;
	    }
	    upload(context) {
	        if (!this.uploaded) {
	            this.layoutVertexBuffer = context.createVertexBuffer(this.layoutVertexArray, members$4);
	            this.indexBuffer = context.createIndexBuffer(this.indexArray);
	            this.indexBuffer2 = context.createIndexBuffer(this.indexArray2);
	        }
	        this.programConfigurations.upload(context);
	        this.uploaded = true;
	    }
	    destroy() {
	        if (!this.layoutVertexBuffer)
	            return;
	        this.layoutVertexBuffer.destroy();
	        this.indexBuffer.destroy();
	        this.indexBuffer2.destroy();
	        this.programConfigurations.destroy();
	        this.segments.destroy();
	        this.segments2.destroy();
	    }
	    addFeature(feature, geometry, index, canonical, imagePositions, availableImages = []) {
	        for (const polygon of classifyRings$1(geometry, EARCUT_MAX_RINGS$1)) {
	            let numVertices = 0;
	            for (const ring of polygon) {
	                numVertices += ring.length;
	            }
	            const triangleSegment = this.segments.prepareSegment(numVertices, this.layoutVertexArray, this.indexArray);
	            const triangleIndex = triangleSegment.vertexLength;
	            const flattened = [];
	            const holeIndices = [];
	            for (const ring of polygon) {
	                if (ring.length === 0) {
	                    continue;
	                }
	                if (ring !== polygon[0]) {
	                    holeIndices.push(flattened.length / 2);
	                }
	                const lineSegment = this.segments2.prepareSegment(ring.length, this.layoutVertexArray, this.indexArray2);
	                const lineIndex = lineSegment.vertexLength;
	                this.layoutVertexArray.emplaceBack(ring[0].x, ring[0].y);
	                this.indexArray2.emplaceBack(lineIndex + ring.length - 1, lineIndex);
	                flattened.push(ring[0].x);
	                flattened.push(ring[0].y);
	                for (let i = 1; i < ring.length; i++) {
	                    this.layoutVertexArray.emplaceBack(ring[i].x, ring[i].y);
	                    this.indexArray2.emplaceBack(lineIndex + i - 1, lineIndex + i);
	                    flattened.push(ring[i].x);
	                    flattened.push(ring[i].y);
	                }
	                lineSegment.vertexLength += ring.length;
	                lineSegment.primitiveLength += ring.length;
	            }
	            const indices = earcut_1(flattened, holeIndices);
	            for (let i = 0; i < indices.length; i += 3) {
	                this.indexArray.emplaceBack(triangleIndex + indices[i], triangleIndex + indices[i + 1], triangleIndex + indices[i + 2]);
	            }
	            triangleSegment.vertexLength += numVertices;
	            triangleSegment.primitiveLength += indices.length / 3;
	        }
	        this.programConfigurations.populatePaintArrays(this.layoutVertexArray.length, feature, index, imagePositions, availableImages, canonical);
	    }
	}
	register(FillBucket, 'FillBucket', {
	    omit: [
	        'layers',
	        'patternFeatures'
	    ]
	});

	const layout$3 = new Properties({ 'fill-sort-key': new DataDrivenProperty(spec['layout_fill']['fill-sort-key']) });
	const paint$6 = new Properties({
	    'fill-antialias': new DataConstantProperty(spec['paint_fill']['fill-antialias']),
	    'fill-opacity': new DataDrivenProperty(spec['paint_fill']['fill-opacity']),
	    'fill-color': new DataDrivenProperty(spec['paint_fill']['fill-color']),
	    'fill-outline-color': new DataDrivenProperty(spec['paint_fill']['fill-outline-color']),
	    'fill-translate': new DataConstantProperty(spec['paint_fill']['fill-translate']),
	    'fill-translate-anchor': new DataConstantProperty(spec['paint_fill']['fill-translate-anchor']),
	    'fill-pattern': new CrossFadedDataDrivenProperty(spec['paint_fill']['fill-pattern'])
	});
	var properties$6 = {
	    paint: paint$6,
	    layout: layout$3
	};

	class FillStyleLayer extends StyleLayer {
	    constructor(layer) {
	        super(layer, properties$6);
	    }
	    getProgramIds() {
	        const pattern = this.paint.get('fill-pattern');
	        const image = pattern && pattern.constantOr(1);
	        const ids = [image ? 'fillPattern' : 'fill'];
	        if (this.paint.get('fill-antialias')) {
	            ids.push(image && !this.getPaintProperty('fill-outline-color') ? 'fillOutlinePattern' : 'fillOutline');
	        }
	        return ids;
	    }
	    getProgramConfiguration(zoom) {
	        return new ProgramConfiguration(this, zoom);
	    }
	    recalculate(parameters, availableImages) {
	        super.recalculate(parameters, availableImages);
	        const outlineColor = this.paint._values['fill-outline-color'];
	        if (outlineColor.value.kind === 'constant' && outlineColor.value.value === undefined) {
	            this.paint._values['fill-outline-color'] = this.paint._values['fill-color'];
	        }
	    }
	    createBucket(parameters) {
	        return new FillBucket(parameters);
	    }
	    queryRadius() {
	        return translateDistance(this.paint.get('fill-translate'));
	    }
	    queryIntersectsFeature(queryGeometry, feature, featureState, geometry, zoom, transform) {
	        if (queryGeometry.queryGeometry.isAboveHorizon)
	            return false;
	        const translatedPolygon = translate$1(queryGeometry.tilespaceGeometry, this.paint.get('fill-translate'), this.paint.get('fill-translate-anchor'), transform.angle, queryGeometry.pixelToTileUnitsFactor);
	        return polygonIntersectsMultiPolygon(translatedPolygon, geometry);
	    }
	    isTileClipped() {
	        return true;
	    }
	}

	const fillExtrusionAttributes = createLayout([{
	        name: 'a_pos_normal_ed',
	        components: 4,
	        type: 'Int16'
	    }]);
	const centroidAttributes = createLayout([{
	        name: 'a_centroid_pos',
	        components: 2,
	        type: 'Uint16'
	    }]);
	const fillExtrusionAttributesExt = createLayout([
	    {
	        name: 'a_pos_3',
	        components: 3,
	        type: 'Int16'
	    },
	    {
	        name: 'a_pos_normal_3',
	        components: 3,
	        type: 'Int16'
	    }
	]);
	const {members: members$3, size: size$3, alignment: alignment$3} = fillExtrusionAttributes;

	var vectortilefeature = VectorTileFeature$1;
	function VectorTileFeature$1(pbf, end, extent, keys, values) {
	    this.properties = {};
	    this.extent = extent;
	    this.type = 0;
	    this._pbf = pbf;
	    this._geometry = -1;
	    this._keys = keys;
	    this._values = values;
	    pbf.readFields(readFeature, this, end);
	}
	function readFeature(tag, feature, pbf) {
	    if (tag == 1)
	        feature.id = pbf.readVarint();
	    else if (tag == 2)
	        readTag(pbf, feature);
	    else if (tag == 3)
	        feature.type = pbf.readVarint();
	    else if (tag == 4)
	        feature._geometry = pbf.pos;
	}
	function readTag(pbf, feature) {
	    var end = pbf.readVarint() + pbf.pos;
	    while (pbf.pos < end) {
	        var key = feature._keys[pbf.readVarint()], value = feature._values[pbf.readVarint()];
	        feature.properties[key] = value;
	    }
	}
	VectorTileFeature$1.types = [
	    'Unknown',
	    'Point',
	    'LineString',
	    'Polygon'
	];
	VectorTileFeature$1.prototype.loadGeometry = function () {
	    var pbf = this._pbf;
	    pbf.pos = this._geometry;
	    var end = pbf.readVarint() + pbf.pos, cmd = 1, length = 0, x = 0, y = 0, lines = [], line;
	    while (pbf.pos < end) {
	        if (length <= 0) {
	            var cmdLen = pbf.readVarint();
	            cmd = cmdLen & 7;
	            length = cmdLen >> 3;
	        }
	        length--;
	        if (cmd === 1 || cmd === 2) {
	            x += pbf.readSVarint();
	            y += pbf.readSVarint();
	            if (cmd === 1) {
	                if (line)
	                    lines.push(line);
	                line = [];
	            }
	            line.push(new pointGeometry(x, y));
	        } else if (cmd === 7) {
	            if (line) {
	                line.push(line[0].clone());
	            }
	        } else {
	            throw new Error('unknown command ' + cmd);
	        }
	    }
	    if (line)
	        lines.push(line);
	    return lines;
	};
	VectorTileFeature$1.prototype.bbox = function () {
	    var pbf = this._pbf;
	    pbf.pos = this._geometry;
	    var end = pbf.readVarint() + pbf.pos, cmd = 1, length = 0, x = 0, y = 0, x1 = Infinity, x2 = -Infinity, y1 = Infinity, y2 = -Infinity;
	    while (pbf.pos < end) {
	        if (length <= 0) {
	            var cmdLen = pbf.readVarint();
	            cmd = cmdLen & 7;
	            length = cmdLen >> 3;
	        }
	        length--;
	        if (cmd === 1 || cmd === 2) {
	            x += pbf.readSVarint();
	            y += pbf.readSVarint();
	            if (x < x1)
	                x1 = x;
	            if (x > x2)
	                x2 = x;
	            if (y < y1)
	                y1 = y;
	            if (y > y2)
	                y2 = y;
	        } else if (cmd !== 7) {
	            throw new Error('unknown command ' + cmd);
	        }
	    }
	    return [
	        x1,
	        y1,
	        x2,
	        y2
	    ];
	};
	VectorTileFeature$1.prototype.toGeoJSON = function (x, y, z) {
	    var size = this.extent * Math.pow(2, z), x0 = this.extent * x, y0 = this.extent * y, coords = this.loadGeometry(), type = VectorTileFeature$1.types[this.type], i, j;
	    function project(line) {
	        for (var j = 0; j < line.length; j++) {
	            var p = line[j], y2 = 180 - (p.y + y0) * 360 / size;
	            line[j] = [
	                (p.x + x0) * 360 / size - 180,
	                360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90
	            ];
	        }
	    }
	    switch (this.type) {
	    case 1:
	        var points = [];
	        for (i = 0; i < coords.length; i++) {
	            points[i] = coords[i][0];
	        }
	        coords = points;
	        project(coords);
	        break;
	    case 2:
	        for (i = 0; i < coords.length; i++) {
	            project(coords[i]);
	        }
	        break;
	    case 3:
	        coords = classifyRings(coords);
	        for (i = 0; i < coords.length; i++) {
	            for (j = 0; j < coords[i].length; j++) {
	                project(coords[i][j]);
	            }
	        }
	        break;
	    }
	    if (coords.length === 1) {
	        coords = coords[0];
	    } else {
	        type = 'Multi' + type;
	    }
	    var result = {
	        type: 'Feature',
	        geometry: {
	            type: type,
	            coordinates: coords
	        },
	        properties: this.properties
	    };
	    if ('id' in this) {
	        result.id = this.id;
	    }
	    return result;
	};
	function classifyRings(rings) {
	    var len = rings.length;
	    if (len <= 1)
	        return [rings];
	    var polygons = [], polygon, ccw;
	    for (var i = 0; i < len; i++) {
	        var area = signedArea(rings[i]);
	        if (area === 0)
	            continue;
	        if (ccw === undefined)
	            ccw = area < 0;
	        if (ccw === area < 0) {
	            if (polygon)
	                polygons.push(polygon);
	            polygon = [rings[i]];
	        } else {
	            polygon.push(rings[i]);
	        }
	    }
	    if (polygon)
	        polygons.push(polygon);
	    return polygons;
	}
	function signedArea(ring) {
	    var sum = 0;
	    for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
	        p1 = ring[i];
	        p2 = ring[j];
	        sum += (p2.x - p1.x) * (p1.y + p2.y);
	    }
	    return sum;
	}

	var vectortilelayer = VectorTileLayer$1;
	function VectorTileLayer$1(pbf, end) {
	    this.version = 1;
	    this.name = null;
	    this.extent = 4096;
	    this.length = 0;
	    this._pbf = pbf;
	    this._keys = [];
	    this._values = [];
	    this._features = [];
	    pbf.readFields(readLayer, this, end);
	    this.length = this._features.length;
	}
	function readLayer(tag, layer, pbf) {
	    if (tag === 15)
	        layer.version = pbf.readVarint();
	    else if (tag === 1)
	        layer.name = pbf.readString();
	    else if (tag === 5)
	        layer.extent = pbf.readVarint();
	    else if (tag === 2)
	        layer._features.push(pbf.pos);
	    else if (tag === 3)
	        layer._keys.push(pbf.readString());
	    else if (tag === 4)
	        layer._values.push(readValueMessage(pbf));
	}
	function readValueMessage(pbf) {
	    var value = null, end = pbf.readVarint() + pbf.pos;
	    while (pbf.pos < end) {
	        var tag = pbf.readVarint() >> 3;
	        value = tag === 1 ? pbf.readString() : tag === 2 ? pbf.readFloat() : tag === 3 ? pbf.readDouble() : tag === 4 ? pbf.readVarint64() : tag === 5 ? pbf.readVarint() : tag === 6 ? pbf.readSVarint() : tag === 7 ? pbf.readBoolean() : null;
	    }
	    return value;
	}
	VectorTileLayer$1.prototype.feature = function (i) {
	    if (i < 0 || i >= this._features.length)
	        throw new Error('feature index out of bounds');
	    this._pbf.pos = this._features[i];
	    var end = this._pbf.readVarint() + this._pbf.pos;
	    return new vectortilefeature(this._pbf, end, this.extent, this._keys, this._values);
	};

	var vectortile = VectorTile$1;
	function VectorTile$1(pbf, end) {
	    this.layers = pbf.readFields(readTile, {}, end);
	}
	function readTile(tag, layers, pbf) {
	    if (tag === 3) {
	        var layer = new vectortilelayer(pbf, pbf.readVarint() + pbf.pos);
	        if (layer.length)
	            layers[layer.name] = layer;
	    }
	}

	var VectorTile = vectortile;
	var VectorTileFeature = vectortilefeature;
	var VectorTileLayer = vectortilelayer;

	var vectorTile = {
		VectorTile: VectorTile,
		VectorTileFeature: VectorTileFeature,
		VectorTileLayer: VectorTileLayer
	};

	function clipPolygon(polygons, clipAxis1, clipAxis2, axis) {
	    const intersectX = (ring, ax, ay, bx, by, x) => {
	        ring.push(new pointGeometry(x, ay + (by - ay) * ((x - ax) / (bx - ax))));
	    };
	    const intersectY = (ring, ax, ay, bx, by, y) => {
	        ring.push(new pointGeometry(ax + (bx - ax) * ((y - ay) / (by - ay)), y));
	    };
	    const polygonsClipped = [];
	    const intersect = axis === 0 ? intersectX : intersectY;
	    for (const polygon of polygons) {
	        const polygonClipped = [];
	        for (const ring of polygon) {
	            if (ring.length <= 2) {
	                continue;
	            }
	            const clipped = [];
	            for (let i = 0; i < ring.length - 1; i++) {
	                const ax = ring[i].x;
	                const ay = ring[i].y;
	                const bx = ring[i + 1].x;
	                const by = ring[i + 1].y;
	                const a = axis === 0 ? ax : ay;
	                const b = axis === 0 ? bx : by;
	                if (a < clipAxis1) {
	                    if (b > clipAxis1) {
	                        intersect(clipped, ax, ay, bx, by, clipAxis1);
	                    }
	                } else if (a > clipAxis2) {
	                    if (b < clipAxis2) {
	                        intersect(clipped, ax, ay, bx, by, clipAxis2);
	                    }
	                } else {
	                    clipped.push(ring[i]);
	                }
	                if (b < clipAxis1 && a >= clipAxis1) {
	                    intersect(clipped, ax, ay, bx, by, clipAxis1);
	                }
	                if (b > clipAxis2 && a <= clipAxis2) {
	                    intersect(clipped, ax, ay, bx, by, clipAxis2);
	                }
	            }
	            let last = ring[ring.length - 1];
	            const a = axis === 0 ? last.x : last.y;
	            if (a >= clipAxis1 && a <= clipAxis2) {
	                clipped.push(last);
	            }
	            if (clipped.length) {
	                last = clipped[clipped.length - 1];
	                if (clipped[0].x !== last.x || clipped[0].y !== last.y) {
	                    clipped.push(clipped[0]);
	                }
	                polygonClipped.push(clipped);
	            }
	        }
	        if (polygonClipped.length) {
	            polygonsClipped.push(polygonClipped);
	        }
	    }
	    return polygonsClipped;
	}
	function subdividePolygons(polygons, bounds, gridSizeX, gridSizeY, padding = 0, splitFn) {
	    const outPolygons = [];
	    if (!polygons.length || !gridSizeX || !gridSizeY) {
	        return outPolygons;
	    }
	    const addResult = (clipped, bounds) => {
	        for (const polygon of clipped) {
	            outPolygons.push({
	                polygon,
	                bounds
	            });
	        }
	    };
	    const hSplits = Math.ceil(Math.log2(gridSizeX));
	    const vSplits = Math.ceil(Math.log2(gridSizeY));
	    const initialSplits = hSplits - vSplits;
	    const splits = [];
	    for (let i = 0; i < Math.abs(initialSplits); i++) {
	        splits.push(initialSplits > 0 ? 0 : 1);
	    }
	    for (let i = 0; i < Math.min(hSplits, vSplits); i++) {
	        splits.push(0);
	        splits.push(1);
	    }
	    let split = polygons;
	    split = clipPolygon(split, bounds[0].y - padding, bounds[1].y + padding, 1);
	    split = clipPolygon(split, bounds[0].x - padding, bounds[1].x + padding, 0);
	    if (!split.length) {
	        return outPolygons;
	    }
	    const stack = [];
	    if (splits.length) {
	        stack.push({
	            polygons: split,
	            bounds,
	            depth: 0
	        });
	    } else {
	        addResult(split, bounds);
	    }
	    while (stack.length) {
	        const frame = stack.pop();
	        const depth = frame.depth;
	        const axis = splits[depth];
	        const bboxMin = frame.bounds[0];
	        const bboxMax = frame.bounds[1];
	        const splitMin = axis === 0 ? bboxMin.x : bboxMin.y;
	        const splitMax = axis === 0 ? bboxMax.x : bboxMax.y;
	        const splitMid = splitFn ? splitFn(axis, splitMin, splitMax) : 0.5 * (splitMin + splitMax);
	        const lclip = clipPolygon(frame.polygons, splitMin - padding, splitMid + padding, axis);
	        const rclip = clipPolygon(frame.polygons, splitMid - padding, splitMax + padding, axis);
	        if (lclip.length) {
	            const bbMaxX = axis === 0 ? splitMid : bboxMax.x;
	            const bbMaxY = axis === 1 ? splitMid : bboxMax.y;
	            const bbMax = new pointGeometry(bbMaxX, bbMaxY);
	            const lclipBounds = [
	                bboxMin,
	                bbMax
	            ];
	            if (splits.length > depth + 1) {
	                stack.push({
	                    polygons: lclip,
	                    bounds: lclipBounds,
	                    depth: depth + 1
	                });
	            } else {
	                addResult(lclip, lclipBounds);
	            }
	        }
	        if (rclip.length) {
	            const bbMinX = axis === 0 ? splitMid : bboxMin.x;
	            const bbMinY = axis === 1 ? splitMid : bboxMin.y;
	            const bbMin = new pointGeometry(bbMinX, bbMinY);
	            const rclipBounds = [
	                bbMin,
	                bboxMax
	            ];
	            if (splits.length > depth + 1) {
	                stack.push({
	                    polygons: rclip,
	                    bounds: rclipBounds,
	                    depth: depth + 1
	                });
	            } else {
	                addResult(rclip, rclipBounds);
	            }
	        }
	    }
	    return outPolygons;
	}

	const vectorTileFeatureTypes$2 = vectorTile.VectorTileFeature.types;
	const EARCUT_MAX_RINGS = 500;
	const FACTOR = Math.pow(2, 13);
	const ELEVATION_SCALE = 7;
	const ELEVATION_OFFSET = 450;
	function addVertex$1(vertexArray, x, y, nxRatio, nySign, normalUp, top, e) {
	    vertexArray.emplaceBack((x << 1) + top, (y << 1) + normalUp, (Math.floor(nxRatio * FACTOR) << 1) + nySign, Math.round(e));
	}
	function addGlobeExtVertex(vertexArray, pos, normal) {
	    const encode = 1 << 14;
	    vertexArray.emplaceBack(pos.x, pos.y, pos.z, normal[0] * encode, normal[1] * encode, normal[2] * encode);
	}
	class PartMetadata {
	    constructor() {
	        this.acc = new pointGeometry(0, 0);
	        this.polyCount = [];
	    }
	    startRing(p) {
	        this.currentPolyCount = {
	            edges: 0,
	            top: 0
	        };
	        this.polyCount.push(this.currentPolyCount);
	        if (this.min)
	            return;
	        this.min = new pointGeometry(p.x, p.y);
	        this.max = new pointGeometry(p.x, p.y);
	    }
	    append(p, prev) {
	        this.currentPolyCount.edges++;
	        this.acc._add(p);
	        const min = this.min, max = this.max;
	        if (p.x < min.x) {
	            min.x = p.x;
	        } else if (p.x > max.x) {
	            max.x = p.x;
	        }
	        if (p.y < min.y) {
	            min.y = p.y;
	        } else if (p.y > max.y) {
	            max.y = p.y;
	        }
	        if (((p.x === 0 || p.x === EXTENT) && p.x === prev.x) !== ((p.y === 0 || p.y === EXTENT) && p.y === prev.y)) {
	            this.processBorderOverlap(p, prev);
	        }
	        if (prev.x < 0 !== p.x < 0) {
	            this.addBorderIntersection(0, number(prev.y, p.y, (0 - prev.x) / (p.x - prev.x)));
	        }
	        if (prev.x > EXTENT !== p.x > EXTENT) {
	            this.addBorderIntersection(1, number(prev.y, p.y, (EXTENT - prev.x) / (p.x - prev.x)));
	        }
	        if (prev.y < 0 !== p.y < 0) {
	            this.addBorderIntersection(2, number(prev.x, p.x, (0 - prev.y) / (p.y - prev.y)));
	        }
	        if (prev.y > EXTENT !== p.y > EXTENT) {
	            this.addBorderIntersection(3, number(prev.x, p.x, (EXTENT - prev.y) / (p.y - prev.y)));
	        }
	    }
	    addBorderIntersection(index, i) {
	        if (!this.borders) {
	            this.borders = [
	                [
	                    Number.MAX_VALUE,
	                    -Number.MAX_VALUE
	                ],
	                [
	                    Number.MAX_VALUE,
	                    -Number.MAX_VALUE
	                ],
	                [
	                    Number.MAX_VALUE,
	                    -Number.MAX_VALUE
	                ],
	                [
	                    Number.MAX_VALUE,
	                    -Number.MAX_VALUE
	                ]
	            ];
	        }
	        const b = this.borders[index];
	        if (i < b[0])
	            b[0] = i;
	        if (i > b[1])
	            b[1] = i;
	    }
	    processBorderOverlap(p, prev) {
	        if (p.x === prev.x) {
	            if (p.y === prev.y)
	                return;
	            const index = p.x === 0 ? 0 : 1;
	            this.addBorderIntersection(index, prev.y);
	            this.addBorderIntersection(index, p.y);
	        } else {
	            const index = p.y === 0 ? 2 : 3;
	            this.addBorderIntersection(index, prev.x);
	            this.addBorderIntersection(index, p.x);
	        }
	    }
	    centroid() {
	        const count = this.polyCount.reduce((acc, p) => acc + p.edges, 0);
	        return count !== 0 ? this.acc.div(count)._round() : new pointGeometry(0, 0);
	    }
	    span() {
	        return new pointGeometry(this.max.x - this.min.x, this.max.y - this.min.y);
	    }
	    intersectsCount() {
	        return this.borders.reduce((acc, p) => acc + +(p[0] !== Number.MAX_VALUE), 0);
	    }
	}
	class FillExtrusionBucket {
	    constructor(options) {
	        this.zoom = options.zoom;
	        this.canonical = options.canonical;
	        this.overscaling = options.overscaling;
	        this.layers = options.layers;
	        this.layerIds = this.layers.map(layer => layer.id);
	        this.index = options.index;
	        this.hasPattern = false;
	        this.projection = options.projection;
	        this.layoutVertexArray = new StructArrayLayout4i8();
	        this.centroidVertexArray = new FillExtrusionCentroidArray();
	        this.indexArray = new StructArrayLayout3ui6();
	        this.programConfigurations = new ProgramConfigurationSet(options.layers, options.zoom);
	        this.segments = new SegmentVector();
	        this.stateDependentLayerIds = this.layers.filter(l => l.isStateDependent()).map(l => l.id);
	        this.enableTerrain = options.enableTerrain;
	    }
	    populate(features, options, canonical, tileTransform) {
	        this.features = [];
	        this.hasPattern = hasPattern('fill-extrusion', this.layers, options);
	        this.featuresOnBorder = [];
	        this.borders = [
	            [],
	            [],
	            [],
	            []
	        ];
	        this.borderDoneWithNeighborZ = [
	            -1,
	            -1,
	            -1,
	            -1
	        ];
	        this.tileToMeter = tileToMeter(canonical);
	        for (const {feature, id, index, sourceLayerIndex} of features) {
	            const needGeometry = this.layers[0]._featureFilter.needGeometry;
	            const evaluationFeature = toEvaluationFeature(feature, needGeometry);
	            if (!this.layers[0]._featureFilter.filter(new EvaluationParameters(this.zoom), evaluationFeature, canonical))
	                continue;
	            const bucketFeature = {
	                id,
	                sourceLayerIndex,
	                index,
	                geometry: needGeometry ? evaluationFeature.geometry : loadGeometry(feature, canonical, tileTransform),
	                properties: feature.properties,
	                type: feature.type,
	                patterns: {}
	            };
	            const vertexArrayOffset = this.layoutVertexArray.length;
	            if (this.hasPattern) {
	                this.features.push(addPatternDependencies('fill-extrusion', this.layers, bucketFeature, this.zoom, options));
	            } else {
	                this.addFeature(bucketFeature, bucketFeature.geometry, index, canonical, {}, options.availableImages, tileTransform);
	            }
	            options.featureIndex.insert(feature, bucketFeature.geometry, index, sourceLayerIndex, this.index, vertexArrayOffset);
	        }
	        this.sortBorders();
	    }
	    addFeatures(options, canonical, imagePositions, availableImages, tileTransform) {
	        for (const feature of this.features) {
	            const {geometry} = feature;
	            this.addFeature(feature, geometry, feature.index, canonical, imagePositions, availableImages, tileTransform);
	        }
	        this.sortBorders();
	    }
	    update(states, vtLayer, availableImages, imagePositions) {
	        if (!this.stateDependentLayers.length)
	            return;
	        this.programConfigurations.updatePaintArrays(states, vtLayer, this.stateDependentLayers, availableImages, imagePositions);
	    }
	    isEmpty() {
	        return this.layoutVertexArray.length === 0;
	    }
	    uploadPending() {
	        return !this.uploaded || this.programConfigurations.needsUpload;
	    }
	    upload(context) {
	        if (!this.uploaded) {
	            this.layoutVertexBuffer = context.createVertexBuffer(this.layoutVertexArray, members$3);
	            this.indexBuffer = context.createIndexBuffer(this.indexArray);
	            if (this.layoutVertexExtArray) {
	                this.layoutVertexExtBuffer = context.createVertexBuffer(this.layoutVertexExtArray, fillExtrusionAttributesExt.members, true);
	            }
	        }
	        this.programConfigurations.upload(context);
	        this.uploaded = true;
	    }
	    uploadCentroid(context) {
	        if (this.centroidVertexArray.length === 0)
	            return;
	        if (!this.centroidVertexBuffer) {
	            this.centroidVertexBuffer = context.createVertexBuffer(this.centroidVertexArray, centroidAttributes.members, true);
	        } else if (this.needsCentroidUpdate) {
	            this.centroidVertexBuffer.updateData(this.centroidVertexArray);
	        }
	        this.needsCentroidUpdate = false;
	    }
	    destroy() {
	        if (!this.layoutVertexBuffer)
	            return;
	        this.layoutVertexBuffer.destroy();
	        if (this.centroidVertexBuffer) {
	            this.centroidVertexBuffer.destroy();
	        }
	        if (this.layoutVertexExtBuffer) {
	            this.layoutVertexExtBuffer.destroy();
	        }
	        this.indexBuffer.destroy();
	        this.programConfigurations.destroy();
	        this.segments.destroy();
	    }
	    addFeature(feature, geometry, index, canonical, imagePositions, availableImages, tileTransform) {
	        const tileBounds = [
	            new pointGeometry(0, 0),
	            new pointGeometry(EXTENT, EXTENT)
	        ];
	        const projection = tileTransform.projection;
	        const isGlobe = projection.name === 'globe';
	        const metadata = this.enableTerrain && !isGlobe ? new PartMetadata() : null;
	        if (isGlobe && !this.layoutVertexExtArray) {
	            this.layoutVertexExtArray = new FillExtrusionExtArray();
	        }
	        const polygons = classifyRings$1(geometry, EARCUT_MAX_RINGS);
	        for (let i = polygons.length - 1; i >= 0; i--) {
	            const polygon = polygons[i];
	            if (polygon.length === 0 || isEntirelyOutside(polygon[0])) {
	                polygons.splice(i, 1);
	            }
	        }
	        let clippedPolygons;
	        if (isGlobe) {
	            clippedPolygons = resampleFillExtrusionPolygonsForGlobe(polygons, tileBounds, canonical);
	        } else {
	            clippedPolygons = [];
	            for (const polygon of polygons) {
	                clippedPolygons.push({
	                    polygon,
	                    bounds: tileBounds
	                });
	            }
	        }
	        for (const clippedPolygon of clippedPolygons) {
	            const polygon = clippedPolygon.polygon;
	            let numVertices = 0;
	            let segment = this.segments.prepareSegment(4, this.layoutVertexArray, this.indexArray);
	            for (let i = 0; i < polygon.length; i++) {
	                const ring = polygon[i];
	                if (ring.length === 0) {
	                    continue;
	                }
	                numVertices += ring.length;
	                let edgeDistance = 0;
	                if (metadata)
	                    metadata.startRing(ring[0]);
	                for (let p = 0; p < ring.length; p++) {
	                    const p1 = ring[p];
	                    if (p >= 1) {
	                        const p2 = ring[p - 1];
	                        if (!isBoundaryEdge(p1, p2, clippedPolygon.bounds)) {
	                            if (metadata)
	                                metadata.append(p1, p2);
	                            if (segment.vertexLength + 4 > SegmentVector.MAX_VERTEX_ARRAY_LENGTH) {
	                                segment = this.segments.prepareSegment(4, this.layoutVertexArray, this.indexArray);
	                            }
	                            const d = p1.sub(p2)._perp();
	                            const nxRatio = d.x / (Math.abs(d.x) + Math.abs(d.y));
	                            const nySign = d.y > 0 ? 1 : 0;
	                            const dist = p2.dist(p1);
	                            if (edgeDistance + dist > 32768)
	                                edgeDistance = 0;
	                            addVertex$1(this.layoutVertexArray, p1.x, p1.y, nxRatio, nySign, 0, 0, edgeDistance);
	                            addVertex$1(this.layoutVertexArray, p1.x, p1.y, nxRatio, nySign, 0, 1, edgeDistance);
	                            edgeDistance += dist;
	                            addVertex$1(this.layoutVertexArray, p2.x, p2.y, nxRatio, nySign, 0, 0, edgeDistance);
	                            addVertex$1(this.layoutVertexArray, p2.x, p2.y, nxRatio, nySign, 0, 1, edgeDistance);
	                            const bottomRight = segment.vertexLength;
	                            this.indexArray.emplaceBack(bottomRight, bottomRight + 2, bottomRight + 1);
	                            this.indexArray.emplaceBack(bottomRight + 1, bottomRight + 2, bottomRight + 3);
	                            segment.vertexLength += 4;
	                            segment.primitiveLength += 2;
	                            if (isGlobe) {
	                                const array = this.layoutVertexExtArray;
	                                const projectedP1 = projection.projectTilePoint(p1.x, p1.y, canonical);
	                                const projectedP2 = projection.projectTilePoint(p2.x, p2.y, canonical);
	                                const n1 = projection.upVector(canonical, p1.x, p1.y);
	                                const n2 = projection.upVector(canonical, p2.x, p2.y);
	                                addGlobeExtVertex(array, projectedP1, n1);
	                                addGlobeExtVertex(array, projectedP1, n1);
	                                addGlobeExtVertex(array, projectedP2, n2);
	                                addGlobeExtVertex(array, projectedP2, n2);
	                            }
	                        }
	                    }
	                }
	            }
	            if (segment.vertexLength + numVertices > SegmentVector.MAX_VERTEX_ARRAY_LENGTH) {
	                segment = this.segments.prepareSegment(numVertices, this.layoutVertexArray, this.indexArray);
	            }
	            if (vectorTileFeatureTypes$2[feature.type] !== 'Polygon')
	                continue;
	            const flattened = [];
	            const holeIndices = [];
	            const triangleIndex = segment.vertexLength;
	            for (let i = 0; i < polygon.length; i++) {
	                const ring = polygon[i];
	                if (ring.length === 0) {
	                    continue;
	                }
	                if (ring !== polygon[0]) {
	                    holeIndices.push(flattened.length / 2);
	                }
	                for (let i = 0; i < ring.length; i++) {
	                    const p = ring[i];
	                    addVertex$1(this.layoutVertexArray, p.x, p.y, 0, 0, 1, 1, 0);
	                    flattened.push(p.x);
	                    flattened.push(p.y);
	                    if (metadata)
	                        metadata.currentPolyCount.top++;
	                    if (isGlobe) {
	                        const array = this.layoutVertexExtArray;
	                        const projectedP = projection.projectTilePoint(p.x, p.y, canonical);
	                        const n = projection.upVector(canonical, p.x, p.y);
	                        addGlobeExtVertex(array, projectedP, n);
	                    }
	                }
	            }
	            const indices = earcut_1(flattened, holeIndices);
	            for (let j = 0; j < indices.length; j += 3) {
	                this.indexArray.emplaceBack(triangleIndex + indices[j], triangleIndex + indices[j + 2], triangleIndex + indices[j + 1]);
	            }
	            segment.primitiveLength += indices.length / 3;
	            segment.vertexLength += numVertices;
	        }
	        if (metadata && metadata.polyCount.length > 0) {
	            if (metadata.borders) {
	                metadata.vertexArrayOffset = this.centroidVertexArray.length;
	                const borders = metadata.borders;
	                const index = this.featuresOnBorder.push(metadata) - 1;
	                for (let i = 0; i < 4; i++) {
	                    if (borders[i][0] !== Number.MAX_VALUE) {
	                        this.borders[i].push(index);
	                    }
	                }
	            }
	            this.encodeCentroid(metadata.borders ? undefined : metadata.centroid(), metadata);
	        }
	        this.programConfigurations.populatePaintArrays(this.layoutVertexArray.length, feature, index, imagePositions, availableImages, canonical);
	    }
	    sortBorders() {
	        for (let i = 0; i < 4; i++) {
	            this.borders[i].sort((a, b) => this.featuresOnBorder[a].borders[i][0] - this.featuresOnBorder[b].borders[i][0]);
	        }
	    }
	    encodeCentroid(c, metadata, append = true) {
	        let x, y;
	        if (c) {
	            if (c.y !== 0) {
	                const span = metadata.span()._mult(this.tileToMeter);
	                x = (Math.max(c.x, 1) << 3) + Math.min(7, Math.round(span.x / 10));
	                y = (Math.max(c.y, 1) << 3) + Math.min(7, Math.round(span.y / 10));
	            } else {
	                x = Math.ceil((c.x + ELEVATION_OFFSET) * ELEVATION_SCALE);
	                y = 0;
	            }
	        } else {
	            x = 0;
	            y = +append;
	        }
	        let offset = append ? this.centroidVertexArray.length : metadata.vertexArrayOffset;
	        for (const polyInfo of metadata.polyCount) {
	            if (append) {
	                this.centroidVertexArray.resize(this.centroidVertexArray.length + polyInfo.edges * 4 + polyInfo.top);
	            }
	            for (let i = 0; i < polyInfo.edges * 2; i++) {
	                this.centroidVertexArray.emplace(offset++, 0, y);
	                this.centroidVertexArray.emplace(offset++, x, y);
	            }
	            for (let i = 0; i < polyInfo.top; i++) {
	                this.centroidVertexArray.emplace(offset++, x, y);
	            }
	        }
	    }
	}
	register(FillExtrusionBucket, 'FillExtrusionBucket', {
	    omit: [
	        'layers',
	        'features'
	    ]
	});
	register(PartMetadata, 'PartMetadata');
	function isBoundaryEdge(p1, p2, bounds) {
	    return p1.x === p2.x && (p1.x < bounds[0].x || p1.x > bounds[1].x) || p1.y === p2.y && (p1.y < bounds[0].y || p1.y > bounds[1].y);
	}
	function isEntirelyOutside(ring) {
	    return ring.every(p => p.x <= 0) || ring.every(p => p.x >= EXTENT) || ring.every(p => p.y <= 0) || ring.every(p => p.y >= EXTENT);
	}
	function tileToMeter(canonical) {
	    const circumferenceAtEquator = 40075017;
	    const mercatorY = canonical.y / (1 << canonical.z);
	    const exp = Math.exp(Math.PI * (1 - 2 * mercatorY));
	    return circumferenceAtEquator * 2 * exp / (exp * exp + 1) / EXTENT / (1 << canonical.z);
	}
	function fillExtrusionHeightLift() {
	    const angle = Math.PI / 32;
	    const tanAngle = Math.tan(angle);
	    const r = earthRadius;
	    return r * Math.sqrt(1 + 2 * tanAngle * tanAngle) - r;
	}
	function resampleFillExtrusionPolygonsForGlobe(polygons, tileBounds, tileID) {
	    const cellCount = 360 / 32;
	    const tiles = 1 << tileID.z;
	    const leftLng = lngFromMercatorX(tileID.x / tiles);
	    const rightLng = lngFromMercatorX((tileID.x + 1) / tiles);
	    const topLat = latFromMercatorY(tileID.y / tiles);
	    const bottomLat = latFromMercatorY((tileID.y + 1) / tiles);
	    const cellCountOnXAxis = Math.ceil((rightLng - leftLng) / cellCount);
	    const cellCountOnYAxis = Math.ceil((topLat - bottomLat) / cellCount);
	    const splitFn = (axis, min, max) => {
	        if (axis === 0) {
	            return 0.5 * (min + max);
	        } else {
	            const maxLat = latFromMercatorY((tileID.y + min / EXTENT) / tiles);
	            const minLat = latFromMercatorY((tileID.y + max / EXTENT) / tiles);
	            const midLat = 0.5 * (minLat + maxLat);
	            return (mercatorYfromLat(midLat) * tiles - tileID.y) * EXTENT;
	        }
	    };
	    return subdividePolygons(polygons, tileBounds, cellCountOnXAxis, cellCountOnYAxis, 1, splitFn);
	}

	const paint$5 = new Properties({
	    'fill-extrusion-opacity': new DataConstantProperty(spec['paint_fill-extrusion']['fill-extrusion-opacity']),
	    'fill-extrusion-color': new DataDrivenProperty(spec['paint_fill-extrusion']['fill-extrusion-color']),
	    'fill-extrusion-translate': new DataConstantProperty(spec['paint_fill-extrusion']['fill-extrusion-translate']),
	    'fill-extrusion-translate-anchor': new DataConstantProperty(spec['paint_fill-extrusion']['fill-extrusion-translate-anchor']),
	    'fill-extrusion-pattern': new CrossFadedDataDrivenProperty(spec['paint_fill-extrusion']['fill-extrusion-pattern']),
	    'fill-extrusion-height': new DataDrivenProperty(spec['paint_fill-extrusion']['fill-extrusion-height']),
	    'fill-extrusion-base': new DataDrivenProperty(spec['paint_fill-extrusion']['fill-extrusion-base']),
	    'fill-extrusion-vertical-gradient': new DataConstantProperty(spec['paint_fill-extrusion']['fill-extrusion-vertical-gradient'])
	});
	var properties$5 = { paint: paint$5 };

	/**
	 * getTileBBox
	 *
	 * @param    {Number}  x  Tile coordinate x
	 * @param    {Number}  y  Tile coordinate y
	 * @param    {Number}  z  Tile zoom
	 * @returns  {String}  String of the bounding box
	 */
	function getTileBBox(x, y, z) {
	    // for Google/OSM tile scheme we need to alter the y
	    y = (Math.pow(2, z) - y - 1);

	    var min = getMercCoords(x * 256, y * 256, z),
	        max = getMercCoords((x + 1) * 256, (y + 1) * 256, z);

	    return min[0] + ',' + min[1] + ',' + max[0] + ',' + max[1];
	}


	/**
	 * getMercCoords
	 *
	 * @param    {Number}  x  Pixel coordinate x
	 * @param    {Number}  y  Pixel coordinate y
	 * @param    {Number}  z  Tile zoom
	 * @returns  {Array}   [x, y]
	 */
	function getMercCoords(x, y, z) {
	    var resolution = (2 * Math.PI * 6378137 / 256) / Math.pow(2, z),
	        merc_x = (x * resolution - 2 * Math.PI  * 6378137 / 2.0),
	        merc_y = (y * resolution - 2 * Math.PI  * 6378137 / 2.0);

	    return [merc_x, merc_y];
	}

	class CanonicalTileID {
	    constructor(z, x, y) {
	        this.z = z;
	        this.x = x;
	        this.y = y;
	        this.key = calculateKey(0, z, z, x, y);
	    }
	    equals(id) {
	        return this.z === id.z && this.x === id.x && this.y === id.y;
	    }
	    url(urls, scheme) {
	        const bbox = getTileBBox(this.x, this.y, this.z);
	        const quadkey = getQuadkey(this.z, this.x, this.y);
	        return urls[(this.x + this.y) % urls.length].replace('{prefix}', (this.x % 16).toString(16) + (this.y % 16).toString(16)).replace(/{z}/g, String(this.z)).replace(/{x}/g, String(this.x)).replace(/{y}/g, String(scheme === 'tms' ? Math.pow(2, this.z) - this.y - 1 : this.y)).replace('{quadkey}', quadkey).replace('{bbox-epsg-3857}', bbox);
	    }
	    toString() {
	        return `${ this.z }/${ this.x }/${ this.y }`;
	    }
	}
	class UnwrappedTileID {
	    constructor(wrap, canonical) {
	        this.wrap = wrap;
	        this.canonical = canonical;
	        this.key = calculateKey(wrap, canonical.z, canonical.z, canonical.x, canonical.y);
	    }
	}
	class OverscaledTileID {
	    constructor(overscaledZ, wrap, z, x, y) {
	        this.overscaledZ = overscaledZ;
	        this.wrap = wrap;
	        this.canonical = new CanonicalTileID(z, +x, +y);
	        this.key = wrap === 0 && overscaledZ === z ? this.canonical.key : calculateKey(wrap, overscaledZ, z, x, y);
	    }
	    equals(id) {
	        return this.overscaledZ === id.overscaledZ && this.wrap === id.wrap && this.canonical.equals(id.canonical);
	    }
	    scaledTo(targetZ) {
	        const zDifference = this.canonical.z - targetZ;
	        if (targetZ > this.canonical.z) {
	            return new OverscaledTileID(targetZ, this.wrap, this.canonical.z, this.canonical.x, this.canonical.y);
	        } else {
	            return new OverscaledTileID(targetZ, this.wrap, targetZ, this.canonical.x >> zDifference, this.canonical.y >> zDifference);
	        }
	    }
	    calculateScaledKey(targetZ, withWrap = true) {
	        if (this.overscaledZ === targetZ && withWrap)
	            return this.key;
	        if (targetZ > this.canonical.z) {
	            return calculateKey(this.wrap * +withWrap, targetZ, this.canonical.z, this.canonical.x, this.canonical.y);
	        } else {
	            const zDifference = this.canonical.z - targetZ;
	            return calculateKey(this.wrap * +withWrap, targetZ, targetZ, this.canonical.x >> zDifference, this.canonical.y >> zDifference);
	        }
	    }
	    isChildOf(parent) {
	        if (parent.wrap !== this.wrap) {
	            return false;
	        }
	        const zDifference = this.canonical.z - parent.canonical.z;
	        return parent.overscaledZ === 0 || parent.overscaledZ < this.overscaledZ && parent.canonical.x === this.canonical.x >> zDifference && parent.canonical.y === this.canonical.y >> zDifference;
	    }
	    children(sourceMaxZoom) {
	        if (this.overscaledZ >= sourceMaxZoom) {
	            return [new OverscaledTileID(this.overscaledZ + 1, this.wrap, this.canonical.z, this.canonical.x, this.canonical.y)];
	        }
	        const z = this.canonical.z + 1;
	        const x = this.canonical.x * 2;
	        const y = this.canonical.y * 2;
	        return [
	            new OverscaledTileID(z, this.wrap, z, x, y),
	            new OverscaledTileID(z, this.wrap, z, x + 1, y),
	            new OverscaledTileID(z, this.wrap, z, x, y + 1),
	            new OverscaledTileID(z, this.wrap, z, x + 1, y + 1)
	        ];
	    }
	    isLessThan(rhs) {
	        if (this.wrap < rhs.wrap)
	            return true;
	        if (this.wrap > rhs.wrap)
	            return false;
	        if (this.overscaledZ < rhs.overscaledZ)
	            return true;
	        if (this.overscaledZ > rhs.overscaledZ)
	            return false;
	        if (this.canonical.x < rhs.canonical.x)
	            return true;
	        if (this.canonical.x > rhs.canonical.x)
	            return false;
	        if (this.canonical.y < rhs.canonical.y)
	            return true;
	        return false;
	    }
	    wrapped() {
	        return new OverscaledTileID(this.overscaledZ, 0, this.canonical.z, this.canonical.x, this.canonical.y);
	    }
	    unwrapTo(wrap) {
	        return new OverscaledTileID(this.overscaledZ, wrap, this.canonical.z, this.canonical.x, this.canonical.y);
	    }
	    overscaleFactor() {
	        return Math.pow(2, this.overscaledZ - this.canonical.z);
	    }
	    toUnwrapped() {
	        return new UnwrappedTileID(this.wrap, this.canonical);
	    }
	    toString() {
	        return `${ this.overscaledZ }/${ this.canonical.x }/${ this.canonical.y }`;
	    }
	}
	function calculateKey(wrap, overscaledZ, z, x, y) {
	    const dim = 1 << Math.min(z, 22);
	    let xy = dim * (y % dim) + x % dim;
	    if (wrap && z < 22) {
	        const bitsAvailable = 2 * (22 - z);
	        xy += dim * dim * ((wrap < 0 ? -2 * wrap - 1 : 2 * wrap) % (1 << bitsAvailable));
	    }
	    const key = (xy * 32 + z) * 16 + (overscaledZ - z);
	    return key;
	}
	function getQuadkey(z, x, y) {
	    let quadkey = '', mask;
	    for (let i = z; i > 0; i--) {
	        mask = 1 << i - 1;
	        quadkey += (x & mask ? 1 : 0) + (y & mask ? 2 : 0);
	    }
	    return quadkey;
	}
	register(CanonicalTileID, 'CanonicalTileID');
	register(OverscaledTileID, 'OverscaledTileID', { omit: ['projMatrix'] });

	class FillExtrusionStyleLayer extends StyleLayer {
	    constructor(layer) {
	        super(layer, properties$5);
	    }
	    createBucket(parameters) {
	        return new FillExtrusionBucket(parameters);
	    }
	    queryRadius() {
	        return translateDistance(this.paint.get('fill-extrusion-translate'));
	    }
	    is3D() {
	        return true;
	    }
	    getProgramIds() {
	        const patternProperty = this.paint.get('fill-extrusion-pattern');
	        const image = patternProperty.constantOr(1);
	        return [image ? 'fillExtrusionPattern' : 'fillExtrusion'];
	    }
	    getProgramConfiguration(zoom) {
	        return new ProgramConfiguration(this, zoom);
	    }
	    queryIntersectsFeature(queryGeometry, feature, featureState, geometry, zoom, transform, pixelPosMatrix, elevationHelper, layoutVertexArrayOffset) {
	        const translation = tilespaceTranslate(this.paint.get('fill-extrusion-translate'), this.paint.get('fill-extrusion-translate-anchor'), transform.angle, queryGeometry.pixelToTileUnitsFactor);
	        const height = this.paint.get('fill-extrusion-height').evaluate(feature, featureState);
	        const base = this.paint.get('fill-extrusion-base').evaluate(feature, featureState);
	        const centroid = [
	            0,
	            0
	        ];
	        const terrainVisible = elevationHelper && transform.elevation;
	        const exaggeration = transform.elevation ? transform.elevation.exaggeration() : 1;
	        const bucket = queryGeometry.tile.getBucket(this);
	        if (terrainVisible && bucket instanceof FillExtrusionBucket) {
	            const centroidVertexArray = bucket.centroidVertexArray;
	            const centroidOffset = layoutVertexArrayOffset + 1;
	            if (centroidOffset < centroidVertexArray.length) {
	                const centroidVertexObject = centroidVertexArray.get(centroidOffset);
	                centroid[0] = centroidVertexObject.a_centroid_pos0;
	                centroid[1] = centroidVertexObject.a_centroid_pos1;
	            }
	        }
	        const isHidden = centroid[0] === 0 && centroid[1] === 1;
	        if (isHidden)
	            return false;
	        if (transform.projection.name === 'globe') {
	            const bounds = [
	                new pointGeometry(0, 0),
	                new pointGeometry(EXTENT, EXTENT)
	            ];
	            const resampledGeometry = resampleFillExtrusionPolygonsForGlobe([geometry], bounds, queryGeometry.tileID.canonical);
	            geometry = resampledGeometry.map(clipped => clipped.polygon).flat();
	        }
	        const demSampler = terrainVisible ? elevationHelper : null;
	        const projected = projectExtrusion(transform, geometry, base, height, translation, pixelPosMatrix, demSampler, centroid, exaggeration, transform.center.lat, queryGeometry.tileID.canonical);
	        const projectedBase = projected[0];
	        const projectedTop = projected[1];
	        const screenQuery = queryGeometry.queryGeometry;
	        const projectedQueryGeometry = screenQuery.isPointQuery() ? screenQuery.screenBounds : screenQuery.screenGeometry;
	        return checkIntersection(projectedBase, projectedTop, projectedQueryGeometry);
	    }
	}
	function dot(a, b) {
	    return a.x * b.x + a.y * b.y;
	}
	function getIntersectionDistance(projectedQueryGeometry, projectedFace) {
	    if (projectedQueryGeometry.length === 1) {
	        let i = 0;
	        const a = projectedFace[i++];
	        let b;
	        while (!b || a.equals(b)) {
	            b = projectedFace[i++];
	            if (!b)
	                return Infinity;
	        }
	        for (; i < projectedFace.length; i++) {
	            const c = projectedFace[i];
	            const p = projectedQueryGeometry[0];
	            const ab = b.sub(a);
	            const ac = c.sub(a);
	            const ap = p.sub(a);
	            const dotABAB = dot(ab, ab);
	            const dotABAC = dot(ab, ac);
	            const dotACAC = dot(ac, ac);
	            const dotAPAB = dot(ap, ab);
	            const dotAPAC = dot(ap, ac);
	            const denom = dotABAB * dotACAC - dotABAC * dotABAC;
	            const v = (dotACAC * dotAPAB - dotABAC * dotAPAC) / denom;
	            const w = (dotABAB * dotAPAC - dotABAC * dotAPAB) / denom;
	            const u = 1 - v - w;
	            const distance = a.z * u + b.z * v + c.z * w;
	            if (isFinite(distance))
	                return distance;
	        }
	        return Infinity;
	    } else {
	        let closestDistance = Infinity;
	        for (const p of projectedFace) {
	            closestDistance = Math.min(closestDistance, p.z);
	        }
	        return closestDistance;
	    }
	}
	function checkIntersection(projectedBase, projectedTop, projectedQueryGeometry) {
	    let closestDistance = Infinity;
	    if (polygonIntersectsMultiPolygon(projectedQueryGeometry, projectedTop)) {
	        closestDistance = getIntersectionDistance(projectedQueryGeometry, projectedTop[0]);
	    }
	    for (let r = 0; r < projectedTop.length; r++) {
	        const ringTop = projectedTop[r];
	        const ringBase = projectedBase[r];
	        for (let p = 0; p < ringTop.length - 1; p++) {
	            const topA = ringTop[p];
	            const topB = ringTop[p + 1];
	            const baseA = ringBase[p];
	            const baseB = ringBase[p + 1];
	            const face = [
	                topA,
	                topB,
	                baseB,
	                baseA,
	                topA
	            ];
	            if (polygonIntersectsPolygon(projectedQueryGeometry, face)) {
	                closestDistance = Math.min(closestDistance, getIntersectionDistance(projectedQueryGeometry, face));
	            }
	        }
	    }
	    return closestDistance === Infinity ? false : closestDistance;
	}
	function projectExtrusion(tr, geometry, zBase, zTop, translation, m, demSampler, centroid, exaggeration, lat, tileID) {
	    if (tr.projection.name === 'globe') {
	        return projectExtrusionGlobe(tr, geometry, zBase, zTop, translation, m, demSampler, centroid, exaggeration, lat, tileID);
	    } else {
	        if (demSampler) {
	            return projectExtrusion3D(geometry, zBase, zTop, translation, m, demSampler, centroid, exaggeration, lat);
	        } else {
	            return projectExtrusion2D(geometry, zBase, zTop, translation, m);
	        }
	    }
	}
	function projectExtrusionGlobe(tr, geometry, zBase, zTop, translation, m, demSampler, centroid, exaggeration, lat, tileID) {
	    const projectedBase = [];
	    const projectedTop = [];
	    const elevationScale = tr.projection.upVectorScale(tileID, tr.center.lat, tr.worldSize).metersToTile;
	    const basePoint = [
	        0,
	        0,
	        0,
	        1
	    ];
	    const topPoint = [
	        0,
	        0,
	        0,
	        1
	    ];
	    const setPoint = (point, x, y, z) => {
	        point[0] = x;
	        point[1] = y;
	        point[2] = z;
	        point[3] = 1;
	    };
	    const lift = fillExtrusionHeightLift();
	    if (zBase > 0) {
	        zBase += lift;
	    }
	    zTop += lift;
	    for (const r of geometry) {
	        const ringBase = [];
	        const ringTop = [];
	        for (const p of r) {
	            const x = p.x + translation.x;
	            const y = p.y + translation.y;
	            const reproj = tr.projection.projectTilePoint(x, y, tileID);
	            const dir = tr.projection.upVector(tileID, p.x, p.y);
	            let zBasePoint = zBase;
	            let zTopPoint = zTop;
	            if (demSampler) {
	                const offset = getTerrainHeightOffset(x, y, zBase, zTop, demSampler, centroid, exaggeration, lat);
	                zBasePoint += offset.base;
	                zTopPoint += offset.top;
	            }
	            if (zBase !== 0) {
	                setPoint(basePoint, reproj.x + dir[0] * elevationScale * zBasePoint, reproj.y + dir[1] * elevationScale * zBasePoint, reproj.z + dir[2] * elevationScale * zBasePoint);
	            } else {
	                setPoint(basePoint, reproj.x, reproj.y, reproj.z);
	            }
	            setPoint(topPoint, reproj.x + dir[0] * elevationScale * zTopPoint, reproj.y + dir[1] * elevationScale * zTopPoint, reproj.z + dir[2] * elevationScale * zTopPoint);
	            transformMat4$1(basePoint, basePoint, m);
	            transformMat4$1(topPoint, topPoint, m);
	            ringBase.push(toPoint(basePoint));
	            ringTop.push(toPoint(topPoint));
	        }
	        projectedBase.push(ringBase);
	        projectedTop.push(ringTop);
	    }
	    return [
	        projectedBase,
	        projectedTop
	    ];
	}
	function projectExtrusion2D(geometry, zBase, zTop, translation, m) {
	    const projectedBase = [];
	    const projectedTop = [];
	    const baseXZ = m[8] * zBase;
	    const baseYZ = m[9] * zBase;
	    const baseZZ = m[10] * zBase;
	    const baseWZ = m[11] * zBase;
	    const topXZ = m[8] * zTop;
	    const topYZ = m[9] * zTop;
	    const topZZ = m[10] * zTop;
	    const topWZ = m[11] * zTop;
	    for (const r of geometry) {
	        const ringBase = [];
	        const ringTop = [];
	        for (const p of r) {
	            const x = p.x + translation.x;
	            const y = p.y + translation.y;
	            const sX = m[0] * x + m[4] * y + m[12];
	            const sY = m[1] * x + m[5] * y + m[13];
	            const sZ = m[2] * x + m[6] * y + m[14];
	            const sW = m[3] * x + m[7] * y + m[15];
	            const baseX = sX + baseXZ;
	            const baseY = sY + baseYZ;
	            const baseZ = sZ + baseZZ;
	            const baseW = Math.max(sW + baseWZ, 0.00001);
	            const topX = sX + topXZ;
	            const topY = sY + topYZ;
	            const topZ = sZ + topZZ;
	            const topW = Math.max(sW + topWZ, 0.00001);
	            const b = new pointGeometry(baseX / baseW, baseY / baseW);
	            b.z = baseZ / baseW;
	            ringBase.push(b);
	            const t = new pointGeometry(topX / topW, topY / topW);
	            t.z = topZ / topW;
	            ringTop.push(t);
	        }
	        projectedBase.push(ringBase);
	        projectedTop.push(ringTop);
	    }
	    return [
	        projectedBase,
	        projectedTop
	    ];
	}
	function projectExtrusion3D(geometry, zBase, zTop, translation, m, demSampler, centroid, exaggeration, lat) {
	    const projectedBase = [];
	    const projectedTop = [];
	    const v = [
	        0,
	        0,
	        0,
	        1
	    ];
	    for (const r of geometry) {
	        const ringBase = [];
	        const ringTop = [];
	        for (const p of r) {
	            const x = p.x + translation.x;
	            const y = p.y + translation.y;
	            const heightOffset = getTerrainHeightOffset(x, y, zBase, zTop, demSampler, centroid, exaggeration, lat);
	            v[0] = x;
	            v[1] = y;
	            v[2] = heightOffset.base;
	            v[3] = 1;
	            transformMat4(v, v, m);
	            v[3] = Math.max(v[3], 0.00001);
	            const base = toPoint([
	                v[0] / v[3],
	                v[1] / v[3],
	                v[2] / v[3]
	            ]);
	            v[0] = x;
	            v[1] = y;
	            v[2] = heightOffset.top;
	            v[3] = 1;
	            transformMat4(v, v, m);
	            v[3] = Math.max(v[3], 0.00001);
	            const top = toPoint([
	                v[0] / v[3],
	                v[1] / v[3],
	                v[2] / v[3]
	            ]);
	            ringBase.push(base);
	            ringTop.push(top);
	        }
	        projectedBase.push(ringBase);
	        projectedTop.push(ringTop);
	    }
	    return [
	        projectedBase,
	        projectedTop
	    ];
	}
	function toPoint(v) {
	    const p = new pointGeometry(v[0], v[1]);
	    p.z = v[2];
	    return p;
	}
	function getTerrainHeightOffset(x, y, zBase, zTop, demSampler, centroid, exaggeration, lat) {
	    const ele = exaggeration * demSampler.getElevationAt(x, y, true, true);
	    const flatRoof = centroid[0] !== 0;
	    const centroidElevation = flatRoof ? centroid[1] === 0 ? exaggeration * elevationFromUint16(centroid[0]) : exaggeration * flatElevation(demSampler, centroid, lat) : ele;
	    return {
	        base: ele + (zBase === 0) ? -1 : zBase,
	        top: flatRoof ? Math.max(centroidElevation + zTop, ele + zBase + 2) : ele + zTop
	    };
	}
	function elevationFromUint16(n) {
	    return n / ELEVATION_SCALE - ELEVATION_OFFSET;
	}
	function flatElevation(demSampler, centroid, lat) {
	    const posX = Math.floor(centroid[0] / 8);
	    const posY = Math.floor(centroid[1] / 8);
	    const spanX = 10 * (centroid[0] - posX * 8);
	    const spanY = 10 * (centroid[1] - posY * 8);
	    const z = demSampler.getElevationAt(posX, posY, true, true);
	    const meterToDEM = demSampler.getMeterToDEM(lat);
	    const wX = Math.floor(0.5 * (spanX * meterToDEM - 1));
	    const wY = Math.floor(0.5 * (spanY * meterToDEM - 1));
	    const posPx = demSampler.tileCoordToPixel(posX, posY);
	    const offsetX = 2 * wX + 1;
	    const offsetY = 2 * wY + 1;
	    const corners = fourSample(demSampler, posPx.x - wX, posPx.y - wY, offsetX, offsetY);
	    const diffX = Math.abs(corners[0] - corners[1]);
	    const diffY = Math.abs(corners[2] - corners[3]);
	    const diffZ = Math.abs(corners[0] - corners[2]);
	    const diffW = Math.abs(corners[1] - corners[3]);
	    const diffSumX = diffX + diffY;
	    const diffSumY = diffZ + diffW;
	    const slopeX = Math.min(0.25, meterToDEM * 0.5 * diffSumX / offsetX);
	    const slopeY = Math.min(0.25, meterToDEM * 0.5 * diffSumY / offsetY);
	    return z + Math.max(slopeX * spanX, slopeY * spanY);
	}
	function fourSample(demSampler, posX, posY, offsetX, offsetY) {
	    return [
	        demSampler.getElevationAtPixel(posX, posY, true),
	        demSampler.getElevationAtPixel(posX + offsetY, posY, true),
	        demSampler.getElevationAtPixel(posX, posY + offsetY, true),
	        demSampler.getElevationAtPixel(posX + offsetX, posY + offsetY, true)
	    ];
	}

	const lineLayoutAttributes = createLayout([
	    {
	        name: 'a_pos_normal',
	        components: 2,
	        type: 'Int16'
	    },
	    {
	        name: 'a_data',
	        components: 4,
	        type: 'Uint8'
	    },
	    {
	        name: 'a_linesofar',
	        components: 1,
	        type: 'Float32'
	    }
	], 4);
	const {members: members$2, size: size$2, alignment: alignment$2} = lineLayoutAttributes;

	const lineLayoutAttributesExt = createLayout([{
	        name: 'a_packed',
	        components: 4,
	        type: 'Float32'
	    }]);
	const {members: members$1, size: size$1, alignment: alignment$1} = lineLayoutAttributesExt;

	const vectorTileFeatureTypes$1 = vectorTile.VectorTileFeature.types;
	const EXTRUDE_SCALE = 63;
	const COS_HALF_SHARP_CORNER = Math.cos(75 / 2 * (Math.PI / 180));
	const SHARP_CORNER_OFFSET = 15;
	const DEG_PER_TRIANGLE = 20;
	class LineBucket {
	    constructor(options) {
	        this.zoom = options.zoom;
	        this.overscaling = options.overscaling;
	        this.layers = options.layers;
	        this.layerIds = this.layers.map(layer => layer.id);
	        this.index = options.index;
	        this.projection = options.projection;
	        this.hasPattern = false;
	        this.patternFeatures = [];
	        this.lineClipsArray = [];
	        this.gradients = {};
	        this.layers.forEach(layer => {
	            this.gradients[layer.id] = {};
	        });
	        this.layoutVertexArray = new StructArrayLayout2i4ub1f12();
	        this.layoutVertexArray2 = new StructArrayLayout4f16();
	        this.indexArray = new StructArrayLayout3ui6();
	        this.programConfigurations = new ProgramConfigurationSet(options.layers, options.zoom);
	        this.segments = new SegmentVector();
	        this.maxLineLength = 0;
	        this.stateDependentLayerIds = this.layers.filter(l => l.isStateDependent()).map(l => l.id);
	    }
	    populate(features, options, canonical, tileTransform) {
	        this.hasPattern = hasPattern('line', this.layers, options);
	        const lineSortKey = this.layers[0].layout.get('line-sort-key');
	        const bucketFeatures = [];
	        for (const {feature, id, index, sourceLayerIndex} of features) {
	            const needGeometry = this.layers[0]._featureFilter.needGeometry;
	            const evaluationFeature = toEvaluationFeature(feature, needGeometry);
	            if (!this.layers[0]._featureFilter.filter(new EvaluationParameters(this.zoom), evaluationFeature, canonical))
	                continue;
	            const sortKey = lineSortKey ? lineSortKey.evaluate(evaluationFeature, {}, canonical) : undefined;
	            const bucketFeature = {
	                id,
	                properties: feature.properties,
	                type: feature.type,
	                sourceLayerIndex,
	                index,
	                geometry: needGeometry ? evaluationFeature.geometry : loadGeometry(feature, canonical, tileTransform),
	                patterns: {},
	                sortKey
	            };
	            bucketFeatures.push(bucketFeature);
	        }
	        if (lineSortKey) {
	            bucketFeatures.sort((a, b) => {
	                return a.sortKey - b.sortKey;
	            });
	        }
	        const {lineAtlas, featureIndex} = options;
	        const hasFeatureDashes = this.addConstantDashes(lineAtlas);
	        for (const bucketFeature of bucketFeatures) {
	            const {geometry, index, sourceLayerIndex} = bucketFeature;
	            if (hasFeatureDashes) {
	                this.addFeatureDashes(bucketFeature, lineAtlas);
	            }
	            if (this.hasPattern) {
	                const patternBucketFeature = addPatternDependencies('line', this.layers, bucketFeature, this.zoom, options);
	                this.patternFeatures.push(patternBucketFeature);
	            } else {
	                this.addFeature(bucketFeature, geometry, index, canonical, lineAtlas.positions, options.availableImages);
	            }
	            const feature = features[index].feature;
	            featureIndex.insert(feature, geometry, index, sourceLayerIndex, this.index);
	        }
	    }
	    addConstantDashes(lineAtlas) {
	        let hasFeatureDashes = false;
	        for (const layer of this.layers) {
	            const dashPropertyValue = layer.paint.get('line-dasharray').value;
	            const capPropertyValue = layer.layout.get('line-cap').value;
	            if (dashPropertyValue.kind !== 'constant' || capPropertyValue.kind !== 'constant') {
	                hasFeatureDashes = true;
	            } else {
	                const constCap = capPropertyValue.value;
	                const constDash = dashPropertyValue.value;
	                if (!constDash)
	                    continue;
	                lineAtlas.addDash(constDash.from, constCap);
	                lineAtlas.addDash(constDash.to, constCap);
	                if (constDash.other)
	                    lineAtlas.addDash(constDash.other, constCap);
	            }
	        }
	        return hasFeatureDashes;
	    }
	    addFeatureDashes(feature, lineAtlas) {
	        const zoom = this.zoom;
	        for (const layer of this.layers) {
	            const dashPropertyValue = layer.paint.get('line-dasharray').value;
	            const capPropertyValue = layer.layout.get('line-cap').value;
	            if (dashPropertyValue.kind === 'constant' && capPropertyValue.kind === 'constant')
	                continue;
	            let minDashArray, midDashArray, maxDashArray, minCap, midCap, maxCap;
	            if (dashPropertyValue.kind === 'constant') {
	                const constDash = dashPropertyValue.value;
	                if (!constDash)
	                    continue;
	                minDashArray = constDash.other || constDash.to;
	                midDashArray = constDash.to;
	                maxDashArray = constDash.from;
	            } else {
	                minDashArray = dashPropertyValue.evaluate({ zoom: zoom - 1 }, feature);
	                midDashArray = dashPropertyValue.evaluate({ zoom }, feature);
	                maxDashArray = dashPropertyValue.evaluate({ zoom: zoom + 1 }, feature);
	            }
	            if (capPropertyValue.kind === 'constant') {
	                minCap = midCap = maxCap = capPropertyValue.value;
	            } else {
	                minCap = capPropertyValue.evaluate({ zoom: zoom - 1 }, feature);
	                midCap = capPropertyValue.evaluate({ zoom }, feature);
	                maxCap = capPropertyValue.evaluate({ zoom: zoom + 1 }, feature);
	            }
	            lineAtlas.addDash(minDashArray, minCap);
	            lineAtlas.addDash(midDashArray, midCap);
	            lineAtlas.addDash(maxDashArray, maxCap);
	            const min = lineAtlas.getKey(minDashArray, minCap);
	            const mid = lineAtlas.getKey(midDashArray, midCap);
	            const max = lineAtlas.getKey(maxDashArray, maxCap);
	            feature.patterns[layer.id] = {
	                min,
	                mid,
	                max
	            };
	        }
	    }
	    update(states, vtLayer, availableImages, imagePositions) {
	        if (!this.stateDependentLayers.length)
	            return;
	        this.programConfigurations.updatePaintArrays(states, vtLayer, this.stateDependentLayers, availableImages, imagePositions);
	    }
	    addFeatures(options, canonical, imagePositions, availableImages, _) {
	        for (const feature of this.patternFeatures) {
	            this.addFeature(feature, feature.geometry, feature.index, canonical, imagePositions, availableImages);
	        }
	    }
	    isEmpty() {
	        return this.layoutVertexArray.length === 0;
	    }
	    uploadPending() {
	        return !this.uploaded || this.programConfigurations.needsUpload;
	    }
	    upload(context) {
	        if (!this.uploaded) {
	            if (this.layoutVertexArray2.length !== 0) {
	                this.layoutVertexBuffer2 = context.createVertexBuffer(this.layoutVertexArray2, members$1);
	            }
	            this.layoutVertexBuffer = context.createVertexBuffer(this.layoutVertexArray, members$2);
	            this.indexBuffer = context.createIndexBuffer(this.indexArray);
	        }
	        this.programConfigurations.upload(context);
	        this.uploaded = true;
	    }
	    destroy() {
	        if (!this.layoutVertexBuffer)
	            return;
	        this.layoutVertexBuffer.destroy();
	        this.indexBuffer.destroy();
	        this.programConfigurations.destroy();
	        this.segments.destroy();
	    }
	    lineFeatureClips(feature) {
	        if (!!feature.properties && feature.properties.hasOwnProperty('mapbox_clip_start') && feature.properties.hasOwnProperty('mapbox_clip_end')) {
	            const start = +feature.properties['mapbox_clip_start'];
	            const end = +feature.properties['mapbox_clip_end'];
	            return {
	                start,
	                end
	            };
	        }
	    }
	    addFeature(feature, geometry, index, canonical, imagePositions, availableImages) {
	        const layout = this.layers[0].layout;
	        const join = layout.get('line-join').evaluate(feature, {});
	        const cap = layout.get('line-cap').evaluate(feature, {});
	        const miterLimit = layout.get('line-miter-limit');
	        const roundLimit = layout.get('line-round-limit');
	        this.lineClips = this.lineFeatureClips(feature);
	        for (const line of geometry) {
	            this.addLine(line, feature, join, cap, miterLimit, roundLimit);
	        }
	        this.programConfigurations.populatePaintArrays(this.layoutVertexArray.length, feature, index, imagePositions, availableImages, canonical);
	    }
	    addLine(vertices, feature, join, cap, miterLimit, roundLimit) {
	        this.distance = 0;
	        this.scaledDistance = 0;
	        this.totalDistance = 0;
	        this.lineSoFar = 0;
	        if (this.lineClips) {
	            this.lineClipsArray.push(this.lineClips);
	            for (let i = 0; i < vertices.length - 1; i++) {
	                this.totalDistance += vertices[i].dist(vertices[i + 1]);
	            }
	            this.updateScaledDistance();
	            this.maxLineLength = Math.max(this.maxLineLength, this.totalDistance);
	        }
	        const isPolygon = vectorTileFeatureTypes$1[feature.type] === 'Polygon';
	        let len = vertices.length;
	        while (len >= 2 && vertices[len - 1].equals(vertices[len - 2])) {
	            len--;
	        }
	        let first = 0;
	        while (first < len - 1 && vertices[first].equals(vertices[first + 1])) {
	            first++;
	        }
	        if (len < (isPolygon ? 3 : 2))
	            return;
	        if (join === 'bevel')
	            miterLimit = 1.05;
	        const sharpCornerOffset = this.overscaling <= 16 ? SHARP_CORNER_OFFSET * EXTENT / (512 * this.overscaling) : 0;
	        const segment = this.segments.prepareSegment(len * 10, this.layoutVertexArray, this.indexArray);
	        let currentVertex;
	        let prevVertex = undefined;
	        let nextVertex = undefined;
	        let prevNormal = undefined;
	        let nextNormal = undefined;
	        this.e1 = this.e2 = -1;
	        if (isPolygon) {
	            currentVertex = vertices[len - 2];
	            nextNormal = vertices[first].sub(currentVertex)._unit()._perp();
	        }
	        for (let i = first; i < len; i++) {
	            nextVertex = i === len - 1 ? isPolygon ? vertices[first + 1] : undefined : vertices[i + 1];
	            if (nextVertex && vertices[i].equals(nextVertex))
	                continue;
	            if (nextNormal)
	                prevNormal = nextNormal;
	            if (currentVertex)
	                prevVertex = currentVertex;
	            currentVertex = vertices[i];
	            nextNormal = nextVertex ? nextVertex.sub(currentVertex)._unit()._perp() : prevNormal;
	            prevNormal = prevNormal || nextNormal;
	            let joinNormal = prevNormal.add(nextNormal);
	            if (joinNormal.x !== 0 || joinNormal.y !== 0) {
	                joinNormal._unit();
	            }
	            const cosAngle = prevNormal.x * nextNormal.x + prevNormal.y * nextNormal.y;
	            const cosHalfAngle = joinNormal.x * nextNormal.x + joinNormal.y * nextNormal.y;
	            const miterLength = cosHalfAngle !== 0 ? 1 / cosHalfAngle : Infinity;
	            const approxAngle = 2 * Math.sqrt(2 - 2 * cosHalfAngle);
	            const isSharpCorner = cosHalfAngle < COS_HALF_SHARP_CORNER && prevVertex && nextVertex;
	            const lineTurnsLeft = prevNormal.x * nextNormal.y - prevNormal.y * nextNormal.x > 0;
	            if (isSharpCorner && i > first) {
	                const prevSegmentLength = currentVertex.dist(prevVertex);
	                if (prevSegmentLength > 2 * sharpCornerOffset) {
	                    const newPrevVertex = currentVertex.sub(currentVertex.sub(prevVertex)._mult(sharpCornerOffset / prevSegmentLength)._round());
	                    this.updateDistance(prevVertex, newPrevVertex);
	                    this.addCurrentVertex(newPrevVertex, prevNormal, 0, 0, segment);
	                    prevVertex = newPrevVertex;
	                }
	            }
	            const middleVertex = prevVertex && nextVertex;
	            let currentJoin = middleVertex ? join : isPolygon ? 'butt' : cap;
	            if (middleVertex && currentJoin === 'round') {
	                if (miterLength < roundLimit) {
	                    currentJoin = 'miter';
	                } else if (miterLength <= 2) {
	                    currentJoin = 'fakeround';
	                }
	            }
	            if (currentJoin === 'miter' && miterLength > miterLimit) {
	                currentJoin = 'bevel';
	            }
	            if (currentJoin === 'bevel') {
	                if (miterLength > 2)
	                    currentJoin = 'flipbevel';
	                if (miterLength < miterLimit)
	                    currentJoin = 'miter';
	            }
	            if (prevVertex)
	                this.updateDistance(prevVertex, currentVertex);
	            if (currentJoin === 'miter') {
	                joinNormal._mult(miterLength);
	                this.addCurrentVertex(currentVertex, joinNormal, 0, 0, segment);
	            } else if (currentJoin === 'flipbevel') {
	                if (miterLength > 100) {
	                    joinNormal = nextNormal.mult(-1);
	                } else {
	                    const bevelLength = miterLength * prevNormal.add(nextNormal).mag() / prevNormal.sub(nextNormal).mag();
	                    joinNormal._perp()._mult(bevelLength * (lineTurnsLeft ? -1 : 1));
	                }
	                this.addCurrentVertex(currentVertex, joinNormal, 0, 0, segment);
	                this.addCurrentVertex(currentVertex, joinNormal.mult(-1), 0, 0, segment);
	            } else if (currentJoin === 'bevel' || currentJoin === 'fakeround') {
	                const offset = -Math.sqrt(miterLength * miterLength - 1);
	                const offsetA = lineTurnsLeft ? offset : 0;
	                const offsetB = lineTurnsLeft ? 0 : offset;
	                if (prevVertex) {
	                    this.addCurrentVertex(currentVertex, prevNormal, offsetA, offsetB, segment);
	                }
	                if (currentJoin === 'fakeround') {
	                    const n = Math.round(approxAngle * 180 / Math.PI / DEG_PER_TRIANGLE);
	                    for (let m = 1; m < n; m++) {
	                        let t = m / n;
	                        if (t !== 0.5) {
	                            const t2 = t - 0.5;
	                            const A = 1.0904 + cosAngle * (-3.2452 + cosAngle * (3.55645 - cosAngle * 1.43519));
	                            const B = 0.848013 + cosAngle * (-1.06021 + cosAngle * 0.215638);
	                            t = t + t * t2 * (t - 1) * (A * t2 * t2 + B);
	                        }
	                        const extrude = nextNormal.sub(prevNormal)._mult(t)._add(prevNormal)._unit()._mult(lineTurnsLeft ? -1 : 1);
	                        this.addHalfVertex(currentVertex, extrude.x, extrude.y, false, lineTurnsLeft, 0, segment);
	                    }
	                }
	                if (nextVertex) {
	                    this.addCurrentVertex(currentVertex, nextNormal, -offsetA, -offsetB, segment);
	                }
	            } else if (currentJoin === 'butt') {
	                this.addCurrentVertex(currentVertex, joinNormal, 0, 0, segment);
	            } else if (currentJoin === 'square') {
	                const offset = prevVertex ? 1 : -1;
	                if (!prevVertex) {
	                    this.addCurrentVertex(currentVertex, joinNormal, offset, offset, segment);
	                }
	                this.addCurrentVertex(currentVertex, joinNormal, 0, 0, segment);
	                if (prevVertex) {
	                    this.addCurrentVertex(currentVertex, joinNormal, offset, offset, segment);
	                }
	            } else if (currentJoin === 'round') {
	                if (prevVertex) {
	                    this.addCurrentVertex(currentVertex, prevNormal, 0, 0, segment);
	                    this.addCurrentVertex(currentVertex, prevNormal, 1, 1, segment, true);
	                }
	                if (nextVertex) {
	                    this.addCurrentVertex(currentVertex, nextNormal, -1, -1, segment, true);
	                    this.addCurrentVertex(currentVertex, nextNormal, 0, 0, segment);
	                }
	            }
	            if (isSharpCorner && i < len - 1) {
	                const nextSegmentLength = currentVertex.dist(nextVertex);
	                if (nextSegmentLength > 2 * sharpCornerOffset) {
	                    const newCurrentVertex = currentVertex.add(nextVertex.sub(currentVertex)._mult(sharpCornerOffset / nextSegmentLength)._round());
	                    this.updateDistance(currentVertex, newCurrentVertex);
	                    this.addCurrentVertex(newCurrentVertex, nextNormal, 0, 0, segment);
	                    currentVertex = newCurrentVertex;
	                }
	            }
	        }
	    }
	    addCurrentVertex(p, normal, endLeft, endRight, segment, round = false) {
	        const leftX = normal.x + normal.y * endLeft;
	        const leftY = normal.y - normal.x * endLeft;
	        const rightX = -normal.x + normal.y * endRight;
	        const rightY = -normal.y - normal.x * endRight;
	        this.addHalfVertex(p, leftX, leftY, round, false, endLeft, segment);
	        this.addHalfVertex(p, rightX, rightY, round, true, -endRight, segment);
	    }
	    addHalfVertex({x, y}, extrudeX, extrudeY, round, up, dir, segment) {
	        this.layoutVertexArray.emplaceBack((x << 1) + (round ? 1 : 0), (y << 1) + (up ? 1 : 0), Math.round(EXTRUDE_SCALE * extrudeX) + 128, Math.round(EXTRUDE_SCALE * extrudeY) + 128, (dir === 0 ? 0 : dir < 0 ? -1 : 1) + 1, 0, this.lineSoFar);
	        if (this.lineClips) {
	            this.layoutVertexArray2.emplaceBack(this.scaledDistance, this.lineClipsArray.length, this.lineClips.start, this.lineClips.end);
	        }
	        const e = segment.vertexLength++;
	        if (this.e1 >= 0 && this.e2 >= 0) {
	            this.indexArray.emplaceBack(this.e1, this.e2, e);
	            segment.primitiveLength++;
	        }
	        if (up) {
	            this.e2 = e;
	        } else {
	            this.e1 = e;
	        }
	    }
	    updateScaledDistance() {
	        if (this.lineClips) {
	            const featureShare = this.lineClips.end - this.lineClips.start;
	            const totalFeatureLength = this.totalDistance / featureShare;
	            this.scaledDistance = this.distance / this.totalDistance;
	            this.lineSoFar = totalFeatureLength * this.lineClips.start + this.distance;
	        } else {
	            this.lineSoFar = this.distance;
	        }
	    }
	    updateDistance(prev, next) {
	        this.distance += prev.dist(next);
	        this.updateScaledDistance();
	    }
	}
	register(LineBucket, 'LineBucket', {
	    omit: [
	        'layers',
	        'patternFeatures'
	    ]
	});

	const layout$2 = new Properties({
	    'line-cap': new DataDrivenProperty(spec['layout_line']['line-cap']),
	    'line-join': new DataDrivenProperty(spec['layout_line']['line-join']),
	    'line-miter-limit': new DataConstantProperty(spec['layout_line']['line-miter-limit']),
	    'line-round-limit': new DataConstantProperty(spec['layout_line']['line-round-limit']),
	    'line-sort-key': new DataDrivenProperty(spec['layout_line']['line-sort-key'])
	});
	const paint$4 = new Properties({
	    'line-opacity': new DataDrivenProperty(spec['paint_line']['line-opacity']),
	    'line-color': new DataDrivenProperty(spec['paint_line']['line-color']),
	    'line-translate': new DataConstantProperty(spec['paint_line']['line-translate']),
	    'line-translate-anchor': new DataConstantProperty(spec['paint_line']['line-translate-anchor']),
	    'line-width': new DataDrivenProperty(spec['paint_line']['line-width']),
	    'line-gap-width': new DataDrivenProperty(spec['paint_line']['line-gap-width']),
	    'line-offset': new DataDrivenProperty(spec['paint_line']['line-offset']),
	    'line-blur': new DataDrivenProperty(spec['paint_line']['line-blur']),
	    'line-dasharray': new CrossFadedDataDrivenProperty(spec['paint_line']['line-dasharray']),
	    'line-pattern': new CrossFadedDataDrivenProperty(spec['paint_line']['line-pattern']),
	    'line-gradient': new ColorRampProperty(spec['paint_line']['line-gradient']),
	    'line-trim-offset': new DataConstantProperty(spec['paint_line']['line-trim-offset'])
	});
	var properties$4 = {
	    paint: paint$4,
	    layout: layout$2
	};

	class LineFloorwidthProperty extends DataDrivenProperty {
	    possiblyEvaluate(value, parameters) {
	        parameters = new EvaluationParameters(Math.floor(parameters.zoom), {
	            now: parameters.now,
	            fadeDuration: parameters.fadeDuration,
	            zoomHistory: parameters.zoomHistory,
	            transition: parameters.transition
	        });
	        return super.possiblyEvaluate(value, parameters);
	    }
	    evaluate(value, globals, feature, featureState) {
	        globals = extend$1({}, globals, { zoom: Math.floor(globals.zoom) });
	        return super.evaluate(value, globals, feature, featureState);
	    }
	}
	const lineFloorwidthProperty = new LineFloorwidthProperty(properties$4.paint.properties['line-width'].specification);
	lineFloorwidthProperty.useIntegerZoom = true;
	class LineStyleLayer extends StyleLayer {
	    constructor(layer) {
	        super(layer, properties$4);
	        this.gradientVersion = 0;
	    }
	    _handleSpecialPaintPropertyUpdate(name) {
	        if (name === 'line-gradient') {
	            const expression = this._transitionablePaint._values['line-gradient'].value.expression;
	            this.stepInterpolant = expression._styleExpression && expression._styleExpression.expression instanceof Step$1;
	            this.gradientVersion = (this.gradientVersion + 1) % Number.MAX_SAFE_INTEGER;
	        }
	    }
	    gradientExpression() {
	        return this._transitionablePaint._values['line-gradient'].value.expression;
	    }
	    recalculate(parameters, availableImages) {
	        super.recalculate(parameters, availableImages);
	        this.paint._values['line-floorwidth'] = lineFloorwidthProperty.possiblyEvaluate(this._transitioningPaint._values['line-width'].value, parameters);
	    }
	    createBucket(parameters) {
	        return new LineBucket(parameters);
	    }
	    getProgramIds() {
	        const patternProperty = this.paint.get('line-pattern');
	        const image = patternProperty.constantOr(1);
	        const programId = image ? 'linePattern' : 'line';
	        return [programId];
	    }
	    getProgramConfiguration(zoom) {
	        return new ProgramConfiguration(this, zoom);
	    }
	    queryRadius(bucket) {
	        const lineBucket = bucket;
	        const width = getLineWidth(getMaximumPaintValue('line-width', this, lineBucket), getMaximumPaintValue('line-gap-width', this, lineBucket));
	        const offset = getMaximumPaintValue('line-offset', this, lineBucket);
	        return width / 2 + Math.abs(offset) + translateDistance(this.paint.get('line-translate'));
	    }
	    queryIntersectsFeature(queryGeometry, feature, featureState, geometry, zoom, transform) {
	        if (queryGeometry.queryGeometry.isAboveHorizon)
	            return false;
	        const translatedPolygon = translate$1(queryGeometry.tilespaceGeometry, this.paint.get('line-translate'), this.paint.get('line-translate-anchor'), transform.angle, queryGeometry.pixelToTileUnitsFactor);
	        const halfWidth = queryGeometry.pixelToTileUnitsFactor / 2 * getLineWidth(this.paint.get('line-width').evaluate(feature, featureState), this.paint.get('line-gap-width').evaluate(feature, featureState));
	        const lineOffset = this.paint.get('line-offset').evaluate(feature, featureState);
	        if (lineOffset) {
	            geometry = offsetLine(geometry, lineOffset * queryGeometry.pixelToTileUnitsFactor);
	        }
	        return polygonIntersectsBufferedMultiLine(translatedPolygon, geometry, halfWidth);
	    }
	    isTileClipped() {
	        return true;
	    }
	}
	function getLineWidth(lineWidth, lineGapWidth) {
	    if (lineGapWidth > 0) {
	        return lineGapWidth + 2 * lineWidth;
	    } else {
	        return lineWidth;
	    }
	}
	function offsetLine(rings, offset) {
	    const newRings = [];
	    const zero = new pointGeometry(0, 0);
	    for (let k = 0; k < rings.length; k++) {
	        const ring = rings[k];
	        const newRing = [];
	        for (let i = 0; i < ring.length; i++) {
	            const a = ring[i - 1];
	            const b = ring[i];
	            const c = ring[i + 1];
	            const aToB = i === 0 ? zero : b.sub(a)._unit()._perp();
	            const bToC = i === ring.length - 1 ? zero : c.sub(b)._unit()._perp();
	            const extrude = aToB._add(bToC)._unit();
	            const cosHalfAngle = extrude.x * bToC.x + extrude.y * bToC.y;
	            extrude._mult(1 / cosHalfAngle);
	            newRing.push(extrude._mult(offset)._add(b));
	        }
	        newRings.push(newRing);
	    }
	    return newRings;
	}

	const symbolLayoutAttributes = createLayout([
	    {
	        name: 'a_pos_offset',
	        components: 4,
	        type: 'Int16'
	    },
	    {
	        name: 'a_tex_size',
	        components: 4,
	        type: 'Uint16'
	    },
	    {
	        name: 'a_pixeloffset',
	        components: 4,
	        type: 'Int16'
	    }
	], 4);
	const symbolGlobeExtAttributes = createLayout([
	    {
	        name: 'a_globe_anchor',
	        components: 3,
	        type: 'Int16'
	    },
	    {
	        name: 'a_globe_normal',
	        components: 3,
	        type: 'Float32'
	    }
	], 4);
	const dynamicLayoutAttributes = createLayout([{
	        name: 'a_projected_pos',
	        components: 4,
	        type: 'Float32'
	    }], 4);
	createLayout([{
	        name: 'a_fade_opacity',
	        components: 1,
	        type: 'Uint32'
	    }], 4);
	const collisionVertexAttributes = createLayout([
	    {
	        name: 'a_placed',
	        components: 2,
	        type: 'Uint8'
	    },
	    {
	        name: 'a_shift',
	        components: 2,
	        type: 'Float32'
	    }
	]);
	const collisionVertexAttributesExt = createLayout([
	    {
	        name: 'a_size_scale',
	        components: 1,
	        type: 'Float32'
	    },
	    {
	        name: 'a_padding',
	        components: 2,
	        type: 'Float32'
	    }
	]);
	createLayout([
	    {
	        type: 'Int16',
	        name: 'projectedAnchorX'
	    },
	    {
	        type: 'Int16',
	        name: 'projectedAnchorY'
	    },
	    {
	        type: 'Int16',
	        name: 'projectedAnchorZ'
	    },
	    {
	        type: 'Int16',
	        name: 'tileAnchorX'
	    },
	    {
	        type: 'Int16',
	        name: 'tileAnchorY'
	    },
	    {
	        type: 'Float32',
	        name: 'x1'
	    },
	    {
	        type: 'Float32',
	        name: 'y1'
	    },
	    {
	        type: 'Float32',
	        name: 'x2'
	    },
	    {
	        type: 'Float32',
	        name: 'y2'
	    },
	    {
	        type: 'Int16',
	        name: 'padding'
	    },
	    {
	        type: 'Uint32',
	        name: 'featureIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'sourceLayerIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'bucketIndex'
	    }
	]);
	const collisionBoxLayout = createLayout([
	    {
	        name: 'a_pos',
	        components: 3,
	        type: 'Int16'
	    },
	    {
	        name: 'a_anchor_pos',
	        components: 2,
	        type: 'Int16'
	    },
	    {
	        name: 'a_extrude',
	        components: 2,
	        type: 'Int16'
	    }
	], 4);
	const collisionCircleLayout = createLayout([
	    {
	        name: 'a_pos_2f',
	        components: 2,
	        type: 'Float32'
	    },
	    {
	        name: 'a_radius',
	        components: 1,
	        type: 'Float32'
	    },
	    {
	        name: 'a_flags',
	        components: 2,
	        type: 'Int16'
	    }
	], 4);
	createLayout([{
	        name: 'triangle',
	        components: 3,
	        type: 'Uint16'
	    }]);
	createLayout([
	    {
	        type: 'Int16',
	        name: 'projectedAnchorX'
	    },
	    {
	        type: 'Int16',
	        name: 'projectedAnchorY'
	    },
	    {
	        type: 'Int16',
	        name: 'projectedAnchorZ'
	    },
	    {
	        type: 'Float32',
	        name: 'tileAnchorX'
	    },
	    {
	        type: 'Float32',
	        name: 'tileAnchorY'
	    },
	    {
	        type: 'Uint16',
	        name: 'glyphStartIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'numGlyphs'
	    },
	    {
	        type: 'Uint32',
	        name: 'vertexStartIndex'
	    },
	    {
	        type: 'Uint32',
	        name: 'lineStartIndex'
	    },
	    {
	        type: 'Uint32',
	        name: 'lineLength'
	    },
	    {
	        type: 'Uint16',
	        name: 'segment'
	    },
	    {
	        type: 'Uint16',
	        name: 'lowerSize'
	    },
	    {
	        type: 'Uint16',
	        name: 'upperSize'
	    },
	    {
	        type: 'Float32',
	        name: 'lineOffsetX'
	    },
	    {
	        type: 'Float32',
	        name: 'lineOffsetY'
	    },
	    {
	        type: 'Uint8',
	        name: 'writingMode'
	    },
	    {
	        type: 'Uint8',
	        name: 'placedOrientation'
	    },
	    {
	        type: 'Uint8',
	        name: 'hidden'
	    },
	    {
	        type: 'Uint32',
	        name: 'crossTileID'
	    },
	    {
	        type: 'Int16',
	        name: 'associatedIconIndex'
	    },
	    {
	        type: 'Uint8',
	        name: 'flipState'
	    }
	]);
	createLayout([
	    {
	        type: 'Int16',
	        name: 'projectedAnchorX'
	    },
	    {
	        type: 'Int16',
	        name: 'projectedAnchorY'
	    },
	    {
	        type: 'Int16',
	        name: 'projectedAnchorZ'
	    },
	    {
	        type: 'Float32',
	        name: 'tileAnchorX'
	    },
	    {
	        type: 'Float32',
	        name: 'tileAnchorY'
	    },
	    {
	        type: 'Int16',
	        name: 'rightJustifiedTextSymbolIndex'
	    },
	    {
	        type: 'Int16',
	        name: 'centerJustifiedTextSymbolIndex'
	    },
	    {
	        type: 'Int16',
	        name: 'leftJustifiedTextSymbolIndex'
	    },
	    {
	        type: 'Int16',
	        name: 'verticalPlacedTextSymbolIndex'
	    },
	    {
	        type: 'Int16',
	        name: 'placedIconSymbolIndex'
	    },
	    {
	        type: 'Int16',
	        name: 'verticalPlacedIconSymbolIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'key'
	    },
	    {
	        type: 'Uint16',
	        name: 'textBoxStartIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'textBoxEndIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'verticalTextBoxStartIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'verticalTextBoxEndIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'iconBoxStartIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'iconBoxEndIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'verticalIconBoxStartIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'verticalIconBoxEndIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'featureIndex'
	    },
	    {
	        type: 'Uint16',
	        name: 'numHorizontalGlyphVertices'
	    },
	    {
	        type: 'Uint16',
	        name: 'numVerticalGlyphVertices'
	    },
	    {
	        type: 'Uint16',
	        name: 'numIconVertices'
	    },
	    {
	        type: 'Uint16',
	        name: 'numVerticalIconVertices'
	    },
	    {
	        type: 'Uint16',
	        name: 'useRuntimeCollisionCircles'
	    },
	    {
	        type: 'Uint32',
	        name: 'crossTileID'
	    },
	    {
	        type: 'Float32',
	        components: 2,
	        name: 'textOffset'
	    },
	    {
	        type: 'Float32',
	        name: 'collisionCircleDiameter'
	    }
	]);
	createLayout([{
	        type: 'Float32',
	        name: 'offsetX'
	    }]);
	createLayout([
	    {
	        type: 'Int16',
	        name: 'x'
	    },
	    {
	        type: 'Int16',
	        name: 'y'
	    },
	    {
	        type: 'Int16',
	        name: 'tileUnitDistanceFromAnchor'
	    }
	]);

	var ONE_EM = 24;

	const SIZE_PACK_FACTOR = 128;
	function getSizeData(tileZoom, value) {
	    const {expression} = value;
	    if (expression.kind === 'constant') {
	        const layoutSize = expression.evaluate(new EvaluationParameters(tileZoom + 1));
	        return {
	            kind: 'constant',
	            layoutSize
	        };
	    } else if (expression.kind === 'source') {
	        return { kind: 'source' };
	    } else {
	        const {zoomStops, interpolationType} = expression;
	        let lower = 0;
	        while (lower < zoomStops.length && zoomStops[lower] <= tileZoom)
	            lower++;
	        lower = Math.max(0, lower - 1);
	        let upper = lower;
	        while (upper < zoomStops.length && zoomStops[upper] < tileZoom + 1)
	            upper++;
	        upper = Math.min(zoomStops.length - 1, upper);
	        const minZoom = zoomStops[lower];
	        const maxZoom = zoomStops[upper];
	        if (expression.kind === 'composite') {
	            return {
	                kind: 'composite',
	                minZoom,
	                maxZoom,
	                interpolationType
	            };
	        }
	        const minSize = expression.evaluate(new EvaluationParameters(minZoom));
	        const maxSize = expression.evaluate(new EvaluationParameters(maxZoom));
	        return {
	            kind: 'camera',
	            minZoom,
	            maxZoom,
	            minSize,
	            maxSize,
	            interpolationType
	        };
	    }
	}
	function evaluateSizeForFeature(sizeData, {uSize, uSizeT}, {lowerSize, upperSize}) {
	    if (sizeData.kind === 'source') {
	        return lowerSize / SIZE_PACK_FACTOR;
	    } else if (sizeData.kind === 'composite') {
	        return number(lowerSize / SIZE_PACK_FACTOR, upperSize / SIZE_PACK_FACTOR, uSizeT);
	    }
	    return uSize;
	}
	function evaluateSizeForZoom(sizeData, zoom) {
	    let uSizeT = 0;
	    let uSize = 0;
	    if (sizeData.kind === 'constant') {
	        uSize = sizeData.layoutSize;
	    } else if (sizeData.kind !== 'source') {
	        const {interpolationType, minZoom, maxZoom} = sizeData;
	        const t = !interpolationType ? 0 : clamp(Interpolate$1.interpolationFactor(interpolationType, zoom, minZoom, maxZoom), 0, 1);
	        if (sizeData.kind === 'camera') {
	            uSize = number(sizeData.minSize, sizeData.maxSize, t);
	        } else {
	            uSizeT = t;
	        }
	    }
	    return {
	        uSizeT,
	        uSize
	    };
	}

	var symbolSize = /*#__PURE__*/Object.freeze({
	__proto__: null,
	getSizeData: getSizeData,
	evaluateSizeForFeature: evaluateSizeForFeature,
	evaluateSizeForZoom: evaluateSizeForZoom,
	SIZE_PACK_FACTOR: SIZE_PACK_FACTOR
	});

	function transformText(text, layer, feature) {
	    const transform = layer.layout.get('text-transform').evaluate(feature, {});
	    if (transform === 'uppercase') {
	        text = text.toLocaleUpperCase();
	    } else if (transform === 'lowercase') {
	        text = text.toLocaleLowerCase();
	    }
	    if (plugin.applyArabicShaping) {
	        text = plugin.applyArabicShaping(text);
	    }
	    return text;
	}
	function transformText$1 (text, layer, feature) {
	    text.sections.forEach(section => {
	        section.text = transformText(section.text, layer, feature);
	    });
	    return text;
	}

	function mergeLines (features) {
	    const leftIndex = {};
	    const rightIndex = {};
	    const mergedFeatures = [];
	    let mergedIndex = 0;
	    function add(k) {
	        mergedFeatures.push(features[k]);
	        mergedIndex++;
	    }
	    function mergeFromRight(leftKey, rightKey, geom) {
	        const i = rightIndex[leftKey];
	        delete rightIndex[leftKey];
	        rightIndex[rightKey] = i;
	        mergedFeatures[i].geometry[0].pop();
	        mergedFeatures[i].geometry[0] = mergedFeatures[i].geometry[0].concat(geom[0]);
	        return i;
	    }
	    function mergeFromLeft(leftKey, rightKey, geom) {
	        const i = leftIndex[rightKey];
	        delete leftIndex[rightKey];
	        leftIndex[leftKey] = i;
	        mergedFeatures[i].geometry[0].shift();
	        mergedFeatures[i].geometry[0] = geom[0].concat(mergedFeatures[i].geometry[0]);
	        return i;
	    }
	    function getKey(text, geom, onRight) {
	        const point = onRight ? geom[0][geom[0].length - 1] : geom[0][0];
	        return `${ text }:${ point.x }:${ point.y }`;
	    }
	    for (let k = 0; k < features.length; k++) {
	        const feature = features[k];
	        const geom = feature.geometry;
	        const text = feature.text ? feature.text.toString() : null;
	        if (!text) {
	            add(k);
	            continue;
	        }
	        const leftKey = getKey(text, geom), rightKey = getKey(text, geom, true);
	        if (leftKey in rightIndex && rightKey in leftIndex && rightIndex[leftKey] !== leftIndex[rightKey]) {
	            const j = mergeFromLeft(leftKey, rightKey, geom);
	            const i = mergeFromRight(leftKey, rightKey, mergedFeatures[j].geometry);
	            delete leftIndex[leftKey];
	            delete rightIndex[rightKey];
	            rightIndex[getKey(text, mergedFeatures[i].geometry, true)] = i;
	            mergedFeatures[j].geometry = null;
	        } else if (leftKey in rightIndex) {
	            mergeFromRight(leftKey, rightKey, geom);
	        } else if (rightKey in leftIndex) {
	            mergeFromLeft(leftKey, rightKey, geom);
	        } else {
	            add(k);
	            leftIndex[leftKey] = mergedIndex - 1;
	            rightIndex[rightKey] = mergedIndex - 1;
	        }
	    }
	    return mergedFeatures.filter(f => f.geometry);
	}

	const verticalizedCharacterMap = {
	    '!': '\uFE15',
	    '#': '\uFF03',
	    '$': '\uFF04',
	    '%': '\uFF05',
	    '&': '\uFF06',
	    '(': '\uFE35',
	    ')': '\uFE36',
	    '*': '\uFF0A',
	    '+': '\uFF0B',
	    ',': '\uFE10',
	    '-': '\uFE32',
	    '.': '\u30FB',
	    '/': '\uFF0F',
	    ':': '\uFE13',
	    ';': '\uFE14',
	    '<': '\uFE3F',
	    '=': '\uFF1D',
	    '>': '\uFE40',
	    '?': '\uFE16',
	    '@': '\uFF20',
	    '[': '\uFE47',
	    '\\': '\uFF3C',
	    ']': '\uFE48',
	    '^': '\uFF3E',
	    '_': '︳',
	    '`': '\uFF40',
	    '{': '\uFE37',
	    '|': '\u2015',
	    '}': '\uFE38',
	    '~': '\uFF5E',
	    '\xA2': '\uFFE0',
	    '\xA3': '\uFFE1',
	    '\xA5': '\uFFE5',
	    '\xA6': '\uFFE4',
	    '\xAC': '\uFFE2',
	    '\xAF': '\uFFE3',
	    '\u2013': '\uFE32',
	    '\u2014': '\uFE31',
	    '\u2018': '\uFE43',
	    '\u2019': '\uFE44',
	    '\u201C': '\uFE41',
	    '\u201D': '\uFE42',
	    '\u2026': '\uFE19',
	    '\u2027': '\u30FB',
	    '\u20A9': '\uFFE6',
	    '\u3001': '\uFE11',
	    '\u3002': '\uFE12',
	    '\u3008': '\uFE3F',
	    '\u3009': '\uFE40',
	    '\u300A': '\uFE3D',
	    '\u300B': '\uFE3E',
	    '\u300C': '\uFE41',
	    '\u300D': '\uFE42',
	    '\u300E': '\uFE43',
	    '\u300F': '\uFE44',
	    '\u3010': '\uFE3B',
	    '\u3011': '\uFE3C',
	    '\u3014': '\uFE39',
	    '\u3015': '\uFE3A',
	    '\u3016': '\uFE17',
	    '\u3017': '\uFE18',
	    '\uFF01': '\uFE15',
	    '\uFF08': '\uFE35',
	    '\uFF09': '\uFE36',
	    '\uFF0C': '\uFE10',
	    '\uFF0D': '\uFE32',
	    '\uFF0E': '\u30FB',
	    '\uFF1A': '\uFE13',
	    '\uFF1B': '\uFE14',
	    '\uFF1C': '\uFE3F',
	    '\uFF1E': '\uFE40',
	    '\uFF1F': '\uFE16',
	    '\uFF3B': '\uFE47',
	    '\uFF3D': '\uFE48',
	    '＿': '︳',
	    '\uFF5B': '\uFE37',
	    '\uFF5C': '\u2015',
	    '\uFF5D': '\uFE38',
	    '\uFF5F': '\uFE35',
	    '\uFF60': '\uFE36',
	    '\uFF61': '\uFE12',
	    '\uFF62': '\uFE41',
	    '\uFF63': '\uFE42'
	};
	function verticalizePunctuation(input, skipContextChecking) {
	    let output = '';
	    for (let i = 0; i < input.length; i++) {
	        const nextCharCode = input.charCodeAt(i + 1) || null;
	        const prevCharCode = input.charCodeAt(i - 1) || null;
	        const canReplacePunctuation = skipContextChecking || (!nextCharCode || !charHasRotatedVerticalOrientation(nextCharCode) || verticalizedCharacterMap[input[i + 1]]) && (!prevCharCode || !charHasRotatedVerticalOrientation(prevCharCode) || verticalizedCharacterMap[input[i - 1]]);
	        if (canReplacePunctuation && verticalizedCharacterMap[input[i]]) {
	            output += verticalizedCharacterMap[input[i]];
	        } else {
	            output += input[i];
	        }
	    }
	    return output;
	}
	function isVerticalClosePunctuation(chr) {
	    return chr === '\uFE36' || chr === '\uFE48' || chr === '\uFE38' || chr === '\uFE44' || chr === '\uFE42' || chr === '\uFE3E' || chr === '\uFE3C' || chr === '\uFE3A' || chr === '\uFE18' || chr === '\uFE40' || chr === '\uFE10' || chr === '\uFE13' || chr === '\uFE14' || chr === '\uFF40' || chr === '\uFFE3' || chr === '\uFE11' || chr === '\uFE12';
	}
	function isVerticalOpenPunctuation(chr) {
	    return chr === '\uFE35' || chr === '\uFE47' || chr === '\uFE37' || chr === '\uFE43' || chr === '\uFE41' || chr === '\uFE3D' || chr === '\uFE3B' || chr === '\uFE39' || chr === '\uFE17' || chr === '\uFE3F';
	}

	var read = function (buffer, offset, isLE, mLen, nBytes) {
	    var e, m;
	    var eLen = nBytes * 8 - mLen - 1;
	    var eMax = (1 << eLen) - 1;
	    var eBias = eMax >> 1;
	    var nBits = -7;
	    var i = isLE ? nBytes - 1 : 0;
	    var d = isLE ? -1 : 1;
	    var s = buffer[offset + i];
	    i += d;
	    e = s & (1 << -nBits) - 1;
	    s >>= -nBits;
	    nBits += eLen;
	    for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {
	    }
	    m = e & (1 << -nBits) - 1;
	    e >>= -nBits;
	    nBits += mLen;
	    for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {
	    }
	    if (e === 0) {
	        e = 1 - eBias;
	    } else if (e === eMax) {
	        return m ? NaN : (s ? -1 : 1) * Infinity;
	    } else {
	        m = m + Math.pow(2, mLen);
	        e = e - eBias;
	    }
	    return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
	};
	var write = function (buffer, value, offset, isLE, mLen, nBytes) {
	    var e, m, c;
	    var eLen = nBytes * 8 - mLen - 1;
	    var eMax = (1 << eLen) - 1;
	    var eBias = eMax >> 1;
	    var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
	    var i = isLE ? 0 : nBytes - 1;
	    var d = isLE ? 1 : -1;
	    var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;
	    value = Math.abs(value);
	    if (isNaN(value) || value === Infinity) {
	        m = isNaN(value) ? 1 : 0;
	        e = eMax;
	    } else {
	        e = Math.floor(Math.log(value) / Math.LN2);
	        if (value * (c = Math.pow(2, -e)) < 1) {
	            e--;
	            c *= 2;
	        }
	        if (e + eBias >= 1) {
	            value += rt / c;
	        } else {
	            value += rt * Math.pow(2, 1 - eBias);
	        }
	        if (value * c >= 2) {
	            e++;
	            c /= 2;
	        }
	        if (e + eBias >= eMax) {
	            m = 0;
	            e = eMax;
	        } else if (e + eBias >= 1) {
	            m = (value * c - 1) * Math.pow(2, mLen);
	            e = e + eBias;
	        } else {
	            m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
	            e = 0;
	        }
	    }
	    for (; mLen >= 8; buffer[offset + i] = m & 255, i += d, m /= 256, mLen -= 8) {
	    }
	    e = e << mLen | m;
	    eLen += mLen;
	    for (; eLen > 0; buffer[offset + i] = e & 255, i += d, e /= 256, eLen -= 8) {
	    }
	    buffer[offset + i - d] |= s * 128;
	};

	var ieee754 = {
		read: read,
		write: write
	};

	var pbf = Pbf;

	function Pbf(buf) {
	    this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
	    this.pos = 0;
	    this.type = 0;
	    this.length = this.buf.length;
	}
	Pbf.Varint = 0;
	Pbf.Fixed64 = 1;
	Pbf.Bytes = 2;
	Pbf.Fixed32 = 5;
	var SHIFT_LEFT_32 = (1 << 16) * (1 << 16), SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32;
	var TEXT_DECODER_MIN_LENGTH = 12;
	var utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf8');
	Pbf.prototype = {
	    destroy: function () {
	        this.buf = null;
	    },
	    readFields: function (readField, result, end) {
	        end = end || this.length;
	        while (this.pos < end) {
	            var val = this.readVarint(), tag = val >> 3, startPos = this.pos;
	            this.type = val & 7;
	            readField(tag, result, this);
	            if (this.pos === startPos)
	                this.skip(val);
	        }
	        return result;
	    },
	    readMessage: function (readField, result) {
	        return this.readFields(readField, result, this.readVarint() + this.pos);
	    },
	    readFixed32: function () {
	        var val = readUInt32(this.buf, this.pos);
	        this.pos += 4;
	        return val;
	    },
	    readSFixed32: function () {
	        var val = readInt32(this.buf, this.pos);
	        this.pos += 4;
	        return val;
	    },
	    readFixed64: function () {
	        var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
	        this.pos += 8;
	        return val;
	    },
	    readSFixed64: function () {
	        var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
	        this.pos += 8;
	        return val;
	    },
	    readFloat: function () {
	        var val = ieee754.read(this.buf, this.pos, true, 23, 4);
	        this.pos += 4;
	        return val;
	    },
	    readDouble: function () {
	        var val = ieee754.read(this.buf, this.pos, true, 52, 8);
	        this.pos += 8;
	        return val;
	    },
	    readVarint: function (isSigned) {
	        var buf = this.buf, val, b;
	        b = buf[this.pos++];
	        val = b & 127;
	        if (b < 128)
	            return val;
	        b = buf[this.pos++];
	        val |= (b & 127) << 7;
	        if (b < 128)
	            return val;
	        b = buf[this.pos++];
	        val |= (b & 127) << 14;
	        if (b < 128)
	            return val;
	        b = buf[this.pos++];
	        val |= (b & 127) << 21;
	        if (b < 128)
	            return val;
	        b = buf[this.pos];
	        val |= (b & 15) << 28;
	        return readVarintRemainder(val, isSigned, this);
	    },
	    readVarint64: function () {
	        return this.readVarint(true);
	    },
	    readSVarint: function () {
	        var num = this.readVarint();
	        return num % 2 === 1 ? (num + 1) / -2 : num / 2;
	    },
	    readBoolean: function () {
	        return Boolean(this.readVarint());
	    },
	    readString: function () {
	        var end = this.readVarint() + this.pos;
	        var pos = this.pos;
	        this.pos = end;
	        if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
	            return readUtf8TextDecoder(this.buf, pos, end);
	        }
	        return readUtf8(this.buf, pos, end);
	    },
	    readBytes: function () {
	        var end = this.readVarint() + this.pos, buffer = this.buf.subarray(this.pos, end);
	        this.pos = end;
	        return buffer;
	    },
	    readPackedVarint: function (arr, isSigned) {
	        if (this.type !== Pbf.Bytes)
	            return arr.push(this.readVarint(isSigned));
	        var end = readPackedEnd(this);
	        arr = arr || [];
	        while (this.pos < end)
	            arr.push(this.readVarint(isSigned));
	        return arr;
	    },
	    readPackedSVarint: function (arr) {
	        if (this.type !== Pbf.Bytes)
	            return arr.push(this.readSVarint());
	        var end = readPackedEnd(this);
	        arr = arr || [];
	        while (this.pos < end)
	            arr.push(this.readSVarint());
	        return arr;
	    },
	    readPackedBoolean: function (arr) {
	        if (this.type !== Pbf.Bytes)
	            return arr.push(this.readBoolean());
	        var end = readPackedEnd(this);
	        arr = arr || [];
	        while (this.pos < end)
	            arr.push(this.readBoolean());
	        return arr;
	    },
	    readPackedFloat: function (arr) {
	        if (this.type !== Pbf.Bytes)
	            return arr.push(this.readFloat());
	        var end = readPackedEnd(this);
	        arr = arr || [];
	        while (this.pos < end)
	            arr.push(this.readFloat());
	        return arr;
	    },
	    readPackedDouble: function (arr) {
	        if (this.type !== Pbf.Bytes)
	            return arr.push(this.readDouble());
	        var end = readPackedEnd(this);
	        arr = arr || [];
	        while (this.pos < end)
	            arr.push(this.readDouble());
	        return arr;
	    },
	    readPackedFixed32: function (arr) {
	        if (this.type !== Pbf.Bytes)
	            return arr.push(this.readFixed32());
	        var end = readPackedEnd(this);
	        arr = arr || [];
	        while (this.pos < end)
	            arr.push(this.readFixed32());
	        return arr;
	    },
	    readPackedSFixed32: function (arr) {
	        if (this.type !== Pbf.Bytes)
	            return arr.push(this.readSFixed32());
	        var end = readPackedEnd(this);
	        arr = arr || [];
	        while (this.pos < end)
	            arr.push(this.readSFixed32());
	        return arr;
	    },
	    readPackedFixed64: function (arr) {
	        if (this.type !== Pbf.Bytes)
	            return arr.push(this.readFixed64());
	        var end = readPackedEnd(this);
	        arr = arr || [];
	        while (this.pos < end)
	            arr.push(this.readFixed64());
	        return arr;
	    },
	    readPackedSFixed64: function (arr) {
	        if (this.type !== Pbf.Bytes)
	            return arr.push(this.readSFixed64());
	        var end = readPackedEnd(this);
	        arr = arr || [];
	        while (this.pos < end)
	            arr.push(this.readSFixed64());
	        return arr;
	    },
	    skip: function (val) {
	        var type = val & 7;
	        if (type === Pbf.Varint)
	            while (this.buf[this.pos++] > 127) {
	            }
	        else if (type === Pbf.Bytes)
	            this.pos = this.readVarint() + this.pos;
	        else if (type === Pbf.Fixed32)
	            this.pos += 4;
	        else if (type === Pbf.Fixed64)
	            this.pos += 8;
	        else
	            throw new Error('Unimplemented type: ' + type);
	    },
	    writeTag: function (tag, type) {
	        this.writeVarint(tag << 3 | type);
	    },
	    realloc: function (min) {
	        var length = this.length || 16;
	        while (length < this.pos + min)
	            length *= 2;
	        if (length !== this.length) {
	            var buf = new Uint8Array(length);
	            buf.set(this.buf);
	            this.buf = buf;
	            this.length = length;
	        }
	    },
	    finish: function () {
	        this.length = this.pos;
	        this.pos = 0;
	        return this.buf.subarray(0, this.length);
	    },
	    writeFixed32: function (val) {
	        this.realloc(4);
	        writeInt32(this.buf, val, this.pos);
	        this.pos += 4;
	    },
	    writeSFixed32: function (val) {
	        this.realloc(4);
	        writeInt32(this.buf, val, this.pos);
	        this.pos += 4;
	    },
	    writeFixed64: function (val) {
	        this.realloc(8);
	        writeInt32(this.buf, val & -1, this.pos);
	        writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
	        this.pos += 8;
	    },
	    writeSFixed64: function (val) {
	        this.realloc(8);
	        writeInt32(this.buf, val & -1, this.pos);
	        writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
	        this.pos += 8;
	    },
	    writeVarint: function (val) {
	        val = +val || 0;
	        if (val > 268435455 || val < 0) {
	            writeBigVarint(val, this);
	            return;
	        }
	        this.realloc(4);
	        this.buf[this.pos++] = val & 127 | (val > 127 ? 128 : 0);
	        if (val <= 127)
	            return;
	        this.buf[this.pos++] = (val >>>= 7) & 127 | (val > 127 ? 128 : 0);
	        if (val <= 127)
	            return;
	        this.buf[this.pos++] = (val >>>= 7) & 127 | (val > 127 ? 128 : 0);
	        if (val <= 127)
	            return;
	        this.buf[this.pos++] = val >>> 7 & 127;
	    },
	    writeSVarint: function (val) {
	        this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
	    },
	    writeBoolean: function (val) {
	        this.writeVarint(Boolean(val));
	    },
	    writeString: function (str) {
	        str = String(str);
	        this.realloc(str.length * 4);
	        this.pos++;
	        var startPos = this.pos;
	        this.pos = writeUtf8(this.buf, str, this.pos);
	        var len = this.pos - startPos;
	        if (len >= 128)
	            makeRoomForExtraLength(startPos, len, this);
	        this.pos = startPos - 1;
	        this.writeVarint(len);
	        this.pos += len;
	    },
	    writeFloat: function (val) {
	        this.realloc(4);
	        ieee754.write(this.buf, val, this.pos, true, 23, 4);
	        this.pos += 4;
	    },
	    writeDouble: function (val) {
	        this.realloc(8);
	        ieee754.write(this.buf, val, this.pos, true, 52, 8);
	        this.pos += 8;
	    },
	    writeBytes: function (buffer) {
	        var len = buffer.length;
	        this.writeVarint(len);
	        this.realloc(len);
	        for (var i = 0; i < len; i++)
	            this.buf[this.pos++] = buffer[i];
	    },
	    writeRawMessage: function (fn, obj) {
	        this.pos++;
	        var startPos = this.pos;
	        fn(obj, this);
	        var len = this.pos - startPos;
	        if (len >= 128)
	            makeRoomForExtraLength(startPos, len, this);
	        this.pos = startPos - 1;
	        this.writeVarint(len);
	        this.pos += len;
	    },
	    writeMessage: function (tag, fn, obj) {
	        this.writeTag(tag, Pbf.Bytes);
	        this.writeRawMessage(fn, obj);
	    },
	    writePackedVarint: function (tag, arr) {
	        if (arr.length)
	            this.writeMessage(tag, writePackedVarint, arr);
	    },
	    writePackedSVarint: function (tag, arr) {
	        if (arr.length)
	            this.writeMessage(tag, writePackedSVarint, arr);
	    },
	    writePackedBoolean: function (tag, arr) {
	        if (arr.length)
	            this.writeMessage(tag, writePackedBoolean, arr);
	    },
	    writePackedFloat: function (tag, arr) {
	        if (arr.length)
	            this.writeMessage(tag, writePackedFloat, arr);
	    },
	    writePackedDouble: function (tag, arr) {
	        if (arr.length)
	            this.writeMessage(tag, writePackedDouble, arr);
	    },
	    writePackedFixed32: function (tag, arr) {
	        if (arr.length)
	            this.writeMessage(tag, writePackedFixed32, arr);
	    },
	    writePackedSFixed32: function (tag, arr) {
	        if (arr.length)
	            this.writeMessage(tag, writePackedSFixed32, arr);
	    },
	    writePackedFixed64: function (tag, arr) {
	        if (arr.length)
	            this.writeMessage(tag, writePackedFixed64, arr);
	    },
	    writePackedSFixed64: function (tag, arr) {
	        if (arr.length)
	            this.writeMessage(tag, writePackedSFixed64, arr);
	    },
	    writeBytesField: function (tag, buffer) {
	        this.writeTag(tag, Pbf.Bytes);
	        this.writeBytes(buffer);
	    },
	    writeFixed32Field: function (tag, val) {
	        this.writeTag(tag, Pbf.Fixed32);
	        this.writeFixed32(val);
	    },
	    writeSFixed32Field: function (tag, val) {
	        this.writeTag(tag, Pbf.Fixed32);
	        this.writeSFixed32(val);
	    },
	    writeFixed64Field: function (tag, val) {
	        this.writeTag(tag, Pbf.Fixed64);
	        this.writeFixed64(val);
	    },
	    writeSFixed64Field: function (tag, val) {
	        this.writeTag(tag, Pbf.Fixed64);
	        this.writeSFixed64(val);
	    },
	    writeVarintField: function (tag, val) {
	        this.writeTag(tag, Pbf.Varint);
	        this.writeVarint(val);
	    },
	    writeSVarintField: function (tag, val) {
	        this.writeTag(tag, Pbf.Varint);
	        this.writeSVarint(val);
	    },
	    writeStringField: function (tag, str) {
	        this.writeTag(tag, Pbf.Bytes);
	        this.writeString(str);
	    },
	    writeFloatField: function (tag, val) {
	        this.writeTag(tag, Pbf.Fixed32);
	        this.writeFloat(val);
	    },
	    writeDoubleField: function (tag, val) {
	        this.writeTag(tag, Pbf.Fixed64);
	        this.writeDouble(val);
	    },
	    writeBooleanField: function (tag, val) {
	        this.writeVarintField(tag, Boolean(val));
	    }
	};
	function readVarintRemainder(l, s, p) {
	    var buf = p.buf, h, b;
	    b = buf[p.pos++];
	    h = (b & 112) >> 4;
	    if (b < 128)
	        return toNum(l, h, s);
	    b = buf[p.pos++];
	    h |= (b & 127) << 3;
	    if (b < 128)
	        return toNum(l, h, s);
	    b = buf[p.pos++];
	    h |= (b & 127) << 10;
	    if (b < 128)
	        return toNum(l, h, s);
	    b = buf[p.pos++];
	    h |= (b & 127) << 17;
	    if (b < 128)
	        return toNum(l, h, s);
	    b = buf[p.pos++];
	    h |= (b & 127) << 24;
	    if (b < 128)
	        return toNum(l, h, s);
	    b = buf[p.pos++];
	    h |= (b & 1) << 31;
	    if (b < 128)
	        return toNum(l, h, s);
	    throw new Error('Expected varint not more than 10 bytes');
	}
	function readPackedEnd(pbf) {
	    return pbf.type === Pbf.Bytes ? pbf.readVarint() + pbf.pos : pbf.pos + 1;
	}
	function toNum(low, high, isSigned) {
	    if (isSigned) {
	        return high * 4294967296 + (low >>> 0);
	    }
	    return (high >>> 0) * 4294967296 + (low >>> 0);
	}
	function writeBigVarint(val, pbf) {
	    var low, high;
	    if (val >= 0) {
	        low = val % 4294967296 | 0;
	        high = val / 4294967296 | 0;
	    } else {
	        low = ~(-val % 4294967296);
	        high = ~(-val / 4294967296);
	        if (low ^ 4294967295) {
	            low = low + 1 | 0;
	        } else {
	            low = 0;
	            high = high + 1 | 0;
	        }
	    }
	    if (val >= 18446744073709552000 || val < -18446744073709552000) {
	        throw new Error('Given varint doesn\'t fit into 10 bytes');
	    }
	    pbf.realloc(10);
	    writeBigVarintLow(low, high, pbf);
	    writeBigVarintHigh(high, pbf);
	}
	function writeBigVarintLow(low, high, pbf) {
	    pbf.buf[pbf.pos++] = low & 127 | 128;
	    low >>>= 7;
	    pbf.buf[pbf.pos++] = low & 127 | 128;
	    low >>>= 7;
	    pbf.buf[pbf.pos++] = low & 127 | 128;
	    low >>>= 7;
	    pbf.buf[pbf.pos++] = low & 127 | 128;
	    low >>>= 7;
	    pbf.buf[pbf.pos] = low & 127;
	}
	function writeBigVarintHigh(high, pbf) {
	    var lsb = (high & 7) << 4;
	    pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 128 : 0);
	    if (!high)
	        return;
	    pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
	    if (!high)
	        return;
	    pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
	    if (!high)
	        return;
	    pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
	    if (!high)
	        return;
	    pbf.buf[pbf.pos++] = high & 127 | ((high >>>= 7) ? 128 : 0);
	    if (!high)
	        return;
	    pbf.buf[pbf.pos++] = high & 127;
	}
	function makeRoomForExtraLength(startPos, len, pbf) {
	    var extraLen = len <= 16383 ? 1 : len <= 2097151 ? 2 : len <= 268435455 ? 3 : Math.floor(Math.log(len) / (Math.LN2 * 7));
	    pbf.realloc(extraLen);
	    for (var i = pbf.pos - 1; i >= startPos; i--)
	        pbf.buf[i + extraLen] = pbf.buf[i];
	}
	function writePackedVarint(arr, pbf) {
	    for (var i = 0; i < arr.length; i++)
	        pbf.writeVarint(arr[i]);
	}
	function writePackedSVarint(arr, pbf) {
	    for (var i = 0; i < arr.length; i++)
	        pbf.writeSVarint(arr[i]);
	}
	function writePackedFloat(arr, pbf) {
	    for (var i = 0; i < arr.length; i++)
	        pbf.writeFloat(arr[i]);
	}
	function writePackedDouble(arr, pbf) {
	    for (var i = 0; i < arr.length; i++)
	        pbf.writeDouble(arr[i]);
	}
	function writePackedBoolean(arr, pbf) {
	    for (var i = 0; i < arr.length; i++)
	        pbf.writeBoolean(arr[i]);
	}
	function writePackedFixed32(arr, pbf) {
	    for (var i = 0; i < arr.length; i++)
	        pbf.writeFixed32(arr[i]);
	}
	function writePackedSFixed32(arr, pbf) {
	    for (var i = 0; i < arr.length; i++)
	        pbf.writeSFixed32(arr[i]);
	}
	function writePackedFixed64(arr, pbf) {
	    for (var i = 0; i < arr.length; i++)
	        pbf.writeFixed64(arr[i]);
	}
	function writePackedSFixed64(arr, pbf) {
	    for (var i = 0; i < arr.length; i++)
	        pbf.writeSFixed64(arr[i]);
	}
	function readUInt32(buf, pos) {
	    return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + buf[pos + 3] * 16777216;
	}
	function writeInt32(buf, val, pos) {
	    buf[pos] = val;
	    buf[pos + 1] = val >>> 8;
	    buf[pos + 2] = val >>> 16;
	    buf[pos + 3] = val >>> 24;
	}
	function readInt32(buf, pos) {
	    return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + (buf[pos + 3] << 24);
	}
	function readUtf8(buf, pos, end) {
	    var str = '';
	    var i = pos;
	    while (i < end) {
	        var b0 = buf[i];
	        var c = null;
	        var bytesPerSequence = b0 > 239 ? 4 : b0 > 223 ? 3 : b0 > 191 ? 2 : 1;
	        if (i + bytesPerSequence > end)
	            break;
	        var b1, b2, b3;
	        if (bytesPerSequence === 1) {
	            if (b0 < 128) {
	                c = b0;
	            }
	        } else if (bytesPerSequence === 2) {
	            b1 = buf[i + 1];
	            if ((b1 & 192) === 128) {
	                c = (b0 & 31) << 6 | b1 & 63;
	                if (c <= 127) {
	                    c = null;
	                }
	            }
	        } else if (bytesPerSequence === 3) {
	            b1 = buf[i + 1];
	            b2 = buf[i + 2];
	            if ((b1 & 192) === 128 && (b2 & 192) === 128) {
	                c = (b0 & 15) << 12 | (b1 & 63) << 6 | b2 & 63;
	                if (c <= 2047 || c >= 55296 && c <= 57343) {
	                    c = null;
	                }
	            }
	        } else if (bytesPerSequence === 4) {
	            b1 = buf[i + 1];
	            b2 = buf[i + 2];
	            b3 = buf[i + 3];
	            if ((b1 & 192) === 128 && (b2 & 192) === 128 && (b3 & 192) === 128) {
	                c = (b0 & 15) << 18 | (b1 & 63) << 12 | (b2 & 63) << 6 | b3 & 63;
	                if (c <= 65535 || c >= 1114112) {
	                    c = null;
	                }
	            }
	        }
	        if (c === null) {
	            c = 65533;
	            bytesPerSequence = 1;
	        } else if (c > 65535) {
	            c -= 65536;
	            str += String.fromCharCode(c >>> 10 & 1023 | 55296);
	            c = 56320 | c & 1023;
	        }
	        str += String.fromCharCode(c);
	        i += bytesPerSequence;
	    }
	    return str;
	}
	function readUtf8TextDecoder(buf, pos, end) {
	    return utf8TextDecoder.decode(buf.subarray(pos, end));
	}
	function writeUtf8(buf, str, pos) {
	    for (var i = 0, c, lead; i < str.length; i++) {
	        c = str.charCodeAt(i);
	        if (c > 55295 && c < 57344) {
	            if (lead) {
	                if (c < 56320) {
	                    buf[pos++] = 239;
	                    buf[pos++] = 191;
	                    buf[pos++] = 189;
	                    lead = c;
	                    continue;
	                } else {
	                    c = lead - 55296 << 10 | c - 56320 | 65536;
	                    lead = null;
	                }
	            } else {
	                if (c > 56319 || i + 1 === str.length) {
	                    buf[pos++] = 239;
	                    buf[pos++] = 191;
	                    buf[pos++] = 189;
	                } else {
	                    lead = c;
	                }
	                continue;
	            }
	        } else if (lead) {
	            buf[pos++] = 239;
	            buf[pos++] = 191;
	            buf[pos++] = 189;
	            lead = null;
	        }
	        if (c < 128) {
	            buf[pos++] = c;
	        } else {
	            if (c < 2048) {
	                buf[pos++] = c >> 6 | 192;
	            } else {
	                if (c < 65536) {
	                    buf[pos++] = c >> 12 | 224;
	                } else {
	                    buf[pos++] = c >> 18 | 240;
	                    buf[pos++] = c >> 12 & 63 | 128;
	                }
	                buf[pos++] = c >> 6 & 63 | 128;
	            }
	            buf[pos++] = c & 63 | 128;
	        }
	    }
	    return pos;
	}

	const border$1 = 3;
	function readFontstacks(tag, glyphData, pbf) {
	    glyphData.glyphs = [];
	    if (tag === 1) {
	        pbf.readMessage(readFontstack, glyphData);
	    }
	}
	function readFontstack(tag, glyphData, pbf) {
	    if (tag === 3) {
	        const {id, bitmap, width, height, left, top, advance} = pbf.readMessage(readGlyph, {});
	        glyphData.glyphs.push({
	            id,
	            bitmap: new AlphaImage({
	                width: width + 2 * border$1,
	                height: height + 2 * border$1
	            }, bitmap),
	            metrics: {
	                width,
	                height,
	                left,
	                top,
	                advance
	            }
	        });
	    } else if (tag === 4) {
	        glyphData.ascender = pbf.readSVarint();
	    } else if (tag === 5) {
	        glyphData.descender = pbf.readSVarint();
	    }
	}
	function readGlyph(tag, glyph, pbf) {
	    if (tag === 1)
	        glyph.id = pbf.readVarint();
	    else if (tag === 2)
	        glyph.bitmap = pbf.readBytes();
	    else if (tag === 3)
	        glyph.width = pbf.readVarint();
	    else if (tag === 4)
	        glyph.height = pbf.readVarint();
	    else if (tag === 5)
	        glyph.left = pbf.readSVarint();
	    else if (tag === 6)
	        glyph.top = pbf.readSVarint();
	    else if (tag === 7)
	        glyph.advance = pbf.readVarint();
	}
	function parseGlyphPBF (data) {
	    return new pbf(data).readFields(readFontstacks, {});
	}
	const GLYPH_PBF_BORDER = border$1;

	function potpack(boxes) {

	    // calculate total box area and maximum box width
	    let area = 0;
	    let maxWidth = 0;

	    for (const box of boxes) {
	        area += box.w * box.h;
	        maxWidth = Math.max(maxWidth, box.w);
	    }

	    // sort the boxes for insertion by height, descending
	    boxes.sort((a, b) => b.h - a.h);

	    // aim for a squarish resulting container,
	    // slightly adjusted for sub-100% space utilization
	    const startWidth = Math.max(Math.ceil(Math.sqrt(area / 0.95)), maxWidth);

	    // start with a single empty space, unbounded at the bottom
	    const spaces = [{x: 0, y: 0, w: startWidth, h: Infinity}];

	    let width = 0;
	    let height = 0;

	    for (const box of boxes) {
	        // look through spaces backwards so that we check smaller spaces first
	        for (let i = spaces.length - 1; i >= 0; i--) {
	            const space = spaces[i];

	            // look for empty spaces that can accommodate the current box
	            if (box.w > space.w || box.h > space.h) continue;

	            // found the space; add the box to its top-left corner
	            // |-------|-------|
	            // |  box  |       |
	            // |_______|       |
	            // |         space |
	            // |_______________|
	            box.x = space.x;
	            box.y = space.y;

	            height = Math.max(height, box.y + box.h);
	            width = Math.max(width, box.x + box.w);

	            if (box.w === space.w && box.h === space.h) {
	                // space matches the box exactly; remove it
	                const last = spaces.pop();
	                if (i < spaces.length) spaces[i] = last;

	            } else if (box.h === space.h) {
	                // space matches the box height; update it accordingly
	                // |-------|---------------|
	                // |  box  | updated space |
	                // |_______|_______________|
	                space.x += box.w;
	                space.w -= box.w;

	            } else if (box.w === space.w) {
	                // space matches the box width; update it accordingly
	                // |---------------|
	                // |      box      |
	                // |_______________|
	                // | updated space |
	                // |_______________|
	                space.y += box.h;
	                space.h -= box.h;

	            } else {
	                // otherwise the box splits the space into two spaces
	                // |-------|-----------|
	                // |  box  | new space |
	                // |_______|___________|
	                // | updated space     |
	                // |___________________|
	                spaces.push({
	                    x: space.x + box.w,
	                    y: space.y,
	                    w: space.w - box.w,
	                    h: box.h
	                });
	                space.y += box.h;
	                space.h -= box.h;
	            }
	            break;
	        }
	    }

	    return {
	        w: width, // container width
	        h: height, // container height
	        fill: (area / (width * height)) || 0 // space utilization
	    };
	}

	const IMAGE_PADDING = 1;
	class ImagePosition {
	    constructor(paddedRect, {pixelRatio, version, stretchX, stretchY, content}) {
	        this.paddedRect = paddedRect;
	        this.pixelRatio = pixelRatio;
	        this.stretchX = stretchX;
	        this.stretchY = stretchY;
	        this.content = content;
	        this.version = version;
	    }
	    get tl() {
	        return [
	            this.paddedRect.x + IMAGE_PADDING,
	            this.paddedRect.y + IMAGE_PADDING
	        ];
	    }
	    get br() {
	        return [
	            this.paddedRect.x + this.paddedRect.w - IMAGE_PADDING,
	            this.paddedRect.y + this.paddedRect.h - IMAGE_PADDING
	        ];
	    }
	    get displaySize() {
	        return [
	            (this.paddedRect.w - IMAGE_PADDING * 2) / this.pixelRatio,
	            (this.paddedRect.h - IMAGE_PADDING * 2) / this.pixelRatio
	        ];
	    }
	}
	class ImageAtlas {
	    constructor(icons, patterns) {
	        const iconPositions = {}, patternPositions = {};
	        this.haveRenderCallbacks = [];
	        const bins = [];
	        this.addImages(icons, iconPositions, bins);
	        this.addImages(patterns, patternPositions, bins);
	        const {w, h} = potpack(bins);
	        const image = new RGBAImage({
	            width: w || 1,
	            height: h || 1
	        });
	        for (const id in icons) {
	            const src = icons[id];
	            const bin = iconPositions[id].paddedRect;
	            RGBAImage.copy(src.data, image, {
	                x: 0,
	                y: 0
	            }, {
	                x: bin.x + IMAGE_PADDING,
	                y: bin.y + IMAGE_PADDING
	            }, src.data);
	        }
	        for (const id in patterns) {
	            const src = patterns[id];
	            const bin = patternPositions[id].paddedRect;
	            const x = bin.x + IMAGE_PADDING, y = bin.y + IMAGE_PADDING, w = src.data.width, h = src.data.height;
	            RGBAImage.copy(src.data, image, {
	                x: 0,
	                y: 0
	            }, {
	                x,
	                y
	            }, src.data);
	            RGBAImage.copy(src.data, image, {
	                x: 0,
	                y: h - 1
	            }, {
	                x,
	                y: y - 1
	            }, {
	                width: w,
	                height: 1
	            });
	            RGBAImage.copy(src.data, image, {
	                x: 0,
	                y: 0
	            }, {
	                x,
	                y: y + h
	            }, {
	                width: w,
	                height: 1
	            });
	            RGBAImage.copy(src.data, image, {
	                x: w - 1,
	                y: 0
	            }, {
	                x: x - 1,
	                y
	            }, {
	                width: 1,
	                height: h
	            });
	            RGBAImage.copy(src.data, image, {
	                x: 0,
	                y: 0
	            }, {
	                x: x + w,
	                y
	            }, {
	                width: 1,
	                height: h
	            });
	        }
	        this.image = image;
	        this.iconPositions = iconPositions;
	        this.patternPositions = patternPositions;
	    }
	    addImages(images, positions, bins) {
	        for (const id in images) {
	            const src = images[id];
	            const bin = {
	                x: 0,
	                y: 0,
	                w: src.data.width + 2 * IMAGE_PADDING,
	                h: src.data.height + 2 * IMAGE_PADDING
	            };
	            bins.push(bin);
	            positions[id] = new ImagePosition(bin, src);
	            if (src.hasRenderCallback) {
	                this.haveRenderCallbacks.push(id);
	            }
	        }
	    }
	    patchUpdatedImages(imageManager, texture) {
	        this.haveRenderCallbacks = this.haveRenderCallbacks.filter(id => imageManager.hasImage(id));
	        imageManager.dispatchRenderCallbacks(this.haveRenderCallbacks);
	        for (const name in imageManager.updatedImages) {
	            this.patchUpdatedImage(this.iconPositions[name], imageManager.getImage(name), texture);
	            this.patchUpdatedImage(this.patternPositions[name], imageManager.getImage(name), texture);
	        }
	    }
	    patchUpdatedImage(position, image, texture) {
	        if (!position || !image)
	            return;
	        if (position.version === image.version)
	            return;
	        position.version = image.version;
	        const [x, y] = position.tl;
	        texture.update(image.data, undefined, {
	            x,
	            y
	        });
	    }
	}
	register(ImagePosition, 'ImagePosition');
	register(ImageAtlas, 'ImageAtlas');

	const WritingMode = {
	    horizontal: 1,
	    vertical: 2,
	    horizontalOnly: 3
	};
	const SHAPING_DEFAULT_OFFSET = -17;
	function isEmpty(positionedLines) {
	    for (const line of positionedLines) {
	        if (line.positionedGlyphs.length !== 0) {
	            return false;
	        }
	    }
	    return true;
	}
	const PUAbegin = 57344;
	const PUAend = 63743;
	class SectionOptions {
	    constructor() {
	        this.scale = 1;
	        this.fontStack = '';
	        this.imageName = null;
	    }
	    static forText(scale, fontStack) {
	        const textOptions = new SectionOptions();
	        textOptions.scale = scale || 1;
	        textOptions.fontStack = fontStack;
	        return textOptions;
	    }
	    static forImage(imageName) {
	        const imageOptions = new SectionOptions();
	        imageOptions.imageName = imageName;
	        return imageOptions;
	    }
	}
	class TaggedString {
	    constructor() {
	        this.text = '';
	        this.sectionIndex = [];
	        this.sections = [];
	        this.imageSectionID = null;
	    }
	    static fromFeature(text, defaultFontStack) {
	        const result = new TaggedString();
	        for (let i = 0; i < text.sections.length; i++) {
	            const section = text.sections[i];
	            if (!section.image) {
	                result.addTextSection(section, defaultFontStack);
	            } else {
	                result.addImageSection(section);
	            }
	        }
	        return result;
	    }
	    length() {
	        return this.text.length;
	    }
	    getSection(index) {
	        return this.sections[this.sectionIndex[index]];
	    }
	    getSections() {
	        return this.sections;
	    }
	    getSectionIndex(index) {
	        return this.sectionIndex[index];
	    }
	    getCharCode(index) {
	        return this.text.charCodeAt(index);
	    }
	    verticalizePunctuation(skipContextChecking) {
	        this.text = verticalizePunctuation(this.text, skipContextChecking);
	    }
	    trim() {
	        let beginningWhitespace = 0;
	        for (let i = 0; i < this.text.length && whitespace[this.text.charCodeAt(i)]; i++) {
	            beginningWhitespace++;
	        }
	        let trailingWhitespace = this.text.length;
	        for (let i = this.text.length - 1; i >= 0 && i >= beginningWhitespace && whitespace[this.text.charCodeAt(i)]; i--) {
	            trailingWhitespace--;
	        }
	        this.text = this.text.substring(beginningWhitespace, trailingWhitespace);
	        this.sectionIndex = this.sectionIndex.slice(beginningWhitespace, trailingWhitespace);
	    }
	    substring(start, end) {
	        const substring = new TaggedString();
	        substring.text = this.text.substring(start, end);
	        substring.sectionIndex = this.sectionIndex.slice(start, end);
	        substring.sections = this.sections;
	        return substring;
	    }
	    toString() {
	        return this.text;
	    }
	    getMaxScale() {
	        return this.sectionIndex.reduce((max, index) => Math.max(max, this.sections[index].scale), 0);
	    }
	    addTextSection(section, defaultFontStack) {
	        this.text += section.text;
	        this.sections.push(SectionOptions.forText(section.scale, section.fontStack || defaultFontStack));
	        const index = this.sections.length - 1;
	        for (let i = 0; i < section.text.length; ++i) {
	            this.sectionIndex.push(index);
	        }
	    }
	    addImageSection(section) {
	        const imageName = section.image ? section.image.name : '';
	        if (imageName.length === 0) {
	            warnOnce(`Can't add FormattedSection with an empty image.`);
	            return;
	        }
	        const nextImageSectionCharCode = this.getNextImageSectionCharCode();
	        if (!nextImageSectionCharCode) {
	            warnOnce(`Reached maximum number of images ${ PUAend - PUAbegin + 2 }`);
	            return;
	        }
	        this.text += String.fromCharCode(nextImageSectionCharCode);
	        this.sections.push(SectionOptions.forImage(imageName));
	        this.sectionIndex.push(this.sections.length - 1);
	    }
	    getNextImageSectionCharCode() {
	        if (!this.imageSectionID) {
	            this.imageSectionID = PUAbegin;
	            return this.imageSectionID;
	        }
	        if (this.imageSectionID >= PUAend)
	            return null;
	        return ++this.imageSectionID;
	    }
	}
	function breakLines(input, lineBreakPoints) {
	    const lines = [];
	    const text = input.text;
	    let start = 0;
	    for (const lineBreak of lineBreakPoints) {
	        lines.push(input.substring(start, lineBreak));
	        start = lineBreak;
	    }
	    if (start < text.length) {
	        lines.push(input.substring(start, text.length));
	    }
	    return lines;
	}
	function shapeText(text, glyphMap, glyphPositions, imagePositions, defaultFontStack, maxWidth, lineHeight, textAnchor, textJustify, spacing, translate, writingMode, allowVerticalPlacement, symbolPlacement, layoutTextSize, layoutTextSizeThisZoom) {
	    const logicalInput = TaggedString.fromFeature(text, defaultFontStack);
	    if (writingMode === WritingMode.vertical) {
	        logicalInput.verticalizePunctuation(allowVerticalPlacement);
	    }
	    let lines;
	    const {processBidirectionalText, processStyledBidirectionalText} = plugin;
	    if (processBidirectionalText && logicalInput.sections.length === 1) {
	        lines = [];
	        const untaggedLines = processBidirectionalText(logicalInput.toString(), determineLineBreaks(logicalInput, spacing, maxWidth, glyphMap, imagePositions, symbolPlacement, layoutTextSize));
	        for (const line of untaggedLines) {
	            const taggedLine = new TaggedString();
	            taggedLine.text = line;
	            taggedLine.sections = logicalInput.sections;
	            for (let i = 0; i < line.length; i++) {
	                taggedLine.sectionIndex.push(0);
	            }
	            lines.push(taggedLine);
	        }
	    } else if (processStyledBidirectionalText) {
	        lines = [];
	        const processedLines = processStyledBidirectionalText(logicalInput.text, logicalInput.sectionIndex, determineLineBreaks(logicalInput, spacing, maxWidth, glyphMap, imagePositions, symbolPlacement, layoutTextSize));
	        for (const line of processedLines) {
	            const taggedLine = new TaggedString();
	            taggedLine.text = line[0];
	            taggedLine.sectionIndex = line[1];
	            taggedLine.sections = logicalInput.sections;
	            lines.push(taggedLine);
	        }
	    } else {
	        lines = breakLines(logicalInput, determineLineBreaks(logicalInput, spacing, maxWidth, glyphMap, imagePositions, symbolPlacement, layoutTextSize));
	    }
	    const positionedLines = [];
	    const shaping = {
	        positionedLines,
	        text: logicalInput.toString(),
	        top: translate[1],
	        bottom: translate[1],
	        left: translate[0],
	        right: translate[0],
	        writingMode,
	        iconsInText: false,
	        verticalizable: false,
	        hasBaseline: false
	    };
	    shapeLines(shaping, glyphMap, glyphPositions, imagePositions, lines, lineHeight, textAnchor, textJustify, writingMode, spacing, allowVerticalPlacement, layoutTextSizeThisZoom);
	    if (isEmpty(positionedLines))
	        return false;
	    return shaping;
	}
	const whitespace = {
	    [9]: true,
	    [10]: true,
	    [11]: true,
	    [12]: true,
	    [13]: true,
	    [32]: true
	};
	const breakable = {
	    [10]: true,
	    [32]: true,
	    [38]: true,
	    [40]: true,
	    [41]: true,
	    [43]: true,
	    [45]: true,
	    [47]: true,
	    [173]: true,
	    [183]: true,
	    [8203]: true,
	    [8208]: true,
	    [8211]: true,
	    [8231]: true
	};
	function getGlyphAdvance(codePoint, section, glyphMap, imagePositions, spacing, layoutTextSize) {
	    if (!section.imageName) {
	        const positions = glyphMap[section.fontStack];
	        const glyph = positions && positions.glyphs[codePoint];
	        if (!glyph)
	            return 0;
	        return glyph.metrics.advance * section.scale + spacing;
	    } else {
	        const imagePosition = imagePositions[section.imageName];
	        if (!imagePosition)
	            return 0;
	        return imagePosition.displaySize[0] * section.scale * ONE_EM / layoutTextSize + spacing;
	    }
	}
	function determineAverageLineWidth(logicalInput, spacing, maxWidth, glyphMap, imagePositions, layoutTextSize) {
	    let totalWidth = 0;
	    for (let index = 0; index < logicalInput.length(); index++) {
	        const section = logicalInput.getSection(index);
	        totalWidth += getGlyphAdvance(logicalInput.getCharCode(index), section, glyphMap, imagePositions, spacing, layoutTextSize);
	    }
	    const lineCount = Math.max(1, Math.ceil(totalWidth / maxWidth));
	    return totalWidth / lineCount;
	}
	function calculateBadness(lineWidth, targetWidth, penalty, isLastBreak) {
	    const raggedness = Math.pow(lineWidth - targetWidth, 2);
	    if (isLastBreak) {
	        if (lineWidth < targetWidth) {
	            return raggedness / 2;
	        } else {
	            return raggedness * 2;
	        }
	    }
	    return raggedness + Math.abs(penalty) * penalty;
	}
	function calculatePenalty(codePoint, nextCodePoint, penalizableIdeographicBreak) {
	    let penalty = 0;
	    if (codePoint === 10) {
	        penalty -= 10000;
	    }
	    if (penalizableIdeographicBreak) {
	        penalty += 150;
	    }
	    if (codePoint === 40 || codePoint === 65288) {
	        penalty += 50;
	    }
	    if (nextCodePoint === 41 || nextCodePoint === 65289) {
	        penalty += 50;
	    }
	    return penalty;
	}
	function evaluateBreak(breakIndex, breakX, targetWidth, potentialBreaks, penalty, isLastBreak) {
	    let bestPriorBreak = null;
	    let bestBreakBadness = calculateBadness(breakX, targetWidth, penalty, isLastBreak);
	    for (const potentialBreak of potentialBreaks) {
	        const lineWidth = breakX - potentialBreak.x;
	        const breakBadness = calculateBadness(lineWidth, targetWidth, penalty, isLastBreak) + potentialBreak.badness;
	        if (breakBadness <= bestBreakBadness) {
	            bestPriorBreak = potentialBreak;
	            bestBreakBadness = breakBadness;
	        }
	    }
	    return {
	        index: breakIndex,
	        x: breakX,
	        priorBreak: bestPriorBreak,
	        badness: bestBreakBadness
	    };
	}
	function leastBadBreaks(lastLineBreak) {
	    if (!lastLineBreak) {
	        return [];
	    }
	    return leastBadBreaks(lastLineBreak.priorBreak).concat(lastLineBreak.index);
	}
	function determineLineBreaks(logicalInput, spacing, maxWidth, glyphMap, imagePositions, symbolPlacement, layoutTextSize) {
	    if (symbolPlacement !== 'point')
	        return [];
	    if (!logicalInput)
	        return [];
	    const potentialLineBreaks = [];
	    const targetWidth = determineAverageLineWidth(logicalInput, spacing, maxWidth, glyphMap, imagePositions, layoutTextSize);
	    const hasServerSuggestedBreakpoints = logicalInput.text.indexOf('\u200B') >= 0;
	    let currentX = 0;
	    for (let i = 0; i < logicalInput.length(); i++) {
	        const section = logicalInput.getSection(i);
	        const codePoint = logicalInput.getCharCode(i);
	        if (!whitespace[codePoint])
	            currentX += getGlyphAdvance(codePoint, section, glyphMap, imagePositions, spacing, layoutTextSize);
	        if (i < logicalInput.length() - 1) {
	            const ideographicBreak = charAllowsIdeographicBreaking(codePoint);
	            if (breakable[codePoint] || ideographicBreak || section.imageName) {
	                potentialLineBreaks.push(evaluateBreak(i + 1, currentX, targetWidth, potentialLineBreaks, calculatePenalty(codePoint, logicalInput.getCharCode(i + 1), ideographicBreak && hasServerSuggestedBreakpoints), false));
	            }
	        }
	    }
	    return leastBadBreaks(evaluateBreak(logicalInput.length(), currentX, targetWidth, potentialLineBreaks, 0, true));
	}
	function getAnchorAlignment(anchor) {
	    let horizontalAlign = 0.5, verticalAlign = 0.5;
	    switch (anchor) {
	    case 'right':
	    case 'top-right':
	    case 'bottom-right':
	        horizontalAlign = 1;
	        break;
	    case 'left':
	    case 'top-left':
	    case 'bottom-left':
	        horizontalAlign = 0;
	        break;
	    }
	    switch (anchor) {
	    case 'bottom':
	    case 'bottom-right':
	    case 'bottom-left':
	        verticalAlign = 1;
	        break;
	    case 'top':
	    case 'top-right':
	    case 'top-left':
	        verticalAlign = 0;
	        break;
	    }
	    return {
	        horizontalAlign,
	        verticalAlign
	    };
	}
	function shapeLines(shaping, glyphMap, glyphPositions, imagePositions, lines, lineHeight, textAnchor, textJustify, writingMode, spacing, allowVerticalPlacement, layoutTextSizeThisZoom) {
	    let x = 0;
	    let y = 0;
	    let maxLineLength = 0;
	    const justify = textJustify === 'right' ? 1 : textJustify === 'left' ? 0 : 0.5;
	    let hasBaseline = false;
	    for (const line of lines) {
	        const sections = line.getSections();
	        for (const section of sections) {
	            if (section.imageName)
	                continue;
	            const glyphData = glyphMap[section.fontStack];
	            if (!glyphData)
	                continue;
	            hasBaseline = glyphData.ascender !== undefined && glyphData.descender !== undefined;
	            if (!hasBaseline)
	                break;
	        }
	        if (!hasBaseline)
	            break;
	    }
	    let lineIndex = 0;
	    for (const line of lines) {
	        line.trim();
	        const lineMaxScale = line.getMaxScale();
	        const maxLineOffset = (lineMaxScale - 1) * ONE_EM;
	        const positionedLine = {
	            positionedGlyphs: [],
	            lineOffset: 0
	        };
	        shaping.positionedLines[lineIndex] = positionedLine;
	        const positionedGlyphs = positionedLine.positionedGlyphs;
	        let lineOffset = 0;
	        if (!line.length()) {
	            y += lineHeight;
	            ++lineIndex;
	            continue;
	        }
	        let biggestHeight = 0;
	        let baselineOffset = 0;
	        for (let i = 0; i < line.length(); i++) {
	            const section = line.getSection(i);
	            const sectionIndex = line.getSectionIndex(i);
	            const codePoint = line.getCharCode(i);
	            let sectionScale = section.scale;
	            let metrics = null;
	            let rect = null;
	            let imageName = null;
	            let verticalAdvance = ONE_EM;
	            let glyphOffset = 0;
	            const vertical = !(writingMode === WritingMode.horizontal || !allowVerticalPlacement && !charHasUprightVerticalOrientation(codePoint) || allowVerticalPlacement && (whitespace[codePoint] || charInComplexShapingScript(codePoint)));
	            if (!section.imageName) {
	                const glyphPositionData = glyphPositions[section.fontStack];
	                if (!glyphPositionData)
	                    continue;
	                if (glyphPositionData[codePoint]) {
	                    rect = glyphPositionData[codePoint];
	                }
	                const glyphData = glyphMap[section.fontStack];
	                if (!glyphData)
	                    continue;
	                const glyph = glyphData.glyphs[codePoint];
	                if (!glyph)
	                    continue;
	                metrics = glyph.metrics;
	                verticalAdvance = codePoint !== 8203 ? ONE_EM : 0;
	                if (hasBaseline) {
	                    const ascender = glyphData.ascender !== undefined ? Math.abs(glyphData.ascender) : 0;
	                    const descender = glyphData.descender !== undefined ? Math.abs(glyphData.descender) : 0;
	                    const value = (ascender + descender) * sectionScale;
	                    if (biggestHeight < value) {
	                        biggestHeight = value;
	                        baselineOffset = (ascender - descender) / 2 * sectionScale;
	                    }
	                    glyphOffset = -ascender * sectionScale;
	                } else {
	                    glyphOffset = SHAPING_DEFAULT_OFFSET + (lineMaxScale - sectionScale) * ONE_EM;
	                }
	            } else {
	                const imagePosition = imagePositions[section.imageName];
	                if (!imagePosition)
	                    continue;
	                imageName = section.imageName;
	                shaping.iconsInText = shaping.iconsInText || true;
	                rect = imagePosition.paddedRect;
	                const size = imagePosition.displaySize;
	                sectionScale = sectionScale * ONE_EM / layoutTextSizeThisZoom;
	                metrics = {
	                    width: size[0],
	                    height: size[1],
	                    left: IMAGE_PADDING,
	                    top: -GLYPH_PBF_BORDER,
	                    advance: vertical ? size[1] : size[0],
	                    localGlyph: false
	                };
	                if (!hasBaseline) {
	                    glyphOffset = SHAPING_DEFAULT_OFFSET + lineMaxScale * ONE_EM - size[1] * sectionScale;
	                } else {
	                    const imageAscender = metrics.height;
	                    glyphOffset = -imageAscender * sectionScale;
	                }
	                verticalAdvance = metrics.advance;
	                const offset = (vertical ? size[0] : size[1]) * sectionScale - ONE_EM * lineMaxScale;
	                if (offset > 0 && offset > lineOffset) {
	                    lineOffset = offset;
	                }
	            }
	            if (!vertical) {
	                positionedGlyphs.push({
	                    glyph: codePoint,
	                    imageName,
	                    x,
	                    y: y + glyphOffset,
	                    vertical,
	                    scale: sectionScale,
	                    localGlyph: metrics.localGlyph,
	                    fontStack: section.fontStack,
	                    sectionIndex,
	                    metrics,
	                    rect
	                });
	                x += metrics.advance * sectionScale + spacing;
	            } else {
	                shaping.verticalizable = true;
	                positionedGlyphs.push({
	                    glyph: codePoint,
	                    imageName,
	                    x,
	                    y: y + glyphOffset,
	                    vertical,
	                    scale: sectionScale,
	                    localGlyph: metrics.localGlyph,
	                    fontStack: section.fontStack,
	                    sectionIndex,
	                    metrics,
	                    rect
	                });
	                x += verticalAdvance * sectionScale + spacing;
	            }
	        }
	        if (positionedGlyphs.length !== 0) {
	            const lineLength = x - spacing;
	            maxLineLength = Math.max(lineLength, maxLineLength);
	            if (hasBaseline) {
	                justifyLine(positionedGlyphs, justify, lineOffset, baselineOffset, lineHeight * lineMaxScale / 2);
	            } else {
	                justifyLine(positionedGlyphs, justify, lineOffset, 0, lineHeight / 2);
	            }
	        }
	        x = 0;
	        const currentLineHeight = lineHeight * lineMaxScale + lineOffset;
	        positionedLine.lineOffset = Math.max(lineOffset, maxLineOffset);
	        y += currentLineHeight;
	        ++lineIndex;
	    }
	    const height = y;
	    const {horizontalAlign, verticalAlign} = getAnchorAlignment(textAnchor);
	    align(shaping.positionedLines, justify, horizontalAlign, verticalAlign, maxLineLength, height);
	    shaping.top += -verticalAlign * height;
	    shaping.bottom = shaping.top + height;
	    shaping.left += -horizontalAlign * maxLineLength;
	    shaping.right = shaping.left + maxLineLength;
	    shaping.hasBaseline = hasBaseline;
	}
	function justifyLine(positionedGlyphs, justify, lineOffset, baselineOffset, halfLineHeight) {
	    if (!justify && !lineOffset && !baselineOffset && !halfLineHeight) {
	        return;
	    }
	    const end = positionedGlyphs.length - 1;
	    const lastGlyph = positionedGlyphs[end];
	    const lastAdvance = lastGlyph.metrics.advance * lastGlyph.scale;
	    const lineIndent = (lastGlyph.x + lastAdvance) * justify;
	    for (let j = 0; j <= end; j++) {
	        positionedGlyphs[j].x -= lineIndent;
	        positionedGlyphs[j].y += lineOffset + baselineOffset + halfLineHeight;
	    }
	}
	function align(positionedLines, justify, horizontalAlign, verticalAlign, maxLineLength, blockHeight) {
	    const shiftX = (justify - horizontalAlign) * maxLineLength;
	    const shiftY = -blockHeight * verticalAlign;
	    for (const line of positionedLines) {
	        for (const positionedGlyph of line.positionedGlyphs) {
	            positionedGlyph.x += shiftX;
	            positionedGlyph.y += shiftY;
	        }
	    }
	}
	function shapeIcon(image, iconOffset, iconAnchor) {
	    const {horizontalAlign, verticalAlign} = getAnchorAlignment(iconAnchor);
	    const dx = iconOffset[0];
	    const dy = iconOffset[1];
	    const x1 = dx - image.displaySize[0] * horizontalAlign;
	    const x2 = x1 + image.displaySize[0];
	    const y1 = dy - image.displaySize[1] * verticalAlign;
	    const y2 = y1 + image.displaySize[1];
	    return {
	        image,
	        top: y1,
	        bottom: y2,
	        left: x1,
	        right: x2
	    };
	}
	function fitIconToText(shapedIcon, shapedText, textFit, padding, iconOffset, fontScale) {
	    const image = shapedIcon.image;
	    let collisionPadding;
	    if (image.content) {
	        const content = image.content;
	        const pixelRatio = image.pixelRatio || 1;
	        collisionPadding = [
	            content[0] / pixelRatio,
	            content[1] / pixelRatio,
	            image.displaySize[0] - content[2] / pixelRatio,
	            image.displaySize[1] - content[3] / pixelRatio
	        ];
	    }
	    const textLeft = shapedText.left * fontScale;
	    const textRight = shapedText.right * fontScale;
	    let top, right, bottom, left;
	    if (textFit === 'width' || textFit === 'both') {
	        left = iconOffset[0] + textLeft - padding[3];
	        right = iconOffset[0] + textRight + padding[1];
	    } else {
	        left = iconOffset[0] + (textLeft + textRight - image.displaySize[0]) / 2;
	        right = left + image.displaySize[0];
	    }
	    const textTop = shapedText.top * fontScale;
	    const textBottom = shapedText.bottom * fontScale;
	    if (textFit === 'height' || textFit === 'both') {
	        top = iconOffset[1] + textTop - padding[0];
	        bottom = iconOffset[1] + textBottom + padding[2];
	    } else {
	        top = iconOffset[1] + (textTop + textBottom - image.displaySize[1]) / 2;
	        bottom = top + image.displaySize[1];
	    }
	    return {
	        image,
	        top,
	        right,
	        bottom,
	        left,
	        collisionPadding
	    };
	}

	class Anchor extends pointGeometry {
	    constructor(x, y, z, angle, segment) {
	        super(x, y);
	        this.angle = angle;
	        this.z = z;
	        if (segment !== undefined) {
	            this.segment = segment;
	        }
	    }
	    clone() {
	        return new Anchor(this.x, this.y, this.z, this.angle, this.segment);
	    }
	}
	register(Anchor, 'Anchor');

	function checkMaxAngle(line, anchor, labelLength, windowSize, maxAngle) {
	    if (anchor.segment === undefined)
	        return true;
	    let p = anchor;
	    let index = anchor.segment + 1;
	    let anchorDistance = 0;
	    while (anchorDistance > -labelLength / 2) {
	        index--;
	        if (index < 0)
	            return false;
	        anchorDistance -= line[index].dist(p);
	        p = line[index];
	    }
	    anchorDistance += line[index].dist(line[index + 1]);
	    index++;
	    const recentCorners = [];
	    let recentAngleDelta = 0;
	    while (anchorDistance < labelLength / 2) {
	        const prev = line[index - 1];
	        const current = line[index];
	        const next = line[index + 1];
	        if (!next)
	            return false;
	        let angleDelta = prev.angleTo(current) - current.angleTo(next);
	        angleDelta = Math.abs((angleDelta + 3 * Math.PI) % (Math.PI * 2) - Math.PI);
	        recentCorners.push({
	            distance: anchorDistance,
	            angleDelta
	        });
	        recentAngleDelta += angleDelta;
	        while (anchorDistance - recentCorners[0].distance > windowSize) {
	            recentAngleDelta -= recentCorners.shift().angleDelta;
	        }
	        if (recentAngleDelta > maxAngle)
	            return false;
	        index++;
	        anchorDistance += current.dist(next);
	    }
	    return true;
	}

	function getLineLength(line) {
	    let lineLength = 0;
	    for (let k = 0; k < line.length - 1; k++) {
	        lineLength += line[k].dist(line[k + 1]);
	    }
	    return lineLength;
	}
	function getAngleWindowSize(shapedText, glyphSize, boxScale) {
	    return shapedText ? 3 / 5 * glyphSize * boxScale : 0;
	}
	function getShapedLabelLength(shapedText, shapedIcon) {
	    return Math.max(shapedText ? shapedText.right - shapedText.left : 0, shapedIcon ? shapedIcon.right - shapedIcon.left : 0);
	}
	function getCenterAnchor(line, maxAngle, shapedText, shapedIcon, glyphSize, boxScale) {
	    const angleWindowSize = getAngleWindowSize(shapedText, glyphSize, boxScale);
	    const labelLength = getShapedLabelLength(shapedText, shapedIcon) * boxScale;
	    let prevDistance = 0;
	    const centerDistance = getLineLength(line) / 2;
	    for (let i = 0; i < line.length - 1; i++) {
	        const a = line[i], b = line[i + 1];
	        const segmentDistance = a.dist(b);
	        if (prevDistance + segmentDistance > centerDistance) {
	            const t = (centerDistance - prevDistance) / segmentDistance, x = number(a.x, b.x, t), y = number(a.y, b.y, t);
	            const anchor = new Anchor(x, y, 0, b.angleTo(a), i);
	            if (!angleWindowSize || checkMaxAngle(line, anchor, labelLength, angleWindowSize, maxAngle)) {
	                return anchor;
	            } else {
	                return;
	            }
	        }
	        prevDistance += segmentDistance;
	    }
	}
	function getAnchors(line, spacing, maxAngle, shapedText, shapedIcon, glyphSize, boxScale, overscaling, tileExtent) {
	    const angleWindowSize = getAngleWindowSize(shapedText, glyphSize, boxScale);
	    const shapedLabelLength = getShapedLabelLength(shapedText, shapedIcon);
	    const labelLength = shapedLabelLength * boxScale;
	    const isLineContinued = line[0].x === 0 || line[0].x === tileExtent || line[0].y === 0 || line[0].y === tileExtent;
	    if (spacing - labelLength < spacing / 4) {
	        spacing = labelLength + spacing / 4;
	    }
	    const fixedExtraOffset = glyphSize * 2;
	    const offset = !isLineContinued ? (shapedLabelLength / 2 + fixedExtraOffset) * boxScale * overscaling % spacing : spacing / 2 * overscaling % spacing;
	    return resample(line, offset, spacing, angleWindowSize, maxAngle, labelLength, isLineContinued, false, tileExtent);
	}
	function resample(line, offset, spacing, angleWindowSize, maxAngle, labelLength, isLineContinued, placeAtMiddle, tileExtent) {
	    const halfLabelLength = labelLength / 2;
	    const lineLength = getLineLength(line);
	    let distance = 0, markedDistance = offset - spacing;
	    let anchors = [];
	    for (let i = 0; i < line.length - 1; i++) {
	        const a = line[i], b = line[i + 1];
	        const segmentDist = a.dist(b), angle = b.angleTo(a);
	        while (markedDistance + spacing < distance + segmentDist) {
	            markedDistance += spacing;
	            const t = (markedDistance - distance) / segmentDist, x = number(a.x, b.x, t), y = number(a.y, b.y, t);
	            if (x >= 0 && x < tileExtent && y >= 0 && y < tileExtent && markedDistance - halfLabelLength >= 0 && markedDistance + halfLabelLength <= lineLength) {
	                const anchor = new Anchor(x, y, 0, angle, i);
	                anchor._round();
	                if (!angleWindowSize || checkMaxAngle(line, anchor, labelLength, angleWindowSize, maxAngle)) {
	                    anchors.push(anchor);
	                }
	            }
	        }
	        distance += segmentDist;
	    }
	    if (!placeAtMiddle && !anchors.length && !isLineContinued) {
	        anchors = resample(line, distance / 2, spacing, angleWindowSize, maxAngle, labelLength, isLineContinued, true, tileExtent);
	    }
	    return anchors;
	}

	function clipLine(lines, x1, y1, x2, y2) {
	    const clippedLines = [];
	    for (let l = 0; l < lines.length; l++) {
	        const line = lines[l];
	        let clippedLine;
	        for (let i = 0; i < line.length - 1; i++) {
	            let p0 = line[i];
	            let p1 = line[i + 1];
	            if (p0.x < x1 && p1.x < x1) {
	                continue;
	            } else if (p0.x < x1) {
	                p0 = new pointGeometry(x1, p0.y + (p1.y - p0.y) * ((x1 - p0.x) / (p1.x - p0.x)))._round();
	            } else if (p1.x < x1) {
	                p1 = new pointGeometry(x1, p0.y + (p1.y - p0.y) * ((x1 - p0.x) / (p1.x - p0.x)))._round();
	            }
	            if (p0.y < y1 && p1.y < y1) {
	                continue;
	            } else if (p0.y < y1) {
	                p0 = new pointGeometry(p0.x + (p1.x - p0.x) * ((y1 - p0.y) / (p1.y - p0.y)), y1)._round();
	            } else if (p1.y < y1) {
	                p1 = new pointGeometry(p0.x + (p1.x - p0.x) * ((y1 - p0.y) / (p1.y - p0.y)), y1)._round();
	            }
	            if (p0.x >= x2 && p1.x >= x2) {
	                continue;
	            } else if (p0.x >= x2) {
	                p0 = new pointGeometry(x2, p0.y + (p1.y - p0.y) * ((x2 - p0.x) / (p1.x - p0.x)))._round();
	            } else if (p1.x >= x2) {
	                p1 = new pointGeometry(x2, p0.y + (p1.y - p0.y) * ((x2 - p0.x) / (p1.x - p0.x)))._round();
	            }
	            if (p0.y >= y2 && p1.y >= y2) {
	                continue;
	            } else if (p0.y >= y2) {
	                p0 = new pointGeometry(p0.x + (p1.x - p0.x) * ((y2 - p0.y) / (p1.y - p0.y)), y2)._round();
	            } else if (p1.y >= y2) {
	                p1 = new pointGeometry(p0.x + (p1.x - p0.x) * ((y2 - p0.y) / (p1.y - p0.y)), y2)._round();
	            }
	            if (!clippedLine || !p0.equals(clippedLine[clippedLine.length - 1])) {
	                clippedLine = [p0];
	                clippedLines.push(clippedLine);
	            }
	            clippedLine.push(p1);
	        }
	    }
	    return clippedLines;
	}

	function loadGlyphRange (fontstack, range, urlTemplate, requestManager, callback) {
	    const begin = range * 256;
	    const end = begin + 255;
	    const request = requestManager.transformRequest(requestManager.normalizeGlyphsURL(urlTemplate).replace('{fontstack}', fontstack).replace('{range}', `${ begin }-${ end }`), ResourceType.Glyphs);
	    getArrayBuffer(request, (err, data) => {
	        if (err) {
	            callback(err);
	        } else if (data) {
	            const glyphs = {};
	            const glyphData = parseGlyphPBF(data);
	            for (const glyph of glyphData.glyphs) {
	                glyphs[glyph.id] = glyph;
	            }
	            callback(null, {
	                glyphs,
	                ascender: glyphData.ascender,
	                descender: glyphData.descender
	            });
	        }
	    });
	}

	const INF = 100000000000000000000;
	class TinySDF {
	    constructor({fontSize = 24, buffer = 3, radius = 8, cutoff = 0.25, fontFamily = 'sans-serif', fontWeight = 'normal', fontStyle = 'normal'} = {}) {
	        this.buffer = buffer;
	        this.cutoff = cutoff;
	        this.radius = radius;
	        const size = this.size = fontSize + buffer * 4;
	        const canvas = this._createCanvas(size);
	        const ctx = this.ctx = canvas.getContext('2d', { willReadFrequently: true });
	        ctx.font = `${ fontStyle } ${ fontWeight } ${ fontSize }px ${ fontFamily }`;
	        ctx.textBaseline = 'alphabetic';
	        ctx.textAlign = 'left';
	        ctx.fillStyle = 'black';
	        this.gridOuter = new Float64Array(size * size);
	        this.gridInner = new Float64Array(size * size);
	        this.f = new Float64Array(size);
	        this.z = new Float64Array(size + 1);
	        this.v = new Uint16Array(size);
	    }
	    _createCanvas(size) {
	        const canvas = document.createElement('canvas');
	        canvas.width = canvas.height = size;
	        return canvas;
	    }
	    draw(char) {
	        const {
	            width: glyphAdvance,
	            actualBoundingBoxAscent,
	            actualBoundingBoxDescent,
	            actualBoundingBoxLeft,
	            actualBoundingBoxRight
	        } = this.ctx.measureText(char);
	        const glyphTop = Math.ceil(actualBoundingBoxAscent);
	        const glyphLeft = 0;
	        const glyphWidth = Math.min(this.size - this.buffer, Math.ceil(actualBoundingBoxRight - actualBoundingBoxLeft));
	        const glyphHeight = Math.min(this.size - this.buffer, glyphTop + Math.ceil(actualBoundingBoxDescent));
	        const width = glyphWidth + 2 * this.buffer;
	        const height = glyphHeight + 2 * this.buffer;
	        const len = Math.max(width * height, 0);
	        const data = new Uint8ClampedArray(len);
	        const glyph = {
	            data,
	            width,
	            height,
	            glyphWidth,
	            glyphHeight,
	            glyphTop,
	            glyphLeft,
	            glyphAdvance
	        };
	        if (glyphWidth === 0 || glyphHeight === 0)
	            return glyph;
	        const {ctx, buffer, gridInner, gridOuter} = this;
	        ctx.clearRect(buffer, buffer, glyphWidth, glyphHeight);
	        ctx.fillText(char, buffer, buffer + glyphTop);
	        const imgData = ctx.getImageData(buffer, buffer, glyphWidth, glyphHeight);
	        gridOuter.fill(INF, 0, len);
	        gridInner.fill(0, 0, len);
	        for (let y = 0; y < glyphHeight; y++) {
	            for (let x = 0; x < glyphWidth; x++) {
	                const a = imgData.data[4 * (y * glyphWidth + x) + 3] / 255;
	                if (a === 0)
	                    continue;
	                const j = (y + buffer) * width + x + buffer;
	                if (a === 1) {
	                    gridOuter[j] = 0;
	                    gridInner[j] = INF;
	                } else {
	                    const d = 0.5 - a;
	                    gridOuter[j] = d > 0 ? d * d : 0;
	                    gridInner[j] = d < 0 ? d * d : 0;
	                }
	            }
	        }
	        edt(gridOuter, 0, 0, width, height, width, this.f, this.v, this.z);
	        edt(gridInner, buffer, buffer, glyphWidth, glyphHeight, width, this.f, this.v, this.z);
	        for (let i = 0; i < len; i++) {
	            const d = Math.sqrt(gridOuter[i]) - Math.sqrt(gridInner[i]);
	            data[i] = Math.round(255 - 255 * (d / this.radius + this.cutoff));
	        }
	        return glyph;
	    }
	}
	function edt(data, x0, y0, width, height, gridSize, f, v, z) {
	    for (let x = x0; x < x0 + width; x++)
	        edt1d(data, y0 * gridSize + x, gridSize, height, f, v, z);
	    for (let y = y0; y < y0 + height; y++)
	        edt1d(data, y * gridSize + x0, 1, width, f, v, z);
	}
	function edt1d(grid, offset, stride, length, f, v, z) {
	    v[0] = 0;
	    z[0] = -INF;
	    z[1] = INF;
	    f[0] = grid[offset];
	    for (let q = 1, k = 0, s = 0; q < length; q++) {
	        f[q] = grid[offset + q * stride];
	        const q2 = q * q;
	        do {
	            const r = v[k];
	            s = (f[q] - f[r] + q2 - r * r) / (q - r) / 2;
	        } while (s <= z[k] && --k > -1);
	        k++;
	        v[k] = q;
	        z[k] = s;
	        z[k + 1] = INF;
	    }
	    for (let q = 0, k = 0; q < length; q++) {
	        while (z[k + 1] < q)
	            k++;
	        const r = v[k];
	        const qr = q - r;
	        grid[offset + q * stride] = f[r] + qr * qr;
	    }
	}

	const SDF_SCALE = 2;
	const LocalGlyphMode = {
	    none: 0,
	    ideographs: 1,
	    all: 2
	};
	class GlyphManager {
	    constructor(requestManager, localGlyphMode, localFontFamily) {
	        this.requestManager = requestManager;
	        this.localGlyphMode = localGlyphMode;
	        this.localFontFamily = localFontFamily;
	        this.entries = {};
	        this.localGlyphs = {
	            '200': {},
	            '400': {},
	            '500': {},
	            '900': {}
	        };
	    }
	    setURL(url) {
	        this.url = url;
	    }
	    getGlyphs(glyphs, callback) {
	        const all = [];
	        for (const stack in glyphs) {
	            for (const id of glyphs[stack]) {
	                all.push({
	                    stack,
	                    id
	                });
	            }
	        }
	        asyncAll(all, ({stack, id}, fnCallback) => {
	            let entry = this.entries[stack];
	            if (!entry) {
	                entry = this.entries[stack] = {
	                    glyphs: {},
	                    requests: {},
	                    ranges: {},
	                    ascender: undefined,
	                    descender: undefined
	                };
	            }
	            let glyph = entry.glyphs[id];
	            if (glyph !== undefined) {
	                fnCallback(null, {
	                    stack,
	                    id,
	                    glyph
	                });
	                return;
	            }
	            glyph = this._tinySDF(entry, stack, id);
	            if (glyph) {
	                entry.glyphs[id] = glyph;
	                fnCallback(null, {
	                    stack,
	                    id,
	                    glyph
	                });
	                return;
	            }
	            const range = Math.floor(id / 256);
	            if (range * 256 > 65535) {
	                fnCallback(new Error('glyphs > 65535 not supported'));
	                return;
	            }
	            if (entry.ranges[range]) {
	                fnCallback(null, {
	                    stack,
	                    id,
	                    glyph
	                });
	                return;
	            }
	            let requests = entry.requests[range];
	            if (!requests) {
	                requests = entry.requests[range] = [];
	                GlyphManager.loadGlyphRange(stack, range, this.url, this.requestManager, (err, response) => {
	                    if (response) {
	                        entry.ascender = response.ascender;
	                        entry.descender = response.descender;
	                        for (const id in response.glyphs) {
	                            if (!this._doesCharSupportLocalGlyph(+id)) {
	                                entry.glyphs[+id] = response.glyphs[+id];
	                            }
	                        }
	                        entry.ranges[range] = true;
	                    }
	                    for (const cb of requests) {
	                        cb(err, response);
	                    }
	                    delete entry.requests[range];
	                });
	            }
	            requests.push((err, result) => {
	                if (err) {
	                    fnCallback(err);
	                } else if (result) {
	                    fnCallback(null, {
	                        stack,
	                        id,
	                        glyph: result.glyphs[id] || null
	                    });
	                }
	            });
	        }, (err, glyphs) => {
	            if (err) {
	                callback(err);
	            } else if (glyphs) {
	                const result = {};
	                for (const {stack, id, glyph} of glyphs) {
	                    if (result[stack] === undefined)
	                        result[stack] = {};
	                    if (result[stack].glyphs === undefined)
	                        result[stack].glyphs = {};
	                    result[stack].glyphs[id] = glyph && {
	                        id: glyph.id,
	                        bitmap: glyph.bitmap.clone(),
	                        metrics: glyph.metrics
	                    };
	                    result[stack].ascender = this.entries[stack].ascender;
	                    result[stack].descender = this.entries[stack].descender;
	                }
	                callback(null, result);
	            }
	        });
	    }
	    _doesCharSupportLocalGlyph(id) {
	        if (this.localGlyphMode === LocalGlyphMode.none) {
	            return false;
	        } else if (this.localGlyphMode === LocalGlyphMode.all) {
	            return !!this.localFontFamily;
	        } else {
	            return !!this.localFontFamily && (unicodeBlockLookup['CJK Unified Ideographs'](id) || unicodeBlockLookup['Hangul Syllables'](id) || unicodeBlockLookup['Hiragana'](id) || unicodeBlockLookup['Katakana'](id) || unicodeBlockLookup['CJK Symbols and Punctuation'](id));
	        }
	    }
	    _tinySDF(entry, stack, id) {
	        const fontFamily = this.localFontFamily;
	        if (!fontFamily || !this._doesCharSupportLocalGlyph(id))
	            return;
	        let tinySDF = entry.tinySDF;
	        if (!tinySDF) {
	            let fontWeight = '400';
	            if (/bold/i.test(stack)) {
	                fontWeight = '900';
	            } else if (/medium/i.test(stack)) {
	                fontWeight = '500';
	            } else if (/light/i.test(stack)) {
	                fontWeight = '200';
	            }
	            const fontSize = 24 * SDF_SCALE;
	            const buffer = 3 * SDF_SCALE;
	            const radius = 8 * SDF_SCALE;
	            tinySDF = entry.tinySDF = new GlyphManager.TinySDF({
	                fontFamily,
	                fontWeight,
	                fontSize,
	                buffer,
	                radius
	            });
	            tinySDF.fontWeight = fontWeight;
	        }
	        if (this.localGlyphs[tinySDF.fontWeight][id]) {
	            return this.localGlyphs[tinySDF.fontWeight][id];
	        }
	        const char = String.fromCharCode(id);
	        const {data, width, height, glyphWidth, glyphHeight, glyphLeft, glyphTop, glyphAdvance} = tinySDF.draw(char);
	        const baselineAdjustment = 27;
	        const glyph = this.localGlyphs[tinySDF.fontWeight][id] = {
	            id,
	            bitmap: new AlphaImage({
	                width,
	                height
	            }, data),
	            metrics: {
	                width: glyphWidth / SDF_SCALE,
	                height: glyphHeight / SDF_SCALE,
	                left: glyphLeft / SDF_SCALE,
	                top: glyphTop / SDF_SCALE - baselineAdjustment,
	                advance: glyphAdvance / SDF_SCALE,
	                localGlyph: true
	            }
	        };
	        return glyph;
	    }
	}
	GlyphManager.loadGlyphRange = loadGlyphRange;
	GlyphManager.TinySDF = TinySDF;

	const border = IMAGE_PADDING;
	function getIconQuads(shapedIcon, iconRotate, isSDFIcon, hasIconTextFit) {
	    const quads = [];
	    const image = shapedIcon.image;
	    const pixelRatio = image.pixelRatio;
	    const imageWidth = image.paddedRect.w - 2 * border;
	    const imageHeight = image.paddedRect.h - 2 * border;
	    const iconWidth = shapedIcon.right - shapedIcon.left;
	    const iconHeight = shapedIcon.bottom - shapedIcon.top;
	    const stretchX = image.stretchX || [[
	            0,
	            imageWidth
	        ]];
	    const stretchY = image.stretchY || [[
	            0,
	            imageHeight
	        ]];
	    const reduceRanges = (sum, range) => sum + range[1] - range[0];
	    const stretchWidth = stretchX.reduce(reduceRanges, 0);
	    const stretchHeight = stretchY.reduce(reduceRanges, 0);
	    const fixedWidth = imageWidth - stretchWidth;
	    const fixedHeight = imageHeight - stretchHeight;
	    let stretchOffsetX = 0;
	    let stretchContentWidth = stretchWidth;
	    let stretchOffsetY = 0;
	    let stretchContentHeight = stretchHeight;
	    let fixedOffsetX = 0;
	    let fixedContentWidth = fixedWidth;
	    let fixedOffsetY = 0;
	    let fixedContentHeight = fixedHeight;
	    if (image.content && hasIconTextFit) {
	        const content = image.content;
	        stretchOffsetX = sumWithinRange(stretchX, 0, content[0]);
	        stretchOffsetY = sumWithinRange(stretchY, 0, content[1]);
	        stretchContentWidth = sumWithinRange(stretchX, content[0], content[2]);
	        stretchContentHeight = sumWithinRange(stretchY, content[1], content[3]);
	        fixedOffsetX = content[0] - stretchOffsetX;
	        fixedOffsetY = content[1] - stretchOffsetY;
	        fixedContentWidth = content[2] - content[0] - stretchContentWidth;
	        fixedContentHeight = content[3] - content[1] - stretchContentHeight;
	    }
	    const makeBox = (left, top, right, bottom) => {
	        const leftEm = getEmOffset(left.stretch - stretchOffsetX, stretchContentWidth, iconWidth, shapedIcon.left);
	        const leftPx = getPxOffset(left.fixed - fixedOffsetX, fixedContentWidth, left.stretch, stretchWidth);
	        const topEm = getEmOffset(top.stretch - stretchOffsetY, stretchContentHeight, iconHeight, shapedIcon.top);
	        const topPx = getPxOffset(top.fixed - fixedOffsetY, fixedContentHeight, top.stretch, stretchHeight);
	        const rightEm = getEmOffset(right.stretch - stretchOffsetX, stretchContentWidth, iconWidth, shapedIcon.left);
	        const rightPx = getPxOffset(right.fixed - fixedOffsetX, fixedContentWidth, right.stretch, stretchWidth);
	        const bottomEm = getEmOffset(bottom.stretch - stretchOffsetY, stretchContentHeight, iconHeight, shapedIcon.top);
	        const bottomPx = getPxOffset(bottom.fixed - fixedOffsetY, fixedContentHeight, bottom.stretch, stretchHeight);
	        const tl = new pointGeometry(leftEm, topEm);
	        const tr = new pointGeometry(rightEm, topEm);
	        const br = new pointGeometry(rightEm, bottomEm);
	        const bl = new pointGeometry(leftEm, bottomEm);
	        const pixelOffsetTL = new pointGeometry(leftPx / pixelRatio, topPx / pixelRatio);
	        const pixelOffsetBR = new pointGeometry(rightPx / pixelRatio, bottomPx / pixelRatio);
	        const angle = iconRotate * Math.PI / 180;
	        if (angle) {
	            const sin = Math.sin(angle), cos = Math.cos(angle), matrix = [
	                    cos,
	                    -sin,
	                    sin,
	                    cos
	                ];
	            tl._matMult(matrix);
	            tr._matMult(matrix);
	            bl._matMult(matrix);
	            br._matMult(matrix);
	        }
	        const x1 = left.stretch + left.fixed;
	        const x2 = right.stretch + right.fixed;
	        const y1 = top.stretch + top.fixed;
	        const y2 = bottom.stretch + bottom.fixed;
	        const subRect = {
	            x: image.paddedRect.x + border + x1,
	            y: image.paddedRect.y + border + y1,
	            w: x2 - x1,
	            h: y2 - y1
	        };
	        const minFontScaleX = fixedContentWidth / pixelRatio / iconWidth;
	        const minFontScaleY = fixedContentHeight / pixelRatio / iconHeight;
	        return {
	            tl,
	            tr,
	            bl,
	            br,
	            tex: subRect,
	            writingMode: undefined,
	            glyphOffset: [
	                0,
	                0
	            ],
	            sectionIndex: 0,
	            pixelOffsetTL,
	            pixelOffsetBR,
	            minFontScaleX,
	            minFontScaleY,
	            isSDF: isSDFIcon
	        };
	    };
	    if (!hasIconTextFit || !image.stretchX && !image.stretchY) {
	        quads.push(makeBox({
	            fixed: 0,
	            stretch: -1
	        }, {
	            fixed: 0,
	            stretch: -1
	        }, {
	            fixed: 0,
	            stretch: imageWidth + 1
	        }, {
	            fixed: 0,
	            stretch: imageHeight + 1
	        }));
	    } else {
	        const xCuts = stretchZonesToCuts(stretchX, fixedWidth, stretchWidth);
	        const yCuts = stretchZonesToCuts(stretchY, fixedHeight, stretchHeight);
	        for (let xi = 0; xi < xCuts.length - 1; xi++) {
	            const x1 = xCuts[xi];
	            const x2 = xCuts[xi + 1];
	            for (let yi = 0; yi < yCuts.length - 1; yi++) {
	                const y1 = yCuts[yi];
	                const y2 = yCuts[yi + 1];
	                quads.push(makeBox(x1, y1, x2, y2));
	            }
	        }
	    }
	    return quads;
	}
	function sumWithinRange(ranges, min, max) {
	    let sum = 0;
	    for (const range of ranges) {
	        sum += Math.max(min, Math.min(max, range[1])) - Math.max(min, Math.min(max, range[0]));
	    }
	    return sum;
	}
	function stretchZonesToCuts(stretchZones, fixedSize, stretchSize) {
	    const cuts = [{
	            fixed: -border,
	            stretch: 0
	        }];
	    for (const [c1, c2] of stretchZones) {
	        const last = cuts[cuts.length - 1];
	        cuts.push({
	            fixed: c1 - last.stretch,
	            stretch: last.stretch
	        });
	        cuts.push({
	            fixed: c1 - last.stretch,
	            stretch: last.stretch + (c2 - c1)
	        });
	    }
	    cuts.push({
	        fixed: fixedSize + border,
	        stretch: stretchSize
	    });
	    return cuts;
	}
	function getEmOffset(stretchOffset, stretchSize, iconSize, iconOffset) {
	    return stretchOffset / stretchSize * iconSize + iconOffset;
	}
	function getPxOffset(fixedOffset, fixedSize, stretchOffset, stretchSize) {
	    return fixedOffset - fixedSize * stretchOffset / stretchSize;
	}
	function getRotateOffset(textOffset) {
	    const x = textOffset[0], y = textOffset[1];
	    const product = x * y;
	    if (product > 0) {
	        return [
	            x,
	            -y
	        ];
	    } else if (product < 0) {
	        return [
	            -x,
	            y
	        ];
	    } else if (x === 0) {
	        return [
	            y,
	            x
	        ];
	    } else {
	        return [
	            y,
	            -x
	        ];
	    }
	}
	function getMidlineOffset(shaping, lineHeight, previousOffset, lineIndex) {
	    const currentLineHeight = lineHeight + shaping.positionedLines[lineIndex].lineOffset;
	    if (lineIndex === 0) {
	        return previousOffset + currentLineHeight / 2;
	    }
	    const aboveLineHeight = lineHeight + shaping.positionedLines[lineIndex - 1].lineOffset;
	    return previousOffset + (currentLineHeight + aboveLineHeight) / 2;
	}
	function getGlyphQuads(anchor, shaping, textOffset, layer, alongLine, feature, imageMap, allowVerticalPlacement) {
	    const quads = [];
	    if (shaping.positionedLines.length === 0)
	        return quads;
	    const textRotate = layer.layout.get('text-rotate').evaluate(feature, {}) * Math.PI / 180;
	    const rotateOffset = getRotateOffset(textOffset);
	    let shapingHeight = Math.abs(shaping.top - shaping.bottom);
	    for (const line of shaping.positionedLines) {
	        shapingHeight -= line.lineOffset;
	    }
	    const lineCounts = shaping.positionedLines.length;
	    const lineHeight = shapingHeight / lineCounts;
	    let currentOffset = shaping.top - textOffset[1];
	    for (let lineIndex = 0; lineIndex < lineCounts; ++lineIndex) {
	        const line = shaping.positionedLines[lineIndex];
	        currentOffset = getMidlineOffset(shaping, lineHeight, currentOffset, lineIndex);
	        for (const positionedGlyph of line.positionedGlyphs) {
	            if (!positionedGlyph.rect)
	                continue;
	            const textureRect = positionedGlyph.rect || {};
	            const glyphPadding = 1;
	            let rectBuffer = GLYPH_PBF_BORDER + glyphPadding;
	            let isSDF = true;
	            let pixelRatio = 1;
	            let lineOffset = 0;
	            if (positionedGlyph.imageName) {
	                const image = imageMap[positionedGlyph.imageName];
	                if (!image)
	                    continue;
	                if (image.sdf) {
	                    warnOnce('SDF images are not supported in formatted text and will be ignored.');
	                    continue;
	                }
	                isSDF = false;
	                pixelRatio = image.pixelRatio;
	                rectBuffer = IMAGE_PADDING / pixelRatio;
	            }
	            const rotateVerticalGlyph = (alongLine || allowVerticalPlacement) && positionedGlyph.vertical;
	            const halfAdvance = positionedGlyph.metrics.advance * positionedGlyph.scale / 2;
	            const metrics = positionedGlyph.metrics;
	            const rect = positionedGlyph.rect;
	            if (rect === null)
	                continue;
	            if (allowVerticalPlacement && shaping.verticalizable) {
	                lineOffset = positionedGlyph.imageName ? halfAdvance - positionedGlyph.metrics.width * positionedGlyph.scale / 2 : 0;
	            }
	            const glyphOffset = alongLine ? [
	                positionedGlyph.x + halfAdvance,
	                positionedGlyph.y
	            ] : [
	                0,
	                0
	            ];
	            let builtInOffset = [
	                0,
	                0
	            ];
	            let verticalizedLabelOffset = [
	                0,
	                0
	            ];
	            let useRotateOffset = false;
	            if (!alongLine) {
	                if (rotateVerticalGlyph) {
	                    verticalizedLabelOffset = [
	                        positionedGlyph.x + halfAdvance + rotateOffset[0],
	                        positionedGlyph.y + rotateOffset[1] - lineOffset
	                    ];
	                    useRotateOffset = true;
	                } else {
	                    builtInOffset = [
	                        positionedGlyph.x + halfAdvance + textOffset[0],
	                        positionedGlyph.y + textOffset[1] - lineOffset
	                    ];
	                }
	            }
	            const paddedWidth = rect.w * positionedGlyph.scale / (pixelRatio * (positionedGlyph.localGlyph ? SDF_SCALE : 1));
	            const paddedHeight = rect.h * positionedGlyph.scale / (pixelRatio * (positionedGlyph.localGlyph ? SDF_SCALE : 1));
	            let tl, tr, bl, br;
	            if (!rotateVerticalGlyph) {
	                const x1 = (metrics.left - rectBuffer) * positionedGlyph.scale - halfAdvance + builtInOffset[0];
	                const y1 = (-metrics.top - rectBuffer) * positionedGlyph.scale + builtInOffset[1];
	                const x2 = x1 + paddedWidth;
	                const y2 = y1 + paddedHeight;
	                tl = new pointGeometry(x1, y1);
	                tr = new pointGeometry(x2, y1);
	                bl = new pointGeometry(x1, y2);
	                br = new pointGeometry(x2, y2);
	            } else {
	                const yShift = positionedGlyph.y - currentOffset;
	                const center = new pointGeometry(-halfAdvance, halfAdvance - yShift);
	                const verticalRotation = -Math.PI / 2;
	                const verticalOffsetCorrection = new pointGeometry(...verticalizedLabelOffset);
	                tl = new pointGeometry(-halfAdvance + builtInOffset[0], builtInOffset[1]);
	                tl._rotateAround(verticalRotation, center)._add(verticalOffsetCorrection);
	                tl.x += -yShift + halfAdvance;
	                tl.y -= (metrics.left - rectBuffer) * positionedGlyph.scale;
	                const verticalAdvance = positionedGlyph.imageName ? metrics.advance * positionedGlyph.scale : ONE_EM * positionedGlyph.scale;
	                const chr = String.fromCharCode(positionedGlyph.glyph);
	                if (isVerticalClosePunctuation(chr)) {
	                    tl.x += (-rectBuffer + 1) * positionedGlyph.scale;
	                } else if (isVerticalOpenPunctuation(chr)) {
	                    const xOffset = verticalAdvance - metrics.height * positionedGlyph.scale;
	                    tl.x += xOffset + (-rectBuffer - 1) * positionedGlyph.scale;
	                } else if (!positionedGlyph.imageName && (metrics.width + rectBuffer * 2 !== rect.w || metrics.height + rectBuffer * 2 !== rect.h)) {
	                    const perfectPaddedHeight = (metrics.height + rectBuffer * 2) * positionedGlyph.scale;
	                    const delta = verticalAdvance - perfectPaddedHeight;
	                    tl.x += delta / 2;
	                } else {
	                    const delta = verticalAdvance - paddedHeight;
	                    tl.x += delta / 2;
	                }
	                tr = new pointGeometry(tl.x, tl.y - paddedWidth);
	                bl = new pointGeometry(tl.x + paddedHeight, tl.y);
	                br = new pointGeometry(tl.x + paddedHeight, tl.y - paddedWidth);
	            }
	            if (textRotate) {
	                let center;
	                if (!alongLine) {
	                    if (useRotateOffset) {
	                        center = new pointGeometry(rotateOffset[0], rotateOffset[1]);
	                    } else {
	                        center = new pointGeometry(textOffset[0], textOffset[1]);
	                    }
	                } else {
	                    center = new pointGeometry(0, 0);
	                }
	                tl._rotateAround(textRotate, center);
	                tr._rotateAround(textRotate, center);
	                bl._rotateAround(textRotate, center);
	                br._rotateAround(textRotate, center);
	            }
	            const pixelOffsetTL = new pointGeometry(0, 0);
	            const pixelOffsetBR = new pointGeometry(0, 0);
	            const minFontScaleX = 0;
	            const minFontScaleY = 0;
	            quads.push({
	                tl,
	                tr,
	                bl,
	                br,
	                tex: textureRect,
	                writingMode: shaping.writingMode,
	                glyphOffset,
	                sectionIndex: positionedGlyph.sectionIndex,
	                isSDF,
	                pixelOffsetTL,
	                pixelOffsetBR,
	                minFontScaleX,
	                minFontScaleY
	            });
	        }
	    }
	    return quads;
	}

	class TinyQueue {
	    constructor(data = [], compare = defaultCompare) {
	        this.data = data;
	        this.length = this.data.length;
	        this.compare = compare;
	        if (this.length > 0) {
	            for (let i = (this.length >> 1) - 1; i >= 0; i--)
	                this._down(i);
	        }
	    }
	    push(item) {
	        this.data.push(item);
	        this.length++;
	        this._up(this.length - 1);
	    }
	    pop() {
	        if (this.length === 0)
	            return undefined;
	        const top = this.data[0];
	        const bottom = this.data.pop();
	        this.length--;
	        if (this.length > 0) {
	            this.data[0] = bottom;
	            this._down(0);
	        }
	        return top;
	    }
	    peek() {
	        return this.data[0];
	    }
	    _up(pos) {
	        const {data, compare} = this;
	        const item = data[pos];
	        while (pos > 0) {
	            const parent = pos - 1 >> 1;
	            const current = data[parent];
	            if (compare(item, current) >= 0)
	                break;
	            data[pos] = current;
	            pos = parent;
	        }
	        data[pos] = item;
	    }
	    _down(pos) {
	        const {data, compare} = this;
	        const halfLength = this.length >> 1;
	        const item = data[pos];
	        while (pos < halfLength) {
	            let left = (pos << 1) + 1;
	            let best = data[left];
	            const right = left + 1;
	            if (right < this.length && compare(data[right], best) < 0) {
	                left = right;
	                best = data[right];
	            }
	            if (compare(best, item) >= 0)
	                break;
	            data[pos] = best;
	            pos = left;
	        }
	        data[pos] = item;
	    }
	}
	function defaultCompare(a, b) {
	    return a < b ? -1 : a > b ? 1 : 0;
	}

	function findPoleOfInaccessibility (polygonRings, precision = 1, debug = false) {
	    let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
	    const outerRing = polygonRings[0];
	    for (let i = 0; i < outerRing.length; i++) {
	        const p = outerRing[i];
	        if (!i || p.x < minX)
	            minX = p.x;
	        if (!i || p.y < minY)
	            minY = p.y;
	        if (!i || p.x > maxX)
	            maxX = p.x;
	        if (!i || p.y > maxY)
	            maxY = p.y;
	    }
	    const width = maxX - minX;
	    const height = maxY - minY;
	    const cellSize = Math.min(width, height);
	    let h = cellSize / 2;
	    const cellQueue = new TinyQueue([], compareMax);
	    if (cellSize === 0)
	        return new pointGeometry(minX, minY);
	    for (let x = minX; x < maxX; x += cellSize) {
	        for (let y = minY; y < maxY; y += cellSize) {
	            cellQueue.push(new Cell(x + h, y + h, h, polygonRings));
	        }
	    }
	    let bestCell = getCentroidCell(polygonRings);
	    let numProbes = cellQueue.length;
	    while (cellQueue.length) {
	        const cell = cellQueue.pop();
	        if (cell.d > bestCell.d || !bestCell.d) {
	            bestCell = cell;
	            if (debug)
	                console.log('found best %d after %d probes', Math.round(10000 * cell.d) / 10000, numProbes);
	        }
	        if (cell.max - bestCell.d <= precision)
	            continue;
	        h = cell.h / 2;
	        cellQueue.push(new Cell(cell.p.x - h, cell.p.y - h, h, polygonRings));
	        cellQueue.push(new Cell(cell.p.x + h, cell.p.y - h, h, polygonRings));
	        cellQueue.push(new Cell(cell.p.x - h, cell.p.y + h, h, polygonRings));
	        cellQueue.push(new Cell(cell.p.x + h, cell.p.y + h, h, polygonRings));
	        numProbes += 4;
	    }
	    if (debug) {
	        console.log(`num probes: ${ numProbes }`);
	        console.log(`best distance: ${ bestCell.d }`);
	    }
	    return bestCell.p;
	}
	function compareMax(a, b) {
	    return b.max - a.max;
	}
	function Cell(x, y, h, polygon) {
	    this.p = new pointGeometry(x, y);
	    this.h = h;
	    this.d = pointToPolygonDist(this.p, polygon);
	    this.max = this.d + this.h * Math.SQRT2;
	}
	function pointToPolygonDist(p, polygon) {
	    let inside = false;
	    let minDistSq = Infinity;
	    for (let k = 0; k < polygon.length; k++) {
	        const ring = polygon[k];
	        for (let i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
	            const a = ring[i];
	            const b = ring[j];
	            if (a.y > p.y !== b.y > p.y && p.x < (b.x - a.x) * (p.y - a.y) / (b.y - a.y) + a.x)
	                inside = !inside;
	            minDistSq = Math.min(minDistSq, distToSegmentSquared(p, a, b));
	        }
	    }
	    return (inside ? 1 : -1) * Math.sqrt(minDistSq);
	}
	function getCentroidCell(polygon) {
	    let area = 0;
	    let x = 0;
	    let y = 0;
	    const points = polygon[0];
	    for (let i = 0, len = points.length, j = len - 1; i < len; j = i++) {
	        const a = points[i];
	        const b = points[j];
	        const f = a.x * b.y - b.x * a.y;
	        x += (a.x + b.x) * f;
	        y += (a.y + b.y) * f;
	        area += f * 3;
	    }
	    return new Cell(x / area, y / area, 0, polygon);
	}

	const baselineOffset = 7;
	const INVALID_TEXT_OFFSET = Number.POSITIVE_INFINITY;
	const sqrt2 = Math.sqrt(2);
	function evaluateVariableOffset(anchor, offset) {
	    function fromRadialOffset(anchor, radialOffset) {
	        let x = 0, y = 0;
	        if (radialOffset < 0)
	            radialOffset = 0;
	        const hypotenuse = radialOffset / sqrt2;
	        switch (anchor) {
	        case 'top-right':
	        case 'top-left':
	            y = hypotenuse - baselineOffset;
	            break;
	        case 'bottom-right':
	        case 'bottom-left':
	            y = -hypotenuse + baselineOffset;
	            break;
	        case 'bottom':
	            y = -radialOffset + baselineOffset;
	            break;
	        case 'top':
	            y = radialOffset - baselineOffset;
	            break;
	        }
	        switch (anchor) {
	        case 'top-right':
	        case 'bottom-right':
	            x = -hypotenuse;
	            break;
	        case 'top-left':
	        case 'bottom-left':
	            x = hypotenuse;
	            break;
	        case 'left':
	            x = radialOffset;
	            break;
	        case 'right':
	            x = -radialOffset;
	            break;
	        }
	        return [
	            x,
	            y
	        ];
	    }
	    function fromTextOffset(anchor, offsetX, offsetY) {
	        let x = 0, y = 0;
	        offsetX = Math.abs(offsetX);
	        offsetY = Math.abs(offsetY);
	        switch (anchor) {
	        case 'top-right':
	        case 'top-left':
	        case 'top':
	            y = offsetY - baselineOffset;
	            break;
	        case 'bottom-right':
	        case 'bottom-left':
	        case 'bottom':
	            y = -offsetY + baselineOffset;
	            break;
	        }
	        switch (anchor) {
	        case 'top-right':
	        case 'bottom-right':
	        case 'right':
	            x = -offsetX;
	            break;
	        case 'top-left':
	        case 'bottom-left':
	        case 'left':
	            x = offsetX;
	            break;
	        }
	        return [
	            x,
	            y
	        ];
	    }
	    return offset[1] !== INVALID_TEXT_OFFSET ? fromTextOffset(anchor, offset[0], offset[1]) : fromRadialOffset(anchor, offset[0]);
	}
	function performSymbolLayout(bucket, glyphMap, glyphPositions, imageMap, imagePositions, showCollisionBoxes, availableImages, canonical, tileZoom, projection) {
	    bucket.createArrays();
	    const tileSize = 512 * bucket.overscaling;
	    bucket.tilePixelRatio = EXTENT / tileSize;
	    bucket.compareText = {};
	    bucket.iconsNeedLinear = false;
	    const layout = bucket.layers[0].layout;
	    const unevaluatedLayoutValues = bucket.layers[0]._unevaluatedLayout._values;
	    const sizes = {};
	    if (bucket.textSizeData.kind === 'composite') {
	        const {minZoom, maxZoom} = bucket.textSizeData;
	        sizes.compositeTextSizes = [
	            unevaluatedLayoutValues['text-size'].possiblyEvaluate(new EvaluationParameters(minZoom), canonical),
	            unevaluatedLayoutValues['text-size'].possiblyEvaluate(new EvaluationParameters(maxZoom), canonical)
	        ];
	    }
	    if (bucket.iconSizeData.kind === 'composite') {
	        const {minZoom, maxZoom} = bucket.iconSizeData;
	        sizes.compositeIconSizes = [
	            unevaluatedLayoutValues['icon-size'].possiblyEvaluate(new EvaluationParameters(minZoom), canonical),
	            unevaluatedLayoutValues['icon-size'].possiblyEvaluate(new EvaluationParameters(maxZoom), canonical)
	        ];
	    }
	    sizes.layoutTextSize = unevaluatedLayoutValues['text-size'].possiblyEvaluate(new EvaluationParameters(tileZoom + 1), canonical);
	    sizes.layoutIconSize = unevaluatedLayoutValues['icon-size'].possiblyEvaluate(new EvaluationParameters(tileZoom + 1), canonical);
	    sizes.textMaxSize = unevaluatedLayoutValues['text-size'].possiblyEvaluate(new EvaluationParameters(18), canonical);
	    const textAlongLine = layout.get('text-rotation-alignment') === 'map' && layout.get('symbol-placement') !== 'point';
	    const textSize = layout.get('text-size');
	    for (const feature of bucket.features) {
	        const fontstack = layout.get('text-font').evaluate(feature, {}, canonical).join(',');
	        const layoutTextSizeThisZoom = textSize.evaluate(feature, {}, canonical);
	        const layoutTextSize = sizes.layoutTextSize.evaluate(feature, {}, canonical);
	        const layoutIconSize = sizes.layoutIconSize.evaluate(feature, {}, canonical);
	        const shapedTextOrientations = {
	            horizontal: {},
	            vertical: undefined
	        };
	        const text = feature.text;
	        let textOffset = [
	            0,
	            0
	        ];
	        if (text) {
	            const unformattedText = text.toString();
	            const spacing = layout.get('text-letter-spacing').evaluate(feature, {}, canonical) * ONE_EM;
	            const lineHeight = layout.get('text-line-height').evaluate(feature, {}, canonical) * ONE_EM;
	            const spacingIfAllowed = allowsLetterSpacing(unformattedText) ? spacing : 0;
	            const textAnchor = layout.get('text-anchor').evaluate(feature, {}, canonical);
	            const variableTextAnchor = layout.get('text-variable-anchor');
	            if (!variableTextAnchor) {
	                const radialOffset = layout.get('text-radial-offset').evaluate(feature, {}, canonical);
	                if (radialOffset) {
	                    textOffset = evaluateVariableOffset(textAnchor, [
	                        radialOffset * ONE_EM,
	                        INVALID_TEXT_OFFSET
	                    ]);
	                } else {
	                    textOffset = layout.get('text-offset').evaluate(feature, {}, canonical).map(t => t * ONE_EM);
	                }
	            }
	            let textJustify = textAlongLine ? 'center' : layout.get('text-justify').evaluate(feature, {}, canonical);
	            const symbolPlacement = layout.get('symbol-placement');
	            const isPointPlacement = symbolPlacement === 'point';
	            const maxWidth = symbolPlacement === 'point' ? layout.get('text-max-width').evaluate(feature, {}, canonical) * ONE_EM : 0;
	            const addVerticalShapingIfNeeded = textJustify => {
	                if (bucket.allowVerticalPlacement && allowsVerticalWritingMode(unformattedText)) {
	                    shapedTextOrientations.vertical = shapeText(text, glyphMap, glyphPositions, imagePositions, fontstack, maxWidth, lineHeight, textAnchor, textJustify, spacingIfAllowed, textOffset, WritingMode.vertical, true, symbolPlacement, layoutTextSize, layoutTextSizeThisZoom);
	                }
	            };
	            if (!textAlongLine && variableTextAnchor) {
	                const justifications = textJustify === 'auto' ? variableTextAnchor.map(a => getAnchorJustification(a)) : [textJustify];
	                let singleLine = false;
	                for (let i = 0; i < justifications.length; i++) {
	                    const justification = justifications[i];
	                    if (shapedTextOrientations.horizontal[justification])
	                        continue;
	                    if (singleLine) {
	                        shapedTextOrientations.horizontal[justification] = shapedTextOrientations.horizontal[0];
	                    } else {
	                        const shaping = shapeText(text, glyphMap, glyphPositions, imagePositions, fontstack, maxWidth, lineHeight, 'center', justification, spacingIfAllowed, textOffset, WritingMode.horizontal, false, symbolPlacement, layoutTextSize, layoutTextSizeThisZoom);
	                        if (shaping) {
	                            shapedTextOrientations.horizontal[justification] = shaping;
	                            singleLine = shaping.positionedLines.length === 1;
	                        }
	                    }
	                }
	                addVerticalShapingIfNeeded('left');
	            } else {
	                if (textJustify === 'auto') {
	                    textJustify = getAnchorJustification(textAnchor);
	                }
	                if (isPointPlacement || (layout.get('text-writing-mode').indexOf('horizontal') >= 0 || !allowsVerticalWritingMode(unformattedText))) {
	                    const shaping = shapeText(text, glyphMap, glyphPositions, imagePositions, fontstack, maxWidth, lineHeight, textAnchor, textJustify, spacingIfAllowed, textOffset, WritingMode.horizontal, false, symbolPlacement, layoutTextSize, layoutTextSizeThisZoom);
	                    if (shaping)
	                        shapedTextOrientations.horizontal[textJustify] = shaping;
	                }
	                addVerticalShapingIfNeeded(symbolPlacement === 'point' ? 'left' : textJustify);
	            }
	        }
	        let shapedIcon;
	        let isSDFIcon = false;
	        if (feature.icon && feature.icon.name) {
	            const image = imageMap[feature.icon.name];
	            if (image) {
	                shapedIcon = shapeIcon(imagePositions[feature.icon.name], layout.get('icon-offset').evaluate(feature, {}, canonical), layout.get('icon-anchor').evaluate(feature, {}, canonical));
	                isSDFIcon = image.sdf;
	                if (bucket.sdfIcons === undefined) {
	                    bucket.sdfIcons = image.sdf;
	                } else if (bucket.sdfIcons !== image.sdf) {
	                    warnOnce('Style sheet warning: Cannot mix SDF and non-SDF icons in one buffer');
	                }
	                if (image.pixelRatio !== bucket.pixelRatio) {
	                    bucket.iconsNeedLinear = true;
	                } else if (layout.get('icon-rotate').constantOr(1) !== 0) {
	                    bucket.iconsNeedLinear = true;
	                }
	            }
	        }
	        const shapedText = getDefaultHorizontalShaping(shapedTextOrientations.horizontal) || shapedTextOrientations.vertical;
	        if (!bucket.iconsInText) {
	            bucket.iconsInText = shapedText ? shapedText.iconsInText : false;
	        }
	        if (shapedText || shapedIcon) {
	            addFeature(bucket, feature, shapedTextOrientations, shapedIcon, imageMap, sizes, layoutTextSize, layoutIconSize, textOffset, isSDFIcon, availableImages, canonical, projection);
	        }
	    }
	    if (showCollisionBoxes) {
	        bucket.generateCollisionDebugBuffers(tileZoom, bucket.collisionBoxArray);
	    }
	}
	function getAnchorJustification(anchor) {
	    switch (anchor) {
	    case 'right':
	    case 'top-right':
	    case 'bottom-right':
	        return 'right';
	    case 'left':
	    case 'top-left':
	    case 'bottom-left':
	        return 'left';
	    }
	    return 'center';
	}
	function tilePixelRatioForSymbolSpacing(overscaleFactor, overscaledZ) {
	    if (overscaledZ > 18 && overscaleFactor > 2) {
	        overscaleFactor >>= 1;
	    }
	    const tilePixelRatio = EXTENT / (512 * overscaleFactor);
	    return Math.max(tilePixelRatio, 1);
	}
	function addFeature(bucket, feature, shapedTextOrientations, shapedIcon, imageMap, sizes, layoutTextSize, layoutIconSize, textOffset, isSDFIcon, availableImages, canonical, projection) {
	    let textMaxSize = sizes.textMaxSize.evaluate(feature, {}, canonical);
	    if (textMaxSize === undefined) {
	        textMaxSize = layoutTextSize;
	    }
	    const layout = bucket.layers[0].layout;
	    const iconOffset = layout.get('icon-offset').evaluate(feature, {}, canonical);
	    const defaultShaping = getDefaultHorizontalShaping(shapedTextOrientations.horizontal) || shapedTextOrientations.vertical;
	    const isGlobe = projection.name === 'globe';
	    const glyphSize = ONE_EM, fontScale = layoutTextSize / glyphSize, textMaxBoxScale = bucket.tilePixelRatio * textMaxSize / glyphSize, iconBoxScale = bucket.tilePixelRatio * layoutIconSize, symbolMinDistance = tilePixelRatioForSymbolSpacing(bucket.overscaling, bucket.zoom) * layout.get('symbol-spacing'), textPadding = layout.get('text-padding') * bucket.tilePixelRatio, iconPadding = layout.get('icon-padding') * bucket.tilePixelRatio, textMaxAngle = degToRad(layout.get('text-max-angle')), textAlongLine = layout.get('text-rotation-alignment') === 'map' && layout.get('symbol-placement') !== 'point', iconAlongLine = layout.get('icon-rotation-alignment') === 'map' && layout.get('symbol-placement') !== 'point', symbolPlacement = layout.get('symbol-placement'), textRepeatDistance = symbolMinDistance / 2;
	    const iconTextFit = layout.get('icon-text-fit');
	    let verticallyShapedIcon;
	    if (shapedIcon && iconTextFit !== 'none') {
	        if (bucket.allowVerticalPlacement && shapedTextOrientations.vertical) {
	            verticallyShapedIcon = fitIconToText(shapedIcon, shapedTextOrientations.vertical, iconTextFit, layout.get('icon-text-fit-padding'), iconOffset, fontScale);
	        }
	        if (defaultShaping) {
	            shapedIcon = fitIconToText(shapedIcon, defaultShaping, iconTextFit, layout.get('icon-text-fit-padding'), iconOffset, fontScale);
	        }
	    }
	    const addSymbolAtAnchor = (line, anchor, canonicalId) => {
	        if (anchor.x < 0 || anchor.x >= EXTENT || anchor.y < 0 || anchor.y >= EXTENT) {
	            return;
	        }
	        let globe = null;
	        if (isGlobe) {
	            const {x, y, z} = projection.projectTilePoint(anchor.x, anchor.y, canonicalId);
	            globe = {
	                anchor: new Anchor(x, y, z, 0, undefined),
	                up: projection.upVector(canonicalId, anchor.x, anchor.y)
	            };
	        }
	        addSymbol(bucket, anchor, globe, line, shapedTextOrientations, shapedIcon, imageMap, verticallyShapedIcon, bucket.layers[0], bucket.collisionBoxArray, feature.index, feature.sourceLayerIndex, bucket.index, textPadding, textAlongLine, textOffset, iconBoxScale, iconPadding, iconAlongLine, iconOffset, feature, sizes, isSDFIcon, availableImages, canonical);
	    };
	    if (symbolPlacement === 'line') {
	        for (const line of clipLine(feature.geometry, 0, 0, EXTENT, EXTENT)) {
	            const anchors = getAnchors(line, symbolMinDistance, textMaxAngle, shapedTextOrientations.vertical || defaultShaping, shapedIcon, glyphSize, textMaxBoxScale, bucket.overscaling, EXTENT);
	            for (const anchor of anchors) {
	                const shapedText = defaultShaping;
	                if (!shapedText || !anchorIsTooClose(bucket, shapedText.text, textRepeatDistance, anchor)) {
	                    addSymbolAtAnchor(line, anchor, canonical);
	                }
	            }
	        }
	    } else if (symbolPlacement === 'line-center') {
	        for (const line of feature.geometry) {
	            if (line.length > 1) {
	                const anchor = getCenterAnchor(line, textMaxAngle, shapedTextOrientations.vertical || defaultShaping, shapedIcon, glyphSize, textMaxBoxScale);
	                if (anchor) {
	                    addSymbolAtAnchor(line, anchor, canonical);
	                }
	            }
	        }
	    } else if (feature.type === 'Polygon') {
	        for (const polygon of classifyRings$1(feature.geometry, 0)) {
	            const poi = findPoleOfInaccessibility(polygon, 16);
	            addSymbolAtAnchor(polygon[0], new Anchor(poi.x, poi.y, 0, 0, undefined), canonical);
	        }
	    } else if (feature.type === 'LineString') {
	        for (const line of feature.geometry) {
	            addSymbolAtAnchor(line, new Anchor(line[0].x, line[0].y, 0, 0, undefined), canonical);
	        }
	    } else if (feature.type === 'Point') {
	        for (const points of feature.geometry) {
	            for (const point of points) {
	                addSymbolAtAnchor([point], new Anchor(point.x, point.y, 0, 0, undefined), canonical);
	            }
	        }
	    }
	}
	const MAX_GLYPH_ICON_SIZE = 255;
	const MAX_PACKED_SIZE = MAX_GLYPH_ICON_SIZE * SIZE_PACK_FACTOR;
	function addTextVertices(bucket, globe, tileAnchor, shapedText, imageMap, layer, textAlongLine, feature, textOffset, lineArray, writingMode, placementTypes, placedTextSymbolIndices, placedIconIndex, sizes, availableImages, canonical) {
	    const glyphQuads = getGlyphQuads(tileAnchor, shapedText, textOffset, layer, textAlongLine, feature, imageMap, bucket.allowVerticalPlacement);
	    const sizeData = bucket.textSizeData;
	    let textSizeData = null;
	    if (sizeData.kind === 'source') {
	        textSizeData = [SIZE_PACK_FACTOR * layer.layout.get('text-size').evaluate(feature, {}, canonical)];
	        if (textSizeData[0] > MAX_PACKED_SIZE) {
	            warnOnce(`${ bucket.layerIds[0] }: Value for "text-size" is >= ${ MAX_GLYPH_ICON_SIZE }. Reduce your "text-size".`);
	        }
	    } else if (sizeData.kind === 'composite') {
	        textSizeData = [
	            SIZE_PACK_FACTOR * sizes.compositeTextSizes[0].evaluate(feature, {}, canonical),
	            SIZE_PACK_FACTOR * sizes.compositeTextSizes[1].evaluate(feature, {}, canonical)
	        ];
	        if (textSizeData[0] > MAX_PACKED_SIZE || textSizeData[1] > MAX_PACKED_SIZE) {
	            warnOnce(`${ bucket.layerIds[0] }: Value for "text-size" is >= ${ MAX_GLYPH_ICON_SIZE }. Reduce your "text-size".`);
	        }
	    }
	    bucket.addSymbols(bucket.text, glyphQuads, textSizeData, textOffset, textAlongLine, feature, writingMode, globe, tileAnchor, lineArray.lineStartIndex, lineArray.lineLength, placedIconIndex, availableImages, canonical);
	    for (const placementType of placementTypes) {
	        placedTextSymbolIndices[placementType] = bucket.text.placedSymbolArray.length - 1;
	    }
	    return glyphQuads.length * 4;
	}
	function getDefaultHorizontalShaping(horizontalShaping) {
	    for (const justification in horizontalShaping) {
	        return horizontalShaping[justification];
	    }
	    return null;
	}
	function evaluateBoxCollisionFeature(collisionBoxArray, projectedAnchor, tileAnchor, featureIndex, sourceLayerIndex, bucketIndex, shaped, padding, rotate, textOffset) {
	    let y1 = shaped.top;
	    let y2 = shaped.bottom;
	    let x1 = shaped.left;
	    let x2 = shaped.right;
	    const collisionPadding = shaped.collisionPadding;
	    if (collisionPadding) {
	        x1 -= collisionPadding[0];
	        y1 -= collisionPadding[1];
	        x2 += collisionPadding[2];
	        y2 += collisionPadding[3];
	    }
	    if (rotate) {
	        const tl = new pointGeometry(x1, y1);
	        const tr = new pointGeometry(x2, y1);
	        const bl = new pointGeometry(x1, y2);
	        const br = new pointGeometry(x2, y2);
	        const rotateRadians = degToRad(rotate);
	        let rotateCenter = new pointGeometry(0, 0);
	        if (textOffset) {
	            rotateCenter = new pointGeometry(textOffset[0], textOffset[1]);
	        }
	        tl._rotateAround(rotateRadians, rotateCenter);
	        tr._rotateAround(rotateRadians, rotateCenter);
	        bl._rotateAround(rotateRadians, rotateCenter);
	        br._rotateAround(rotateRadians, rotateCenter);
	        x1 = Math.min(tl.x, tr.x, bl.x, br.x);
	        x2 = Math.max(tl.x, tr.x, bl.x, br.x);
	        y1 = Math.min(tl.y, tr.y, bl.y, br.y);
	        y2 = Math.max(tl.y, tr.y, bl.y, br.y);
	    }
	    collisionBoxArray.emplaceBack(projectedAnchor.x, projectedAnchor.y, projectedAnchor.z, tileAnchor.x, tileAnchor.y, x1, y1, x2, y2, padding, featureIndex, sourceLayerIndex, bucketIndex);
	    return collisionBoxArray.length - 1;
	}
	function evaluateCircleCollisionFeature(shaped) {
	    if (shaped.collisionPadding) {
	        shaped.top -= shaped.collisionPadding[1];
	        shaped.bottom += shaped.collisionPadding[3];
	    }
	    const height = shaped.bottom - shaped.top;
	    return height > 0 ? Math.max(10, height) : null;
	}
	function addSymbol(bucket, anchor, globe, line, shapedTextOrientations, shapedIcon, imageMap, verticallyShapedIcon, layer, collisionBoxArray, featureIndex, sourceLayerIndex, bucketIndex, textPadding, textAlongLine, textOffset, iconBoxScale, iconPadding, iconAlongLine, iconOffset, feature, sizes, isSDFIcon, availableImages, canonical) {
	    const lineArray = bucket.addToLineVertexArray(anchor, line);
	    let textBoxIndex, iconBoxIndex, verticalTextBoxIndex, verticalIconBoxIndex;
	    let textCircle, verticalTextCircle, verticalIconCircle;
	    let numIconVertices = 0;
	    let numVerticalIconVertices = 0;
	    let numHorizontalGlyphVertices = 0;
	    let numVerticalGlyphVertices = 0;
	    let placedIconSymbolIndex = -1;
	    let verticalPlacedIconSymbolIndex = -1;
	    const placedTextSymbolIndices = {};
	    let key = murmurhashJs('');
	    const collisionFeatureAnchor = globe ? globe.anchor : anchor;
	    let textOffset0 = 0;
	    let textOffset1 = 0;
	    if (layer._unevaluatedLayout.getValue('text-radial-offset') === undefined) {
	        [textOffset0, textOffset1] = layer.layout.get('text-offset').evaluate(feature, {}, canonical).map(t => t * ONE_EM);
	    } else {
	        textOffset0 = layer.layout.get('text-radial-offset').evaluate(feature, {}, canonical) * ONE_EM;
	        textOffset1 = INVALID_TEXT_OFFSET;
	    }
	    if (bucket.allowVerticalPlacement && shapedTextOrientations.vertical) {
	        const verticalShaping = shapedTextOrientations.vertical;
	        if (textAlongLine) {
	            verticalTextCircle = evaluateCircleCollisionFeature(verticalShaping);
	            if (verticallyShapedIcon) {
	                verticalIconCircle = evaluateCircleCollisionFeature(verticallyShapedIcon);
	            }
	        } else {
	            const textRotation = layer.layout.get('text-rotate').evaluate(feature, {}, canonical);
	            const verticalTextRotation = textRotation + 90;
	            verticalTextBoxIndex = evaluateBoxCollisionFeature(collisionBoxArray, collisionFeatureAnchor, anchor, featureIndex, sourceLayerIndex, bucketIndex, verticalShaping, textPadding, verticalTextRotation, textOffset);
	            if (verticallyShapedIcon) {
	                verticalIconBoxIndex = evaluateBoxCollisionFeature(collisionBoxArray, collisionFeatureAnchor, anchor, featureIndex, sourceLayerIndex, bucketIndex, verticallyShapedIcon, iconPadding, verticalTextRotation);
	            }
	        }
	    }
	    if (shapedIcon) {
	        const iconRotate = layer.layout.get('icon-rotate').evaluate(feature, {}, canonical);
	        const hasIconTextFit = layer.layout.get('icon-text-fit') !== 'none';
	        const iconQuads = getIconQuads(shapedIcon, iconRotate, isSDFIcon, hasIconTextFit);
	        const verticalIconQuads = verticallyShapedIcon ? getIconQuads(verticallyShapedIcon, iconRotate, isSDFIcon, hasIconTextFit) : undefined;
	        iconBoxIndex = evaluateBoxCollisionFeature(collisionBoxArray, collisionFeatureAnchor, anchor, featureIndex, sourceLayerIndex, bucketIndex, shapedIcon, iconPadding, iconRotate);
	        numIconVertices = iconQuads.length * 4;
	        const sizeData = bucket.iconSizeData;
	        let iconSizeData = null;
	        if (sizeData.kind === 'source') {
	            iconSizeData = [SIZE_PACK_FACTOR * layer.layout.get('icon-size').evaluate(feature, {}, canonical)];
	            if (iconSizeData[0] > MAX_PACKED_SIZE) {
	                warnOnce(`${ bucket.layerIds[0] }: Value for "icon-size" is >= ${ MAX_GLYPH_ICON_SIZE }. Reduce your "icon-size".`);
	            }
	        } else if (sizeData.kind === 'composite') {
	            iconSizeData = [
	                SIZE_PACK_FACTOR * sizes.compositeIconSizes[0].evaluate(feature, {}, canonical),
	                SIZE_PACK_FACTOR * sizes.compositeIconSizes[1].evaluate(feature, {}, canonical)
	            ];
	            if (iconSizeData[0] > MAX_PACKED_SIZE || iconSizeData[1] > MAX_PACKED_SIZE) {
	                warnOnce(`${ bucket.layerIds[0] }: Value for "icon-size" is >= ${ MAX_GLYPH_ICON_SIZE }. Reduce your "icon-size".`);
	            }
	        }
	        bucket.addSymbols(bucket.icon, iconQuads, iconSizeData, iconOffset, iconAlongLine, feature, false, globe, anchor, lineArray.lineStartIndex, lineArray.lineLength, -1, availableImages, canonical);
	        placedIconSymbolIndex = bucket.icon.placedSymbolArray.length - 1;
	        if (verticalIconQuads) {
	            numVerticalIconVertices = verticalIconQuads.length * 4;
	            bucket.addSymbols(bucket.icon, verticalIconQuads, iconSizeData, iconOffset, iconAlongLine, feature, WritingMode.vertical, globe, anchor, lineArray.lineStartIndex, lineArray.lineLength, -1, availableImages, canonical);
	            verticalPlacedIconSymbolIndex = bucket.icon.placedSymbolArray.length - 1;
	        }
	    }
	    for (const justification in shapedTextOrientations.horizontal) {
	        const shaping = shapedTextOrientations.horizontal[justification];
	        if (!textBoxIndex) {
	            key = murmurhashJs(shaping.text);
	            if (textAlongLine) {
	                textCircle = evaluateCircleCollisionFeature(shaping);
	            } else {
	                const textRotate = layer.layout.get('text-rotate').evaluate(feature, {}, canonical);
	                textBoxIndex = evaluateBoxCollisionFeature(collisionBoxArray, collisionFeatureAnchor, anchor, featureIndex, sourceLayerIndex, bucketIndex, shaping, textPadding, textRotate, textOffset);
	            }
	        }
	        const singleLine = shaping.positionedLines.length === 1;
	        numHorizontalGlyphVertices += addTextVertices(bucket, globe, anchor, shaping, imageMap, layer, textAlongLine, feature, textOffset, lineArray, shapedTextOrientations.vertical ? WritingMode.horizontal : WritingMode.horizontalOnly, singleLine ? Object.keys(shapedTextOrientations.horizontal) : [justification], placedTextSymbolIndices, placedIconSymbolIndex, sizes, availableImages, canonical);
	        if (singleLine) {
	            break;
	        }
	    }
	    if (shapedTextOrientations.vertical) {
	        numVerticalGlyphVertices += addTextVertices(bucket, globe, anchor, shapedTextOrientations.vertical, imageMap, layer, textAlongLine, feature, textOffset, lineArray, WritingMode.vertical, ['vertical'], placedTextSymbolIndices, verticalPlacedIconSymbolIndex, sizes, availableImages, canonical);
	    }
	    let collisionCircleDiameter = -1;
	    const getCollisionCircleHeight = (diameter, prevHeight) => {
	        return diameter ? Math.max(diameter, prevHeight) : prevHeight;
	    };
	    collisionCircleDiameter = getCollisionCircleHeight(textCircle, collisionCircleDiameter);
	    collisionCircleDiameter = getCollisionCircleHeight(verticalTextCircle, collisionCircleDiameter);
	    collisionCircleDiameter = getCollisionCircleHeight(verticalIconCircle, collisionCircleDiameter);
	    const useRuntimeCollisionCircles = collisionCircleDiameter > -1 ? 1 : 0;
	    if (bucket.glyphOffsetArray.length >= SymbolBucket.MAX_GLYPHS)
	        warnOnce('Too many glyphs being rendered in a tile. See https://github.com/mapbox/mapbox-gl-js/issues/2907');
	    if (feature.sortKey !== undefined) {
	        bucket.addToSortKeyRanges(bucket.symbolInstances.length, feature.sortKey);
	    }
	    const projectedAnchor = collisionFeatureAnchor;
	    bucket.symbolInstances.emplaceBack(projectedAnchor.x, projectedAnchor.y, projectedAnchor.z, anchor.x, anchor.y, placedTextSymbolIndices.right >= 0 ? placedTextSymbolIndices.right : -1, placedTextSymbolIndices.center >= 0 ? placedTextSymbolIndices.center : -1, placedTextSymbolIndices.left >= 0 ? placedTextSymbolIndices.left : -1, placedTextSymbolIndices.vertical >= 0 ? placedTextSymbolIndices.vertical : -1, placedIconSymbolIndex, verticalPlacedIconSymbolIndex, key, textBoxIndex !== undefined ? textBoxIndex : bucket.collisionBoxArray.length, textBoxIndex !== undefined ? textBoxIndex + 1 : bucket.collisionBoxArray.length, verticalTextBoxIndex !== undefined ? verticalTextBoxIndex : bucket.collisionBoxArray.length, verticalTextBoxIndex !== undefined ? verticalTextBoxIndex + 1 : bucket.collisionBoxArray.length, iconBoxIndex !== undefined ? iconBoxIndex : bucket.collisionBoxArray.length, iconBoxIndex !== undefined ? iconBoxIndex + 1 : bucket.collisionBoxArray.length, verticalIconBoxIndex ? verticalIconBoxIndex : bucket.collisionBoxArray.length, verticalIconBoxIndex ? verticalIconBoxIndex + 1 : bucket.collisionBoxArray.length, featureIndex, numHorizontalGlyphVertices, numVerticalGlyphVertices, numIconVertices, numVerticalIconVertices, useRuntimeCollisionCircles, 0, textOffset0, textOffset1, collisionCircleDiameter);
	}
	function anchorIsTooClose(bucket, text, repeatDistance, anchor) {
	    const compareText = bucket.compareText;
	    if (!(text in compareText)) {
	        compareText[text] = [];
	    } else {
	        const otherAnchors = compareText[text];
	        for (let k = otherAnchors.length - 1; k >= 0; k--) {
	            if (anchor.dist(otherAnchors[k]) < repeatDistance) {
	                return true;
	            }
	        }
	    }
	    compareText[text].push(anchor);
	    return false;
	}

	const layout$1 = createLayout([
	    {
	        type: 'Float32',
	        name: 'a_globe_pos',
	        components: 3
	    },
	    {
	        type: 'Float32',
	        name: 'a_merc_pos',
	        components: 2
	    },
	    {
	        type: 'Float32',
	        name: 'a_uv',
	        components: 2
	    }
	]);
	const {members, size, alignment} = layout$1;

	const posAttributesGlobeExt = createLayout([{
	        name: 'a_pos_3',
	        components: 3,
	        type: 'Int16'
	    }]);
	var posAttributes = createLayout([{
	        name: 'a_pos',
	        type: 'Int16',
	        components: 2
	    }]);

	const GLOBE_ZOOM_THRESHOLD_MIN = 5;
	const GLOBE_ZOOM_THRESHOLD_MAX = 6;
	const GLOBE_SCALE_MATCH_LATITUDE = 45;
	const GLOBE_RADIUS = EXTENT / Math.PI / 2;
	const GLOBE_METERS_TO_ECEF = mercatorZfromAltitude(1, 0) * 2 * GLOBE_RADIUS * Math.PI;
	const GLOBE_NORMALIZATION_BIT_RANGE = 15;
	const GLOBE_NORMALIZATION_MASK = (1 << GLOBE_NORMALIZATION_BIT_RANGE - 1) - 1;
	const GLOBE_VERTEX_GRID_SIZE = 64;
	const GLOBE_LATITUDINAL_GRID_LOD_TABLE = [
	    GLOBE_VERTEX_GRID_SIZE,
	    GLOBE_VERTEX_GRID_SIZE / 2,
	    GLOBE_VERTEX_GRID_SIZE / 4
	];
	const TILE_SIZE = 512;
	const GLOBE_MIN = -GLOBE_RADIUS;
	const GLOBE_MAX = GLOBE_RADIUS;
	const GLOBE_LOW_ZOOM_TILE_AABBS = [
	    new Aabb([
	        GLOBE_MIN,
	        GLOBE_MIN,
	        GLOBE_MIN
	    ], [
	        GLOBE_MAX,
	        GLOBE_MAX,
	        GLOBE_MAX
	    ]),
	    new Aabb([
	        GLOBE_MIN,
	        GLOBE_MIN,
	        GLOBE_MIN
	    ], [
	        0,
	        0,
	        GLOBE_MAX
	    ]),
	    new Aabb([
	        0,
	        GLOBE_MIN,
	        GLOBE_MIN
	    ], [
	        GLOBE_MAX,
	        0,
	        GLOBE_MAX
	    ]),
	    new Aabb([
	        GLOBE_MIN,
	        0,
	        GLOBE_MIN
	    ], [
	        0,
	        GLOBE_MAX,
	        GLOBE_MAX
	    ]),
	    new Aabb([
	        0,
	        0,
	        GLOBE_MIN
	    ], [
	        GLOBE_MAX,
	        GLOBE_MAX,
	        GLOBE_MAX
	    ])
	];
	function globePointCoordinate(tr, x, y, clampToHorizon = true) {
	    const point0 = scale$1([], tr._camera.position, tr.worldSize);
	    const point1 = [
	        x,
	        y,
	        1,
	        1
	    ];
	    transformMat4(point1, point1, tr.pixelMatrixInverse);
	    scale(point1, point1, 1 / point1[3]);
	    const p0p1 = sub([], point1, point0);
	    const dir = normalize$2([], p0p1);
	    const m = tr.globeMatrix;
	    const globeCenter = [
	        m[12],
	        m[13],
	        m[14]
	    ];
	    const p0toCenter = sub([], globeCenter, point0);
	    const p0toCenterDist = length$2(p0toCenter);
	    const centerDir = normalize$2([], p0toCenter);
	    const radius = tr.worldSize / (2 * Math.PI);
	    const cosAngle = dot$1(centerDir, dir);
	    const origoTangentAngle = Math.asin(radius / p0toCenterDist);
	    const origoDirAngle = Math.acos(cosAngle);
	    if (origoTangentAngle < origoDirAngle) {
	        if (!clampToHorizon)
	            return null;
	        const clampedP1 = [], origoToP1 = [];
	        scale$1(clampedP1, dir, p0toCenterDist / cosAngle);
	        normalize$2(origoToP1, sub(origoToP1, clampedP1, p0toCenter));
	        normalize$2(dir, add(dir, p0toCenter, scale$1(dir, origoToP1, Math.tan(origoTangentAngle) * p0toCenterDist)));
	    }
	    const pointOnGlobe = [];
	    const ray = new Ray(point0, dir);
	    ray.closestPointOnSphere(globeCenter, radius, pointOnGlobe);
	    const xa = normalize$2([], getColumn(m, 0));
	    const ya = normalize$2([], getColumn(m, 1));
	    const za = normalize$2([], getColumn(m, 2));
	    const xp = dot$1(xa, pointOnGlobe);
	    const yp = dot$1(ya, pointOnGlobe);
	    const zp = dot$1(za, pointOnGlobe);
	    const lat = radToDeg(Math.asin(-yp / radius));
	    let lng = radToDeg(Math.atan2(xp, zp));
	    lng = tr.center.lng + shortestAngle(tr.center.lng, lng);
	    const mx = mercatorXfromLng(lng);
	    const my = clamp(mercatorYfromLat(lat), 0, 1);
	    return new MercatorCoordinate(mx, my);
	}
	class Arc {
	    constructor(p0, p1, center) {
	        this.a = sub([], p0, center);
	        this.b = sub([], p1, center);
	        this.center = center;
	        const an = normalize$2([], this.a);
	        const bn = normalize$2([], this.b);
	        this.angle = Math.acos(dot$1(an, bn));
	    }
	}
	function slerp(a, b, angle, t) {
	    const sina = Math.sin(angle);
	    return a * (Math.sin((1 - t) * angle) / sina) + b * (Math.sin(t * angle) / sina);
	}
	function localExtremum(arc, dim) {
	    if (arc.angle === 0) {
	        return null;
	    }
	    let t;
	    if (arc.a[dim] === 0) {
	        t = 1 / arc.angle * 0.5 * Math.PI;
	    } else {
	        t = 1 / arc.angle * Math.atan(arc.b[dim] / arc.a[dim] / Math.sin(arc.angle) - 1 / Math.tan(arc.angle));
	    }
	    if (t < 0 || t > 1) {
	        return null;
	    }
	    return slerp(arc.a[dim], arc.b[dim], arc.angle, clamp(t, 0, 1)) + arc.center[dim];
	}
	function globeTileBounds(id) {
	    if (id.z <= 1) {
	        return GLOBE_LOW_ZOOM_TILE_AABBS[id.z + id.y * 2 + id.x];
	    }
	    const [min, max] = globeTileLatLngCorners(id);
	    const corners = [
	        latLngToECEF(min[0], min[1]),
	        latLngToECEF(min[0], max[1]),
	        latLngToECEF(max[0], min[1]),
	        latLngToECEF(max[0], max[1])
	    ];
	    const bMin = [
	        GLOBE_MAX,
	        GLOBE_MAX,
	        GLOBE_MAX
	    ];
	    const bMax = [
	        GLOBE_MIN,
	        GLOBE_MIN,
	        GLOBE_MIN
	    ];
	    for (const p of corners) {
	        bMin[0] = Math.min(bMin[0], p[0]);
	        bMin[1] = Math.min(bMin[1], p[1]);
	        bMin[2] = Math.min(bMin[2], p[2]);
	        bMax[0] = Math.max(bMax[0], p[0]);
	        bMax[1] = Math.max(bMax[1], p[1]);
	        bMax[2] = Math.max(bMax[2], p[2]);
	    }
	    return new Aabb(bMin, bMax);
	}
	function aabbForTileOnGlobe(tr, numTiles, tileId) {
	    const scale = numTiles / tr.worldSize;
	    const mx = Number.MAX_VALUE;
	    const cornerMax = [
	        -mx,
	        -mx,
	        -mx
	    ];
	    const cornerMin = [
	        mx,
	        mx,
	        mx
	    ];
	    const m = identity$2(new Float64Array(16));
	    scale$2(m, m, [
	        scale,
	        scale,
	        scale
	    ]);
	    multiply$2(m, m, tr.globeMatrix);
	    if (tileId.z <= 1) {
	        const aabb = globeTileBounds(tileId);
	        const corners = aabb.getCorners();
	        for (let i = 0; i < corners.length; i++) {
	            transformMat4$1(corners[i], corners[i], m);
	            min(cornerMin, cornerMin, corners[i]);
	            max(cornerMax, cornerMax, corners[i]);
	        }
	        return new Aabb(cornerMin, cornerMax);
	    }
	    const [nw, se] = globeTileLatLngCorners(tileId);
	    const bounds = new LngLatBounds();
	    bounds.setSouthWest([
	        nw[1],
	        se[0]
	    ]);
	    bounds.setNorthEast([
	        se[1],
	        nw[0]
	    ]);
	    const corners = [
	        latLngToECEF(bounds.getSouth(), bounds.getWest()),
	        latLngToECEF(bounds.getSouth(), bounds.getEast()),
	        latLngToECEF(bounds.getNorth(), bounds.getEast()),
	        latLngToECEF(bounds.getNorth(), bounds.getWest())
	    ];
	    for (let i = 0; i < corners.length; i++) {
	        transformMat4$1(corners[i], corners[i], m);
	        min(cornerMin, cornerMin, corners[i]);
	        max(cornerMax, cornerMax, corners[i]);
	    }
	    if (bounds.contains(tr.center)) {
	        cornerMax[2] = 0;
	        const point = tr.point;
	        const center = [
	            point.x * scale,
	            point.y * scale,
	            0
	        ];
	        min(cornerMin, cornerMin, center);
	        max(cornerMax, cornerMax, center);
	        return new Aabb(cornerMin, cornerMax);
	    }
	    const globeCenter = [
	        m[12],
	        m[13],
	        m[14]
	    ];
	    const centerLng = tr.center.lng;
	    const centerLat = clamp(tr.center.lat, -MAX_MERCATOR_LATITUDE, MAX_MERCATOR_LATITUDE);
	    const center = [
	        mercatorXfromLng(centerLng),
	        mercatorYfromLat(centerLat)
	    ];
	    const tileCenterLng = bounds.getCenter().lng;
	    const tileCenterLat = clamp(bounds.getCenter().lat, -MAX_MERCATOR_LATITUDE, MAX_MERCATOR_LATITUDE);
	    const tileCenter = [
	        mercatorXfromLng(tileCenterLng),
	        mercatorYfromLat(tileCenterLat)
	    ];
	    let arcCenter = new Array(3);
	    let closestArcIdx = 0;
	    let dx = center[0] - tileCenter[0];
	    const dy = center[1] - tileCenter[1];
	    if (dx > 0.5) {
	        dx -= 1;
	    } else if (dx < -0.5) {
	        dx += 1;
	    }
	    if (Math.abs(dx) > Math.abs(dy)) {
	        closestArcIdx = dx >= 0 ? 1 : 3;
	        arcCenter = globeCenter;
	    } else {
	        closestArcIdx = dy >= 0 ? 0 : 2;
	        const yAxis = [
	            m[4],
	            m[5],
	            m[6]
	        ];
	        let shift;
	        if (dy >= 0) {
	            shift = -Math.sin(degToRad(bounds.getSouth())) * GLOBE_RADIUS;
	        } else {
	            shift = -Math.sin(degToRad(bounds.getNorth())) * GLOBE_RADIUS;
	        }
	        arcCenter = scaleAndAdd(arcCenter, globeCenter, yAxis, shift);
	    }
	    const arcA = corners[closestArcIdx];
	    const arcB = corners[(closestArcIdx + 1) % 4];
	    const closestArc = new Arc(arcA, arcB, arcCenter);
	    const arcBounds = [
	        localExtremum(closestArc, 0) || arcA[0],
	        localExtremum(closestArc, 1) || arcA[1],
	        localExtremum(closestArc, 2) || arcA[2]
	    ];
	    cornerMin[2] = Math.min(arcA[2], arcB[2]);
	    min(cornerMin, cornerMin, arcBounds);
	    max(cornerMax, cornerMax, arcBounds);
	    return new Aabb(cornerMin, cornerMax);
	}
	function globeTileLatLngCorners(id) {
	    const tileScale = 1 << id.z;
	    const left = id.x / tileScale;
	    const right = (id.x + 1) / tileScale;
	    const top = id.y / tileScale;
	    const bottom = (id.y + 1) / tileScale;
	    const latLngTL = [
	        latFromMercatorY(top),
	        lngFromMercatorX(left)
	    ];
	    const latLngBR = [
	        latFromMercatorY(bottom),
	        lngFromMercatorX(right)
	    ];
	    return [
	        latLngTL,
	        latLngBR
	    ];
	}
	function csLatLngToECEF(cosLat, sinLat, lng, radius = GLOBE_RADIUS) {
	    lng = degToRad(lng);
	    const sx = cosLat * Math.sin(lng) * radius;
	    const sy = -sinLat * radius;
	    const sz = cosLat * Math.cos(lng) * radius;
	    return [
	        sx,
	        sy,
	        sz
	    ];
	}
	function latLngToECEF(lat, lng, radius) {
	    return csLatLngToECEF(Math.cos(degToRad(lat)), Math.sin(degToRad(lat)), lng, radius);
	}
	function tileCoordToECEF(x, y, id) {
	    const tiles = Math.pow(2, id.z);
	    const mx = (x / EXTENT + id.x) / tiles;
	    const my = (y / EXTENT + id.y) / tiles;
	    const lat = latFromMercatorY(my);
	    const lng = lngFromMercatorX(mx);
	    const pos = latLngToECEF(lat, lng);
	    return pos;
	}
	function globeECEFOrigin(tileMatrix, id) {
	    const origin = [
	        0,
	        0,
	        0
	    ];
	    const bounds = globeTileBounds(id.canonical);
	    const normalizationMatrix = globeNormalizeECEF(bounds);
	    transformMat4$1(origin, origin, normalizationMatrix);
	    transformMat4$1(origin, origin, tileMatrix);
	    return origin;
	}
	function globeECEFNormalizationScale(bounds) {
	    const maxExt = Math.max(...sub([], bounds.max, bounds.min));
	    return GLOBE_NORMALIZATION_MASK / maxExt;
	}
	function globeNormalizeECEF(bounds) {
	    const m = identity$2(new Float64Array(16));
	    const scale = globeECEFNormalizationScale(bounds);
	    scale$2(m, m, [
	        scale,
	        scale,
	        scale
	    ]);
	    translate(m, m, negate([], bounds.min));
	    return m;
	}
	function globeDenormalizeECEF(bounds) {
	    const m = identity$2(new Float64Array(16));
	    const scale = 1 / globeECEFNormalizationScale(bounds);
	    translate(m, m, bounds.min);
	    scale$2(m, m, [
	        scale,
	        scale,
	        scale
	    ]);
	    return m;
	}
	function globeECEFUnitsToPixelScale(worldSize) {
	    const localRadius = EXTENT / (2 * Math.PI);
	    const wsRadius = worldSize / (2 * Math.PI);
	    return wsRadius / localRadius;
	}
	function globePixelsToTileUnits(zoom, id) {
	    const ecefPerPixel = EXTENT / (TILE_SIZE * Math.pow(2, zoom));
	    const normCoeff = globeECEFNormalizationScale(globeTileBounds(id));
	    return ecefPerPixel * normCoeff;
	}
	function calculateGlobePosMatrix(x, y, worldSize, lng, lat) {
	    const scale = globeECEFUnitsToPixelScale(worldSize);
	    const offset = [
	        x,
	        y,
	        -worldSize / (2 * Math.PI)
	    ];
	    const m = identity$2(new Float64Array(16));
	    translate(m, m, offset);
	    scale$2(m, m, [
	        scale,
	        scale,
	        scale
	    ]);
	    rotateX$1(m, m, degToRad(-lat));
	    rotateY$1(m, m, degToRad(-lng));
	    return m;
	}
	function calculateGlobeMatrix(tr) {
	    const {x, y} = tr.point;
	    const {lng, lat} = tr._center;
	    return calculateGlobePosMatrix(x, y, tr.worldSize, lng, lat);
	}
	function calculateGlobeLabelMatrix(tr, id) {
	    const {x, y} = tr.point;
	    const m = calculateGlobePosMatrix(x, y, tr.worldSize / tr._projectionScaler, 0, 0);
	    return multiply$2(m, m, globeDenormalizeECEF(globeTileBounds(id)));
	}
	function calculateGlobeMercatorMatrix(tr) {
	    const worldSize = tr.worldSize;
	    const point = tr.point;
	    const mercatorZ = mercatorZfromAltitude(1, tr.center.lat) * worldSize;
	    const projectionScaler = mercatorZ / tr.pixelsPerMeter;
	    const zScale = tr.pixelsPerMeter;
	    const ws = worldSize / projectionScaler;
	    const posMatrix = identity$2(new Float64Array(16));
	    translate(posMatrix, posMatrix, [
	        point.x,
	        point.y,
	        0
	    ]);
	    scale$2(posMatrix, posMatrix, [
	        ws,
	        ws,
	        zScale
	    ]);
	    return Float32Array.from(posMatrix);
	}
	function globeToMercatorTransition(zoom) {
	    return smoothstep(GLOBE_ZOOM_THRESHOLD_MIN, GLOBE_ZOOM_THRESHOLD_MAX, zoom);
	}
	function globePoleMatrixForTile(z, x, tr) {
	    const poleMatrix = identity$2(new Float64Array(16));
	    const numTiles = 1 << z;
	    const xOffsetAngle = (x / numTiles - 0.5) * 360;
	    const point = tr.point;
	    const ws = tr.worldSize;
	    const s = tr.worldSize / (tr.tileSize * numTiles);
	    translate(poleMatrix, poleMatrix, [
	        point.x,
	        point.y,
	        -(ws / Math.PI / 2)
	    ]);
	    scale$2(poleMatrix, poleMatrix, [
	        s,
	        s,
	        s
	    ]);
	    rotateX$1(poleMatrix, poleMatrix, degToRad(-tr._center.lat));
	    rotateY$1(poleMatrix, poleMatrix, degToRad(-tr._center.lng + xOffsetAngle));
	    return Float32Array.from(poleMatrix);
	}
	function globeUseCustomAntiAliasing(painter, context, transform) {
	    const transitionT = globeToMercatorTransition(transform.zoom);
	    const useContextAA = painter.style.map._antialias;
	    const hasStandardDerivatives = !!context.extStandardDerivatives;
	    const disabled = context.extStandardDerivativesForceOff || painter.terrain && painter.terrain.exaggeration() > 0;
	    return transitionT === 0 && !useContextAA && !disabled && hasStandardDerivatives;
	}
	function getGridMatrix(id, corners, latitudinalLod) {
	    const [tl, br] = corners;
	    const S = 1 / GLOBE_VERTEX_GRID_SIZE;
	    const x = (br[1] - tl[1]) * S;
	    const latitudinalSubdivs = GLOBE_LATITUDINAL_GRID_LOD_TABLE[latitudinalLod];
	    const y = (br[0] - tl[0]) / latitudinalSubdivs;
	    const tileZoom = 1 << id.z;
	    return [
	        0,
	        x,
	        tileZoom,
	        y,
	        0,
	        id.y,
	        tl[0],
	        tl[1],
	        S
	    ];
	}
	function getLatitudinalLod(lat) {
	    const UPPER_LATITUDE = MAX_MERCATOR_LATITUDE - 5;
	    lat = clamp(lat, -UPPER_LATITUDE, UPPER_LATITUDE) / UPPER_LATITUDE * 90;
	    const t = Math.pow(Math.abs(Math.sin(degToRad(lat))), 3);
	    const lod = Math.round(t * (GLOBE_LATITUDINAL_GRID_LOD_TABLE.length - 1));
	    return lod;
	}
	function globeCenterToScreenPoint(tr) {
	    const pos = [
	        0,
	        0,
	        0
	    ];
	    const matrix = identity$2(new Float64Array(16));
	    multiply$2(matrix, tr.pixelMatrix, tr.globeMatrix);
	    transformMat4$1(pos, pos, matrix);
	    return new pointGeometry(pos[0], pos[1]);
	}
	function cameraPositionInECEF(tr) {
	    const centerToPivot = latLngToECEF(tr._center.lat, tr._center.lng);
	    const south = fromValues(0, 1, 0);
	    let axis = cross([], south, centerToPivot);
	    const rotation = fromRotation([], -tr.angle, centerToPivot);
	    axis = transformMat4$1(axis, axis, rotation);
	    fromRotation(rotation, -tr._pitch, axis);
	    const pivotToCamera = normalize$2([], centerToPivot);
	    scale$1(pivotToCamera, pivotToCamera, tr.cameraToCenterDistance / tr.pixelsPerMeter * GLOBE_METERS_TO_ECEF);
	    transformMat4$1(pivotToCamera, pivotToCamera, rotation);
	    return add([], centerToPivot, pivotToCamera);
	}
	function globeTiltAtLngLat(tr, lngLat) {
	    const centerToPoint = latLngToECEF(lngLat.lat, lngLat.lng);
	    const centerToCamera = cameraPositionInECEF(tr);
	    const pointToCamera = subtract([], centerToCamera, centerToPoint);
	    return angle(pointToCamera, centerToPoint);
	}
	function isLngLatBehindGlobe(tr, lngLat) {
	    return globeTiltAtLngLat(tr, lngLat) > Math.PI / 2 * 1.01;
	}
	const POLE_RAD = degToRad(85);
	const POLE_COS = Math.cos(POLE_RAD);
	const POLE_SIN = Math.sin(POLE_RAD);
	class GlobeSharedBuffers {
	    constructor(context) {
	        this._createGrid(context);
	        this._createPoles(context);
	    }
	    destroy() {
	        this._poleIndexBuffer.destroy();
	        this._gridBuffer.destroy();
	        this._gridIndexBuffer.destroy();
	        this._poleNorthVertexBuffer.destroy();
	        this._poleSouthVertexBuffer.destroy();
	        for (const segments of this._poleSegments)
	            segments.destroy();
	        for (const segments of this._gridSegments)
	            segments.destroy();
	        if (this._wireframeIndexBuffer) {
	            this._wireframeIndexBuffer.destroy();
	            for (const segments of this._wireframeSegments)
	                segments.destroy();
	        }
	    }
	    _createGrid(context) {
	        const gridVertices = new StructArrayLayout2i4();
	        const gridIndices = new StructArrayLayout3ui6();
	        const quadExt = GLOBE_VERTEX_GRID_SIZE;
	        const vertexExt = quadExt + 1;
	        for (let j = 0; j < vertexExt; j++)
	            for (let i = 0; i < vertexExt; i++)
	                gridVertices.emplaceBack(i, j);
	        this._gridSegments = [];
	        for (let k = 0, primitiveOffset = 0; k < GLOBE_LATITUDINAL_GRID_LOD_TABLE.length; k++) {
	            const latitudinalLod = GLOBE_LATITUDINAL_GRID_LOD_TABLE[k];
	            for (let j = 0; j < latitudinalLod; j++) {
	                for (let i = 0; i < quadExt; i++) {
	                    const index = j * vertexExt + i;
	                    gridIndices.emplaceBack(index + 1, index, index + vertexExt);
	                    gridIndices.emplaceBack(index + vertexExt, index + vertexExt + 1, index + 1);
	                }
	            }
	            const numVertices = (latitudinalLod + 1) * vertexExt;
	            const numPrimitives = latitudinalLod * quadExt * 2;
	            this._gridSegments.push(SegmentVector.simpleSegment(0, primitiveOffset, numVertices, numPrimitives));
	            primitiveOffset += numPrimitives;
	        }
	        this._gridBuffer = context.createVertexBuffer(gridVertices, posAttributes.members);
	        this._gridIndexBuffer = context.createIndexBuffer(gridIndices, true);
	    }
	    _createPoles(context) {
	        const poleIndices = new StructArrayLayout3ui6();
	        for (let i = 0; i <= GLOBE_VERTEX_GRID_SIZE; i++) {
	            poleIndices.emplaceBack(0, i + 1, i + 2);
	        }
	        this._poleIndexBuffer = context.createIndexBuffer(poleIndices, true);
	        const northVertices = new StructArrayLayout7f28();
	        const southVertices = new StructArrayLayout7f28();
	        const polePrimitives = GLOBE_VERTEX_GRID_SIZE;
	        const poleVertices = GLOBE_VERTEX_GRID_SIZE + 2;
	        this._poleSegments = [];
	        for (let zoom = 0, offset = 0; zoom < GLOBE_ZOOM_THRESHOLD_MIN; zoom++) {
	            const tiles = 1 << zoom;
	            const radius = tiles * TILE_SIZE / Math.PI / 2;
	            const endAngle = 360 / tiles;
	            northVertices.emplaceBack(0, -radius, 0, 0, 0, 0.5, 0);
	            southVertices.emplaceBack(0, -radius, 0, 0, 0, 0.5, 1);
	            for (let i = 0; i <= GLOBE_VERTEX_GRID_SIZE; i++) {
	                const uvX = i / GLOBE_VERTEX_GRID_SIZE;
	                const angle = number(0, endAngle, uvX);
	                const [gx, gy, gz] = csLatLngToECEF(POLE_COS, POLE_SIN, angle, radius);
	                northVertices.emplaceBack(gx, gy, gz, 0, 0, uvX, 0);
	                southVertices.emplaceBack(gx, gy, gz, 0, 0, uvX, 1);
	            }
	            this._poleSegments.push(SegmentVector.simpleSegment(offset, 0, poleVertices, polePrimitives));
	            offset += poleVertices;
	        }
	        this._poleNorthVertexBuffer = context.createVertexBuffer(northVertices, members, false);
	        this._poleSouthVertexBuffer = context.createVertexBuffer(southVertices, members, false);
	    }
	    getGridBuffers(latitudinalLod) {
	        return [
	            this._gridBuffer,
	            this._gridIndexBuffer,
	            this._gridSegments[latitudinalLod]
	        ];
	    }
	    getPoleBuffers(z) {
	        return [
	            this._poleNorthVertexBuffer,
	            this._poleSouthVertexBuffer,
	            this._poleIndexBuffer,
	            this._poleSegments[z]
	        ];
	    }
	    getWirefameBuffers(context, lod) {
	        if (!this._wireframeSegments) {
	            const wireframeIndices = new StructArrayLayout2ui4();
	            const quadExt = GLOBE_VERTEX_GRID_SIZE;
	            const vertexExt = quadExt + 1;
	            this._wireframeSegments = [];
	            for (let k = 0, primitiveOffset = 0; k < GLOBE_LATITUDINAL_GRID_LOD_TABLE.length; k++) {
	                const latitudinalLod = GLOBE_LATITUDINAL_GRID_LOD_TABLE[k];
	                for (let j = 0; j < latitudinalLod; j++) {
	                    for (let i = 0; i < quadExt; i++) {
	                        const index = j * vertexExt + i;
	                        wireframeIndices.emplaceBack(index, index + 1);
	                        wireframeIndices.emplaceBack(index, index + vertexExt);
	                        wireframeIndices.emplaceBack(index, index + vertexExt + 1);
	                    }
	                }
	                const numVertices = (latitudinalLod + 1) * vertexExt;
	                const numPrimitives = latitudinalLod * quadExt * 3;
	                this._wireframeSegments.push(SegmentVector.simpleSegment(0, primitiveOffset, numVertices, numPrimitives));
	                primitiveOffset += numPrimitives;
	            }
	            this._wireframeIndexBuffer = context.createIndexBuffer(wireframeIndices);
	        }
	        return [
	            this._gridBuffer,
	            this._wireframeIndexBuffer,
	            this._wireframeSegments[lod]
	        ];
	    }
	}

	function farthestPixelDistanceOnPlane(tr, pixelsPerMeter) {
	    const fovAboveCenter = tr.fovAboveCenter;
	    const minElevationInPixels = tr.elevation ? tr.elevation.getMinElevationBelowMSL() * pixelsPerMeter : 0;
	    const cameraToSeaLevelDistance = (tr._camera.position[2] * tr.worldSize - minElevationInPixels) / Math.cos(tr._pitch);
	    const topHalfSurfaceDistance = Math.sin(fovAboveCenter) * cameraToSeaLevelDistance / Math.sin(Math.max(Math.PI / 2 - tr._pitch - fovAboveCenter, 0.01));
	    const furthestDistance = Math.sin(tr._pitch) * topHalfSurfaceDistance + cameraToSeaLevelDistance;
	    const horizonDistance = cameraToSeaLevelDistance * (1 / tr._horizonShift);
	    return Math.min(furthestDistance * 1.01, horizonDistance);
	}
	function farthestPixelDistanceOnSphere(tr, pixelsPerMeter) {
	    const cameraDistance = tr.cameraToCenterDistance;
	    const centerPixelAltitude = tr._centerAltitude * pixelsPerMeter;
	    const camera = tr._camera;
	    const forward = tr._camera.forward();
	    const cameraPosition = add([], scale$1([], forward, -cameraDistance), [
	        0,
	        0,
	        centerPixelAltitude
	    ]);
	    const globeRadius = tr.worldSize / (2 * Math.PI);
	    const globeCenter = [
	        0,
	        0,
	        -globeRadius
	    ];
	    const aspectRatio = tr.width / tr.height;
	    const tanFovAboveCenter = Math.tan(tr.fovAboveCenter);
	    const up = scale$1([], camera.up(), tanFovAboveCenter);
	    const right = scale$1([], camera.right(), tanFovAboveCenter * aspectRatio);
	    const dir = normalize$2([], add([], add([], forward, up), right));
	    const pointOnGlobe = [];
	    const ray = new Ray(cameraPosition, dir);
	    let pixelDistance;
	    if (ray.closestPointOnSphere(globeCenter, globeRadius, pointOnGlobe)) {
	        const p0 = add([], pointOnGlobe, globeCenter);
	        const p1 = sub([], p0, cameraPosition);
	        pixelDistance = Math.cos(tr.fovAboveCenter) * length$2(p1);
	    } else {
	        const globeCenterToCamera = sub([], cameraPosition, globeCenter);
	        const cameraToGlobe = sub([], globeCenter, cameraPosition);
	        normalize$2(cameraToGlobe, cameraToGlobe);
	        const cameraHeight = length$2(globeCenterToCamera) - globeRadius;
	        pixelDistance = Math.sqrt(cameraHeight * (cameraHeight + 2 * globeRadius));
	        const angle = Math.acos(pixelDistance / (globeRadius + cameraHeight)) - Math.acos(dot$1(forward, cameraToGlobe));
	        pixelDistance *= Math.cos(angle);
	    }
	    return pixelDistance * 1.01;
	}

	function tileTransform(id, projection) {
	    if (!projection.isReprojectedInTileSpace) {
	        return {
	            scale: 1 << id.z,
	            x: id.x,
	            y: id.y,
	            x2: id.x + 1,
	            y2: id.y + 1,
	            projection
	        };
	    }
	    const s = Math.pow(2, -id.z);
	    const x1 = id.x * s;
	    const x2 = (id.x + 1) * s;
	    const y1 = id.y * s;
	    const y2 = (id.y + 1) * s;
	    const lng1 = lngFromMercatorX(x1);
	    const lng2 = lngFromMercatorX(x2);
	    const lat1 = latFromMercatorY(y1);
	    const lat2 = latFromMercatorY(y2);
	    const p0 = projection.project(lng1, lat1);
	    const p1 = projection.project(lng2, lat1);
	    const p2 = projection.project(lng2, lat2);
	    const p3 = projection.project(lng1, lat2);
	    let minX = Math.min(p0.x, p1.x, p2.x, p3.x);
	    let minY = Math.min(p0.y, p1.y, p2.y, p3.y);
	    let maxX = Math.max(p0.x, p1.x, p2.x, p3.x);
	    let maxY = Math.max(p0.y, p1.y, p2.y, p3.y);
	    const maxErr = s / 16;
	    function processSegment(pa, pb, ax, ay, bx, by) {
	        const mx = (ax + bx) / 2;
	        const my = (ay + by) / 2;
	        const pm = projection.project(lngFromMercatorX(mx), latFromMercatorY(my));
	        const err = Math.max(0, minX - pm.x, minY - pm.y, pm.x - maxX, pm.y - maxY);
	        minX = Math.min(minX, pm.x);
	        maxX = Math.max(maxX, pm.x);
	        minY = Math.min(minY, pm.y);
	        maxY = Math.max(maxY, pm.y);
	        if (err > maxErr) {
	            processSegment(pa, pm, ax, ay, mx, my);
	            processSegment(pm, pb, mx, my, bx, by);
	        }
	    }
	    processSegment(p0, p1, x1, y1, x2, y1);
	    processSegment(p1, p2, x2, y1, x2, y2);
	    processSegment(p2, p3, x2, y2, x1, y2);
	    processSegment(p3, p0, x1, y2, x1, y1);
	    minX -= maxErr;
	    minY -= maxErr;
	    maxX += maxErr;
	    maxY += maxErr;
	    const max = Math.max(maxX - minX, maxY - minY);
	    const scale = 1 / max;
	    return {
	        scale,
	        x: minX * scale,
	        y: minY * scale,
	        x2: maxX * scale,
	        y2: maxY * scale,
	        projection
	    };
	}
	function tileAABB(tr, numTiles, z, x, y, wrap, min, max, projection) {
	    if (projection.name === 'globe') {
	        const tileId = new CanonicalTileID(z, x, y);
	        return aabbForTileOnGlobe(tr, numTiles, tileId);
	    }
	    const tt = tileTransform({
	        z,
	        x,
	        y
	    }, projection);
	    const tx = tt.x / tt.scale;
	    const ty = tt.y / tt.scale;
	    const tx2 = tt.x2 / tt.scale;
	    const ty2 = tt.y2 / tt.scale;
	    return new Aabb([
	        (wrap + tx) * numTiles,
	        numTiles * ty,
	        min
	    ], [
	        (wrap + tx2) * numTiles,
	        numTiles * ty2,
	        max
	    ]);
	}
	function getTilePoint(tileTransform, {x, y}, wrap = 0) {
	    return new pointGeometry(((x - wrap) * tileTransform.scale - tileTransform.x) * EXTENT, (y * tileTransform.scale - tileTransform.y) * EXTENT);
	}
	function getTileVec3(tileTransform, coord, wrap = 0) {
	    const x = ((coord.x - wrap) * tileTransform.scale - tileTransform.x) * EXTENT;
	    const y = (coord.y * tileTransform.scale - tileTransform.y) * EXTENT;
	    return fromValues(x, y, altitudeFromMercatorZ(coord.z, coord.y));
	}

	const identity = identity$2(new Float32Array(16));
	class Projection {
	    constructor(options) {
	        this.spec = options;
	        this.name = options.name;
	        this.wrap = false;
	        this.requiresDraping = false;
	        this.supportsWorldCopies = false;
	        this.supportsTerrain = false;
	        this.supportsFog = false;
	        this.supportsFreeCamera = false;
	        this.zAxisUnit = 'meters';
	        this.isReprojectedInTileSpace = true;
	        this.unsupportedLayers = ['custom'];
	        this.center = [
	            0,
	            0
	        ];
	        this.range = [
	            3.5,
	            7
	        ];
	    }
	    project(lng, lat) {
	        return {
	            x: 0,
	            y: 0,
	            z: 0
	        };
	    }
	    unproject(x, y) {
	        return new LngLat(0, 0);
	    }
	    projectTilePoint(x, y, _) {
	        return {
	            x,
	            y,
	            z: 0
	        };
	    }
	    locationPoint(tr, lngLat, terrain = true) {
	        return tr._coordinatePoint(tr.locationCoordinate(lngLat), terrain);
	    }
	    pixelsPerMeter(lat, worldSize) {
	        return mercatorZfromAltitude(1, lat) * worldSize;
	    }
	    pixelSpaceConversion(lat, worldSize, interpolationT) {
	        return 1;
	    }
	    farthestPixelDistance(tr) {
	        return farthestPixelDistanceOnPlane(tr, tr.pixelsPerMeter);
	    }
	    pointCoordinate(tr, x, y, z) {
	        const horizonOffset = tr.horizonLineFromTop(false);
	        const clamped = new pointGeometry(x, Math.max(horizonOffset, y));
	        return tr.rayIntersectionCoordinate(tr.pointRayIntersection(clamped, z));
	    }
	    pointCoordinate3D(tr, x, y) {
	        const p = new pointGeometry(x, y);
	        if (tr.elevation) {
	            return tr.elevation.pointCoordinate(p);
	        } else {
	            const mc = this.pointCoordinate(tr, p.x, p.y, 0);
	            return [
	                mc.x,
	                mc.y,
	                mc.z
	            ];
	        }
	    }
	    isPointAboveHorizon(tr, p) {
	        if (tr.elevation) {
	            const raycastOnTerrain = this.pointCoordinate3D(tr, p.x, p.y);
	            return !raycastOnTerrain;
	        }
	        const horizon = tr.horizonLineFromTop();
	        return p.y < horizon;
	    }
	    createInversionMatrix(tr, id) {
	        return identity;
	    }
	    createTileMatrix(tr, worldSize, id) {
	        let scale, scaledX, scaledY;
	        const canonical = id.canonical;
	        const posMatrix = identity$2(new Float64Array(16));
	        if (this.isReprojectedInTileSpace) {
	            const cs = tileTransform(canonical, this);
	            scale = 1;
	            scaledX = cs.x + id.wrap * cs.scale;
	            scaledY = cs.y;
	            scale$2(posMatrix, posMatrix, [
	                scale / cs.scale,
	                scale / cs.scale,
	                tr.pixelsPerMeter / worldSize
	            ]);
	        } else {
	            scale = worldSize / tr.zoomScale(canonical.z);
	            const unwrappedX = canonical.x + Math.pow(2, canonical.z) * id.wrap;
	            scaledX = unwrappedX * scale;
	            scaledY = canonical.y * scale;
	        }
	        translate(posMatrix, posMatrix, [
	            scaledX,
	            scaledY,
	            0
	        ]);
	        scale$2(posMatrix, posMatrix, [
	            scale / EXTENT,
	            scale / EXTENT,
	            1
	        ]);
	        return posMatrix;
	    }
	    upVector(id, x, y) {
	        return [
	            0,
	            0,
	            1
	        ];
	    }
	    upVectorScale(id, latitude, worldSize) {
	        return { metersToTile: 1 };
	    }
	}

	class Albers extends Projection {
	    constructor(options) {
	        super(options);
	        this.range = [
	            4,
	            7
	        ];
	        this.center = options.center || [
	            -96,
	            37.5
	        ];
	        const [lat0, lat1] = this.parallels = options.parallels || [
	            29.5,
	            45.5
	        ];
	        const sy0 = Math.sin(degToRad(lat0));
	        this.n = (sy0 + Math.sin(degToRad(lat1))) / 2;
	        this.c = 1 + sy0 * (2 * this.n - sy0);
	        this.r0 = Math.sqrt(this.c) / this.n;
	    }
	    project(lng, lat) {
	        const {n, c, r0} = this;
	        const lambda = degToRad(lng - this.center[0]);
	        const phi = degToRad(lat);
	        const r = Math.sqrt(c - 2 * n * Math.sin(phi)) / n;
	        const x = r * Math.sin(lambda * n);
	        const y = r * Math.cos(lambda * n) - r0;
	        return {
	            x,
	            y,
	            z: 0
	        };
	    }
	    unproject(x, y) {
	        const {n, c, r0} = this;
	        const r0y = r0 + y;
	        let l = Math.atan2(x, Math.abs(r0y)) * Math.sign(r0y);
	        if (r0y * n < 0) {
	            l -= Math.PI * Math.sign(x) * Math.sign(r0y);
	        }
	        const dt = degToRad(this.center[0]) * n;
	        l = wrap(l, -Math.PI - dt, Math.PI - dt);
	        const lng = radToDeg(l / n) + this.center[0];
	        const phi = Math.asin(clamp((c - (x * x + r0y * r0y) * n * n) / (2 * n), -1, 1));
	        const lat = clamp(radToDeg(phi), -MAX_MERCATOR_LATITUDE, MAX_MERCATOR_LATITUDE);
	        return new LngLat(lng, lat);
	    }
	}

	const a1 = 1.340264;
	const a2 = -0.081106;
	const a3 = 0.000893;
	const a4 = 0.003796;
	const M = Math.sqrt(3) / 2;
	class EqualEarth extends Projection {
	    project(lng, lat) {
	        lat = lat / 180 * Math.PI;
	        lng = lng / 180 * Math.PI;
	        const theta = Math.asin(M * Math.sin(lat));
	        const theta2 = theta * theta;
	        const theta6 = theta2 * theta2 * theta2;
	        const x = lng * Math.cos(theta) / (M * (a1 + 3 * a2 * theta2 + theta6 * (7 * a3 + 9 * a4 * theta2)));
	        const y = theta * (a1 + a2 * theta2 + theta6 * (a3 + a4 * theta2));
	        return {
	            x: (x / Math.PI + 0.5) * 0.5,
	            y: 1 - (y / Math.PI + 1) * 0.5,
	            z: 0
	        };
	    }
	    unproject(x, y) {
	        x = (2 * x - 0.5) * Math.PI;
	        y = (2 * (1 - y) - 1) * Math.PI;
	        let theta = y;
	        let theta2 = theta * theta;
	        let theta6 = theta2 * theta2 * theta2;
	        for (let i = 0, delta, fy, fpy; i < 12; ++i) {
	            fy = theta * (a1 + a2 * theta2 + theta6 * (a3 + a4 * theta2)) - y;
	            fpy = a1 + 3 * a2 * theta2 + theta6 * (7 * a3 + 9 * a4 * theta2);
	            delta = fy / fpy;
	            theta = clamp(theta - delta, -Math.PI / 3, Math.PI / 3);
	            theta2 = theta * theta;
	            theta6 = theta2 * theta2 * theta2;
	            if (Math.abs(delta) < 1e-12)
	                break;
	        }
	        const lambda = M * x * (a1 + 3 * a2 * theta2 + theta6 * (7 * a3 + 9 * a4 * theta2)) / Math.cos(theta);
	        const phi = Math.asin(Math.sin(theta) / M);
	        const lng = clamp(lambda * 180 / Math.PI, -180, 180);
	        const lat = clamp(phi * 180 / Math.PI, -MAX_MERCATOR_LATITUDE, MAX_MERCATOR_LATITUDE);
	        return new LngLat(lng, lat);
	    }
	}

	class Equirectangular extends Projection {
	    constructor(options) {
	        super(options);
	        this.wrap = true;
	        this.supportsWorldCopies = true;
	    }
	    project(lng, lat) {
	        const x = 0.5 + lng / 360;
	        const y = 0.5 - lat / 360;
	        return {
	            x,
	            y,
	            z: 0
	        };
	    }
	    unproject(x, y) {
	        const lng = (x - 0.5) * 360;
	        const lat = clamp((0.5 - y) * 360, -MAX_MERCATOR_LATITUDE, MAX_MERCATOR_LATITUDE);
	        return new LngLat(lng, lat);
	    }
	}

	const halfPi = Math.PI / 2;
	function tany(y) {
	    return Math.tan((halfPi + y) / 2);
	}
	class LambertConformalConic extends Projection {
	    constructor(options) {
	        super(options);
	        this.center = options.center || [
	            0,
	            30
	        ];
	        const [lat0, lat1] = this.parallels = options.parallels || [
	            30,
	            30
	        ];
	        const y0 = degToRad(lat0);
	        const y1 = degToRad(lat1);
	        const cy0 = Math.cos(y0);
	        this.n = y0 === y1 ? Math.sin(y0) : Math.log(cy0 / Math.cos(y1)) / Math.log(tany(y1) / tany(y0));
	        this.f = cy0 * Math.pow(tany(y0), this.n) / this.n;
	    }
	    project(lng, lat) {
	        lat = degToRad(lat);
	        lng = degToRad(lng - this.center[0]);
	        const epsilon = 0.000001;
	        const {n, f} = this;
	        if (f > 0) {
	            if (lat < -halfPi + epsilon)
	                lat = -halfPi + epsilon;
	        } else {
	            if (lat > halfPi - epsilon)
	                lat = halfPi - epsilon;
	        }
	        const r = f / Math.pow(tany(lat), n);
	        const x = r * Math.sin(n * lng);
	        const y = f - r * Math.cos(n * lng);
	        return {
	            x: (x / Math.PI + 0.5) * 0.5,
	            y: 1 - (y / Math.PI + 0.5) * 0.5,
	            z: 0
	        };
	    }
	    unproject(x, y) {
	        x = (2 * x - 0.5) * Math.PI;
	        y = (2 * (1 - y) - 0.5) * Math.PI;
	        const {n, f} = this;
	        const fy = f - y;
	        const signFy = Math.sign(fy);
	        const r = Math.sign(n) * Math.sqrt(x * x + fy * fy);
	        let l = Math.atan2(x, Math.abs(fy)) * signFy;
	        if (fy * n < 0)
	            l -= Math.PI * Math.sign(x) * signFy;
	        const lng = clamp(radToDeg(l / n) + this.center[0], -180, 180);
	        const phi = 2 * Math.atan(Math.pow(f / r, 1 / n)) - halfPi;
	        const lat = clamp(radToDeg(phi), -MAX_MERCATOR_LATITUDE, MAX_MERCATOR_LATITUDE);
	        return new LngLat(lng, lat);
	    }
	}

	class Mercator extends Projection {
	    constructor(options) {
	        super(options);
	        this.wrap = true;
	        this.supportsWorldCopies = true;
	        this.supportsTerrain = true;
	        this.supportsFog = true;
	        this.supportsFreeCamera = true;
	        this.isReprojectedInTileSpace = false;
	        this.unsupportedLayers = [];
	        this.range = null;
	    }
	    project(lng, lat) {
	        const x = mercatorXfromLng(lng);
	        const y = mercatorYfromLat(lat);
	        return {
	            x,
	            y,
	            z: 0
	        };
	    }
	    unproject(x, y) {
	        const lng = lngFromMercatorX(x);
	        const lat = latFromMercatorY(y);
	        return new LngLat(lng, lat);
	    }
	}

	const maxPhi$1 = degToRad(MAX_MERCATOR_LATITUDE);
	class NaturalEarth extends Projection {
	    project(lng, lat) {
	        lat = degToRad(lat);
	        lng = degToRad(lng);
	        const phi2 = lat * lat;
	        const phi4 = phi2 * phi2;
	        const x = lng * (0.8707 - 0.131979 * phi2 + phi4 * (-0.013791 + phi4 * (0.003971 * phi2 - 0.001529 * phi4)));
	        const y = lat * (1.007226 + phi2 * (0.015085 + phi4 * (-0.044475 + 0.028874 * phi2 - 0.005916 * phi4)));
	        return {
	            x: (x / Math.PI + 0.5) * 0.5,
	            y: 1 - (y / Math.PI + 1) * 0.5,
	            z: 0
	        };
	    }
	    unproject(x, y) {
	        x = (2 * x - 0.5) * Math.PI;
	        y = (2 * (1 - y) - 1) * Math.PI;
	        const epsilon = 0.000001;
	        let phi = y;
	        let i = 25;
	        let delta = 0;
	        let phi2 = phi * phi;
	        do {
	            phi2 = phi * phi;
	            const phi4 = phi2 * phi2;
	            delta = (phi * (1.007226 + phi2 * (0.015085 + phi4 * (-0.044475 + 0.028874 * phi2 - 0.005916 * phi4))) - y) / (1.007226 + phi2 * (0.015085 * 3 + phi4 * (-0.044475 * 7 + 0.028874 * 9 * phi2 - 0.005916 * 11 * phi4)));
	            phi = clamp(phi - delta, -maxPhi$1, maxPhi$1);
	        } while (Math.abs(delta) > epsilon && --i > 0);
	        phi2 = phi * phi;
	        const lambda = x / (0.8707 + phi2 * (-0.131979 + phi2 * (-0.013791 + phi2 * phi2 * phi2 * (0.003971 - 0.001529 * phi2))));
	        const lng = clamp(radToDeg(lambda), -180, 180);
	        const lat = radToDeg(phi);
	        return new LngLat(lng, lat);
	    }
	}

	const maxPhi = degToRad(MAX_MERCATOR_LATITUDE);
	class WinkelTripel extends Projection {
	    project(lng, lat) {
	        lat = degToRad(lat);
	        lng = degToRad(lng);
	        const cosLat = Math.cos(lat);
	        const twoOverPi = 2 / Math.PI;
	        const alpha = Math.acos(cosLat * Math.cos(lng / 2));
	        const sinAlphaOverAlpha = Math.sin(alpha) / alpha;
	        const x = 0.5 * (lng * twoOverPi + 2 * cosLat * Math.sin(lng / 2) / sinAlphaOverAlpha) || 0;
	        const y = 0.5 * (lat + Math.sin(lat) / sinAlphaOverAlpha) || 0;
	        return {
	            x: (x / Math.PI + 0.5) * 0.5,
	            y: 1 - (y / Math.PI + 1) * 0.5,
	            z: 0
	        };
	    }
	    unproject(x, y) {
	        x = (2 * x - 0.5) * Math.PI;
	        y = (2 * (1 - y) - 1) * Math.PI;
	        let lambda = x;
	        let phi = y;
	        let i = 25;
	        const epsilon = 0.000001;
	        let dlambda = 0, dphi = 0;
	        do {
	            const cosphi = Math.cos(phi), sinphi = Math.sin(phi), sinphi2 = 2 * sinphi * cosphi, sin2phi = sinphi * sinphi, cos2phi = cosphi * cosphi, coslambda2 = Math.cos(lambda / 2), sinlambda2 = Math.sin(lambda / 2), sinlambda = 2 * coslambda2 * sinlambda2, sin2lambda2 = sinlambda2 * sinlambda2, C = 1 - cos2phi * coslambda2 * coslambda2, F = C ? 1 / C : 0, E = C ? Math.acos(cosphi * coslambda2) * Math.sqrt(1 / C) : 0, fx = 0.5 * (2 * E * cosphi * sinlambda2 + lambda * 2 / Math.PI) - x, fy = 0.5 * (E * sinphi + phi) - y, dxdlambda = 0.5 * F * (cos2phi * sin2lambda2 + E * cosphi * coslambda2 * sin2phi) + 1 / Math.PI, dxdphi = F * (sinlambda * sinphi2 / 4 - E * sinphi * sinlambda2), dydlambda = 0.125 * F * (sinphi2 * sinlambda2 - E * sinphi * cos2phi * sinlambda), dydphi = 0.5 * F * (sin2phi * coslambda2 + E * sin2lambda2 * cosphi) + 0.5, denominator = dxdphi * dydlambda - dydphi * dxdlambda;
	            dlambda = (fy * dxdphi - fx * dydphi) / denominator;
	            dphi = (fx * dydlambda - fy * dxdlambda) / denominator;
	            lambda = clamp(lambda - dlambda, -Math.PI, Math.PI);
	            phi = clamp(phi - dphi, -maxPhi, maxPhi);
	        } while ((Math.abs(dlambda) > epsilon || Math.abs(dphi) > epsilon) && --i > 0);
	        return new LngLat(radToDeg(lambda), radToDeg(phi));
	    }
	}

	class CylindricalEqualArea extends Projection {
	    constructor(options) {
	        super(options);
	        this.center = options.center || [
	            0,
	            0
	        ];
	        this.parallels = options.parallels || [
	            0,
	            0
	        ];
	        this.cosPhi = Math.max(0.01, Math.cos(degToRad(this.parallels[0])));
	        this.scale = 1 / (2 * Math.max(Math.PI * this.cosPhi, 1 / this.cosPhi));
	        this.wrap = true;
	        this.supportsWorldCopies = true;
	    }
	    project(lng, lat) {
	        const {scale, cosPhi} = this;
	        const x = degToRad(lng) * cosPhi;
	        const y = Math.sin(degToRad(lat)) / cosPhi;
	        return {
	            x: x * scale + 0.5,
	            y: -y * scale + 0.5,
	            z: 0
	        };
	    }
	    unproject(x, y) {
	        const {scale, cosPhi} = this;
	        const x_ = (x - 0.5) / scale;
	        const y_ = -(y - 0.5) / scale;
	        const lng = clamp(radToDeg(x_) / cosPhi, -180, 180);
	        const y2 = y_ * cosPhi;
	        const y3 = Math.asin(clamp(y2, -1, 1));
	        const lat = clamp(radToDeg(y3), -MAX_MERCATOR_LATITUDE, MAX_MERCATOR_LATITUDE);
	        return new LngLat(lng, lat);
	    }
	}

	class Globe extends Mercator {
	    constructor(options) {
	        super(options);
	        this.requiresDraping = true;
	        this.supportsWorldCopies = false;
	        this.supportsFog = true;
	        this.zAxisUnit = 'pixels';
	        this.unsupportedLayers = [
	            'debug',
	            'custom'
	        ];
	        this.range = [
	            3,
	            5
	        ];
	    }
	    projectTilePoint(x, y, id) {
	        const tiles = Math.pow(2, id.z);
	        const mx = (x / EXTENT + id.x) / tiles;
	        const my = (y / EXTENT + id.y) / tiles;
	        const lat = latFromMercatorY(my);
	        const lng = lngFromMercatorX(mx);
	        const pos = latLngToECEF(lat, lng);
	        const bounds = globeTileBounds(id);
	        const normalizationMatrix = globeNormalizeECEF(bounds);
	        transformMat4$1(pos, pos, normalizationMatrix);
	        return {
	            x: pos[0],
	            y: pos[1],
	            z: pos[2]
	        };
	    }
	    locationPoint(tr, lngLat) {
	        const pos = latLngToECEF(lngLat.lat, lngLat.lng);
	        const up = normalize$2([], pos);
	        const elevation = tr.elevation ? tr.elevation.getAtPointOrZero(tr.locationCoordinate(lngLat), tr._centerAltitude) : tr._centerAltitude;
	        const upScale = mercatorZfromAltitude(1, 0) * EXTENT * elevation;
	        scaleAndAdd(pos, pos, up, upScale);
	        const matrix = identity$2(new Float64Array(16));
	        multiply$2(matrix, tr.pixelMatrix, tr.globeMatrix);
	        transformMat4$1(pos, pos, matrix);
	        return new pointGeometry(pos[0], pos[1]);
	    }
	    pixelsPerMeter(lat, worldSize) {
	        return mercatorZfromAltitude(1, 0) * worldSize;
	    }
	    pixelSpaceConversion(lat, worldSize, interpolationT) {
	        const referenceScale = mercatorZfromAltitude(1, GLOBE_SCALE_MATCH_LATITUDE) * worldSize;
	        const centerScale = mercatorZfromAltitude(1, lat) * worldSize;
	        const combinedScale = number(referenceScale, centerScale, interpolationT);
	        return this.pixelsPerMeter(lat, worldSize) / combinedScale;
	    }
	    createTileMatrix(tr, worldSize, id) {
	        const decode = globeDenormalizeECEF(globeTileBounds(id.canonical));
	        return multiply$2(new Float64Array(16), tr.globeMatrix, decode);
	    }
	    createInversionMatrix(tr, id) {
	        const {center} = tr;
	        const matrix = identity$2(new Float64Array(16));
	        const encode = globeNormalizeECEF(globeTileBounds(id));
	        multiply$2(matrix, matrix, encode);
	        rotateY$1(matrix, matrix, degToRad(center.lng));
	        rotateX$1(matrix, matrix, degToRad(center.lat));
	        scale$2(matrix, matrix, [
	            tr._projectionScaler,
	            tr._projectionScaler,
	            1
	        ]);
	        return Float32Array.from(matrix);
	    }
	    pointCoordinate(tr, x, y, _) {
	        const coord = globePointCoordinate(tr, x, y, true);
	        if (!coord) {
	            return new MercatorCoordinate(0, 0);
	        }
	        return coord;
	    }
	    pointCoordinate3D(tr, x, y) {
	        const coord = this.pointCoordinate(tr, x, y, 0);
	        return [
	            coord.x,
	            coord.y,
	            coord.z
	        ];
	    }
	    isPointAboveHorizon(tr, p) {
	        const raycastOnGlobe = globePointCoordinate(tr, p.x, p.y, false);
	        return !raycastOnGlobe;
	    }
	    farthestPixelDistance(tr) {
	        const pixelsPerMeter = this.pixelsPerMeter(tr.center.lat, tr.worldSize);
	        const globePixelDistance = farthestPixelDistanceOnSphere(tr, pixelsPerMeter);
	        const t = globeToMercatorTransition(tr.zoom);
	        if (t > 0) {
	            const mercatorPixelsPerMeter = mercatorZfromAltitude(1, tr.center.lat) * tr.worldSize;
	            const mercatorPixelDistance = farthestPixelDistanceOnPlane(tr, mercatorPixelsPerMeter);
	            const pixelRadius = tr.worldSize / (2 * Math.PI);
	            const approxTileArcHalfAngle = Math.max(tr.width, tr.height) / tr.worldSize * Math.PI;
	            const padding = pixelRadius * (1 - Math.cos(approxTileArcHalfAngle));
	            return number(globePixelDistance, mercatorPixelDistance + padding, Math.pow(t, 10));
	        }
	        return globePixelDistance;
	    }
	    upVector(id, x, y) {
	        const tiles = 1 << id.z;
	        const mercX = (x / EXTENT + id.x) / tiles;
	        const mercY = (y / EXTENT + id.y) / tiles;
	        return latLngToECEF(latFromMercatorY(mercY), lngFromMercatorX(mercX), 1);
	    }
	    upVectorScale(id) {
	        return { metersToTile: GLOBE_METERS_TO_ECEF * globeECEFNormalizationScale(globeTileBounds(id)) };
	    }
	}

	function getProjection(config) {
	    const parallels = config.parallels;
	    const isDegenerateConic = parallels ? Math.abs(parallels[0] + parallels[1]) < 0.01 : false;
	    switch (config.name) {
	    case 'mercator':
	        return new Mercator(config);
	    case 'equirectangular':
	        return new Equirectangular(config);
	    case 'naturalEarth':
	        return new NaturalEarth(config);
	    case 'equalEarth':
	        return new EqualEarth(config);
	    case 'winkelTripel':
	        return new WinkelTripel(config);
	    case 'albers':
	        return isDegenerateConic ? new CylindricalEqualArea(config) : new Albers(config);
	    case 'lambertConformalConic':
	        return isDegenerateConic ? new CylindricalEqualArea(config) : new LambertConformalConic(config);
	    case 'globe':
	        return new Globe(config);
	    }
	    throw new Error(`Invalid projection name: ${ config.name }`);
	}

	const vectorTileFeatureTypes = vectorTile.VectorTileFeature.types;
	const shaderOpacityAttributes = [{
	        name: 'a_fade_opacity',
	        components: 1,
	        type: 'Uint8',
	        offset: 0
	    }];
	function addVertex(array, tileAnchorX, tileAnchorY, ox, oy, tx, ty, sizeVertex, isSDF, pixelOffsetX, pixelOffsetY, minFontScaleX, minFontScaleY) {
	    const aSizeX = sizeVertex ? Math.min(MAX_PACKED_SIZE, Math.round(sizeVertex[0])) : 0;
	    const aSizeY = sizeVertex ? Math.min(MAX_PACKED_SIZE, Math.round(sizeVertex[1])) : 0;
	    array.emplaceBack(tileAnchorX, tileAnchorY, Math.round(ox * 32), Math.round(oy * 32), tx, ty, (aSizeX << 1) + (isSDF ? 1 : 0), aSizeY, pixelOffsetX * 16, pixelOffsetY * 16, minFontScaleX * 256, minFontScaleY * 256);
	}
	function addGlobeVertex(array, projAnchorX, projAnchorY, projAnchorZ, normX, normY, normZ) {
	    array.emplaceBack(projAnchorX, projAnchorY, projAnchorZ, normX, normY, normZ);
	}
	function updateGlobeVertexNormal(array, vertexIdx, normX, normY, normZ) {
	    const offset = vertexIdx * 5 + 2;
	    array.float32[offset + 0] = normX;
	    array.float32[offset + 1] = normY;
	    array.float32[offset + 2] = normZ;
	}
	function addDynamicAttributes(dynamicLayoutVertexArray, x, y, z, angle) {
	    dynamicLayoutVertexArray.emplaceBack(x, y, z, angle);
	    dynamicLayoutVertexArray.emplaceBack(x, y, z, angle);
	    dynamicLayoutVertexArray.emplaceBack(x, y, z, angle);
	    dynamicLayoutVertexArray.emplaceBack(x, y, z, angle);
	}
	function containsRTLText(formattedText) {
	    for (const section of formattedText.sections) {
	        if (stringContainsRTLText(section.text)) {
	            return true;
	        }
	    }
	    return false;
	}
	class SymbolBuffers {
	    constructor(programConfigurations) {
	        this.layoutVertexArray = new StructArrayLayout4i4ui4i24();
	        this.indexArray = new StructArrayLayout3ui6();
	        this.programConfigurations = programConfigurations;
	        this.segments = new SegmentVector();
	        this.dynamicLayoutVertexArray = new StructArrayLayout4f16();
	        this.opacityVertexArray = new StructArrayLayout1ul4();
	        this.placedSymbolArray = new PlacedSymbolArray();
	        this.globeExtVertexArray = new StructArrayLayout3i3f20();
	    }
	    isEmpty() {
	        return this.layoutVertexArray.length === 0 && this.indexArray.length === 0 && this.dynamicLayoutVertexArray.length === 0 && this.opacityVertexArray.length === 0;
	    }
	    upload(context, dynamicIndexBuffer, upload, update) {
	        if (this.isEmpty()) {
	            return;
	        }
	        if (upload) {
	            this.layoutVertexBuffer = context.createVertexBuffer(this.layoutVertexArray, symbolLayoutAttributes.members);
	            this.indexBuffer = context.createIndexBuffer(this.indexArray, dynamicIndexBuffer);
	            this.dynamicLayoutVertexBuffer = context.createVertexBuffer(this.dynamicLayoutVertexArray, dynamicLayoutAttributes.members, true);
	            this.opacityVertexBuffer = context.createVertexBuffer(this.opacityVertexArray, shaderOpacityAttributes, true);
	            if (this.globeExtVertexArray.length > 0) {
	                this.globeExtVertexBuffer = context.createVertexBuffer(this.globeExtVertexArray, symbolGlobeExtAttributes.members, true);
	            }
	            this.opacityVertexBuffer.itemSize = 1;
	        }
	        if (upload || update) {
	            this.programConfigurations.upload(context);
	        }
	    }
	    destroy() {
	        if (!this.layoutVertexBuffer)
	            return;
	        this.layoutVertexBuffer.destroy();
	        this.indexBuffer.destroy();
	        this.programConfigurations.destroy();
	        this.segments.destroy();
	        this.dynamicLayoutVertexBuffer.destroy();
	        this.opacityVertexBuffer.destroy();
	        if (this.globeExtVertexBuffer) {
	            this.globeExtVertexBuffer.destroy();
	        }
	    }
	}
	register(SymbolBuffers, 'SymbolBuffers');
	class CollisionBuffers {
	    constructor(LayoutArray, layoutAttributes, IndexArray) {
	        this.layoutVertexArray = new LayoutArray();
	        this.layoutAttributes = layoutAttributes;
	        this.indexArray = new IndexArray();
	        this.segments = new SegmentVector();
	        this.collisionVertexArray = new StructArrayLayout2ub2f12();
	        this.collisionVertexArrayExt = new StructArrayLayout3f12();
	    }
	    upload(context) {
	        this.layoutVertexBuffer = context.createVertexBuffer(this.layoutVertexArray, this.layoutAttributes);
	        this.indexBuffer = context.createIndexBuffer(this.indexArray);
	        this.collisionVertexBuffer = context.createVertexBuffer(this.collisionVertexArray, collisionVertexAttributes.members, true);
	        this.collisionVertexBufferExt = context.createVertexBuffer(this.collisionVertexArrayExt, collisionVertexAttributesExt.members, true);
	    }
	    destroy() {
	        if (!this.layoutVertexBuffer)
	            return;
	        this.layoutVertexBuffer.destroy();
	        this.indexBuffer.destroy();
	        this.segments.destroy();
	        this.collisionVertexBuffer.destroy();
	        this.collisionVertexBufferExt.destroy();
	    }
	}
	register(CollisionBuffers, 'CollisionBuffers');
	class SymbolBucket {
	    constructor(options) {
	        this.collisionBoxArray = options.collisionBoxArray;
	        this.zoom = options.zoom;
	        this.overscaling = options.overscaling;
	        this.layers = options.layers;
	        this.layerIds = this.layers.map(layer => layer.id);
	        this.index = options.index;
	        this.pixelRatio = options.pixelRatio;
	        this.sourceLayerIndex = options.sourceLayerIndex;
	        this.hasPattern = false;
	        this.hasRTLText = false;
	        this.fullyClipped = false;
	        this.sortKeyRanges = [];
	        this.collisionCircleArray = [];
	        this.placementInvProjMatrix = identity$2([]);
	        this.placementViewportMatrix = identity$2([]);
	        const layer = this.layers[0];
	        const unevaluatedLayoutValues = layer._unevaluatedLayout._values;
	        this.textSizeData = getSizeData(this.zoom, unevaluatedLayoutValues['text-size']);
	        this.iconSizeData = getSizeData(this.zoom, unevaluatedLayoutValues['icon-size']);
	        const layout = this.layers[0].layout;
	        const sortKey = layout.get('symbol-sort-key');
	        const zOrder = layout.get('symbol-z-order');
	        this.canOverlap = layout.get('text-allow-overlap') || layout.get('icon-allow-overlap') || layout.get('text-ignore-placement') || layout.get('icon-ignore-placement');
	        this.sortFeaturesByKey = zOrder !== 'viewport-y' && sortKey.constantOr(1) !== undefined;
	        const zOrderByViewportY = zOrder === 'viewport-y' || zOrder === 'auto' && !this.sortFeaturesByKey;
	        this.sortFeaturesByY = zOrderByViewportY && this.canOverlap;
	        this.writingModes = layout.get('text-writing-mode').map(wm => WritingMode[wm]);
	        this.stateDependentLayerIds = this.layers.filter(l => l.isStateDependent()).map(l => l.id);
	        this.sourceID = options.sourceID;
	        this.projection = options.projection;
	    }
	    createArrays() {
	        this.text = new SymbolBuffers(new ProgramConfigurationSet(this.layers, this.zoom, property => /^text/.test(property)));
	        this.icon = new SymbolBuffers(new ProgramConfigurationSet(this.layers, this.zoom, property => /^icon/.test(property)));
	        this.glyphOffsetArray = new GlyphOffsetArray();
	        this.lineVertexArray = new SymbolLineVertexArray();
	        this.symbolInstances = new SymbolInstanceArray();
	    }
	    calculateGlyphDependencies(text, stack, textAlongLine, allowVerticalPlacement, doesAllowVerticalWritingMode) {
	        for (let i = 0; i < text.length; i++) {
	            stack[text.charCodeAt(i)] = true;
	            if (allowVerticalPlacement && doesAllowVerticalWritingMode) {
	                const verticalChar = verticalizedCharacterMap[text.charAt(i)];
	                if (verticalChar) {
	                    stack[verticalChar.charCodeAt(0)] = true;
	                }
	            }
	        }
	    }
	    populate(features, options, canonical, tileTransform) {
	        const layer = this.layers[0];
	        const layout = layer.layout;
	        const isGlobe = this.projection.name === 'globe';
	        const textFont = layout.get('text-font');
	        const textField = layout.get('text-field');
	        const iconImage = layout.get('icon-image');
	        const hasText = (textField.value.kind !== 'constant' || textField.value.value instanceof Formatted && !textField.value.value.isEmpty() || textField.value.value.toString().length > 0) && (textFont.value.kind !== 'constant' || textFont.value.value.length > 0);
	        const hasIcon = iconImage.value.kind !== 'constant' || !!iconImage.value.value || Object.keys(iconImage.parameters).length > 0;
	        const symbolSortKey = layout.get('symbol-sort-key');
	        this.features = [];
	        if (!hasText && !hasIcon) {
	            return;
	        }
	        const icons = options.iconDependencies;
	        const stacks = options.glyphDependencies;
	        const availableImages = options.availableImages;
	        const globalProperties = new EvaluationParameters(this.zoom);
	        for (const {feature, id, index, sourceLayerIndex} of features) {
	            const needGeometry = layer._featureFilter.needGeometry;
	            const evaluationFeature = toEvaluationFeature(feature, needGeometry);
	            if (!layer._featureFilter.filter(globalProperties, evaluationFeature, canonical)) {
	                continue;
	            }
	            if (!needGeometry)
	                evaluationFeature.geometry = loadGeometry(feature, canonical, tileTransform);
	            if (isGlobe && feature.type !== 1 && canonical.z <= 5) {
	                const geom = evaluationFeature.geometry;
	                const tiles = 1 << canonical.z;
	                const mx = canonical.x;
	                const my = canonical.y;
	                const cosAngleThreshold = 0.98078528056;
	                for (let i = 0; i < geom.length; i++) {
	                    geom[i] = resamplePred(geom[i], p => p, (a, b) => {
	                        const v0 = latLngToECEF(latFromMercatorY((a.y / EXTENT + my) / tiles), lngFromMercatorX((a.x / EXTENT + mx) / tiles), 1);
	                        const v1 = latLngToECEF(latFromMercatorY((b.y / EXTENT + my) / tiles), lngFromMercatorX((b.x / EXTENT + mx) / tiles), 1);
	                        return dot$1(v0, v1) < cosAngleThreshold;
	                    });
	                }
	            }
	            let text;
	            if (hasText) {
	                const resolvedTokens = layer.getValueAndResolveTokens('text-field', evaluationFeature, canonical, availableImages);
	                const formattedText = Formatted.factory(resolvedTokens);
	                if (containsRTLText(formattedText)) {
	                    this.hasRTLText = true;
	                }
	                if (!this.hasRTLText || getRTLTextPluginStatus() === 'unavailable' || this.hasRTLText && plugin.isParsed()) {
	                    text = transformText$1(formattedText, layer, evaluationFeature);
	                }
	            }
	            let icon;
	            if (hasIcon) {
	                const resolvedTokens = layer.getValueAndResolveTokens('icon-image', evaluationFeature, canonical, availableImages);
	                if (resolvedTokens instanceof ResolvedImage) {
	                    icon = resolvedTokens;
	                } else {
	                    icon = ResolvedImage.fromString(resolvedTokens);
	                }
	            }
	            if (!text && !icon) {
	                continue;
	            }
	            const sortKey = this.sortFeaturesByKey ? symbolSortKey.evaluate(evaluationFeature, {}, canonical) : undefined;
	            const symbolFeature = {
	                id,
	                text,
	                icon,
	                index,
	                sourceLayerIndex,
	                geometry: evaluationFeature.geometry,
	                properties: feature.properties,
	                type: vectorTileFeatureTypes[feature.type],
	                sortKey
	            };
	            this.features.push(symbolFeature);
	            if (icon) {
	                icons[icon.name] = true;
	            }
	            if (text) {
	                const fontStack = textFont.evaluate(evaluationFeature, {}, canonical).join(',');
	                const textAlongLine = layout.get('text-rotation-alignment') === 'map' && layout.get('symbol-placement') !== 'point';
	                this.allowVerticalPlacement = this.writingModes && this.writingModes.indexOf(WritingMode.vertical) >= 0;
	                for (const section of text.sections) {
	                    if (!section.image) {
	                        const doesAllowVerticalWritingMode = allowsVerticalWritingMode(text.toString());
	                        const sectionFont = section.fontStack || fontStack;
	                        const sectionStack = stacks[sectionFont] = stacks[sectionFont] || {};
	                        this.calculateGlyphDependencies(section.text, sectionStack, textAlongLine, this.allowVerticalPlacement, doesAllowVerticalWritingMode);
	                    } else {
	                        icons[section.image.name] = true;
	                    }
	                }
	            }
	        }
	        if (layout.get('symbol-placement') === 'line') {
	            this.features = mergeLines(this.features);
	        }
	        if (this.sortFeaturesByKey) {
	            this.features.sort((a, b) => {
	                return a.sortKey - b.sortKey;
	            });
	        }
	    }
	    update(states, vtLayer, availableImages, imagePositions) {
	        if (!this.stateDependentLayers.length)
	            return;
	        this.text.programConfigurations.updatePaintArrays(states, vtLayer, this.layers, availableImages, imagePositions);
	        this.icon.programConfigurations.updatePaintArrays(states, vtLayer, this.layers, availableImages, imagePositions);
	    }
	    isEmpty() {
	        return this.symbolInstances.length === 0 && !this.hasRTLText;
	    }
	    uploadPending() {
	        return !this.uploaded || this.text.programConfigurations.needsUpload || this.icon.programConfigurations.needsUpload;
	    }
	    upload(context) {
	        if (!this.uploaded && this.hasDebugData()) {
	            this.textCollisionBox.upload(context);
	            this.iconCollisionBox.upload(context);
	        }
	        this.text.upload(context, this.sortFeaturesByY, !this.uploaded, this.text.programConfigurations.needsUpload);
	        this.icon.upload(context, this.sortFeaturesByY, !this.uploaded, this.icon.programConfigurations.needsUpload);
	        this.uploaded = true;
	    }
	    destroyDebugData() {
	        this.textCollisionBox.destroy();
	        this.iconCollisionBox.destroy();
	    }
	    getProjection() {
	        if (!this.projectionInstance) {
	            this.projectionInstance = getProjection(this.projection);
	        }
	        return this.projectionInstance;
	    }
	    destroy() {
	        this.text.destroy();
	        this.icon.destroy();
	        if (this.hasDebugData()) {
	            this.destroyDebugData();
	        }
	    }
	    addToLineVertexArray(anchor, line) {
	        const lineStartIndex = this.lineVertexArray.length;
	        const segment = anchor.segment;
	        if (segment !== undefined) {
	            let sumForwardLength = anchor.dist(line[segment + 1]);
	            let sumBackwardLength = anchor.dist(line[segment]);
	            const vertices = {};
	            for (let i = segment + 1; i < line.length; i++) {
	                vertices[i] = {
	                    x: line[i].x,
	                    y: line[i].y,
	                    tileUnitDistanceFromAnchor: sumForwardLength
	                };
	                if (i < line.length - 1) {
	                    sumForwardLength += line[i + 1].dist(line[i]);
	                }
	            }
	            for (let i = segment || 0; i >= 0; i--) {
	                vertices[i] = {
	                    x: line[i].x,
	                    y: line[i].y,
	                    tileUnitDistanceFromAnchor: sumBackwardLength
	                };
	                if (i > 0) {
	                    sumBackwardLength += line[i - 1].dist(line[i]);
	                }
	            }
	            for (let i = 0; i < line.length; i++) {
	                const vertex = vertices[i];
	                this.lineVertexArray.emplaceBack(vertex.x, vertex.y, vertex.tileUnitDistanceFromAnchor);
	            }
	        }
	        return {
	            lineStartIndex,
	            lineLength: this.lineVertexArray.length - lineStartIndex
	        };
	    }
	    addSymbols(arrays, quads, sizeVertex, lineOffset, alongLine, feature, writingMode, globe, tileAnchor, lineStartIndex, lineLength, associatedIconIndex, availableImages, canonical) {
	        const indexArray = arrays.indexArray;
	        const layoutVertexArray = arrays.layoutVertexArray;
	        const globeExtVertexArray = arrays.globeExtVertexArray;
	        const segment = arrays.segments.prepareSegment(4 * quads.length, layoutVertexArray, indexArray, this.canOverlap ? feature.sortKey : undefined);
	        const glyphOffsetArrayStart = this.glyphOffsetArray.length;
	        const vertexStartIndex = segment.vertexLength;
	        const angle = this.allowVerticalPlacement && writingMode === WritingMode.vertical ? Math.PI / 2 : 0;
	        const sections = feature.text && feature.text.sections;
	        for (let i = 0; i < quads.length; i++) {
	            const {tl, tr, bl, br, tex, pixelOffsetTL, pixelOffsetBR, minFontScaleX, minFontScaleY, glyphOffset, isSDF, sectionIndex} = quads[i];
	            const index = segment.vertexLength;
	            const y = glyphOffset[1];
	            addVertex(layoutVertexArray, tileAnchor.x, tileAnchor.y, tl.x, y + tl.y, tex.x, tex.y, sizeVertex, isSDF, pixelOffsetTL.x, pixelOffsetTL.y, minFontScaleX, minFontScaleY);
	            addVertex(layoutVertexArray, tileAnchor.x, tileAnchor.y, tr.x, y + tr.y, tex.x + tex.w, tex.y, sizeVertex, isSDF, pixelOffsetBR.x, pixelOffsetTL.y, minFontScaleX, minFontScaleY);
	            addVertex(layoutVertexArray, tileAnchor.x, tileAnchor.y, bl.x, y + bl.y, tex.x, tex.y + tex.h, sizeVertex, isSDF, pixelOffsetTL.x, pixelOffsetBR.y, minFontScaleX, minFontScaleY);
	            addVertex(layoutVertexArray, tileAnchor.x, tileAnchor.y, br.x, y + br.y, tex.x + tex.w, tex.y + tex.h, sizeVertex, isSDF, pixelOffsetBR.x, pixelOffsetBR.y, minFontScaleX, minFontScaleY);
	            if (globe) {
	                const globeAnchor = globe.anchor;
	                const up = globe.up;
	                addGlobeVertex(globeExtVertexArray, globeAnchor.x, globeAnchor.y, globeAnchor.z, up[0], up[1], up[2]);
	                addGlobeVertex(globeExtVertexArray, globeAnchor.x, globeAnchor.y, globeAnchor.z, up[0], up[1], up[2]);
	                addGlobeVertex(globeExtVertexArray, globeAnchor.x, globeAnchor.y, globeAnchor.z, up[0], up[1], up[2]);
	                addGlobeVertex(globeExtVertexArray, globeAnchor.x, globeAnchor.y, globeAnchor.z, up[0], up[1], up[2]);
	                addDynamicAttributes(arrays.dynamicLayoutVertexArray, globeAnchor.x, globeAnchor.y, globeAnchor.z, angle);
	            } else {
	                addDynamicAttributes(arrays.dynamicLayoutVertexArray, tileAnchor.x, tileAnchor.y, tileAnchor.z, angle);
	            }
	            indexArray.emplaceBack(index, index + 1, index + 2);
	            indexArray.emplaceBack(index + 1, index + 2, index + 3);
	            segment.vertexLength += 4;
	            segment.primitiveLength += 2;
	            this.glyphOffsetArray.emplaceBack(glyphOffset[0]);
	            if (i === quads.length - 1 || sectionIndex !== quads[i + 1].sectionIndex) {
	                arrays.programConfigurations.populatePaintArrays(layoutVertexArray.length, feature, feature.index, {}, availableImages, canonical, sections && sections[sectionIndex]);
	            }
	        }
	        const projectedAnchor = globe ? globe.anchor : tileAnchor;
	        arrays.placedSymbolArray.emplaceBack(projectedAnchor.x, projectedAnchor.y, projectedAnchor.z, tileAnchor.x, tileAnchor.y, glyphOffsetArrayStart, this.glyphOffsetArray.length - glyphOffsetArrayStart, vertexStartIndex, lineStartIndex, lineLength, tileAnchor.segment, sizeVertex ? sizeVertex[0] : 0, sizeVertex ? sizeVertex[1] : 0, lineOffset[0], lineOffset[1], writingMode, 0, false, 0, associatedIconIndex, 0);
	    }
	    _commitLayoutVertex(array, boxTileAnchorX, boxTileAnchorY, boxTileAnchorZ, tileAnchorX, tileAnchorY, extrude) {
	        array.emplaceBack(boxTileAnchorX, boxTileAnchorY, boxTileAnchorZ, tileAnchorX, tileAnchorY, Math.round(extrude.x), Math.round(extrude.y));
	    }
	    _addCollisionDebugVertices(box, scale, arrays, boxTileAnchorX, boxTileAnchorY, boxTileAnchorZ, symbolInstance) {
	        const segment = arrays.segments.prepareSegment(4, arrays.layoutVertexArray, arrays.indexArray);
	        const index = segment.vertexLength;
	        const symbolTileAnchorX = symbolInstance.tileAnchorX;
	        const symbolTileAnchorY = symbolInstance.tileAnchorY;
	        for (let i = 0; i < 4; i++) {
	            arrays.collisionVertexArray.emplaceBack(0, 0, 0, 0);
	        }
	        arrays.collisionVertexArrayExt.emplaceBack(scale, -box.padding, -box.padding);
	        arrays.collisionVertexArrayExt.emplaceBack(scale, box.padding, -box.padding);
	        arrays.collisionVertexArrayExt.emplaceBack(scale, box.padding, box.padding);
	        arrays.collisionVertexArrayExt.emplaceBack(scale, -box.padding, box.padding);
	        this._commitLayoutVertex(arrays.layoutVertexArray, boxTileAnchorX, boxTileAnchorY, boxTileAnchorZ, symbolTileAnchorX, symbolTileAnchorY, new pointGeometry(box.x1, box.y1));
	        this._commitLayoutVertex(arrays.layoutVertexArray, boxTileAnchorX, boxTileAnchorY, boxTileAnchorZ, symbolTileAnchorX, symbolTileAnchorY, new pointGeometry(box.x2, box.y1));
	        this._commitLayoutVertex(arrays.layoutVertexArray, boxTileAnchorX, boxTileAnchorY, boxTileAnchorZ, symbolTileAnchorX, symbolTileAnchorY, new pointGeometry(box.x2, box.y2));
	        this._commitLayoutVertex(arrays.layoutVertexArray, boxTileAnchorX, boxTileAnchorY, boxTileAnchorZ, symbolTileAnchorX, symbolTileAnchorY, new pointGeometry(box.x1, box.y2));
	        segment.vertexLength += 4;
	        const indexArray = arrays.indexArray;
	        indexArray.emplaceBack(index, index + 1);
	        indexArray.emplaceBack(index + 1, index + 2);
	        indexArray.emplaceBack(index + 2, index + 3);
	        indexArray.emplaceBack(index + 3, index);
	        segment.primitiveLength += 4;
	    }
	    _addTextDebugCollisionBoxes(size, zoom, collisionBoxArray, startIndex, endIndex, instance) {
	        for (let b = startIndex; b < endIndex; b++) {
	            const box = collisionBoxArray.get(b);
	            const scale = this.getSymbolInstanceTextSize(size, instance, zoom, b);
	            this._addCollisionDebugVertices(box, scale, this.textCollisionBox, box.projectedAnchorX, box.projectedAnchorY, box.projectedAnchorZ, instance);
	        }
	    }
	    _addIconDebugCollisionBoxes(size, zoom, collisionBoxArray, startIndex, endIndex, instance) {
	        for (let b = startIndex; b < endIndex; b++) {
	            const box = collisionBoxArray.get(b);
	            const scale = this.getSymbolInstanceIconSize(size, zoom, b);
	            this._addCollisionDebugVertices(box, scale, this.iconCollisionBox, box.projectedAnchorX, box.projectedAnchorY, box.projectedAnchorZ, instance);
	        }
	    }
	    generateCollisionDebugBuffers(zoom, collisionBoxArray) {
	        if (this.hasDebugData()) {
	            this.destroyDebugData();
	        }
	        this.textCollisionBox = new CollisionBuffers(StructArrayLayout3i2i2i16, collisionBoxLayout.members, StructArrayLayout2ui4);
	        this.iconCollisionBox = new CollisionBuffers(StructArrayLayout3i2i2i16, collisionBoxLayout.members, StructArrayLayout2ui4);
	        const iconSize = evaluateSizeForZoom(this.iconSizeData, zoom);
	        const textSize = evaluateSizeForZoom(this.textSizeData, zoom);
	        for (let i = 0; i < this.symbolInstances.length; i++) {
	            const symbolInstance = this.symbolInstances.get(i);
	            this._addTextDebugCollisionBoxes(textSize, zoom, collisionBoxArray, symbolInstance.textBoxStartIndex, symbolInstance.textBoxEndIndex, symbolInstance);
	            this._addTextDebugCollisionBoxes(textSize, zoom, collisionBoxArray, symbolInstance.verticalTextBoxStartIndex, symbolInstance.verticalTextBoxEndIndex, symbolInstance);
	            this._addIconDebugCollisionBoxes(iconSize, zoom, collisionBoxArray, symbolInstance.iconBoxStartIndex, symbolInstance.iconBoxEndIndex, symbolInstance);
	            this._addIconDebugCollisionBoxes(iconSize, zoom, collisionBoxArray, symbolInstance.verticalIconBoxStartIndex, symbolInstance.verticalIconBoxEndIndex, symbolInstance);
	        }
	    }
	    getSymbolInstanceTextSize(textSize, instance, zoom, boxIndex) {
	        const symbolIndex = instance.rightJustifiedTextSymbolIndex >= 0 ? instance.rightJustifiedTextSymbolIndex : instance.centerJustifiedTextSymbolIndex >= 0 ? instance.centerJustifiedTextSymbolIndex : instance.leftJustifiedTextSymbolIndex >= 0 ? instance.leftJustifiedTextSymbolIndex : instance.verticalPlacedTextSymbolIndex >= 0 ? instance.verticalPlacedTextSymbolIndex : boxIndex;
	        const symbol = this.text.placedSymbolArray.get(symbolIndex);
	        const featureSize = evaluateSizeForFeature(this.textSizeData, textSize, symbol) / ONE_EM;
	        return this.tilePixelRatio * featureSize;
	    }
	    getSymbolInstanceIconSize(iconSize, zoom, index) {
	        const symbol = this.icon.placedSymbolArray.get(index);
	        const featureSize = evaluateSizeForFeature(this.iconSizeData, iconSize, symbol);
	        return this.tilePixelRatio * featureSize;
	    }
	    _commitDebugCollisionVertexUpdate(array, scale, padding) {
	        array.emplaceBack(scale, -padding, -padding);
	        array.emplaceBack(scale, padding, -padding);
	        array.emplaceBack(scale, padding, padding);
	        array.emplaceBack(scale, -padding, padding);
	    }
	    _updateTextDebugCollisionBoxes(size, zoom, collisionBoxArray, startIndex, endIndex, instance) {
	        for (let b = startIndex; b < endIndex; b++) {
	            const box = collisionBoxArray.get(b);
	            const scale = this.getSymbolInstanceTextSize(size, instance, zoom, b);
	            const array = this.textCollisionBox.collisionVertexArrayExt;
	            this._commitDebugCollisionVertexUpdate(array, scale, box.padding);
	        }
	    }
	    _updateIconDebugCollisionBoxes(size, zoom, collisionBoxArray, startIndex, endIndex) {
	        for (let b = startIndex; b < endIndex; b++) {
	            const box = collisionBoxArray.get(b);
	            const scale = this.getSymbolInstanceIconSize(size, zoom, b);
	            const array = this.iconCollisionBox.collisionVertexArrayExt;
	            this._commitDebugCollisionVertexUpdate(array, scale, box.padding);
	        }
	    }
	    updateCollisionDebugBuffers(zoom, collisionBoxArray) {
	        if (!this.hasDebugData()) {
	            return;
	        }
	        if (this.hasTextCollisionBoxData())
	            this.textCollisionBox.collisionVertexArrayExt.clear();
	        if (this.hasIconCollisionBoxData())
	            this.iconCollisionBox.collisionVertexArrayExt.clear();
	        const iconSize = evaluateSizeForZoom(this.iconSizeData, zoom);
	        const textSize = evaluateSizeForZoom(this.textSizeData, zoom);
	        for (let i = 0; i < this.symbolInstances.length; i++) {
	            const symbolInstance = this.symbolInstances.get(i);
	            this._updateTextDebugCollisionBoxes(textSize, zoom, collisionBoxArray, symbolInstance.textBoxStartIndex, symbolInstance.textBoxEndIndex, symbolInstance);
	            this._updateTextDebugCollisionBoxes(textSize, zoom, collisionBoxArray, symbolInstance.verticalTextBoxStartIndex, symbolInstance.verticalTextBoxEndIndex, symbolInstance);
	            this._updateIconDebugCollisionBoxes(iconSize, zoom, collisionBoxArray, symbolInstance.iconBoxStartIndex, symbolInstance.iconBoxEndIndex);
	            this._updateIconDebugCollisionBoxes(iconSize, zoom, collisionBoxArray, symbolInstance.verticalIconBoxStartIndex, symbolInstance.verticalIconBoxEndIndex);
	        }
	        if (this.hasTextCollisionBoxData() && this.textCollisionBox.collisionVertexBufferExt) {
	            this.textCollisionBox.collisionVertexBufferExt.updateData(this.textCollisionBox.collisionVertexArrayExt);
	        }
	        if (this.hasIconCollisionBoxData() && this.iconCollisionBox.collisionVertexBufferExt) {
	            this.iconCollisionBox.collisionVertexBufferExt.updateData(this.iconCollisionBox.collisionVertexArrayExt);
	        }
	    }
	    _deserializeCollisionBoxesForSymbol(collisionBoxArray, textStartIndex, textEndIndex, verticalTextStartIndex, verticalTextEndIndex, iconStartIndex, iconEndIndex, verticalIconStartIndex, verticalIconEndIndex) {
	        const collisionArrays = {};
	        for (let k = textStartIndex; k < textEndIndex; k++) {
	            const box = collisionBoxArray.get(k);
	            collisionArrays.textBox = {
	                x1: box.x1,
	                y1: box.y1,
	                x2: box.x2,
	                y2: box.y2,
	                padding: box.padding,
	                projectedAnchorX: box.projectedAnchorX,
	                projectedAnchorY: box.projectedAnchorY,
	                projectedAnchorZ: box.projectedAnchorZ,
	                tileAnchorX: box.tileAnchorX,
	                tileAnchorY: box.tileAnchorY
	            };
	            collisionArrays.textFeatureIndex = box.featureIndex;
	            break;
	        }
	        for (let k = verticalTextStartIndex; k < verticalTextEndIndex; k++) {
	            const box = collisionBoxArray.get(k);
	            collisionArrays.verticalTextBox = {
	                x1: box.x1,
	                y1: box.y1,
	                x2: box.x2,
	                y2: box.y2,
	                padding: box.padding,
	                projectedAnchorX: box.projectedAnchorX,
	                projectedAnchorY: box.projectedAnchorY,
	                projectedAnchorZ: box.projectedAnchorZ,
	                tileAnchorX: box.tileAnchorX,
	                tileAnchorY: box.tileAnchorY
	            };
	            collisionArrays.verticalTextFeatureIndex = box.featureIndex;
	            break;
	        }
	        for (let k = iconStartIndex; k < iconEndIndex; k++) {
	            const box = collisionBoxArray.get(k);
	            collisionArrays.iconBox = {
	                x1: box.x1,
	                y1: box.y1,
	                x2: box.x2,
	                y2: box.y2,
	                padding: box.padding,
	                projectedAnchorX: box.projectedAnchorX,
	                projectedAnchorY: box.projectedAnchorY,
	                projectedAnchorZ: box.projectedAnchorZ,
	                tileAnchorX: box.tileAnchorX,
	                tileAnchorY: box.tileAnchorY
	            };
	            collisionArrays.iconFeatureIndex = box.featureIndex;
	            break;
	        }
	        for (let k = verticalIconStartIndex; k < verticalIconEndIndex; k++) {
	            const box = collisionBoxArray.get(k);
	            collisionArrays.verticalIconBox = {
	                x1: box.x1,
	                y1: box.y1,
	                x2: box.x2,
	                y2: box.y2,
	                padding: box.padding,
	                projectedAnchorX: box.projectedAnchorX,
	                projectedAnchorY: box.projectedAnchorY,
	                projectedAnchorZ: box.projectedAnchorZ,
	                tileAnchorX: box.tileAnchorX,
	                tileAnchorY: box.tileAnchorY
	            };
	            collisionArrays.verticalIconFeatureIndex = box.featureIndex;
	            break;
	        }
	        return collisionArrays;
	    }
	    deserializeCollisionBoxes(collisionBoxArray) {
	        this.collisionArrays = [];
	        for (let i = 0; i < this.symbolInstances.length; i++) {
	            const symbolInstance = this.symbolInstances.get(i);
	            this.collisionArrays.push(this._deserializeCollisionBoxesForSymbol(collisionBoxArray, symbolInstance.textBoxStartIndex, symbolInstance.textBoxEndIndex, symbolInstance.verticalTextBoxStartIndex, symbolInstance.verticalTextBoxEndIndex, symbolInstance.iconBoxStartIndex, symbolInstance.iconBoxEndIndex, symbolInstance.verticalIconBoxStartIndex, symbolInstance.verticalIconBoxEndIndex));
	        }
	    }
	    hasTextData() {
	        return this.text.segments.get().length > 0;
	    }
	    hasIconData() {
	        return this.icon.segments.get().length > 0;
	    }
	    hasDebugData() {
	        return this.textCollisionBox && this.iconCollisionBox;
	    }
	    hasTextCollisionBoxData() {
	        return this.hasDebugData() && this.textCollisionBox.segments.get().length > 0;
	    }
	    hasIconCollisionBoxData() {
	        return this.hasDebugData() && this.iconCollisionBox.segments.get().length > 0;
	    }
	    addIndicesForPlacedSymbol(iconOrText, placedSymbolIndex) {
	        const placedSymbol = iconOrText.placedSymbolArray.get(placedSymbolIndex);
	        const endIndex = placedSymbol.vertexStartIndex + placedSymbol.numGlyphs * 4;
	        for (let vertexIndex = placedSymbol.vertexStartIndex; vertexIndex < endIndex; vertexIndex += 4) {
	            iconOrText.indexArray.emplaceBack(vertexIndex, vertexIndex + 1, vertexIndex + 2);
	            iconOrText.indexArray.emplaceBack(vertexIndex + 1, vertexIndex + 2, vertexIndex + 3);
	        }
	    }
	    getSortedSymbolIndexes(angle) {
	        if (this.sortedAngle === angle && this.symbolInstanceIndexes !== undefined) {
	            return this.symbolInstanceIndexes;
	        }
	        const sin = Math.sin(angle);
	        const cos = Math.cos(angle);
	        const rotatedYs = [];
	        const featureIndexes = [];
	        const result = [];
	        for (let i = 0; i < this.symbolInstances.length; ++i) {
	            result.push(i);
	            const symbolInstance = this.symbolInstances.get(i);
	            rotatedYs.push(Math.round(sin * symbolInstance.tileAnchorX + cos * symbolInstance.tileAnchorY) | 0);
	            featureIndexes.push(symbolInstance.featureIndex);
	        }
	        result.sort((aIndex, bIndex) => {
	            return rotatedYs[aIndex] - rotatedYs[bIndex] || featureIndexes[bIndex] - featureIndexes[aIndex];
	        });
	        return result;
	    }
	    addToSortKeyRanges(symbolInstanceIndex, sortKey) {
	        const last = this.sortKeyRanges[this.sortKeyRanges.length - 1];
	        if (last && last.sortKey === sortKey) {
	            last.symbolInstanceEnd = symbolInstanceIndex + 1;
	        } else {
	            this.sortKeyRanges.push({
	                sortKey,
	                symbolInstanceStart: symbolInstanceIndex,
	                symbolInstanceEnd: symbolInstanceIndex + 1
	            });
	        }
	    }
	    sortFeatures(angle) {
	        if (!this.sortFeaturesByY)
	            return;
	        if (this.sortedAngle === angle)
	            return;
	        if (this.text.segments.get().length > 1 || this.icon.segments.get().length > 1)
	            return;
	        this.symbolInstanceIndexes = this.getSortedSymbolIndexes(angle);
	        this.sortedAngle = angle;
	        this.text.indexArray.clear();
	        this.icon.indexArray.clear();
	        this.featureSortOrder = [];
	        for (const i of this.symbolInstanceIndexes) {
	            const symbolInstance = this.symbolInstances.get(i);
	            this.featureSortOrder.push(symbolInstance.featureIndex);
	            [
	                symbolInstance.rightJustifiedTextSymbolIndex,
	                symbolInstance.centerJustifiedTextSymbolIndex,
	                symbolInstance.leftJustifiedTextSymbolIndex
	            ].forEach((index, i, array) => {
	                if (index >= 0 && array.indexOf(index) === i) {
	                    this.addIndicesForPlacedSymbol(this.text, index);
	                }
	            });
	            if (symbolInstance.verticalPlacedTextSymbolIndex >= 0) {
	                this.addIndicesForPlacedSymbol(this.text, symbolInstance.verticalPlacedTextSymbolIndex);
	            }
	            if (symbolInstance.placedIconSymbolIndex >= 0) {
	                this.addIndicesForPlacedSymbol(this.icon, symbolInstance.placedIconSymbolIndex);
	            }
	            if (symbolInstance.verticalPlacedIconSymbolIndex >= 0) {
	                this.addIndicesForPlacedSymbol(this.icon, symbolInstance.verticalPlacedIconSymbolIndex);
	            }
	        }
	        if (this.text.indexBuffer)
	            this.text.indexBuffer.updateData(this.text.indexArray);
	        if (this.icon.indexBuffer)
	            this.icon.indexBuffer.updateData(this.icon.indexArray);
	    }
	}
	register(SymbolBucket, 'SymbolBucket', {
	    omit: [
	        'layers',
	        'collisionBoxArray',
	        'features',
	        'compareText'
	    ]
	});
	SymbolBucket.MAX_GLYPHS = 65535;
	SymbolBucket.addDynamicAttributes = addDynamicAttributes;

	function resolveTokens(properties, text) {
	    return text.replace(/{([^{}]+)}/g, (match, key) => {
	        return key in properties ? String(properties[key]) : '';
	    });
	}

	const layout = new Properties({
	    'symbol-placement': new DataConstantProperty(spec['layout_symbol']['symbol-placement']),
	    'symbol-spacing': new DataConstantProperty(spec['layout_symbol']['symbol-spacing']),
	    'symbol-avoid-edges': new DataConstantProperty(spec['layout_symbol']['symbol-avoid-edges']),
	    'symbol-sort-key': new DataDrivenProperty(spec['layout_symbol']['symbol-sort-key']),
	    'symbol-z-order': new DataConstantProperty(spec['layout_symbol']['symbol-z-order']),
	    'icon-allow-overlap': new DataConstantProperty(spec['layout_symbol']['icon-allow-overlap']),
	    'icon-ignore-placement': new DataConstantProperty(spec['layout_symbol']['icon-ignore-placement']),
	    'icon-optional': new DataConstantProperty(spec['layout_symbol']['icon-optional']),
	    'icon-rotation-alignment': new DataConstantProperty(spec['layout_symbol']['icon-rotation-alignment']),
	    'icon-size': new DataDrivenProperty(spec['layout_symbol']['icon-size']),
	    'icon-text-fit': new DataConstantProperty(spec['layout_symbol']['icon-text-fit']),
	    'icon-text-fit-padding': new DataConstantProperty(spec['layout_symbol']['icon-text-fit-padding']),
	    'icon-image': new DataDrivenProperty(spec['layout_symbol']['icon-image']),
	    'icon-rotate': new DataDrivenProperty(spec['layout_symbol']['icon-rotate']),
	    'icon-padding': new DataConstantProperty(spec['layout_symbol']['icon-padding']),
	    'icon-keep-upright': new DataConstantProperty(spec['layout_symbol']['icon-keep-upright']),
	    'icon-offset': new DataDrivenProperty(spec['layout_symbol']['icon-offset']),
	    'icon-anchor': new DataDrivenProperty(spec['layout_symbol']['icon-anchor']),
	    'icon-pitch-alignment': new DataConstantProperty(spec['layout_symbol']['icon-pitch-alignment']),
	    'text-pitch-alignment': new DataConstantProperty(spec['layout_symbol']['text-pitch-alignment']),
	    'text-rotation-alignment': new DataConstantProperty(spec['layout_symbol']['text-rotation-alignment']),
	    'text-field': new DataDrivenProperty(spec['layout_symbol']['text-field']),
	    'text-font': new DataDrivenProperty(spec['layout_symbol']['text-font']),
	    'text-size': new DataDrivenProperty(spec['layout_symbol']['text-size']),
	    'text-max-width': new DataDrivenProperty(spec['layout_symbol']['text-max-width']),
	    'text-line-height': new DataDrivenProperty(spec['layout_symbol']['text-line-height']),
	    'text-letter-spacing': new DataDrivenProperty(spec['layout_symbol']['text-letter-spacing']),
	    'text-justify': new DataDrivenProperty(spec['layout_symbol']['text-justify']),
	    'text-radial-offset': new DataDrivenProperty(spec['layout_symbol']['text-radial-offset']),
	    'text-variable-anchor': new DataConstantProperty(spec['layout_symbol']['text-variable-anchor']),
	    'text-anchor': new DataDrivenProperty(spec['layout_symbol']['text-anchor']),
	    'text-max-angle': new DataConstantProperty(spec['layout_symbol']['text-max-angle']),
	    'text-writing-mode': new DataConstantProperty(spec['layout_symbol']['text-writing-mode']),
	    'text-rotate': new DataDrivenProperty(spec['layout_symbol']['text-rotate']),
	    'text-padding': new DataConstantProperty(spec['layout_symbol']['text-padding']),
	    'text-keep-upright': new DataConstantProperty(spec['layout_symbol']['text-keep-upright']),
	    'text-transform': new DataDrivenProperty(spec['layout_symbol']['text-transform']),
	    'text-offset': new DataDrivenProperty(spec['layout_symbol']['text-offset']),
	    'text-allow-overlap': new DataConstantProperty(spec['layout_symbol']['text-allow-overlap']),
	    'text-ignore-placement': new DataConstantProperty(spec['layout_symbol']['text-ignore-placement']),
	    'text-optional': new DataConstantProperty(spec['layout_symbol']['text-optional'])
	});
	const paint$3 = new Properties({
	    'icon-opacity': new DataDrivenProperty(spec['paint_symbol']['icon-opacity']),
	    'icon-color': new DataDrivenProperty(spec['paint_symbol']['icon-color']),
	    'icon-halo-color': new DataDrivenProperty(spec['paint_symbol']['icon-halo-color']),
	    'icon-halo-width': new DataDrivenProperty(spec['paint_symbol']['icon-halo-width']),
	    'icon-halo-blur': new DataDrivenProperty(spec['paint_symbol']['icon-halo-blur']),
	    'icon-translate': new DataConstantProperty(spec['paint_symbol']['icon-translate']),
	    'icon-translate-anchor': new DataConstantProperty(spec['paint_symbol']['icon-translate-anchor']),
	    'text-opacity': new DataDrivenProperty(spec['paint_symbol']['text-opacity']),
	    'text-color': new DataDrivenProperty(spec['paint_symbol']['text-color'], {
	        runtimeType: ColorType,
	        getOverride: o => o.textColor,
	        hasOverride: o => !!o.textColor
	    }),
	    'text-halo-color': new DataDrivenProperty(spec['paint_symbol']['text-halo-color']),
	    'text-halo-width': new DataDrivenProperty(spec['paint_symbol']['text-halo-width']),
	    'text-halo-blur': new DataDrivenProperty(spec['paint_symbol']['text-halo-blur']),
	    'text-translate': new DataConstantProperty(spec['paint_symbol']['text-translate']),
	    'text-translate-anchor': new DataConstantProperty(spec['paint_symbol']['text-translate-anchor'])
	});
	var properties$3 = {
	    paint: paint$3,
	    layout
	};

	class FormatSectionOverride {
	    constructor(defaultValue) {
	        this.type = defaultValue.property.overrides ? defaultValue.property.overrides.runtimeType : NullType;
	        this.defaultValue = defaultValue;
	    }
	    evaluate(ctx) {
	        if (ctx.formattedSection) {
	            const overrides = this.defaultValue.property.overrides;
	            if (overrides && overrides.hasOverride(ctx.formattedSection)) {
	                return overrides.getOverride(ctx.formattedSection);
	            }
	        }
	        if (ctx.feature && ctx.featureState) {
	            return this.defaultValue.evaluate(ctx.feature, ctx.featureState);
	        }
	        return this.defaultValue.property.specification.default;
	    }
	    eachChild(fn) {
	        if (!this.defaultValue.isConstant()) {
	            const expr = this.defaultValue.value;
	            fn(expr._styleExpression.expression);
	        }
	    }
	    outputDefined() {
	        return false;
	    }
	    serialize() {
	        return null;
	    }
	}
	register(FormatSectionOverride, 'FormatSectionOverride', { omit: ['defaultValue'] });

	class SymbolStyleLayer extends StyleLayer {
	    constructor(layer) {
	        super(layer, properties$3);
	    }
	    recalculate(parameters, availableImages) {
	        super.recalculate(parameters, availableImages);
	        if (this.layout.get('icon-rotation-alignment') === 'auto') {
	            if (this.layout.get('symbol-placement') !== 'point') {
	                this.layout._values['icon-rotation-alignment'] = 'map';
	            } else {
	                this.layout._values['icon-rotation-alignment'] = 'viewport';
	            }
	        }
	        if (this.layout.get('text-rotation-alignment') === 'auto') {
	            if (this.layout.get('symbol-placement') !== 'point') {
	                this.layout._values['text-rotation-alignment'] = 'map';
	            } else {
	                this.layout._values['text-rotation-alignment'] = 'viewport';
	            }
	        }
	        if (this.layout.get('text-pitch-alignment') === 'auto') {
	            this.layout._values['text-pitch-alignment'] = this.layout.get('text-rotation-alignment');
	        }
	        if (this.layout.get('icon-pitch-alignment') === 'auto') {
	            this.layout._values['icon-pitch-alignment'] = this.layout.get('icon-rotation-alignment');
	        }
	        const writingModes = this.layout.get('text-writing-mode');
	        if (writingModes) {
	            const deduped = [];
	            for (const m of writingModes) {
	                if (deduped.indexOf(m) < 0)
	                    deduped.push(m);
	            }
	            this.layout._values['text-writing-mode'] = deduped;
	        } else if (this.layout.get('symbol-placement') === 'point') {
	            this.layout._values['text-writing-mode'] = ['horizontal'];
	        } else {
	            this.layout._values['text-writing-mode'] = [
	                'horizontal',
	                'vertical'
	            ];
	        }
	        this._setPaintOverrides();
	    }
	    getValueAndResolveTokens(name, feature, canonical, availableImages) {
	        const value = this.layout.get(name).evaluate(feature, {}, canonical, availableImages);
	        const unevaluated = this._unevaluatedLayout._values[name];
	        if (!unevaluated.isDataDriven() && !isExpression(unevaluated.value) && value) {
	            return resolveTokens(feature.properties, value);
	        }
	        return value;
	    }
	    createBucket(parameters) {
	        return new SymbolBucket(parameters);
	    }
	    queryRadius() {
	        return 0;
	    }
	    queryIntersectsFeature() {
	        return false;
	    }
	    _setPaintOverrides() {
	        for (const overridable of properties$3.paint.overridableProperties) {
	            if (!SymbolStyleLayer.hasPaintOverride(this.layout, overridable)) {
	                continue;
	            }
	            const overriden = this.paint.get(overridable);
	            const override = new FormatSectionOverride(overriden);
	            const styleExpression = new StyleExpression(override, overriden.property.specification);
	            let expression = null;
	            if (overriden.value.kind === 'constant' || overriden.value.kind === 'source') {
	                expression = new ZoomConstantExpression('source', styleExpression);
	            } else {
	                expression = new ZoomDependentExpression('composite', styleExpression, overriden.value.zoomStops, overriden.value._interpolationType);
	            }
	            this.paint._values[overridable] = new PossiblyEvaluatedPropertyValue(overriden.property, expression, overriden.parameters);
	        }
	    }
	    _handleOverridablePaintPropertyUpdate(name, oldValue, newValue) {
	        if (!this.layout || oldValue.isDataDriven() || newValue.isDataDriven()) {
	            return false;
	        }
	        return SymbolStyleLayer.hasPaintOverride(this.layout, name);
	    }
	    static hasPaintOverride(layout, propertyName) {
	        const textField = layout.get('text-field');
	        const property = properties$3.paint.properties[propertyName];
	        let hasOverrides = false;
	        const checkSections = sections => {
	            for (const section of sections) {
	                if (property.overrides && property.overrides.hasOverride(section)) {
	                    hasOverrides = true;
	                    return;
	                }
	            }
	        };
	        if (textField.value.kind === 'constant' && textField.value.value instanceof Formatted) {
	            checkSections(textField.value.value.sections);
	        } else if (textField.value.kind === 'source') {
	            const checkExpression = expression => {
	                if (hasOverrides)
	                    return;
	                if (expression instanceof Literal$1 && typeOf(expression.value) === FormattedType) {
	                    const formatted = expression.value;
	                    checkSections(formatted.sections);
	                } else if (expression instanceof FormatExpression) {
	                    checkSections(expression.sections);
	                } else {
	                    expression.eachChild(checkExpression);
	                }
	            };
	            const expr = textField.value;
	            if (expr._styleExpression) {
	                checkExpression(expr._styleExpression.expression);
	            }
	        }
	        return hasOverrides;
	    }
	    getProgramConfiguration(zoom) {
	        return new ProgramConfiguration(this, zoom);
	    }
	}

	const paint$2 = new Properties({
	    'background-color': new DataConstantProperty(spec['paint_background']['background-color']),
	    'background-pattern': new CrossFadedProperty(spec['paint_background']['background-pattern']),
	    'background-opacity': new DataConstantProperty(spec['paint_background']['background-opacity'])
	});
	var properties$2 = { paint: paint$2 };

	class BackgroundStyleLayer extends StyleLayer {
	    constructor(layer) {
	        super(layer, properties$2);
	    }
	    getProgramIds() {
	        const image = this.paint.get('background-pattern');
	        return [image ? 'backgroundPattern' : 'background'];
	    }
	}

	const paint$1 = new Properties({
	    'raster-opacity': new DataConstantProperty(spec['paint_raster']['raster-opacity']),
	    'raster-hue-rotate': new DataConstantProperty(spec['paint_raster']['raster-hue-rotate']),
	    'raster-brightness-min': new DataConstantProperty(spec['paint_raster']['raster-brightness-min']),
	    'raster-brightness-max': new DataConstantProperty(spec['paint_raster']['raster-brightness-max']),
	    'raster-saturation': new DataConstantProperty(spec['paint_raster']['raster-saturation']),
	    'raster-contrast': new DataConstantProperty(spec['paint_raster']['raster-contrast']),
	    'raster-resampling': new DataConstantProperty(spec['paint_raster']['raster-resampling']),
	    'raster-fade-duration': new DataConstantProperty(spec['paint_raster']['raster-fade-duration'])
	});
	var properties$1 = { paint: paint$1 };

	class RasterStyleLayer extends StyleLayer {
	    constructor(layer) {
	        super(layer, properties$1);
	    }
	    getProgramIds() {
	        return ['raster'];
	    }
	}

	function validateCustomStyleLayer(layerObject) {
	    const errors = [];
	    const id = layerObject.id;
	    if (id === undefined) {
	        errors.push({ message: `layers.${ id }: missing required property "id"` });
	    }
	    if (layerObject.render === undefined) {
	        errors.push({ message: `layers.${ id }: missing required method "render"` });
	    }
	    if (layerObject.renderingMode && layerObject.renderingMode !== '2d' && layerObject.renderingMode !== '3d') {
	        errors.push({ message: `layers.${ id }: property "renderingMode" must be either "2d" or "3d"` });
	    }
	    return errors;
	}
	class CustomStyleLayer extends StyleLayer {
	    constructor(implementation) {
	        super(implementation, {});
	        this.implementation = implementation;
	    }
	    is3D() {
	        return this.implementation.renderingMode === '3d';
	    }
	    hasOffscreenPass() {
	        return this.implementation.prerender !== undefined;
	    }
	    recalculate() {
	    }
	    updateTransitions() {
	    }
	    hasTransition() {
	        return false;
	    }
	    serialize() {
	    }
	    onAdd(map) {
	        if (this.implementation.onAdd) {
	            this.implementation.onAdd(map, map.painter.context.gl);
	        }
	    }
	    onRemove(map) {
	        if (this.implementation.onRemove) {
	            this.implementation.onRemove(map, map.painter.context.gl);
	        }
	    }
	}

	const paint = new Properties({
	    'sky-type': new DataConstantProperty(spec['paint_sky']['sky-type']),
	    'sky-atmosphere-sun': new DataConstantProperty(spec['paint_sky']['sky-atmosphere-sun']),
	    'sky-atmosphere-sun-intensity': new DataConstantProperty(spec['paint_sky']['sky-atmosphere-sun-intensity']),
	    'sky-gradient-center': new DataConstantProperty(spec['paint_sky']['sky-gradient-center']),
	    'sky-gradient-radius': new DataConstantProperty(spec['paint_sky']['sky-gradient-radius']),
	    'sky-gradient': new ColorRampProperty(spec['paint_sky']['sky-gradient']),
	    'sky-atmosphere-halo-color': new DataConstantProperty(spec['paint_sky']['sky-atmosphere-halo-color']),
	    'sky-atmosphere-color': new DataConstantProperty(spec['paint_sky']['sky-atmosphere-color']),
	    'sky-opacity': new DataConstantProperty(spec['paint_sky']['sky-opacity'])
	});
	var properties = { paint };

	function getCelestialDirection(azimuth, altitude, leftHanded) {
	    const up = [
	        0,
	        0,
	        1
	    ];
	    const rotation = identity$1([]);
	    rotateY(rotation, rotation, leftHanded ? -degToRad(azimuth) + Math.PI : degToRad(azimuth));
	    rotateX(rotation, rotation, -degToRad(altitude));
	    transformQuat(up, up, rotation);
	    return normalize$2(up, up);
	}
	class SkyLayer extends StyleLayer {
	    constructor(layer) {
	        super(layer, properties);
	        this._updateColorRamp();
	    }
	    _handleSpecialPaintPropertyUpdate(name) {
	        if (name === 'sky-gradient') {
	            this._updateColorRamp();
	        } else if (name === 'sky-atmosphere-sun' || name === 'sky-atmosphere-halo-color' || name === 'sky-atmosphere-color' || name === 'sky-atmosphere-sun-intensity') {
	            this._skyboxInvalidated = true;
	        }
	    }
	    _updateColorRamp() {
	        const expression = this._transitionablePaint._values['sky-gradient'].value.expression;
	        this.colorRamp = renderColorRamp({
	            expression,
	            evaluationKey: 'skyRadialProgress'
	        });
	        if (this.colorRampTexture) {
	            this.colorRampTexture.destroy();
	            this.colorRampTexture = null;
	        }
	    }
	    needsSkyboxCapture(painter) {
	        if (!!this._skyboxInvalidated || !this.skyboxTexture || !this.skyboxGeometry) {
	            return true;
	        }
	        if (!this.paint.get('sky-atmosphere-sun')) {
	            const lightPosition = painter.style.light.properties.get('position');
	            return this._lightPosition.azimuthal !== lightPosition.azimuthal || this._lightPosition.polar !== lightPosition.polar;
	        }
	        return false;
	    }
	    getCenter(painter, leftHanded) {
	        const type = this.paint.get('sky-type');
	        if (type === 'atmosphere') {
	            const sunPosition = this.paint.get('sky-atmosphere-sun');
	            const useLightPosition = !sunPosition;
	            const light = painter.style.light;
	            const lightPosition = light.properties.get('position');
	            if (useLightPosition && light.properties.get('anchor') === 'viewport') {
	                warnOnce('The sun direction is attached to a light with viewport anchor, lighting may behave unexpectedly.');
	            }
	            return useLightPosition ? getCelestialDirection(lightPosition.azimuthal, -lightPosition.polar + 90, leftHanded) : getCelestialDirection(sunPosition[0], -sunPosition[1] + 90, leftHanded);
	        }
	        const direction = this.paint.get('sky-gradient-center');
	        return getCelestialDirection(direction[0], -direction[1] + 90, leftHanded);
	    }
	    is3D() {
	        return false;
	    }
	    isSky() {
	        return true;
	    }
	    markSkyboxValid(painter) {
	        this._skyboxInvalidated = false;
	        this._lightPosition = painter.style.light.properties.get('position');
	    }
	    hasOffscreenPass() {
	        return true;
	    }
	    getProgramIds() {
	        const type = this.paint.get('sky-type');
	        if (type === 'atmosphere') {
	            return [
	                'skyboxCapture',
	                'skybox'
	            ];
	        } else if (type === 'gradient') {
	            return ['skyboxGradient'];
	        }
	        return null;
	    }
	}

	const subclasses = {
	    circle: CircleStyleLayer,
	    heatmap: HeatmapStyleLayer,
	    hillshade: HillshadeStyleLayer,
	    fill: FillStyleLayer,
	    'fill-extrusion': FillExtrusionStyleLayer,
	    line: LineStyleLayer,
	    symbol: SymbolStyleLayer,
	    background: BackgroundStyleLayer,
	    raster: RasterStyleLayer,
	    sky: SkyLayer
	};
	function createStyleLayer(layer) {
	    if (layer.type === 'custom') {
	        return new CustomStyleLayer(layer);
	    } else {
	        return new subclasses[layer.type](layer);
	    }
	}

	class Texture {
	    constructor(context, image, format, options) {
	        this.context = context;
	        this.format = format;
	        this.texture = context.gl.createTexture();
	        this.update(image, options);
	    }
	    update(image, options, position) {
	        const {width, height} = image;
	        const {context} = this;
	        const {gl} = context;
	        const {HTMLImageElement, HTMLCanvasElement, HTMLVideoElement, ImageData, ImageBitmap} = window$1;
	        gl.bindTexture(gl.TEXTURE_2D, this.texture);
	        context.pixelStoreUnpackFlipY.set(false);
	        context.pixelStoreUnpack.set(1);
	        context.pixelStoreUnpackPremultiplyAlpha.set(this.format === gl.RGBA && (!options || options.premultiply !== false));
	        if (!position && (!this.size || this.size[0] !== width || this.size[1] !== height)) {
	            this.size = [
	                width,
	                height
	            ];
	            if (image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof HTMLVideoElement || image instanceof ImageData || ImageBitmap && image instanceof ImageBitmap) {
	                gl.texImage2D(gl.TEXTURE_2D, 0, this.format, this.format, gl.UNSIGNED_BYTE, image);
	            } else {
	                gl.texImage2D(gl.TEXTURE_2D, 0, this.format, width, height, 0, this.format, gl.UNSIGNED_BYTE, image.data);
	            }
	        } else {
	            const {x, y} = position || {
	                x: 0,
	                y: 0
	            };
	            if (image instanceof HTMLImageElement || image instanceof HTMLCanvasElement || image instanceof HTMLVideoElement || image instanceof ImageData || ImageBitmap && image instanceof ImageBitmap) {
	                gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, gl.RGBA, gl.UNSIGNED_BYTE, image);
	            } else {
	                gl.texSubImage2D(gl.TEXTURE_2D, 0, x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, image.data);
	            }
	        }
	        this.useMipmap = Boolean(options && options.useMipmap && this.isSizePowerOfTwo());
	        if (this.useMipmap) {
	            gl.generateMipmap(gl.TEXTURE_2D);
	        }
	    }
	    bind(filter, wrap) {
	        const {context} = this;
	        const {gl} = context;
	        gl.bindTexture(gl.TEXTURE_2D, this.texture);
	        if (filter !== this.filter) {
	            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
	            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, this.useMipmap ? filter === gl.NEAREST ? gl.NEAREST_MIPMAP_NEAREST : gl.LINEAR_MIPMAP_NEAREST : filter);
	            this.filter = filter;
	        }
	        if (wrap !== this.wrap) {
	            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrap);
	            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrap);
	            this.wrap = wrap;
	        }
	    }
	    isSizePowerOfTwo() {
	        return this.size[0] === this.size[1] && Math.log(this.size[0]) / Math.LN2 % 1 === 0;
	    }
	    destroy() {
	        const {gl} = this.context;
	        gl.deleteTexture(this.texture);
	        this.texture = null;
	    }
	}

	class LineAtlas {
	    constructor(width, height) {
	        this.width = width;
	        this.height = height;
	        this.nextRow = 0;
	        this.image = new AlphaImage({
	            width,
	            height
	        });
	        this.positions = {};
	        this.uploaded = false;
	    }
	    getDash(dasharray, lineCap) {
	        const key = this.getKey(dasharray, lineCap);
	        return this.positions[key];
	    }
	    trim() {
	        const width = this.width;
	        const height = this.height = nextPowerOfTwo(this.nextRow);
	        this.image.resize({
	            width,
	            height
	        });
	    }
	    getKey(dasharray, lineCap) {
	        return dasharray.join(',') + lineCap;
	    }
	    getDashRanges(dasharray, lineAtlasWidth, stretch) {
	        const oddDashArray = dasharray.length % 2 === 1;
	        const ranges = [];
	        let left = oddDashArray ? -dasharray[dasharray.length - 1] * stretch : 0;
	        let right = dasharray[0] * stretch;
	        let isDash = true;
	        ranges.push({
	            left,
	            right,
	            isDash,
	            zeroLength: dasharray[0] === 0
	        });
	        let currentDashLength = dasharray[0];
	        for (let i = 1; i < dasharray.length; i++) {
	            isDash = !isDash;
	            const dashLength = dasharray[i];
	            left = currentDashLength * stretch;
	            currentDashLength += dashLength;
	            right = currentDashLength * stretch;
	            ranges.push({
	                left,
	                right,
	                isDash,
	                zeroLength: dashLength === 0
	            });
	        }
	        return ranges;
	    }
	    addRoundDash(ranges, stretch, n) {
	        const halfStretch = stretch / 2;
	        for (let y = -n; y <= n; y++) {
	            const row = this.nextRow + n + y;
	            const index = this.width * row;
	            let currIndex = 0;
	            let range = ranges[currIndex];
	            for (let x = 0; x < this.width; x++) {
	                if (x / range.right > 1) {
	                    range = ranges[++currIndex];
	                }
	                const distLeft = Math.abs(x - range.left);
	                const distRight = Math.abs(x - range.right);
	                const minDist = Math.min(distLeft, distRight);
	                let signedDistance;
	                const distMiddle = y / n * (halfStretch + 1);
	                if (range.isDash) {
	                    const distEdge = halfStretch - Math.abs(distMiddle);
	                    signedDistance = Math.sqrt(minDist * minDist + distEdge * distEdge);
	                } else {
	                    signedDistance = halfStretch - Math.sqrt(minDist * minDist + distMiddle * distMiddle);
	                }
	                this.image.data[index + x] = Math.max(0, Math.min(255, signedDistance + 128));
	            }
	        }
	    }
	    addRegularDash(ranges, capLength) {
	        for (let i = ranges.length - 1; i >= 0; --i) {
	            const part = ranges[i];
	            const next = ranges[i + 1];
	            if (part.zeroLength) {
	                ranges.splice(i, 1);
	            } else if (next && next.isDash === part.isDash) {
	                next.left = part.left;
	                ranges.splice(i, 1);
	            }
	        }
	        const first = ranges[0];
	        const last = ranges[ranges.length - 1];
	        if (first.isDash === last.isDash) {
	            first.left = last.left - this.width;
	            last.right = first.right + this.width;
	        }
	        const index = this.width * this.nextRow;
	        let currIndex = 0;
	        let range = ranges[currIndex];
	        for (let x = 0; x < this.width; x++) {
	            if (x / range.right > 1) {
	                range = ranges[++currIndex];
	            }
	            const distLeft = Math.abs(x - range.left);
	            const distRight = Math.abs(x - range.right);
	            const minDist = Math.min(distLeft, distRight);
	            const signedDistance = (range.isDash ? minDist : -minDist) + capLength;
	            this.image.data[index + x] = Math.max(0, Math.min(255, signedDistance + 128));
	        }
	    }
	    addDash(dasharray, lineCap) {
	        const key = this.getKey(dasharray, lineCap);
	        if (this.positions[key])
	            return this.positions[key];
	        const round = lineCap === 'round';
	        const n = round ? 7 : 0;
	        const height = 2 * n + 1;
	        if (this.nextRow + height > this.height) {
	            warnOnce('LineAtlas out of space');
	            return null;
	        }
	        if (dasharray.length === 0) {
	            dasharray.push(1);
	        }
	        let length = 0;
	        for (let i = 0; i < dasharray.length; i++) {
	            if (dasharray[i] < 0) {
	                warnOnce('Negative value is found in line dasharray, replacing values with 0');
	                dasharray[i] = 0;
	            }
	            length += dasharray[i];
	        }
	        if (length !== 0) {
	            const stretch = this.width / length;
	            const ranges = this.getDashRanges(dasharray, this.width, stretch);
	            if (round) {
	                this.addRoundDash(ranges, stretch, n);
	            } else {
	                const capLength = lineCap === 'square' ? 0.5 * stretch : 0;
	                this.addRegularDash(ranges, capLength);
	            }
	        }
	        const y = this.nextRow + n;
	        this.nextRow += height;
	        const pos = {
	            tl: [
	                y,
	                n
	            ],
	            br: [
	                length,
	                0
	            ]
	        };
	        this.positions[key] = pos;
	        return pos;
	    }
	}
	register(LineAtlas, 'LineAtlas');

	class ThrottledInvoker {
	    constructor(callback) {
	        this._callback = callback;
	        this._triggered = false;
	        if (typeof MessageChannel !== 'undefined') {
	            this._channel = new MessageChannel();
	            this._channel.port2.onmessage = () => {
	                this._triggered = false;
	                this._callback();
	            };
	        }
	    }
	    trigger() {
	        if (!this._triggered) {
	            this._triggered = true;
	            if (this._channel) {
	                this._channel.port1.postMessage(true);
	            } else {
	                setTimeout(() => {
	                    this._triggered = false;
	                    this._callback();
	                }, 0);
	            }
	        }
	    }
	    remove() {
	        this._channel = undefined;
	        this._callback = () => {
	        };
	    }
	}

	class Scheduler {
	    constructor() {
	        this.tasks = {};
	        this.taskQueue = [];
	        bindAll(['process'], this);
	        this.invoker = new ThrottledInvoker(this.process);
	        this.nextId = 0;
	    }
	    add(fn, metadata) {
	        const id = this.nextId++;
	        const priority = getPriority(metadata);
	        if (priority === 0) {
	            isWorker() ? void 0 : undefined;
	            try {
	                fn();
	            } finally {
	            }
	            return {
	                cancel: () => {
	                }
	            };
	        }
	        this.tasks[id] = {
	            fn,
	            metadata,
	            priority,
	            id
	        };
	        this.taskQueue.push(id);
	        this.invoker.trigger();
	        return {
	            cancel: () => {
	                delete this.tasks[id];
	            }
	        };
	    }
	    process() {
	        isWorker() ? void 0 : undefined;
	        try {
	            this.taskQueue = this.taskQueue.filter(id => !!this.tasks[id]);
	            if (!this.taskQueue.length) {
	                return;
	            }
	            const id = this.pick();
	            if (id === null)
	                return;
	            const task = this.tasks[id];
	            delete this.tasks[id];
	            if (this.taskQueue.length) {
	                this.invoker.trigger();
	            }
	            if (!task) {
	                return;
	            }
	            task.fn();
	        } finally {
	        }
	    }
	    pick() {
	        let minIndex = null;
	        let minPriority = Infinity;
	        for (let i = 0; i < this.taskQueue.length; i++) {
	            const id = this.taskQueue[i];
	            const task = this.tasks[id];
	            if (task.priority < minPriority) {
	                minPriority = task.priority;
	                minIndex = i;
	            }
	        }
	        if (minIndex === null)
	            return null;
	        const id = this.taskQueue[minIndex];
	        this.taskQueue.splice(minIndex, 1);
	        return id;
	    }
	    remove() {
	        this.invoker.remove();
	    }
	}
	function getPriority({type, isSymbolTile, zoom}) {
	    zoom = zoom || 0;
	    if (type === 'message')
	        return 0;
	    if (type === 'maybePrepare' && !isSymbolTile)
	        return 100 - zoom;
	    if (type === 'parseTile' && !isSymbolTile)
	        return 200 - zoom;
	    if (type === 'parseTile' && isSymbolTile)
	        return 300 - zoom;
	    if (type === 'maybePrepare' && isSymbolTile)
	        return 400 - zoom;
	    return 500;
	}

	class Actor {
	    constructor(target, parent, mapId) {
	        this.target = target;
	        this.parent = parent;
	        this.mapId = mapId;
	        this.callbacks = {};
	        this.cancelCallbacks = {};
	        bindAll(['receive'], this);
	        this.target.addEventListener('message', this.receive, false);
	        this.globalScope = isWorker() ? target : window$1;
	        this.scheduler = new Scheduler();
	    }
	    send(type, data, callback, targetMapId, mustQueue = false, callbackMetadata) {
	        const id = Math.round(Math.random() * 1000000000000000000).toString(36).substring(0, 10);
	        if (callback) {
	            callback.metadata = callbackMetadata;
	            this.callbacks[id] = callback;
	        }
	        const buffers = isSafari(this.globalScope) ? undefined : [];
	        this.target.postMessage({
	            id,
	            type,
	            hasCallback: !!callback,
	            targetMapId,
	            mustQueue,
	            sourceMapId: this.mapId,
	            data: serialize(data, buffers)
	        }, buffers);
	        return {
	            cancel: () => {
	                if (callback) {
	                    delete this.callbacks[id];
	                }
	                this.target.postMessage({
	                    id,
	                    type: '<cancel>',
	                    targetMapId,
	                    sourceMapId: this.mapId
	                });
	            }
	        };
	    }
	    receive(message) {
	        const data = message.data, id = data.id;
	        if (!id) {
	            return;
	        }
	        if (data.targetMapId && this.mapId !== data.targetMapId) {
	            return;
	        }
	        if (data.type === '<cancel>') {
	            const cancel = this.cancelCallbacks[id];
	            delete this.cancelCallbacks[id];
	            if (cancel) {
	                cancel.cancel();
	            }
	        } else {
	            if (data.mustQueue || isWorker()) {
	                const callback = this.callbacks[id];
	                const metadata = callback && callback.metadata || { type: 'message' };
	                this.cancelCallbacks[id] = this.scheduler.add(() => this.processTask(id, data), metadata);
	            } else {
	                this.processTask(id, data);
	            }
	        }
	    }
	    processTask(id, task) {
	        if (task.type === '<response>') {
	            const callback = this.callbacks[id];
	            delete this.callbacks[id];
	            if (callback) {
	                if (task.error) {
	                    callback(deserialize$1(task.error));
	                } else {
	                    callback(null, deserialize$1(task.data));
	                }
	            }
	        } else {
	            const buffers = isSafari(this.globalScope) ? undefined : [];
	            const done = task.hasCallback ? (err, data) => {
	                delete this.cancelCallbacks[id];
	                this.target.postMessage({
	                    id,
	                    type: '<response>',
	                    sourceMapId: this.mapId,
	                    error: err ? serialize(err) : null,
	                    data: serialize(data, buffers)
	                }, buffers);
	            } : _ => {
	            };
	            const params = deserialize$1(task.data);
	            if (this.parent[task.type]) {
	                this.parent[task.type](task.sourceMapId, params, done);
	            } else if (this.parent.getWorkerSource) {
	                const keys = task.type.split('.');
	                const scope = this.parent.getWorkerSource(task.sourceMapId, keys[0], params.source);
	                scope[keys[1]](params, done);
	            } else {
	                done(new Error(`Could not find function ${ task.type }`));
	            }
	        }
	    }
	    remove() {
	        this.scheduler.remove();
	        this.target.removeEventListener('message', this.receive, false);
	    }
	}

	class DictionaryCoder {
	    constructor(strings) {
	        this._stringToNumber = {};
	        this._numberToString = [];
	        for (let i = 0; i < strings.length; i++) {
	            const string = strings[i];
	            this._stringToNumber[string] = i;
	            this._numberToString[i] = string;
	        }
	    }
	    encode(string) {
	        return this._stringToNumber[string];
	    }
	    decode(n) {
	        return this._numberToString[n];
	    }
	}

	const customProps = [
	    'tile',
	    'layer',
	    'source',
	    'sourceLayer',
	    'state'
	];
	class Feature {
	    constructor(vectorTileFeature, z, x, y, id) {
	        this.type = 'Feature';
	        this._vectorTileFeature = vectorTileFeature;
	        this._z = z;
	        this._x = x;
	        this._y = y;
	        this.properties = vectorTileFeature.properties;
	        this.id = id;
	    }
	    get geometry() {
	        if (this._geometry === undefined) {
	            this._geometry = this._vectorTileFeature.toGeoJSON(this._x, this._y, this._z).geometry;
	        }
	        return this._geometry;
	    }
	    set geometry(g) {
	        this._geometry = g;
	    }
	    toJSON() {
	        const json = {
	            type: 'Feature',
	            geometry: this.geometry,
	            properties: this.properties
	        };
	        if (this.id !== undefined)
	            json.id = this.id;
	        for (const key of customProps) {
	            if (this[key] !== undefined)
	                json[key] = this[key];
	        }
	        return json;
	    }
	}

	function deserialize(input, style) {
	    const output = {};
	    if (!style)
	        return output;
	    for (const bucket of input) {
	        const layers = bucket.layerIds.map(id => style.getLayer(id)).filter(Boolean);
	        if (layers.length === 0) {
	            continue;
	        }
	        bucket.layers = layers;
	        if (bucket.stateDependentLayerIds) {
	            bucket.stateDependentLayers = bucket.stateDependentLayerIds.map(lId => layers.filter(l => l.id === lId)[0]);
	        }
	        for (const layer of layers) {
	            output[layer.id] = bucket;
	        }
	    }
	    return output;
	}

	const meshSize = 32;
	const gridSize = meshSize + 1;
	const numTriangles = meshSize * meshSize * 2 - 2;
	const numParentTriangles = numTriangles - meshSize * meshSize;
	const coords = new Uint16Array(numTriangles * 4);
	for (let i = 0; i < numTriangles; i++) {
	    let id = i + 2;
	    let ax = 0, ay = 0, bx = 0, by = 0, cx = 0, cy = 0;
	    if (id & 1) {
	        bx = by = cx = meshSize;
	    } else {
	        ax = ay = cy = meshSize;
	    }
	    while ((id >>= 1) > 1) {
	        const mx = ax + bx >> 1;
	        const my = ay + by >> 1;
	        if (id & 1) {
	            bx = ax;
	            by = ay;
	            ax = cx;
	            ay = cy;
	        } else {
	            ax = bx;
	            ay = by;
	            bx = cx;
	            by = cy;
	        }
	        cx = mx;
	        cy = my;
	    }
	    const k = i * 4;
	    coords[k + 0] = ax;
	    coords[k + 1] = ay;
	    coords[k + 2] = bx;
	    coords[k + 3] = by;
	}
	const reprojectedCoords = new Uint16Array(gridSize * gridSize * 2);
	const used = new Uint8Array(gridSize * gridSize);
	const indexMap = new Uint16Array(gridSize * gridSize);
	const commonRasterTileSize = 256;
	const paddingSize = meshSize / commonRasterTileSize / 4;
	function seamPadding(n) {
	    if (n === 0)
	        return -paddingSize;
	    else if (n === gridSize - 1)
	        return paddingSize;
	    else
	        return 0;
	}
	function getTileMesh(canonical, projection) {
	    const cs = tileTransform(canonical, projection);
	    const z2 = Math.pow(2, canonical.z);
	    for (let y = 0; y < gridSize; y++) {
	        for (let x = 0; x < gridSize; x++) {
	            const lng = lngFromMercatorX((canonical.x + (x + seamPadding(x)) / meshSize) / z2);
	            const lat = latFromMercatorY((canonical.y + (y + seamPadding(y)) / meshSize) / z2);
	            const p = projection.project(lng, lat);
	            const k = y * gridSize + x;
	            reprojectedCoords[2 * k + 0] = Math.round((p.x * cs.scale - cs.x) * EXTENT);
	            reprojectedCoords[2 * k + 1] = Math.round((p.y * cs.scale - cs.y) * EXTENT);
	        }
	    }
	    used.fill(0);
	    indexMap.fill(0);
	    for (let i = numTriangles - 1; i >= 0; i--) {
	        const k = i * 4;
	        const ax = coords[k + 0];
	        const ay = coords[k + 1];
	        const bx = coords[k + 2];
	        const by = coords[k + 3];
	        const mx = ax + bx >> 1;
	        const my = ay + by >> 1;
	        const cx = mx + my - ay;
	        const cy = my + ax - mx;
	        const aIndex = ay * gridSize + ax;
	        const bIndex = by * gridSize + bx;
	        const mIndex = my * gridSize + mx;
	        const rax = reprojectedCoords[2 * aIndex + 0];
	        const ray = reprojectedCoords[2 * aIndex + 1];
	        const rbx = reprojectedCoords[2 * bIndex + 0];
	        const rby = reprojectedCoords[2 * bIndex + 1];
	        const rmx = reprojectedCoords[2 * mIndex + 0];
	        const rmy = reprojectedCoords[2 * mIndex + 1];
	        const isUsed = Math.hypot((rax + rbx) / 2 - rmx, (ray + rby) / 2 - rmy) >= 16;
	        used[mIndex] = used[mIndex] || (isUsed ? 1 : 0);
	        if (i < numParentTriangles) {
	            const leftChildIndex = (ay + cy >> 1) * gridSize + (ax + cx >> 1);
	            const rightChildIndex = (by + cy >> 1) * gridSize + (bx + cx >> 1);
	            used[mIndex] = used[mIndex] || used[leftChildIndex] || used[rightChildIndex];
	        }
	    }
	    const vertices = new StructArrayLayout4i8();
	    const indices = new StructArrayLayout3ui6();
	    let numVertices = 0;
	    function addVertex(x, y) {
	        const k = y * gridSize + x;
	        if (indexMap[k] === 0) {
	            vertices.emplaceBack(reprojectedCoords[2 * k + 0], reprojectedCoords[2 * k + 1], x * EXTENT / meshSize, y * EXTENT / meshSize);
	            indexMap[k] = ++numVertices;
	        }
	        return indexMap[k] - 1;
	    }
	    function addTriangles(ax, ay, bx, by, cx, cy) {
	        const mx = ax + bx >> 1;
	        const my = ay + by >> 1;
	        if (Math.abs(ax - cx) + Math.abs(ay - cy) > 1 && used[my * gridSize + mx]) {
	            addTriangles(cx, cy, ax, ay, mx, my);
	            addTriangles(bx, by, cx, cy, mx, my);
	        } else {
	            const ai = addVertex(ax, ay);
	            const bi = addVertex(bx, by);
	            const ci = addVertex(cx, cy);
	            indices.emplaceBack(ai, bi, ci);
	        }
	    }
	    addTriangles(0, 0, meshSize, meshSize, meshSize, 0);
	    addTriangles(meshSize, meshSize, 0, 0, 0, meshSize);
	    return {
	        vertices,
	        indices
	    };
	}

	var boundsAttributes = createLayout([
	    {
	        name: 'a_pos',
	        type: 'Int16',
	        components: 2
	    },
	    {
	        name: 'a_texture_pos',
	        type: 'Int16',
	        components: 2
	    }
	]);

	const CLOCK_SKEW_RETRY_TIMEOUT = 30000;
	const BOUNDS_FEATURE = (() => {
	    return {
	        type: 2,
	        extent: EXTENT,
	        loadGeometry() {
	            return [[
	                    new pointGeometry(0, 0),
	                    new pointGeometry(EXTENT + 1, 0),
	                    new pointGeometry(EXTENT + 1, EXTENT + 1),
	                    new pointGeometry(0, EXTENT + 1),
	                    new pointGeometry(0, 0)
	                ]];
	        }
	    };
	})();
	class Tile {
	    constructor(tileID, size, tileZoom, painter, isRaster) {
	        this.tileID = tileID;
	        this.uid = uniqueId();
	        this.uses = 0;
	        this.tileSize = size;
	        this.tileZoom = tileZoom;
	        this.buckets = {};
	        this.expirationTime = null;
	        this.queryPadding = 0;
	        this.hasSymbolBuckets = false;
	        this.hasRTLText = false;
	        this.dependencies = {};
	        this.isRaster = isRaster;
	        this.expiredRequestCount = 0;
	        this.state = 'loading';
	        if (painter && painter.transform) {
	            this.projection = painter.transform.projection;
	        }
	    }
	    registerFadeDuration(duration) {
	        const fadeEndTime = duration + this.timeAdded;
	        if (fadeEndTime < exported$1.now())
	            return;
	        if (this.fadeEndTime && fadeEndTime < this.fadeEndTime)
	            return;
	        this.fadeEndTime = fadeEndTime;
	    }
	    wasRequested() {
	        return this.state === 'errored' || this.state === 'loaded' || this.state === 'reloading';
	    }
	    get tileTransform() {
	        if (!this._tileTransform) {
	            this._tileTransform = tileTransform(this.tileID.canonical, this.projection);
	        }
	        return this._tileTransform;
	    }
	    loadVectorData(data, painter, justReloaded) {
	        this.unloadVectorData();
	        this.state = 'loaded';
	        if (!data) {
	            this.collisionBoxArray = new CollisionBoxArray();
	            return;
	        }
	        if (data.featureIndex) {
	            this.latestFeatureIndex = data.featureIndex;
	            if (data.rawTileData) {
	                this.latestRawTileData = data.rawTileData;
	                this.latestFeatureIndex.rawTileData = data.rawTileData;
	            } else if (this.latestRawTileData) {
	                this.latestFeatureIndex.rawTileData = this.latestRawTileData;
	            }
	        }
	        this.collisionBoxArray = data.collisionBoxArray;
	        this.buckets = deserialize(data.buckets, painter.style);
	        this.hasSymbolBuckets = false;
	        for (const id in this.buckets) {
	            const bucket = this.buckets[id];
	            if (bucket instanceof SymbolBucket) {
	                this.hasSymbolBuckets = true;
	                if (justReloaded) {
	                    bucket.justReloaded = true;
	                } else {
	                    break;
	                }
	            }
	        }
	        this.hasRTLText = false;
	        if (this.hasSymbolBuckets) {
	            for (const id in this.buckets) {
	                const bucket = this.buckets[id];
	                if (bucket instanceof SymbolBucket) {
	                    if (bucket.hasRTLText) {
	                        this.hasRTLText = true;
	                        lazyLoadRTLTextPlugin();
	                        break;
	                    }
	                }
	            }
	        }
	        this.queryPadding = 0;
	        for (const id in this.buckets) {
	            const bucket = this.buckets[id];
	            this.queryPadding = Math.max(this.queryPadding, painter.style.getLayer(id).queryRadius(bucket));
	        }
	        if (data.imageAtlas) {
	            this.imageAtlas = data.imageAtlas;
	        }
	        if (data.glyphAtlasImage) {
	            this.glyphAtlasImage = data.glyphAtlasImage;
	        }
	        if (data.lineAtlas) {
	            this.lineAtlas = data.lineAtlas;
	        }
	    }
	    unloadVectorData() {
	        if (!this.hasData())
	            return;
	        for (const id in this.buckets) {
	            this.buckets[id].destroy();
	        }
	        this.buckets = {};
	        if (this.imageAtlas) {
	            this.imageAtlas = null;
	        }
	        if (this.lineAtlas) {
	            this.lineAtlas = null;
	        }
	        if (this.imageAtlasTexture) {
	            this.imageAtlasTexture.destroy();
	        }
	        if (this.glyphAtlasTexture) {
	            this.glyphAtlasTexture.destroy();
	        }
	        if (this.lineAtlasTexture) {
	            this.lineAtlasTexture.destroy();
	        }
	        if (this._tileBoundsBuffer) {
	            this._tileBoundsBuffer.destroy();
	            this._tileBoundsIndexBuffer.destroy();
	            this._tileBoundsSegments.destroy();
	            this._tileBoundsBuffer = null;
	        }
	        if (this._tileDebugBuffer) {
	            this._tileDebugBuffer.destroy();
	            this._tileDebugIndexBuffer.destroy();
	            this._tileDebugSegments.destroy();
	            this._tileDebugBuffer = null;
	        }
	        if (this._globeTileDebugBorderBuffer) {
	            this._globeTileDebugBorderBuffer.destroy();
	            this._globeTileDebugBorderBuffer = null;
	        }
	        if (this._tileDebugTextBuffer) {
	            this._tileDebugTextBuffer.destroy();
	            this._tileDebugTextSegments.destroy();
	            this._tileDebugTextIndexBuffer.destroy();
	            this._tileDebugTextBuffer = null;
	        }
	        if (this._globeTileDebugTextBuffer) {
	            this._globeTileDebugTextBuffer.destroy();
	            this._globeTileDebugTextBuffer = null;
	        }
	        this.latestFeatureIndex = null;
	        this.state = 'unloaded';
	    }
	    getBucket(layer) {
	        return this.buckets[layer.id];
	    }
	    upload(context) {
	        for (const id in this.buckets) {
	            const bucket = this.buckets[id];
	            if (bucket.uploadPending()) {
	                bucket.upload(context);
	            }
	        }
	        const gl = context.gl;
	        if (this.imageAtlas && !this.imageAtlas.uploaded) {
	            this.imageAtlasTexture = new Texture(context, this.imageAtlas.image, gl.RGBA);
	            this.imageAtlas.uploaded = true;
	        }
	        if (this.glyphAtlasImage) {
	            this.glyphAtlasTexture = new Texture(context, this.glyphAtlasImage, gl.ALPHA);
	            this.glyphAtlasImage = null;
	        }
	        if (this.lineAtlas && !this.lineAtlas.uploaded) {
	            this.lineAtlasTexture = new Texture(context, this.lineAtlas.image, gl.ALPHA);
	            this.lineAtlas.uploaded = true;
	        }
	    }
	    prepare(imageManager) {
	        if (this.imageAtlas) {
	            this.imageAtlas.patchUpdatedImages(imageManager, this.imageAtlasTexture);
	        }
	    }
	    queryRenderedFeatures(layers, serializedLayers, sourceFeatureState, tileResult, params, transform, pixelPosMatrix, visualizeQueryGeometry) {
	        if (!this.latestFeatureIndex || !this.latestFeatureIndex.rawTileData)
	            return {};
	        return this.latestFeatureIndex.query({
	            tileResult,
	            pixelPosMatrix,
	            transform,
	            params,
	            tileTransform: this.tileTransform
	        }, layers, serializedLayers, sourceFeatureState);
	    }
	    querySourceFeatures(result, params) {
	        const featureIndex = this.latestFeatureIndex;
	        if (!featureIndex || !featureIndex.rawTileData)
	            return;
	        const vtLayers = featureIndex.loadVTLayers();
	        const sourceLayer = params ? params.sourceLayer : '';
	        const layer = vtLayers._geojsonTileLayer || vtLayers[sourceLayer];
	        if (!layer)
	            return;
	        const filter = createFilter(params && params.filter);
	        const {z, x, y} = this.tileID.canonical;
	        const coord = {
	            z,
	            x,
	            y
	        };
	        for (let i = 0; i < layer.length; i++) {
	            const feature = layer.feature(i);
	            if (filter.needGeometry) {
	                const evaluationFeature = toEvaluationFeature(feature, true);
	                if (!filter.filter(new EvaluationParameters(this.tileID.overscaledZ), evaluationFeature, this.tileID.canonical))
	                    continue;
	            } else if (!filter.filter(new EvaluationParameters(this.tileID.overscaledZ), feature)) {
	                continue;
	            }
	            const id = featureIndex.getId(feature, sourceLayer);
	            const geojsonFeature = new Feature(feature, z, x, y, id);
	            geojsonFeature.tile = coord;
	            result.push(geojsonFeature);
	        }
	    }
	    hasData() {
	        return this.state === 'loaded' || this.state === 'reloading' || this.state === 'expired';
	    }
	    patternsLoaded() {
	        return !!this.imageAtlas && !!Object.keys(this.imageAtlas.patternPositions).length;
	    }
	    setExpiryData(data) {
	        const prior = this.expirationTime;
	        if (data.cacheControl) {
	            const parsedCC = parseCacheControl(data.cacheControl);
	            if (parsedCC['max-age'])
	                this.expirationTime = Date.now() + parsedCC['max-age'] * 1000;
	        } else if (data.expires) {
	            this.expirationTime = new Date(data.expires).getTime();
	        }
	        if (this.expirationTime) {
	            const now = Date.now();
	            let isExpired = false;
	            if (this.expirationTime > now) {
	                isExpired = false;
	            } else if (!prior) {
	                isExpired = true;
	            } else if (this.expirationTime < prior) {
	                isExpired = true;
	            } else {
	                const delta = this.expirationTime - prior;
	                if (!delta) {
	                    isExpired = true;
	                } else {
	                    this.expirationTime = now + Math.max(delta, CLOCK_SKEW_RETRY_TIMEOUT);
	                }
	            }
	            if (isExpired) {
	                this.expiredRequestCount++;
	                this.state = 'expired';
	            } else {
	                this.expiredRequestCount = 0;
	            }
	        }
	    }
	    getExpiryTimeout() {
	        if (this.expirationTime) {
	            if (this.expiredRequestCount) {
	                return 1000 * (1 << Math.min(this.expiredRequestCount - 1, 31));
	            } else {
	                return Math.min(this.expirationTime - new Date().getTime(), Math.pow(2, 31) - 1);
	            }
	        }
	    }
	    setFeatureState(states, painter) {
	        if (!this.latestFeatureIndex || !this.latestFeatureIndex.rawTileData || Object.keys(states).length === 0 || !painter) {
	            return;
	        }
	        const vtLayers = this.latestFeatureIndex.loadVTLayers();
	        const availableImages = painter.style.listImages();
	        for (const id in this.buckets) {
	            if (!painter.style.hasLayer(id))
	                continue;
	            const bucket = this.buckets[id];
	            const sourceLayerId = bucket.layers[0]['sourceLayer'] || '_geojsonTileLayer';
	            const sourceLayer = vtLayers[sourceLayerId];
	            const sourceLayerStates = states[sourceLayerId];
	            if (!sourceLayer || !sourceLayerStates || Object.keys(sourceLayerStates).length === 0)
	                continue;
	            const imagePositions = this.imageAtlas && this.imageAtlas.patternPositions || {};
	            bucket.update(sourceLayerStates, sourceLayer, availableImages, imagePositions);
	            if (bucket instanceof LineBucket || bucket instanceof FillBucket) {
	                const sourceCache = painter.style._getSourceCache(bucket.layers[0].source);
	                if (painter._terrain && painter._terrain.enabled && sourceCache && bucket.programConfigurations.needsUpload) {
	                    painter._terrain._clearRenderCacheForTile(sourceCache.id, this.tileID);
	                }
	            }
	            const layer = painter && painter.style && painter.style.getLayer(id);
	            if (layer) {
	                this.queryPadding = Math.max(this.queryPadding, layer.queryRadius(bucket));
	            }
	        }
	    }
	    holdingForFade() {
	        return this.symbolFadeHoldUntil !== undefined;
	    }
	    symbolFadeFinished() {
	        return !this.symbolFadeHoldUntil || this.symbolFadeHoldUntil < exported$1.now();
	    }
	    clearFadeHold() {
	        this.symbolFadeHoldUntil = undefined;
	    }
	    setHoldDuration(duration) {
	        this.symbolFadeHoldUntil = exported$1.now() + duration;
	    }
	    setTexture(img, painter) {
	        const context = painter.context;
	        const gl = context.gl;
	        this.texture = painter.getTileTexture(img.width);
	        if (this.texture) {
	            this.texture.update(img, { useMipmap: true });
	        } else {
	            this.texture = new Texture(context, img, gl.RGBA, { useMipmap: true });
	            this.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	            if (context.extTextureFilterAnisotropic) {
	                gl.texParameterf(gl.TEXTURE_2D, context.extTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, context.extTextureFilterAnisotropicMax);
	            }
	        }
	    }
	    setDependencies(namespace, dependencies) {
	        const index = {};
	        for (const dep of dependencies) {
	            index[dep] = true;
	        }
	        this.dependencies[namespace] = index;
	    }
	    hasDependency(namespaces, keys) {
	        for (const namespace of namespaces) {
	            const dependencies = this.dependencies[namespace];
	            if (dependencies) {
	                for (const key of keys) {
	                    if (dependencies[key]) {
	                        return true;
	                    }
	                }
	            }
	        }
	        return false;
	    }
	    clearQueryDebugViz() {
	    }
	    _makeDebugTileBoundsBuffers(context, projection) {
	        if (!projection || projection.name === 'mercator' || this._tileDebugBuffer)
	            return;
	        const boundsLine = loadGeometry(BOUNDS_FEATURE, this.tileID.canonical, this.tileTransform)[0];
	        const debugVertices = new StructArrayLayout2i4();
	        const debugIndices = new StructArrayLayout1ui2();
	        for (let i = 0; i < boundsLine.length; i++) {
	            const {x, y} = boundsLine[i];
	            debugVertices.emplaceBack(x, y);
	            debugIndices.emplaceBack(i);
	        }
	        debugIndices.emplaceBack(0);
	        this._tileDebugIndexBuffer = context.createIndexBuffer(debugIndices);
	        this._tileDebugBuffer = context.createVertexBuffer(debugVertices, posAttributes.members);
	        this._tileDebugSegments = SegmentVector.simpleSegment(0, 0, debugVertices.length, debugIndices.length);
	    }
	    _makeTileBoundsBuffers(context, projection) {
	        if (this._tileBoundsBuffer || !projection || projection.name === 'mercator')
	            return;
	        const boundsLine = loadGeometry(BOUNDS_FEATURE, this.tileID.canonical, this.tileTransform)[0];
	        let boundsVertices, boundsIndices;
	        if (this.isRaster) {
	            const mesh = getTileMesh(this.tileID.canonical, projection);
	            boundsVertices = mesh.vertices;
	            boundsIndices = mesh.indices;
	        } else {
	            boundsVertices = new StructArrayLayout4i8();
	            boundsIndices = new StructArrayLayout3ui6();
	            for (const {x, y} of boundsLine) {
	                boundsVertices.emplaceBack(x, y, 0, 0);
	            }
	            const indices = earcut_1(boundsVertices.int16, undefined, 4);
	            for (let i = 0; i < indices.length; i += 3) {
	                boundsIndices.emplaceBack(indices[i], indices[i + 1], indices[i + 2]);
	            }
	        }
	        this._tileBoundsBuffer = context.createVertexBuffer(boundsVertices, boundsAttributes.members);
	        this._tileBoundsIndexBuffer = context.createIndexBuffer(boundsIndices);
	        this._tileBoundsSegments = SegmentVector.simpleSegment(0, 0, boundsVertices.length, boundsIndices.length);
	    }
	    _makeGlobeTileDebugBuffers(context, projection) {
	        if (this._globeTileDebugBorderBuffer || this._globeTileDebugTextBuffer || !projection || projection.name !== 'globe')
	            return;
	        const id = this.tileID.canonical;
	        const bounds = globeTileBounds(id);
	        const normalizationMatrix = globeNormalizeECEF(bounds);
	        this._makeGlobeTileDebugBorderBuffer(context, id, normalizationMatrix);
	        this._makeGlobeTileDebugTextBuffer(context, id, normalizationMatrix);
	    }
	    _makeGlobeTileDebugBorderBuffer(context, id, normalizationMatrix) {
	        const vertices = new StructArrayLayout2i4();
	        const indices = new StructArrayLayout1ui2();
	        const extraGlobe = new StructArrayLayout3i6();
	        const addLine = (sx, sy, ex, ey, pointCount) => {
	            const stepX = (ex - sx) / (pointCount - 1);
	            const stepY = (ey - sy) / (pointCount - 1);
	            const vOffset = vertices.length;
	            for (let i = 0; i < pointCount; i++) {
	                const x = sx + i * stepX;
	                const y = sy + i * stepY;
	                vertices.emplaceBack(x, y);
	                const ecef = tileCoordToECEF(x, y, id);
	                const gp = transformMat4$1(ecef, ecef, normalizationMatrix);
	                extraGlobe.emplaceBack(gp[0], gp[1], gp[2]);
	                indices.emplaceBack(vOffset + i);
	            }
	        };
	        const e = EXTENT;
	        addLine(0, 0, e, 0, 16);
	        addLine(e, 0, e, e, 16);
	        addLine(e, e, 0, e, 16);
	        addLine(0, e, 0, 0, 16);
	        this._tileDebugIndexBuffer = context.createIndexBuffer(indices);
	        this._tileDebugBuffer = context.createVertexBuffer(vertices, posAttributes.members);
	        this._globeTileDebugBorderBuffer = context.createVertexBuffer(extraGlobe, posAttributesGlobeExt.members);
	        this._tileDebugSegments = SegmentVector.simpleSegment(0, 0, vertices.length, indices.length);
	    }
	    _makeGlobeTileDebugTextBuffer(context, id, normalizationMatrix) {
	        const SEGMENTS = 4;
	        const numVertices = SEGMENTS + 1;
	        const step = EXTENT / SEGMENTS;
	        const vertices = new StructArrayLayout2i4();
	        const indices = new StructArrayLayout3ui6();
	        const extraGlobe = new StructArrayLayout3i6();
	        const totalVertices = numVertices * numVertices;
	        const totalTriangles = SEGMENTS * SEGMENTS * 2;
	        indices.reserve(totalTriangles);
	        vertices.reserve(totalVertices);
	        extraGlobe.reserve(totalVertices);
	        const toIndex = (j, i) => {
	            return totalVertices * j + i;
	        };
	        for (let j = 0; j < totalVertices; j++) {
	            const y = j * step;
	            for (let i = 0; i < totalVertices; i++) {
	                const x = i * step;
	                vertices.emplaceBack(x, y);
	                const ecef = tileCoordToECEF(x, y, id);
	                const gp = transformMat4$1(ecef, ecef, normalizationMatrix);
	                extraGlobe.emplaceBack(gp[0], gp[1], gp[2]);
	            }
	        }
	        for (let j = 0; j < SEGMENTS; j++) {
	            for (let i = 0; i < SEGMENTS; i++) {
	                const tl = toIndex(j, i);
	                const tr = toIndex(j, i + 1);
	                const bl = toIndex(j + 1, i);
	                const br = toIndex(j + 1, i + 1);
	                indices.emplaceBack(tl, tr, bl);
	                indices.emplaceBack(bl, tr, br);
	            }
	        }
	        this._tileDebugTextIndexBuffer = context.createIndexBuffer(indices);
	        this._tileDebugTextBuffer = context.createVertexBuffer(vertices, posAttributes.members);
	        this._globeTileDebugTextBuffer = context.createVertexBuffer(extraGlobe, posAttributesGlobeExt.members);
	        this._tileDebugTextSegments = SegmentVector.simpleSegment(0, 0, totalVertices, totalTriangles);
	    }
	}

	class SourceFeatureState {
	    constructor() {
	        this.state = {};
	        this.stateChanges = {};
	        this.deletedStates = {};
	    }
	    updateState(sourceLayer, featureId, newState) {
	        const feature = String(featureId);
	        this.stateChanges[sourceLayer] = this.stateChanges[sourceLayer] || {};
	        this.stateChanges[sourceLayer][feature] = this.stateChanges[sourceLayer][feature] || {};
	        extend$1(this.stateChanges[sourceLayer][feature], newState);
	        if (this.deletedStates[sourceLayer] === null) {
	            this.deletedStates[sourceLayer] = {};
	            for (const ft in this.state[sourceLayer]) {
	                if (ft !== feature)
	                    this.deletedStates[sourceLayer][ft] = null;
	            }
	        } else {
	            const featureDeletionQueued = this.deletedStates[sourceLayer] && this.deletedStates[sourceLayer][feature] === null;
	            if (featureDeletionQueued) {
	                this.deletedStates[sourceLayer][feature] = {};
	                for (const prop in this.state[sourceLayer][feature]) {
	                    if (!newState[prop])
	                        this.deletedStates[sourceLayer][feature][prop] = null;
	                }
	            } else {
	                for (const key in newState) {
	                    const deletionInQueue = this.deletedStates[sourceLayer] && this.deletedStates[sourceLayer][feature] && this.deletedStates[sourceLayer][feature][key] === null;
	                    if (deletionInQueue)
	                        delete this.deletedStates[sourceLayer][feature][key];
	                }
	            }
	        }
	    }
	    removeFeatureState(sourceLayer, featureId, key) {
	        const sourceLayerDeleted = this.deletedStates[sourceLayer] === null;
	        if (sourceLayerDeleted)
	            return;
	        const feature = String(featureId);
	        this.deletedStates[sourceLayer] = this.deletedStates[sourceLayer] || {};
	        if (key && featureId !== undefined) {
	            if (this.deletedStates[sourceLayer][feature] !== null) {
	                this.deletedStates[sourceLayer][feature] = this.deletedStates[sourceLayer][feature] || {};
	                this.deletedStates[sourceLayer][feature][key] = null;
	            }
	        } else if (featureId !== undefined) {
	            const updateInQueue = this.stateChanges[sourceLayer] && this.stateChanges[sourceLayer][feature];
	            if (updateInQueue) {
	                this.deletedStates[sourceLayer][feature] = {};
	                for (key in this.stateChanges[sourceLayer][feature])
	                    this.deletedStates[sourceLayer][feature][key] = null;
	            } else {
	                this.deletedStates[sourceLayer][feature] = null;
	            }
	        } else {
	            this.deletedStates[sourceLayer] = null;
	        }
	    }
	    getState(sourceLayer, featureId) {
	        const feature = String(featureId);
	        const base = this.state[sourceLayer] || {};
	        const changes = this.stateChanges[sourceLayer] || {};
	        const reconciledState = extend$1({}, base[feature], changes[feature]);
	        if (this.deletedStates[sourceLayer] === null)
	            return {};
	        else if (this.deletedStates[sourceLayer]) {
	            const featureDeletions = this.deletedStates[sourceLayer][featureId];
	            if (featureDeletions === null)
	                return {};
	            for (const prop in featureDeletions)
	                delete reconciledState[prop];
	        }
	        return reconciledState;
	    }
	    initializeTileState(tile, painter) {
	        tile.setFeatureState(this.state, painter);
	    }
	    coalesceChanges(tiles, painter) {
	        const featuresChanged = {};
	        for (const sourceLayer in this.stateChanges) {
	            this.state[sourceLayer] = this.state[sourceLayer] || {};
	            const layerStates = {};
	            for (const feature in this.stateChanges[sourceLayer]) {
	                if (!this.state[sourceLayer][feature])
	                    this.state[sourceLayer][feature] = {};
	                extend$1(this.state[sourceLayer][feature], this.stateChanges[sourceLayer][feature]);
	                layerStates[feature] = this.state[sourceLayer][feature];
	            }
	            featuresChanged[sourceLayer] = layerStates;
	        }
	        for (const sourceLayer in this.deletedStates) {
	            this.state[sourceLayer] = this.state[sourceLayer] || {};
	            const layerStates = {};
	            if (this.deletedStates[sourceLayer] === null) {
	                for (const ft in this.state[sourceLayer]) {
	                    layerStates[ft] = {};
	                    this.state[sourceLayer][ft] = {};
	                }
	            } else {
	                for (const feature in this.deletedStates[sourceLayer]) {
	                    const deleteWholeFeatureState = this.deletedStates[sourceLayer][feature] === null;
	                    if (deleteWholeFeatureState)
	                        this.state[sourceLayer][feature] = {};
	                    else {
	                        for (const key of Object.keys(this.deletedStates[sourceLayer][feature])) {
	                            delete this.state[sourceLayer][feature][key];
	                        }
	                    }
	                    layerStates[feature] = this.state[sourceLayer][feature];
	                }
	            }
	            featuresChanged[sourceLayer] = featuresChanged[sourceLayer] || {};
	            extend$1(featuresChanged[sourceLayer], layerStates);
	        }
	        this.stateChanges = {};
	        this.deletedStates = {};
	        if (Object.keys(featuresChanged).length === 0)
	            return;
	        for (const id in tiles) {
	            const tile = tiles[id];
	            tile.setFeatureState(featuresChanged, painter);
	        }
	    }
	}

	class MipLevel {
	    constructor(size_) {
	        this.size = size_;
	        this.minimums = [];
	        this.maximums = [];
	        this.leaves = [];
	    }
	    getElevation(x, y) {
	        const idx = this.toIdx(x, y);
	        return {
	            min: this.minimums[idx],
	            max: this.maximums[idx]
	        };
	    }
	    isLeaf(x, y) {
	        return this.leaves[this.toIdx(x, y)];
	    }
	    toIdx(x, y) {
	        return y * this.size + x;
	    }
	}
	function aabbRayIntersect(min, max, pos, dir) {
	    let tMin = 0;
	    let tMax = Number.MAX_VALUE;
	    const epsilon = 1e-15;
	    for (let i = 0; i < 3; i++) {
	        if (Math.abs(dir[i]) < epsilon) {
	            if (pos[i] < min[i] || pos[i] > max[i])
	                return null;
	        } else {
	            const ood = 1 / dir[i];
	            let t1 = (min[i] - pos[i]) * ood;
	            let t2 = (max[i] - pos[i]) * ood;
	            if (t1 > t2) {
	                const temp = t1;
	                t1 = t2;
	                t2 = temp;
	            }
	            if (t1 > tMin)
	                tMin = t1;
	            if (t2 < tMax)
	                tMax = t2;
	            if (tMin > tMax)
	                return null;
	        }
	    }
	    return tMin;
	}
	function triangleRayIntersect(ax, ay, az, bx, by, bz, cx, cy, cz, pos, dir) {
	    const abX = bx - ax;
	    const abY = by - ay;
	    const abZ = bz - az;
	    const acX = cx - ax;
	    const acY = cy - ay;
	    const acZ = cz - az;
	    const pvecX = dir[1] * acZ - dir[2] * acY;
	    const pvecY = dir[2] * acX - dir[0] * acZ;
	    const pvecZ = dir[0] * acY - dir[1] * acX;
	    const det = abX * pvecX + abY * pvecY + abZ * pvecZ;
	    if (Math.abs(det) < 1e-15)
	        return null;
	    const invDet = 1 / det;
	    const tvecX = pos[0] - ax;
	    const tvecY = pos[1] - ay;
	    const tvecZ = pos[2] - az;
	    const u = (tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ) * invDet;
	    if (u < 0 || u > 1)
	        return null;
	    const qvecX = tvecY * abZ - tvecZ * abY;
	    const qvecY = tvecZ * abX - tvecX * abZ;
	    const qvecZ = tvecX * abY - tvecY * abX;
	    const v = (dir[0] * qvecX + dir[1] * qvecY + dir[2] * qvecZ) * invDet;
	    if (v < 0 || u + v > 1)
	        return null;
	    return (acX * qvecX + acY * qvecY + acZ * qvecZ) * invDet;
	}
	function frac(v, lo, hi) {
	    return (v - lo) / (hi - lo);
	}
	function decodeBounds(x, y, depth, boundsMinx, boundsMiny, boundsMaxx, boundsMaxy, outMin, outMax) {
	    const scale = 1 << depth;
	    const rangex = boundsMaxx - boundsMinx;
	    const rangey = boundsMaxy - boundsMiny;
	    const minX = (x + 0) / scale * rangex + boundsMinx;
	    const maxX = (x + 1) / scale * rangex + boundsMinx;
	    const minY = (y + 0) / scale * rangey + boundsMiny;
	    const maxY = (y + 1) / scale * rangey + boundsMiny;
	    outMin[0] = minX;
	    outMin[1] = minY;
	    outMax[0] = maxX;
	    outMax[1] = maxY;
	}
	const aabbSkirtPadding = 100;
	class DemMinMaxQuadTree {
	    constructor(dem_) {
	        this.maximums = [];
	        this.minimums = [];
	        this.leaves = [];
	        this.childOffsets = [];
	        this.nodeCount = 0;
	        this.dem = dem_;
	        this._siblingOffset = [
	            [
	                0,
	                0
	            ],
	            [
	                1,
	                0
	            ],
	            [
	                0,
	                1
	            ],
	            [
	                1,
	                1
	            ]
	        ];
	        if (!this.dem)
	            return;
	        const mips = buildDemMipmap(this.dem);
	        const maxLvl = mips.length - 1;
	        const rootMip = mips[maxLvl];
	        const min = rootMip.minimums;
	        const max = rootMip.maximums;
	        const leaves = rootMip.leaves;
	        this._addNode(min[0], max[0], leaves[0]);
	        this._construct(mips, 0, 0, maxLvl, 0);
	    }
	    raycastRoot(minx, miny, maxx, maxy, p, d, exaggeration = 1) {
	        const min = [
	            minx,
	            miny,
	            -aabbSkirtPadding
	        ];
	        const max = [
	            maxx,
	            maxy,
	            this.maximums[0] * exaggeration
	        ];
	        return aabbRayIntersect(min, max, p, d);
	    }
	    raycast(rootMinx, rootMiny, rootMaxx, rootMaxy, p, d, exaggeration = 1) {
	        if (!this.nodeCount)
	            return null;
	        const t = this.raycastRoot(rootMinx, rootMiny, rootMaxx, rootMaxy, p, d, exaggeration);
	        if (t == null)
	            return null;
	        const tHits = [];
	        const sortedHits = [];
	        const boundsMin = [];
	        const boundsMax = [];
	        const stack = [{
	                idx: 0,
	                t,
	                nodex: 0,
	                nodey: 0,
	                depth: 0
	            }];
	        while (stack.length > 0) {
	            const {idx, t, nodex, nodey, depth} = stack.pop();
	            if (this.leaves[idx]) {
	                decodeBounds(nodex, nodey, depth, rootMinx, rootMiny, rootMaxx, rootMaxy, boundsMin, boundsMax);
	                const scale = 1 << depth;
	                const minxUv = (nodex + 0) / scale;
	                const maxxUv = (nodex + 1) / scale;
	                const minyUv = (nodey + 0) / scale;
	                const maxyUv = (nodey + 1) / scale;
	                const az = sampleElevation(minxUv, minyUv, this.dem) * exaggeration;
	                const bz = sampleElevation(maxxUv, minyUv, this.dem) * exaggeration;
	                const cz = sampleElevation(maxxUv, maxyUv, this.dem) * exaggeration;
	                const dz = sampleElevation(minxUv, maxyUv, this.dem) * exaggeration;
	                const t0 = triangleRayIntersect(boundsMin[0], boundsMin[1], az, boundsMax[0], boundsMin[1], bz, boundsMax[0], boundsMax[1], cz, p, d);
	                const t1 = triangleRayIntersect(boundsMax[0], boundsMax[1], cz, boundsMin[0], boundsMax[1], dz, boundsMin[0], boundsMin[1], az, p, d);
	                const tMin = Math.min(t0 !== null ? t0 : Number.MAX_VALUE, t1 !== null ? t1 : Number.MAX_VALUE);
	                if (tMin === Number.MAX_VALUE) {
	                    const hitPos = scaleAndAdd([], p, d, t);
	                    const fracx = frac(hitPos[0], boundsMin[0], boundsMax[0]);
	                    const fracy = frac(hitPos[1], boundsMin[1], boundsMax[1]);
	                    if (bilinearLerp(az, bz, dz, cz, fracx, fracy) >= hitPos[2])
	                        return t;
	                } else {
	                    return tMin;
	                }
	                continue;
	            }
	            let hitCount = 0;
	            for (let i = 0; i < this._siblingOffset.length; i++) {
	                const childNodeX = (nodex << 1) + this._siblingOffset[i][0];
	                const childNodeY = (nodey << 1) + this._siblingOffset[i][1];
	                decodeBounds(childNodeX, childNodeY, depth + 1, rootMinx, rootMiny, rootMaxx, rootMaxy, boundsMin, boundsMax);
	                boundsMin[2] = -aabbSkirtPadding;
	                boundsMax[2] = this.maximums[this.childOffsets[idx] + i] * exaggeration;
	                const result = aabbRayIntersect(boundsMin, boundsMax, p, d);
	                if (result != null) {
	                    const tHit = result;
	                    tHits[i] = tHit;
	                    let added = false;
	                    for (let j = 0; j < hitCount && !added; j++) {
	                        if (tHit >= tHits[sortedHits[j]]) {
	                            sortedHits.splice(j, 0, i);
	                            added = true;
	                        }
	                    }
	                    if (!added)
	                        sortedHits[hitCount] = i;
	                    hitCount++;
	                }
	            }
	            for (let i = 0; i < hitCount; i++) {
	                const hitIdx = sortedHits[i];
	                stack.push({
	                    idx: this.childOffsets[idx] + hitIdx,
	                    t: tHits[hitIdx],
	                    nodex: (nodex << 1) + this._siblingOffset[hitIdx][0],
	                    nodey: (nodey << 1) + this._siblingOffset[hitIdx][1],
	                    depth: depth + 1
	                });
	            }
	        }
	        return null;
	    }
	    _addNode(min, max, leaf) {
	        this.minimums.push(min);
	        this.maximums.push(max);
	        this.leaves.push(leaf);
	        this.childOffsets.push(0);
	        return this.nodeCount++;
	    }
	    _construct(mips, x, y, lvl, parentIdx) {
	        if (mips[lvl].isLeaf(x, y) === 1) {
	            return;
	        }
	        if (!this.childOffsets[parentIdx])
	            this.childOffsets[parentIdx] = this.nodeCount;
	        const childLvl = lvl - 1;
	        const childMip = mips[childLvl];
	        let leafMask = 0;
	        let firstNodeIdx = 0;
	        for (let i = 0; i < this._siblingOffset.length; i++) {
	            const childX = x * 2 + this._siblingOffset[i][0];
	            const childY = y * 2 + this._siblingOffset[i][1];
	            const elevation = childMip.getElevation(childX, childY);
	            const leaf = childMip.isLeaf(childX, childY);
	            const nodeIdx = this._addNode(elevation.min, elevation.max, leaf);
	            if (leaf)
	                leafMask |= 1 << i;
	            if (!firstNodeIdx)
	                firstNodeIdx = nodeIdx;
	        }
	        for (let i = 0; i < this._siblingOffset.length; i++) {
	            if (!(leafMask & 1 << i)) {
	                this._construct(mips, x * 2 + this._siblingOffset[i][0], y * 2 + this._siblingOffset[i][1], childLvl, firstNodeIdx + i);
	            }
	        }
	    }
	}
	function bilinearLerp(p00, p10, p01, p11, x, y) {
	    return number(number(p00, p01, y), number(p10, p11, y), x);
	}
	function sampleElevation(fx, fy, dem) {
	    const demSize = dem.dim;
	    const x = clamp(fx * demSize - 0.5, 0, demSize - 1);
	    const y = clamp(fy * demSize - 0.5, 0, demSize - 1);
	    const ixMin = Math.floor(x);
	    const iyMin = Math.floor(y);
	    const ixMax = Math.min(ixMin + 1, demSize - 1);
	    const iyMax = Math.min(iyMin + 1, demSize - 1);
	    const e00 = dem.get(ixMin, iyMin);
	    const e10 = dem.get(ixMax, iyMin);
	    const e01 = dem.get(ixMin, iyMax);
	    const e11 = dem.get(ixMax, iyMax);
	    return bilinearLerp(e00, e10, e01, e11, x - ixMin, y - iyMin);
	}
	function buildDemMipmap(dem) {
	    const demSize = dem.dim;
	    const elevationDiffThreshold = 5;
	    const texelSizeOfMip0 = 8;
	    const levelCount = Math.ceil(Math.log2(demSize / texelSizeOfMip0));
	    const mips = [];
	    let blockCount = Math.ceil(Math.pow(2, levelCount));
	    const blockSize = 1 / blockCount;
	    const blockSamples = (x, y, size, exclusive, outBounds) => {
	        const padding = exclusive ? 1 : 0;
	        const minx = x * size;
	        const maxx = (x + 1) * size - padding;
	        const miny = y * size;
	        const maxy = (y + 1) * size - padding;
	        outBounds[0] = minx;
	        outBounds[1] = miny;
	        outBounds[2] = maxx;
	        outBounds[3] = maxy;
	    };
	    let mip = new MipLevel(blockCount);
	    const blockBounds = [];
	    for (let idx = 0; idx < blockCount * blockCount; idx++) {
	        const y = Math.floor(idx / blockCount);
	        const x = idx % blockCount;
	        blockSamples(x, y, blockSize, false, blockBounds);
	        const e0 = sampleElevation(blockBounds[0], blockBounds[1], dem);
	        const e1 = sampleElevation(blockBounds[2], blockBounds[1], dem);
	        const e2 = sampleElevation(blockBounds[2], blockBounds[3], dem);
	        const e3 = sampleElevation(blockBounds[0], blockBounds[3], dem);
	        mip.minimums.push(Math.min(e0, e1, e2, e3));
	        mip.maximums.push(Math.max(e0, e1, e2, e3));
	        mip.leaves.push(1);
	    }
	    mips.push(mip);
	    for (blockCount /= 2; blockCount >= 1; blockCount /= 2) {
	        const prevMip = mips[mips.length - 1];
	        mip = new MipLevel(blockCount);
	        for (let idx = 0; idx < blockCount * blockCount; idx++) {
	            const y = Math.floor(idx / blockCount);
	            const x = idx % blockCount;
	            blockSamples(x, y, 2, true, blockBounds);
	            const e0 = prevMip.getElevation(blockBounds[0], blockBounds[1]);
	            const e1 = prevMip.getElevation(blockBounds[2], blockBounds[1]);
	            const e2 = prevMip.getElevation(blockBounds[2], blockBounds[3]);
	            const e3 = prevMip.getElevation(blockBounds[0], blockBounds[3]);
	            const l0 = prevMip.isLeaf(blockBounds[0], blockBounds[1]);
	            const l1 = prevMip.isLeaf(blockBounds[2], blockBounds[1]);
	            const l2 = prevMip.isLeaf(blockBounds[2], blockBounds[3]);
	            const l3 = prevMip.isLeaf(blockBounds[0], blockBounds[3]);
	            const minElevation = Math.min(e0.min, e1.min, e2.min, e3.min);
	            const maxElevation = Math.max(e0.max, e1.max, e2.max, e3.max);
	            const canConcatenate = l0 && l1 && l2 && l3;
	            mip.maximums.push(maxElevation);
	            mip.minimums.push(minElevation);
	            if (maxElevation - minElevation <= elevationDiffThreshold && canConcatenate) {
	                mip.leaves.push(1);
	            } else {
	                mip.leaves.push(0);
	            }
	        }
	        mips.push(mip);
	    }
	    return mips;
	}

	const unpackVectors = {
	    mapbox: [
	        6553.6,
	        25.6,
	        0.1,
	        10000
	    ],
	    terrarium: [
	        256,
	        1,
	        1 / 256,
	        32768
	    ]
	};
	class DEMData {
	    get tree() {
	        if (!this._tree)
	            this._buildQuadTree();
	        return this._tree;
	    }
	    constructor(uid, data, encoding, borderReady = false, buildQuadTree = false) {
	        this.uid = uid;
	        if (data.height !== data.width)
	            throw new RangeError('DEM tiles must be square');
	        if (encoding && encoding !== 'mapbox' && encoding !== 'terrarium')
	            return warnOnce(`"${ encoding }" is not a valid encoding type. Valid types include "mapbox" and "terrarium".`);
	        this.stride = data.height;
	        const dim = this.dim = data.height - 2;
	        const values = new Uint32Array(data.data.buffer);
	        this.pixels = new Uint8Array(data.data.buffer);
	        this.encoding = encoding || 'mapbox';
	        this.borderReady = borderReady;
	        if (borderReady)
	            return;
	        for (let x = 0; x < dim; x++) {
	            values[this._idx(-1, x)] = values[this._idx(0, x)];
	            values[this._idx(dim, x)] = values[this._idx(dim - 1, x)];
	            values[this._idx(x, -1)] = values[this._idx(x, 0)];
	            values[this._idx(x, dim)] = values[this._idx(x, dim - 1)];
	        }
	        values[this._idx(-1, -1)] = values[this._idx(0, 0)];
	        values[this._idx(dim, -1)] = values[this._idx(dim - 1, 0)];
	        values[this._idx(-1, dim)] = values[this._idx(0, dim - 1)];
	        values[this._idx(dim, dim)] = values[this._idx(dim - 1, dim - 1)];
	        if (buildQuadTree)
	            this._buildQuadTree();
	    }
	    _buildQuadTree() {
	        this._tree = new DemMinMaxQuadTree(this);
	    }
	    get(x, y, clampToEdge = false) {
	        if (clampToEdge) {
	            x = clamp(x, -1, this.dim);
	            y = clamp(y, -1, this.dim);
	        }
	        const index = this._idx(x, y) * 4;
	        const unpack = this.encoding === 'terrarium' ? this._unpackTerrarium : this._unpackMapbox;
	        return unpack(this.pixels[index], this.pixels[index + 1], this.pixels[index + 2]);
	    }
	    static getUnpackVector(encoding) {
	        return unpackVectors[encoding];
	    }
	    get unpackVector() {
	        return unpackVectors[this.encoding];
	    }
	    _idx(x, y) {
	        if (x < -1 || x >= this.dim + 1 || y < -1 || y >= this.dim + 1)
	            throw new RangeError('out of range source coordinates for DEM data');
	        return (y + 1) * this.stride + (x + 1);
	    }
	    _unpackMapbox(r, g, b) {
	        return (r * 256 * 256 + g * 256 + b) / 10 - 10000;
	    }
	    _unpackTerrarium(r, g, b) {
	        return r * 256 + g + b / 256 - 32768;
	    }
	    static pack(altitude, encoding) {
	        const color = [
	            0,
	            0,
	            0,
	            0
	        ];
	        const vector = DEMData.getUnpackVector(encoding);
	        let v = Math.floor((altitude + vector[3]) / vector[2]);
	        color[2] = v % 256;
	        v = Math.floor(v / 256);
	        color[1] = v % 256;
	        v = Math.floor(v / 256);
	        color[0] = v;
	        return color;
	    }
	    getPixels() {
	        return new RGBAImage({
	            width: this.stride,
	            height: this.stride
	        }, this.pixels);
	    }
	    backfillBorder(borderTile, dx, dy) {
	        if (this.dim !== borderTile.dim)
	            throw new Error('dem dimension mismatch');
	        let xMin = dx * this.dim, xMax = dx * this.dim + this.dim, yMin = dy * this.dim, yMax = dy * this.dim + this.dim;
	        switch (dx) {
	        case -1:
	            xMin = xMax - 1;
	            break;
	        case 1:
	            xMax = xMin + 1;
	            break;
	        }
	        switch (dy) {
	        case -1:
	            yMin = yMax - 1;
	            break;
	        case 1:
	            yMax = yMin + 1;
	            break;
	        }
	        const ox = -dx * this.dim;
	        const oy = -dy * this.dim;
	        for (let y = yMin; y < yMax; y++) {
	            for (let x = xMin; x < xMax; x++) {
	                const i = 4 * this._idx(x, y);
	                const j = 4 * this._idx(x + ox, y + oy);
	                this.pixels[i + 0] = borderTile.pixels[j + 0];
	                this.pixels[i + 1] = borderTile.pixels[j + 1];
	                this.pixels[i + 2] = borderTile.pixels[j + 2];
	                this.pixels[i + 3] = borderTile.pixels[j + 3];
	            }
	        }
	    }
	    onDeserialize() {
	        if (this._tree)
	            this._tree.dem = this;
	    }
	}
	register(DEMData, 'DEMData');
	register(DemMinMaxQuadTree, 'DemMinMaxQuadTree', { omit: ['dem'] });

	class TileCache {
	    constructor(max, onRemove) {
	        this.max = max;
	        this.onRemove = onRemove;
	        this.reset();
	    }
	    reset() {
	        for (const key in this.data) {
	            for (const removedData of this.data[key]) {
	                if (removedData.timeout)
	                    clearTimeout(removedData.timeout);
	                this.onRemove(removedData.value);
	            }
	        }
	        this.data = {};
	        this.order = [];
	        return this;
	    }
	    add(tileID, data, expiryTimeout) {
	        const key = tileID.wrapped().key;
	        if (this.data[key] === undefined) {
	            this.data[key] = [];
	        }
	        const dataWrapper = {
	            value: data,
	            timeout: undefined
	        };
	        if (expiryTimeout !== undefined) {
	            dataWrapper.timeout = setTimeout(() => {
	                this.remove(tileID, dataWrapper);
	            }, expiryTimeout);
	        }
	        this.data[key].push(dataWrapper);
	        this.order.push(key);
	        if (this.order.length > this.max) {
	            const removedData = this._getAndRemoveByKey(this.order[0]);
	            if (removedData)
	                this.onRemove(removedData);
	        }
	        return this;
	    }
	    has(tileID) {
	        return tileID.wrapped().key in this.data;
	    }
	    getAndRemove(tileID) {
	        if (!this.has(tileID)) {
	            return null;
	        }
	        return this._getAndRemoveByKey(tileID.wrapped().key);
	    }
	    _getAndRemoveByKey(key) {
	        const data = this.data[key].shift();
	        if (data.timeout)
	            clearTimeout(data.timeout);
	        if (this.data[key].length === 0) {
	            delete this.data[key];
	        }
	        this.order.splice(this.order.indexOf(key), 1);
	        return data.value;
	    }
	    getByKey(key) {
	        const data = this.data[key];
	        return data ? data[0].value : null;
	    }
	    get(tileID) {
	        if (!this.has(tileID)) {
	            return null;
	        }
	        const data = this.data[tileID.wrapped().key][0];
	        return data.value;
	    }
	    remove(tileID, value) {
	        if (!this.has(tileID)) {
	            return this;
	        }
	        const key = tileID.wrapped().key;
	        const dataIndex = value === undefined ? 0 : this.data[key].indexOf(value);
	        const data = this.data[key][dataIndex];
	        this.data[key].splice(dataIndex, 1);
	        if (data.timeout)
	            clearTimeout(data.timeout);
	        if (this.data[key].length === 0) {
	            delete this.data[key];
	        }
	        this.onRemove(data.value);
	        this.order.splice(this.order.indexOf(key), 1);
	        return this;
	    }
	    setMaxSize(max) {
	        this.max = max;
	        while (this.order.length > this.max) {
	            const removedData = this._getAndRemoveByKey(this.order[0]);
	            if (removedData)
	                this.onRemove(removedData);
	        }
	        return this;
	    }
	    filter(filterFn) {
	        const removed = [];
	        for (const key in this.data) {
	            for (const entry of this.data[key]) {
	                if (!filterFn(entry.value)) {
	                    removed.push(entry);
	                }
	            }
	        }
	        for (const r of removed) {
	            this.remove(r.value.tileID, r);
	        }
	    }
	}

	const ALWAYS$1 = 519;
	class DepthMode {
	    constructor(depthFunc, depthMask, depthRange) {
	        this.func = depthFunc;
	        this.mask = depthMask;
	        this.range = depthRange;
	    }
	}
	DepthMode.ReadOnly = false;
	DepthMode.ReadWrite = true;
	DepthMode.disabled = new DepthMode(ALWAYS$1, DepthMode.ReadOnly, [
	    0,
	    1
	]);

	const ALWAYS = 519;
	const KEEP = 7680;
	class StencilMode {
	    constructor(test, ref, mask, fail, depthFail, pass) {
	        this.test = test;
	        this.ref = ref;
	        this.mask = mask;
	        this.fail = fail;
	        this.depthFail = depthFail;
	        this.pass = pass;
	    }
	}
	StencilMode.disabled = new StencilMode({
	    func: ALWAYS,
	    mask: 0
	}, 0, 0, KEEP, KEEP, KEEP);

	const ZERO = 0;
	const ONE = 1;
	const ONE_MINUS_SRC_ALPHA = 771;
	class ColorMode {
	    constructor(blendFunction, blendColor, mask) {
	        this.blendFunction = blendFunction;
	        this.blendColor = blendColor;
	        this.mask = mask;
	    }
	}
	ColorMode.Replace = [
	    ONE,
	    ZERO
	];
	ColorMode.disabled = new ColorMode(ColorMode.Replace, Color$1.transparent, [
	    false,
	    false,
	    false,
	    false
	]);
	ColorMode.unblended = new ColorMode(ColorMode.Replace, Color$1.transparent, [
	    true,
	    true,
	    true,
	    true
	]);
	ColorMode.alphaBlended = new ColorMode([
	    ONE,
	    ONE_MINUS_SRC_ALPHA
	], Color$1.transparent, [
	    true,
	    true,
	    true,
	    true
	]);

	const BACK = 1029;
	const FRONT = 1028;
	const CCW = 2305;
	const CW = 2304;
	class CullFaceMode {
	    constructor(enable, mode, frontFace) {
	        this.enable = enable;
	        this.mode = mode;
	        this.frontFace = frontFace;
	    }
	}
	CullFaceMode.disabled = new CullFaceMode(false, BACK, CCW);
	CullFaceMode.backCCW = new CullFaceMode(true, BACK, CCW);
	CullFaceMode.backCW = new CullFaceMode(true, BACK, CW);
	CullFaceMode.frontCW = new CullFaceMode(true, FRONT, CW);
	CullFaceMode.frontCCW = new CullFaceMode(true, FRONT, CCW);

	class SourceCache extends Evented {
	    constructor(id, source, onlySymbols) {
	        super();
	        this.id = id;
	        this._onlySymbols = onlySymbols;
	        source.on('data', e => {
	            if (e.dataType === 'source' && e.sourceDataType === 'metadata')
	                this._sourceLoaded = true;
	            if (this._sourceLoaded && !this._paused && e.dataType === 'source' && e.sourceDataType === 'content') {
	                this.reload();
	                if (this.transform) {
	                    this.update(this.transform);
	                }
	            }
	        });
	        source.on('error', () => {
	            this._sourceErrored = true;
	        });
	        this._source = source;
	        this._tiles = {};
	        this._cache = new TileCache(0, this._unloadTile.bind(this));
	        this._timers = {};
	        this._cacheTimers = {};
	        this._minTileCacheSize = source.minTileCacheSize;
	        this._maxTileCacheSize = source.maxTileCacheSize;
	        this._loadedParentTiles = {};
	        this._coveredTiles = {};
	        this._state = new SourceFeatureState();
	        this._isRaster = this._source.type === 'raster' || this._source.type === 'raster-dem' || this._source.type === 'custom' && this._source._dataType === 'raster';
	    }
	    onAdd(map) {
	        this.map = map;
	        this._minTileCacheSize = this._minTileCacheSize === undefined && map ? map._minTileCacheSize : this._minTileCacheSize;
	        this._maxTileCacheSize = this._maxTileCacheSize === undefined && map ? map._maxTileCacheSize : this._maxTileCacheSize;
	    }
	    loaded() {
	        if (this._sourceErrored) {
	            return true;
	        }
	        if (!this._sourceLoaded) {
	            return false;
	        }
	        if (!this._source.loaded()) {
	            return false;
	        }
	        for (const t in this._tiles) {
	            const tile = this._tiles[t];
	            if (tile.state !== 'loaded' && tile.state !== 'errored')
	                return false;
	        }
	        return true;
	    }
	    getSource() {
	        return this._source;
	    }
	    pause() {
	        this._paused = true;
	    }
	    resume() {
	        if (!this._paused)
	            return;
	        const shouldReload = this._shouldReloadOnResume;
	        this._paused = false;
	        this._shouldReloadOnResume = false;
	        if (shouldReload)
	            this.reload();
	        if (this.transform)
	            this.update(this.transform);
	    }
	    _loadTile(tile, callback) {
	        tile.isSymbolTile = this._onlySymbols;
	        return this._source.loadTile(tile, callback);
	    }
	    _unloadTile(tile) {
	        if (this._source.unloadTile)
	            return this._source.unloadTile(tile, () => {
	            });
	    }
	    _abortTile(tile) {
	        if (this._source.abortTile)
	            return this._source.abortTile(tile, () => {
	            });
	    }
	    serialize() {
	        return this._source.serialize();
	    }
	    prepare(context) {
	        if (this._source.prepare) {
	            this._source.prepare();
	        }
	        this._state.coalesceChanges(this._tiles, this.map ? this.map.painter : null);
	        if (this._source.prepareTile) {
	            for (const i in this._tiles) {
	                const tile = this._tiles[i];
	                const data = this._source.prepareTile(tile);
	                if (data && this.map.painter.terrain) {
	                    this.map.painter.terrain._clearRenderCacheForTile(this.id, tile.tileID);
	                }
	                tile.upload(context);
	                tile.prepare(this.map.style.imageManager);
	            }
	            return;
	        }
	        for (const i in this._tiles) {
	            const tile = this._tiles[i];
	            tile.upload(context);
	            tile.prepare(this.map.style.imageManager);
	        }
	    }
	    getIds() {
	        return values(this._tiles).map(tile => tile.tileID).sort(compareTileId).map(id => id.key);
	    }
	    getRenderableIds(symbolLayer) {
	        const renderables = [];
	        for (const id in this._tiles) {
	            if (this._isIdRenderable(+id, symbolLayer))
	                renderables.push(this._tiles[id]);
	        }
	        if (symbolLayer) {
	            return renderables.sort((a_, b_) => {
	                const a = a_.tileID;
	                const b = b_.tileID;
	                const rotatedA = new pointGeometry(a.canonical.x, a.canonical.y)._rotate(this.transform.angle);
	                const rotatedB = new pointGeometry(b.canonical.x, b.canonical.y)._rotate(this.transform.angle);
	                return a.overscaledZ - b.overscaledZ || rotatedB.y - rotatedA.y || rotatedB.x - rotatedA.x;
	            }).map(tile => tile.tileID.key);
	        }
	        return renderables.map(tile => tile.tileID).sort(compareTileId).map(id => id.key);
	    }
	    hasRenderableParent(tileID) {
	        const parentTile = this.findLoadedParent(tileID, 0);
	        if (parentTile) {
	            return this._isIdRenderable(parentTile.tileID.key);
	        }
	        return false;
	    }
	    _isIdRenderable(id, symbolLayer) {
	        return this._tiles[id] && this._tiles[id].hasData() && !this._coveredTiles[id] && (symbolLayer || !this._tiles[id].holdingForFade());
	    }
	    reload() {
	        if (this._paused) {
	            this._shouldReloadOnResume = true;
	            return;
	        }
	        this._cache.reset();
	        for (const i in this._tiles) {
	            if (this._tiles[i].state !== 'errored')
	                this._reloadTile(+i, 'reloading');
	        }
	    }
	    _reloadTile(id, state) {
	        const tile = this._tiles[id];
	        if (!tile)
	            return;
	        if (tile.state !== 'loading') {
	            tile.state = state;
	        }
	        this._loadTile(tile, this._tileLoaded.bind(this, tile, id, state));
	    }
	    _tileLoaded(tile, id, previousState, err) {
	        if (err) {
	            tile.state = 'errored';
	            if (err.status !== 404)
	                this._source.fire(new ErrorEvent(err, { tile }));
	            else {
	                const updateForTerrain = this._source.type === 'raster-dem' && this.usedForTerrain;
	                if (updateForTerrain && this.map.painter.terrain) {
	                    const terrain = this.map.painter.terrain;
	                    this.update(this.transform, terrain.getScaledDemTileSize(), true);
	                    terrain.resetTileLookupCache(this.id);
	                } else {
	                    this.update(this.transform);
	                }
	            }
	            return;
	        }
	        tile.timeAdded = exported$1.now();
	        if (previousState === 'expired')
	            tile.refreshedUponExpiration = true;
	        this._setTileReloadTimer(id, tile);
	        if (this._source.type === 'raster-dem' && tile.dem)
	            this._backfillDEM(tile);
	        this._state.initializeTileState(tile, this.map ? this.map.painter : null);
	        this._source.fire(new Event('data', {
	            dataType: 'source',
	            tile,
	            coord: tile.tileID,
	            'sourceCacheId': this.id
	        }));
	    }
	    _backfillDEM(tile) {
	        const renderables = this.getRenderableIds();
	        for (let i = 0; i < renderables.length; i++) {
	            const borderId = renderables[i];
	            if (tile.neighboringTiles && tile.neighboringTiles[borderId]) {
	                const borderTile = this.getTileByID(borderId);
	                fillBorder(tile, borderTile);
	                fillBorder(borderTile, tile);
	            }
	        }
	        function fillBorder(tile, borderTile) {
	            if (!tile.dem || tile.dem.borderReady)
	                return;
	            tile.needsHillshadePrepare = true;
	            tile.needsDEMTextureUpload = true;
	            let dx = borderTile.tileID.canonical.x - tile.tileID.canonical.x;
	            const dy = borderTile.tileID.canonical.y - tile.tileID.canonical.y;
	            const dim = Math.pow(2, tile.tileID.canonical.z);
	            const borderId = borderTile.tileID.key;
	            if (dx === 0 && dy === 0)
	                return;
	            if (Math.abs(dy) > 1) {
	                return;
	            }
	            if (Math.abs(dx) > 1) {
	                if (Math.abs(dx + dim) === 1) {
	                    dx += dim;
	                } else if (Math.abs(dx - dim) === 1) {
	                    dx -= dim;
	                }
	            }
	            if (!borderTile.dem || !tile.dem)
	                return;
	            tile.dem.backfillBorder(borderTile.dem, dx, dy);
	            if (tile.neighboringTiles && tile.neighboringTiles[borderId])
	                tile.neighboringTiles[borderId].backfilled = true;
	        }
	    }
	    getTile(tileID) {
	        return this.getTileByID(tileID.key);
	    }
	    getTileByID(id) {
	        return this._tiles[id];
	    }
	    _retainLoadedChildren(idealTiles, zoom, maxCoveringZoom, retain) {
	        for (const id in this._tiles) {
	            let tile = this._tiles[id];
	            if (retain[id] || !tile.hasData() || tile.tileID.overscaledZ <= zoom || tile.tileID.overscaledZ > maxCoveringZoom)
	                continue;
	            let topmostLoadedID = tile.tileID;
	            while (tile && tile.tileID.overscaledZ > zoom + 1) {
	                const parentID = tile.tileID.scaledTo(tile.tileID.overscaledZ - 1);
	                tile = this._tiles[parentID.key];
	                if (tile && tile.hasData()) {
	                    topmostLoadedID = parentID;
	                }
	            }
	            let tileID = topmostLoadedID;
	            while (tileID.overscaledZ > zoom) {
	                tileID = tileID.scaledTo(tileID.overscaledZ - 1);
	                if (idealTiles[tileID.key]) {
	                    retain[topmostLoadedID.key] = topmostLoadedID;
	                    break;
	                }
	            }
	        }
	    }
	    findLoadedParent(tileID, minCoveringZoom) {
	        if (tileID.key in this._loadedParentTiles) {
	            const parent = this._loadedParentTiles[tileID.key];
	            if (parent && parent.tileID.overscaledZ >= minCoveringZoom) {
	                return parent;
	            } else {
	                return null;
	            }
	        }
	        for (let z = tileID.overscaledZ - 1; z >= minCoveringZoom; z--) {
	            const parentTileID = tileID.scaledTo(z);
	            const tile = this._getLoadedTile(parentTileID);
	            if (tile) {
	                return tile;
	            }
	        }
	    }
	    _getLoadedTile(tileID) {
	        const tile = this._tiles[tileID.key];
	        if (tile && tile.hasData()) {
	            return tile;
	        }
	        const cachedTile = this._cache.getByKey(this._source.reparseOverscaled ? tileID.wrapped().key : tileID.canonical.key);
	        return cachedTile;
	    }
	    updateCacheSize(transform, tileSize) {
	        tileSize = tileSize || this._source.tileSize;
	        const widthInTiles = Math.ceil(transform.width / tileSize) + 1;
	        const heightInTiles = Math.ceil(transform.height / tileSize) + 1;
	        const approxTilesInView = widthInTiles * heightInTiles;
	        const commonZoomRange = 5;
	        const viewDependentMaxSize = Math.floor(approxTilesInView * commonZoomRange);
	        const minSize = typeof this._minTileCacheSize === 'number' ? Math.max(this._minTileCacheSize, viewDependentMaxSize) : viewDependentMaxSize;
	        const maxSize = typeof this._maxTileCacheSize === 'number' ? Math.min(this._maxTileCacheSize, minSize) : minSize;
	        this._cache.setMaxSize(maxSize);
	    }
	    handleWrapJump(lng) {
	        const prevLng = this._prevLng === undefined ? lng : this._prevLng;
	        const lngDifference = lng - prevLng;
	        const worldDifference = lngDifference / 360;
	        const wrapDelta = Math.round(worldDifference);
	        this._prevLng = lng;
	        if (wrapDelta) {
	            const tiles = {};
	            for (const key in this._tiles) {
	                const tile = this._tiles[key];
	                tile.tileID = tile.tileID.unwrapTo(tile.tileID.wrap + wrapDelta);
	                tiles[tile.tileID.key] = tile;
	            }
	            this._tiles = tiles;
	            for (const id in this._timers) {
	                clearTimeout(this._timers[id]);
	                delete this._timers[id];
	            }
	            for (const id in this._tiles) {
	                const tile = this._tiles[id];
	                this._setTileReloadTimer(+id, tile);
	            }
	        }
	    }
	    update(transform, tileSize, updateForTerrain) {
	        this.transform = transform;
	        if (!this._sourceLoaded || this._paused || this.transform.freezeTileCoverage) {
	            return;
	        }
	        if (this.usedForTerrain && !updateForTerrain) {
	            return;
	        }
	        this.updateCacheSize(transform, tileSize);
	        if (this.transform.projection.name !== 'globe') {
	            this.handleWrapJump(this.transform.center.lng);
	        }
	        this._coveredTiles = {};
	        let idealTileIDs;
	        if (!this.used && !this.usedForTerrain) {
	            idealTileIDs = [];
	        } else if (this._source.tileID) {
	            idealTileIDs = transform.getVisibleUnwrappedCoordinates(this._source.tileID).map(unwrapped => new OverscaledTileID(unwrapped.canonical.z, unwrapped.wrap, unwrapped.canonical.z, unwrapped.canonical.x, unwrapped.canonical.y));
	        } else {
	            idealTileIDs = transform.coveringTiles({
	                tileSize: tileSize || this._source.tileSize,
	                minzoom: this._source.minzoom,
	                maxzoom: this._source.maxzoom,
	                roundZoom: this._source.roundZoom && !updateForTerrain,
	                reparseOverscaled: this._source.reparseOverscaled,
	                isTerrainDEM: this.usedForTerrain
	            });
	            if (this._source.hasTile) {
	                idealTileIDs = idealTileIDs.filter(coord => this._source.hasTile(coord));
	            }
	        }
	        const retain = this._updateRetainedTiles(idealTileIDs);
	        if (isRasterType(this._source.type) && idealTileIDs.length !== 0) {
	            const parentsForFading = {};
	            const fadingTiles = {};
	            const ids = Object.keys(retain);
	            for (const id of ids) {
	                const tileID = retain[id];
	                const tile = this._tiles[id];
	                if (!tile || tile.fadeEndTime && tile.fadeEndTime <= exported$1.now())
	                    continue;
	                const parentTile = this.findLoadedParent(tileID, Math.max(tileID.overscaledZ - SourceCache.maxOverzooming, this._source.minzoom));
	                if (parentTile) {
	                    this._addTile(parentTile.tileID);
	                    parentsForFading[parentTile.tileID.key] = parentTile.tileID;
	                }
	                fadingTiles[id] = tileID;
	            }
	            const minZoom = idealTileIDs[idealTileIDs.length - 1].overscaledZ;
	            for (const id in this._tiles) {
	                const childTile = this._tiles[id];
	                if (retain[id] || !childTile.hasData()) {
	                    continue;
	                }
	                let parentID = childTile.tileID;
	                while (parentID.overscaledZ > minZoom) {
	                    parentID = parentID.scaledTo(parentID.overscaledZ - 1);
	                    const tile = this._tiles[parentID.key];
	                    if (tile && tile.hasData() && fadingTiles[parentID.key]) {
	                        retain[id] = childTile.tileID;
	                        break;
	                    }
	                }
	            }
	            for (const id in parentsForFading) {
	                if (!retain[id]) {
	                    this._coveredTiles[id] = true;
	                    retain[id] = parentsForFading[id];
	                }
	            }
	        }
	        for (const retainedId in retain) {
	            this._tiles[retainedId].clearFadeHold();
	        }
	        const remove = keysDifference(this._tiles, retain);
	        for (const tileID of remove) {
	            const tile = this._tiles[tileID];
	            if (tile.hasSymbolBuckets && !tile.holdingForFade()) {
	                tile.setHoldDuration(this.map._fadeDuration);
	            } else if (!tile.hasSymbolBuckets || tile.symbolFadeFinished()) {
	                this._removeTile(+tileID);
	            }
	        }
	        this._updateLoadedParentTileCache();
	        if (this._onlySymbols && this._source.afterUpdate) {
	            this._source.afterUpdate();
	        }
	    }
	    releaseSymbolFadeTiles() {
	        for (const id in this._tiles) {
	            if (this._tiles[id].holdingForFade()) {
	                this._removeTile(+id);
	            }
	        }
	    }
	    _updateRetainedTiles(idealTileIDs) {
	        const retain = {};
	        if (idealTileIDs.length === 0) {
	            return retain;
	        }
	        const checked = {};
	        const minZoom = idealTileIDs.reduce((min, id) => Math.min(min, id.overscaledZ), Infinity);
	        const maxZoom = idealTileIDs[0].overscaledZ;
	        const minCoveringZoom = Math.max(maxZoom - SourceCache.maxOverzooming, this._source.minzoom);
	        const maxCoveringZoom = Math.max(maxZoom + SourceCache.maxUnderzooming, this._source.minzoom);
	        const missingTiles = {};
	        for (const tileID of idealTileIDs) {
	            const tile = this._addTile(tileID);
	            retain[tileID.key] = tileID;
	            if (tile.hasData())
	                continue;
	            if (minZoom < this._source.maxzoom) {
	                missingTiles[tileID.key] = tileID;
	            }
	        }
	        this._retainLoadedChildren(missingTiles, minZoom, maxCoveringZoom, retain);
	        for (const tileID of idealTileIDs) {
	            let tile = this._tiles[tileID.key];
	            if (tile.hasData())
	                continue;
	            if (tileID.canonical.z >= this._source.maxzoom) {
	                const childCoord = tileID.children(this._source.maxzoom)[0];
	                const childTile = this.getTile(childCoord);
	                if (!!childTile && childTile.hasData()) {
	                    retain[childCoord.key] = childCoord;
	                    continue;
	                }
	            } else {
	                const children = tileID.children(this._source.maxzoom);
	                if (retain[children[0].key] && retain[children[1].key] && retain[children[2].key] && retain[children[3].key])
	                    continue;
	            }
	            let parentWasRequested = tile.wasRequested();
	            for (let overscaledZ = tileID.overscaledZ - 1; overscaledZ >= minCoveringZoom; --overscaledZ) {
	                const parentId = tileID.scaledTo(overscaledZ);
	                if (checked[parentId.key])
	                    break;
	                checked[parentId.key] = true;
	                tile = this.getTile(parentId);
	                if (!tile && parentWasRequested) {
	                    tile = this._addTile(parentId);
	                }
	                if (tile) {
	                    retain[parentId.key] = parentId;
	                    parentWasRequested = tile.wasRequested();
	                    if (tile.hasData())
	                        break;
	                }
	            }
	        }
	        return retain;
	    }
	    _updateLoadedParentTileCache() {
	        this._loadedParentTiles = {};
	        for (const tileKey in this._tiles) {
	            const path = [];
	            let parentTile;
	            let currentId = this._tiles[tileKey].tileID;
	            while (currentId.overscaledZ > 0) {
	                if (currentId.key in this._loadedParentTiles) {
	                    parentTile = this._loadedParentTiles[currentId.key];
	                    break;
	                }
	                path.push(currentId.key);
	                const parentId = currentId.scaledTo(currentId.overscaledZ - 1);
	                parentTile = this._getLoadedTile(parentId);
	                if (parentTile) {
	                    break;
	                }
	                currentId = parentId;
	            }
	            for (const key of path) {
	                this._loadedParentTiles[key] = parentTile;
	            }
	        }
	    }
	    _addTile(tileID) {
	        let tile = this._tiles[tileID.key];
	        if (tile) {
	            if (this._source.prepareTile)
	                this._source.prepareTile(tile);
	            return tile;
	        }
	        tile = this._cache.getAndRemove(tileID);
	        if (tile) {
	            this._setTileReloadTimer(tileID.key, tile);
	            tile.tileID = tileID;
	            this._state.initializeTileState(tile, this.map ? this.map.painter : null);
	            if (this._cacheTimers[tileID.key]) {
	                clearTimeout(this._cacheTimers[tileID.key]);
	                delete this._cacheTimers[tileID.key];
	                this._setTileReloadTimer(tileID.key, tile);
	            }
	        }
	        const cached = Boolean(tile);
	        if (!cached) {
	            const painter = this.map ? this.map.painter : null;
	            tile = new Tile(tileID, this._source.tileSize * tileID.overscaleFactor(), this.transform.tileZoom, painter, this._isRaster);
	            if (this._source.prepareTile) {
	                const data = this._source.prepareTile(tile);
	                if (!data)
	                    this._loadTile(tile, this._tileLoaded.bind(this, tile, tileID.key, tile.state));
	            } else {
	                this._loadTile(tile, this._tileLoaded.bind(this, tile, tileID.key, tile.state));
	            }
	        }
	        if (!tile)
	            return null;
	        tile.uses++;
	        this._tiles[tileID.key] = tile;
	        if (!cached)
	            this._source.fire(new Event('dataloading', {
	                tile,
	                coord: tile.tileID,
	                dataType: 'source'
	            }));
	        return tile;
	    }
	    _setTileReloadTimer(id, tile) {
	        if (id in this._timers) {
	            clearTimeout(this._timers[id]);
	            delete this._timers[id];
	        }
	        const expiryTimeout = tile.getExpiryTimeout();
	        if (expiryTimeout) {
	            this._timers[id] = setTimeout(() => {
	                this._reloadTile(id, 'expired');
	                delete this._timers[id];
	            }, expiryTimeout);
	        }
	    }
	    _removeTile(id) {
	        const tile = this._tiles[id];
	        if (!tile)
	            return;
	        tile.uses--;
	        delete this._tiles[id];
	        if (this._timers[id]) {
	            clearTimeout(this._timers[id]);
	            delete this._timers[id];
	        }
	        if (tile.uses > 0)
	            return;
	        if (tile.hasData() && tile.state !== 'reloading') {
	            this._cache.add(tile.tileID, tile, tile.getExpiryTimeout());
	        } else {
	            tile.aborted = true;
	            this._abortTile(tile);
	            this._unloadTile(tile);
	        }
	    }
	    clearTiles() {
	        this._shouldReloadOnResume = false;
	        this._paused = false;
	        for (const id in this._tiles)
	            this._removeTile(+id);
	        if (this._source._clear)
	            this._source._clear();
	        this._cache.reset();
	        if (this.map && this.usedForTerrain && this.map.painter.terrain) {
	            this.map.painter.terrain.resetTileLookupCache(this.id);
	        }
	    }
	    tilesIn(queryGeometry, use3DQuery, visualizeQueryGeometry) {
	        const tileResults = [];
	        const transform = this.transform;
	        if (!transform)
	            return tileResults;
	        const isGlobe = transform.projection.name === 'globe';
	        const centerX = mercatorXfromLng(transform.center.lng);
	        for (const tileID in this._tiles) {
	            const tile = this._tiles[tileID];
	            if (visualizeQueryGeometry) {
	                tile.clearQueryDebugViz();
	            }
	            if (tile.holdingForFade()) {
	                continue;
	            }
	            let tilesToCheck;
	            if (isGlobe) {
	                const id = tile.tileID.canonical;
	                if (id.z === 0) {
	                    const distances = [
	                        Math.abs(clamp(centerX, ...tileBoundsX(id, -1)) - centerX),
	                        Math.abs(clamp(centerX, ...tileBoundsX(id, 1)) - centerX)
	                    ];
	                    tilesToCheck = [
	                        0,
	                        distances.indexOf(Math.min(...distances)) * 2 - 1
	                    ];
	                } else {
	                    const distances = [
	                        Math.abs(clamp(centerX, ...tileBoundsX(id, -1)) - centerX),
	                        Math.abs(clamp(centerX, ...tileBoundsX(id, 0)) - centerX),
	                        Math.abs(clamp(centerX, ...tileBoundsX(id, 1)) - centerX)
	                    ];
	                    tilesToCheck = [distances.indexOf(Math.min(...distances)) - 1];
	                }
	            } else {
	                tilesToCheck = [0];
	            }
	            for (const wrap of tilesToCheck) {
	                const tileResult = queryGeometry.containsTile(tile, transform, use3DQuery, wrap);
	                if (tileResult) {
	                    tileResults.push(tileResult);
	                }
	            }
	        }
	        return tileResults;
	    }
	    getVisibleCoordinates(symbolLayer) {
	        const coords = this.getRenderableIds(symbolLayer).map(id => this._tiles[id].tileID);
	        for (const coord of coords) {
	            coord.projMatrix = this.transform.calculateProjMatrix(coord.toUnwrapped());
	        }
	        return coords;
	    }
	    hasTransition() {
	        if (this._source.hasTransition()) {
	            return true;
	        }
	        if (isRasterType(this._source.type)) {
	            for (const id in this._tiles) {
	                const tile = this._tiles[id];
	                if (tile.fadeEndTime !== undefined && tile.fadeEndTime >= exported$1.now()) {
	                    return true;
	                }
	            }
	        }
	        return false;
	    }
	    setFeatureState(sourceLayer, featureId, state) {
	        sourceLayer = sourceLayer || '_geojsonTileLayer';
	        this._state.updateState(sourceLayer, featureId, state);
	    }
	    removeFeatureState(sourceLayer, featureId, key) {
	        sourceLayer = sourceLayer || '_geojsonTileLayer';
	        this._state.removeFeatureState(sourceLayer, featureId, key);
	    }
	    getFeatureState(sourceLayer, featureId) {
	        sourceLayer = sourceLayer || '_geojsonTileLayer';
	        return this._state.getState(sourceLayer, featureId);
	    }
	    setDependencies(tileKey, namespace, dependencies) {
	        const tile = this._tiles[tileKey];
	        if (tile) {
	            tile.setDependencies(namespace, dependencies);
	        }
	    }
	    reloadTilesForDependencies(namespaces, keys) {
	        for (const id in this._tiles) {
	            const tile = this._tiles[id];
	            if (tile.hasDependency(namespaces, keys)) {
	                this._reloadTile(+id, 'reloading');
	            }
	        }
	        this._cache.filter(tile => !tile.hasDependency(namespaces, keys));
	    }
	    _preloadTiles(transform, callback) {
	        const coveringTilesIDs = new Map();
	        const transforms = Array.isArray(transform) ? transform : [transform];
	        const terrain = this.map.painter.terrain;
	        const tileSize = this.usedForTerrain && terrain ? terrain.getScaledDemTileSize() : this._source.tileSize;
	        for (const tr of transforms) {
	            const tileIDs = tr.coveringTiles({
	                tileSize,
	                minzoom: this._source.minzoom,
	                maxzoom: this._source.maxzoom,
	                roundZoom: this._source.roundZoom && !this.usedForTerrain,
	                reparseOverscaled: this._source.reparseOverscaled,
	                isTerrainDEM: this.usedForTerrain
	            });
	            for (const tileID of tileIDs) {
	                coveringTilesIDs.set(tileID.key, tileID);
	            }
	            if (this.usedForTerrain) {
	                tr.updateElevation(false);
	            }
	        }
	        const tileIDs = Array.from(coveringTilesIDs.values());
	        asyncAll(tileIDs, (tileID, done) => {
	            const tile = new Tile(tileID, this._source.tileSize * tileID.overscaleFactor(), this.transform.tileZoom, this.map.painter, this._isRaster);
	            this._loadTile(tile, err => {
	                if (this._source.type === 'raster-dem' && tile.dem)
	                    this._backfillDEM(tile);
	                done(err, tile);
	            });
	        }, callback);
	    }
	}
	SourceCache.maxOverzooming = 10;
	SourceCache.maxUnderzooming = 3;
	function compareTileId(a, b) {
	    const aWrap = Math.abs(a.wrap * 2) - +(a.wrap < 0);
	    const bWrap = Math.abs(b.wrap * 2) - +(b.wrap < 0);
	    return a.overscaledZ - b.overscaledZ || bWrap - aWrap || b.canonical.y - a.canonical.y || b.canonical.x - a.canonical.x;
	}
	function isRasterType(type) {
	    return type === 'raster' || type === 'image' || type === 'video';
	}
	function tileBoundsX(id, wrap) {
	    const tiles = 1 << id.z;
	    return [
	        id.x / tiles + wrap,
	        (id.x + 1) / tiles + wrap
	    ];
	}

	class Elevation {
	    isDataAvailableAtPoint(point) {
	        const sourceCache = this._source();
	        if (!sourceCache || point.y < 0 || point.y > 1) {
	            return false;
	        }
	        const cache = sourceCache;
	        const z = cache.getSource().maxzoom;
	        const tiles = 1 << z;
	        const wrap = Math.floor(point.x);
	        const px = point.x - wrap;
	        const x = Math.floor(px * tiles);
	        const y = Math.floor(point.y * tiles);
	        const demTile = this.findDEMTileFor(new OverscaledTileID(z, wrap, z, x, y));
	        return !!(demTile && demTile.dem);
	    }
	    getAtPointOrZero(point, defaultIfNotLoaded = 0) {
	        return this.getAtPoint(point, defaultIfNotLoaded) || 0;
	    }
	    getAtPoint(point, defaultIfNotLoaded, exaggerated = true) {
	        if (defaultIfNotLoaded == null)
	            defaultIfNotLoaded = null;
	        const src = this._source();
	        if (!src)
	            return defaultIfNotLoaded;
	        if (point.y < 0 || point.y > 1) {
	            return defaultIfNotLoaded;
	        }
	        const cache = src;
	        const z = cache.getSource().maxzoom;
	        const tiles = 1 << z;
	        const wrap = Math.floor(point.x);
	        const px = point.x - wrap;
	        const tileID = new OverscaledTileID(z, wrap, z, Math.floor(px * tiles), Math.floor(point.y * tiles));
	        const demTile = this.findDEMTileFor(tileID);
	        if (!(demTile && demTile.dem)) {
	            return defaultIfNotLoaded;
	        }
	        const dem = demTile.dem;
	        const tilesAtTileZoom = 1 << demTile.tileID.canonical.z;
	        const x = (px * tilesAtTileZoom - demTile.tileID.canonical.x) * dem.dim;
	        const y = (point.y * tilesAtTileZoom - demTile.tileID.canonical.y) * dem.dim;
	        const i = Math.floor(x);
	        const j = Math.floor(y);
	        const exaggeration = exaggerated ? this.exaggeration() : 1;
	        return exaggeration * number(number(dem.get(i, j), dem.get(i, j + 1), y - j), number(dem.get(i + 1, j), dem.get(i + 1, j + 1), y - j), x - i);
	    }
	    getAtTileOffset(tileID, x, y) {
	        const tilesAtTileZoom = 1 << tileID.canonical.z;
	        return this.getAtPointOrZero(new MercatorCoordinate(tileID.wrap + (tileID.canonical.x + x / EXTENT) / tilesAtTileZoom, (tileID.canonical.y + y / EXTENT) / tilesAtTileZoom));
	    }
	    getAtTileOffsetFunc(tileID, lat, worldSize, projection) {
	        return p => {
	            const elevation = this.getAtTileOffset(tileID, p.x, p.y);
	            const upVector = projection.upVector(tileID.canonical, p.x, p.y);
	            const upVectorScale = projection.upVectorScale(tileID.canonical, lat, worldSize).metersToTile;
	            scale$1(upVector, upVector, elevation * upVectorScale);
	            return upVector;
	        };
	    }
	    getForTilePoints(tileID, points, interpolated, useDemTile) {
	        const helper = DEMSampler.create(this, tileID, useDemTile);
	        if (!helper) {
	            return false;
	        }
	        points.forEach(p => {
	            p[2] = this.exaggeration() * helper.getElevationAt(p[0], p[1], interpolated);
	        });
	        return true;
	    }
	    getMinMaxForTile(tileID) {
	        const demTile = this.findDEMTileFor(tileID);
	        if (!(demTile && demTile.dem)) {
	            return null;
	        }
	        const dem = demTile.dem;
	        const tree = dem.tree;
	        const demTileID = demTile.tileID;
	        const scale = 1 << tileID.canonical.z - demTileID.canonical.z;
	        let xOffset = tileID.canonical.x / scale - demTileID.canonical.x;
	        let yOffset = tileID.canonical.y / scale - demTileID.canonical.y;
	        let index = 0;
	        for (let i = 0; i < tileID.canonical.z - demTileID.canonical.z; i++) {
	            if (tree.leaves[index])
	                break;
	            xOffset *= 2;
	            yOffset *= 2;
	            const childOffset = 2 * Math.floor(yOffset) + Math.floor(xOffset);
	            index = tree.childOffsets[index] + childOffset;
	            xOffset = xOffset % 1;
	            yOffset = yOffset % 1;
	        }
	        return {
	            min: this.exaggeration() * tree.minimums[index],
	            max: this.exaggeration() * tree.maximums[index]
	        };
	    }
	    getMinElevationBelowMSL() {
	        throw new Error('Pure virtual method called.');
	    }
	    raycast(position, dir, exaggeration) {
	        throw new Error('Pure virtual method called.');
	    }
	    pointCoordinate(screenPoint) {
	        throw new Error('Pure virtual method called.');
	    }
	    _source() {
	        throw new Error('Pure virtual method called.');
	    }
	    exaggeration() {
	        throw new Error('Pure virtual method called.');
	    }
	    findDEMTileFor(_) {
	        throw new Error('Pure virtual method called.');
	    }
	    get visibleDemTiles() {
	        throw new Error('Getter must be implemented in subclass.');
	    }
	}
	class DEMSampler {
	    constructor(demTile, scale, offset) {
	        this._demTile = demTile;
	        this._dem = this._demTile.dem;
	        this._scale = scale;
	        this._offset = offset;
	    }
	    static create(elevation, tileID, useDemTile) {
	        const demTile = useDemTile || elevation.findDEMTileFor(tileID);
	        if (!(demTile && demTile.dem)) {
	            return;
	        }
	        const dem = demTile.dem;
	        const demTileID = demTile.tileID;
	        const scale = 1 << tileID.canonical.z - demTileID.canonical.z;
	        const xOffset = (tileID.canonical.x / scale - demTileID.canonical.x) * dem.dim;
	        const yOffset = (tileID.canonical.y / scale - demTileID.canonical.y) * dem.dim;
	        const k = demTile.tileSize / EXTENT / scale;
	        return new DEMSampler(demTile, k, [
	            xOffset,
	            yOffset
	        ]);
	    }
	    tileCoordToPixel(x, y) {
	        const px = x * this._scale + this._offset[0];
	        const py = y * this._scale + this._offset[1];
	        const i = Math.floor(px);
	        const j = Math.floor(py);
	        return new pointGeometry(i, j);
	    }
	    getElevationAt(x, y, interpolated, clampToEdge) {
	        const px = x * this._scale + this._offset[0];
	        const py = y * this._scale + this._offset[1];
	        const i = Math.floor(px);
	        const j = Math.floor(py);
	        const dem = this._dem;
	        clampToEdge = !!clampToEdge;
	        return interpolated ? number(number(dem.get(i, j, clampToEdge), dem.get(i, j + 1, clampToEdge), py - j), number(dem.get(i + 1, j, clampToEdge), dem.get(i + 1, j + 1, clampToEdge), py - j), px - i) : dem.get(i, j, clampToEdge);
	    }
	    getElevationAtPixel(x, y, clampToEdge) {
	        return this._dem.get(x, y, !!clampToEdge);
	    }
	    getMeterToDEM(lat) {
	        return (1 << this._demTile.tileID.canonical.z) * mercatorZfromAltitude(1, lat) * this._dem.stride;
	    }
	}

	class FeatureIndex {
	    constructor(tileID, promoteId) {
	        this.tileID = tileID;
	        this.x = tileID.canonical.x;
	        this.y = tileID.canonical.y;
	        this.z = tileID.canonical.z;
	        this.grid = new gridIndex(EXTENT, 16, 0);
	        this.featureIndexArray = new FeatureIndexArray();
	        this.promoteId = promoteId;
	    }
	    insert(feature, geometry, featureIndex, sourceLayerIndex, bucketIndex, layoutVertexArrayOffset = 0) {
	        const key = this.featureIndexArray.length;
	        this.featureIndexArray.emplaceBack(featureIndex, sourceLayerIndex, bucketIndex, layoutVertexArrayOffset);
	        const grid = this.grid;
	        for (let r = 0; r < geometry.length; r++) {
	            const ring = geometry[r];
	            const bbox = [
	                Infinity,
	                Infinity,
	                -Infinity,
	                -Infinity
	            ];
	            for (let i = 0; i < ring.length; i++) {
	                const p = ring[i];
	                bbox[0] = Math.min(bbox[0], p.x);
	                bbox[1] = Math.min(bbox[1], p.y);
	                bbox[2] = Math.max(bbox[2], p.x);
	                bbox[3] = Math.max(bbox[3], p.y);
	            }
	            if (bbox[0] < EXTENT && bbox[1] < EXTENT && bbox[2] >= 0 && bbox[3] >= 0) {
	                grid.insert(key, bbox[0], bbox[1], bbox[2], bbox[3]);
	            }
	        }
	    }
	    loadVTLayers() {
	        if (!this.vtLayers) {
	            this.vtLayers = new vectorTile.VectorTile(new pbf(this.rawTileData)).layers;
	            this.sourceLayerCoder = new DictionaryCoder(this.vtLayers ? Object.keys(this.vtLayers).sort() : ['_geojsonTileLayer']);
	            this.vtFeatures = {};
	            for (const layer in this.vtLayers) {
	                this.vtFeatures[layer] = [];
	            }
	        }
	        return this.vtLayers;
	    }
	    query(args, styleLayers, serializedLayers, sourceFeatureState) {
	        this.loadVTLayers();
	        const params = args.params || {}, filter = createFilter(params.filter);
	        const tilespaceGeometry = args.tileResult;
	        const transform = args.transform;
	        const bounds = tilespaceGeometry.bufferedTilespaceBounds;
	        const queryPredicate = (bx1, by1, bx2, by2) => {
	            return polygonIntersectsBox(tilespaceGeometry.bufferedTilespaceGeometry, bx1, by1, bx2, by2);
	        };
	        const matching = this.grid.query(bounds.min.x, bounds.min.y, bounds.max.x, bounds.max.y, queryPredicate);
	        matching.sort(topDownFeatureComparator);
	        let elevationHelper = null;
	        if (transform.elevation && matching.length > 0) {
	            elevationHelper = DEMSampler.create(transform.elevation, this.tileID);
	        }
	        const result = {};
	        let previousIndex;
	        for (let k = 0; k < matching.length; k++) {
	            const index = matching[k];
	            if (index === previousIndex)
	                continue;
	            previousIndex = index;
	            const match = this.featureIndexArray.get(index);
	            let featureGeometry = null;
	            this.loadMatchingFeature(result, match, filter, params.layers, params.availableImages, styleLayers, serializedLayers, sourceFeatureState, (feature, styleLayer, featureState, layoutVertexArrayOffset = 0) => {
	                if (!featureGeometry) {
	                    featureGeometry = loadGeometry(feature, this.tileID.canonical, args.tileTransform);
	                }
	                return styleLayer.queryIntersectsFeature(tilespaceGeometry, feature, featureState, featureGeometry, this.z, args.transform, args.pixelPosMatrix, elevationHelper, layoutVertexArrayOffset);
	            });
	        }
	        return result;
	    }
	    loadMatchingFeature(result, featureIndexData, filter, filterLayerIDs, availableImages, styleLayers, serializedLayers, sourceFeatureState, intersectionTest) {
	        const {featureIndex, bucketIndex, sourceLayerIndex, layoutVertexArrayOffset} = featureIndexData;
	        const layerIDs = this.bucketLayerIDs[bucketIndex];
	        if (filterLayerIDs && !arraysIntersect(filterLayerIDs, layerIDs))
	            return;
	        const sourceLayerName = this.sourceLayerCoder.decode(sourceLayerIndex);
	        const sourceLayer = this.vtLayers[sourceLayerName];
	        const feature = sourceLayer.feature(featureIndex);
	        if (filter.needGeometry) {
	            const evaluationFeature = toEvaluationFeature(feature, true);
	            if (!filter.filter(new EvaluationParameters(this.tileID.overscaledZ), evaluationFeature, this.tileID.canonical)) {
	                return;
	            }
	        } else if (!filter.filter(new EvaluationParameters(this.tileID.overscaledZ), feature)) {
	            return;
	        }
	        const id = this.getId(feature, sourceLayerName);
	        for (let l = 0; l < layerIDs.length; l++) {
	            const layerID = layerIDs[l];
	            if (filterLayerIDs && filterLayerIDs.indexOf(layerID) < 0) {
	                continue;
	            }
	            const styleLayer = styleLayers[layerID];
	            if (!styleLayer)
	                continue;
	            let featureState = {};
	            if (id !== undefined && sourceFeatureState) {
	                featureState = sourceFeatureState.getState(styleLayer.sourceLayer || '_geojsonTileLayer', id);
	            }
	            const serializedLayer = extend$1({}, serializedLayers[layerID]);
	            serializedLayer.paint = evaluateProperties(serializedLayer.paint, styleLayer.paint, feature, featureState, availableImages);
	            serializedLayer.layout = evaluateProperties(serializedLayer.layout, styleLayer.layout, feature, featureState, availableImages);
	            const intersectionZ = !intersectionTest || intersectionTest(feature, styleLayer, featureState, layoutVertexArrayOffset);
	            if (!intersectionZ) {
	                continue;
	            }
	            const geojsonFeature = new Feature(feature, this.z, this.x, this.y, id);
	            geojsonFeature.layer = serializedLayer;
	            let layerResult = result[layerID];
	            if (layerResult === undefined) {
	                layerResult = result[layerID] = [];
	            }
	            layerResult.push({
	                featureIndex,
	                feature: geojsonFeature,
	                intersectionZ
	            });
	        }
	    }
	    lookupSymbolFeatures(symbolFeatureIndexes, serializedLayers, bucketIndex, sourceLayerIndex, filterSpec, filterLayerIDs, availableImages, styleLayers) {
	        const result = {};
	        this.loadVTLayers();
	        const filter = createFilter(filterSpec);
	        for (const symbolFeatureIndex of symbolFeatureIndexes) {
	            this.loadMatchingFeature(result, {
	                bucketIndex,
	                sourceLayerIndex,
	                featureIndex: symbolFeatureIndex,
	                layoutVertexArrayOffset: 0
	            }, filter, filterLayerIDs, availableImages, styleLayers, serializedLayers);
	        }
	        return result;
	    }
	    loadFeature(featureIndexData) {
	        const {featureIndex, sourceLayerIndex} = featureIndexData;
	        this.loadVTLayers();
	        const sourceLayerName = this.sourceLayerCoder.decode(sourceLayerIndex);
	        const featureCache = this.vtFeatures[sourceLayerName];
	        if (featureCache[featureIndex]) {
	            return featureCache[featureIndex];
	        }
	        const sourceLayer = this.vtLayers[sourceLayerName];
	        const feature = sourceLayer.feature(featureIndex);
	        featureCache[featureIndex] = feature;
	        return feature;
	    }
	    hasLayer(id) {
	        for (const layerIDs of this.bucketLayerIDs) {
	            for (const layerID of layerIDs) {
	                if (id === layerID)
	                    return true;
	            }
	        }
	        return false;
	    }
	    getId(feature, sourceLayerId) {
	        let id = feature.id;
	        if (this.promoteId) {
	            const propName = typeof this.promoteId === 'string' ? this.promoteId : this.promoteId[sourceLayerId];
	            id = feature.properties[propName];
	            if (typeof id === 'boolean')
	                id = Number(id);
	        }
	        return id;
	    }
	}
	register(FeatureIndex, 'FeatureIndex', {
	    omit: [
	        'rawTileData',
	        'sourceLayerCoder'
	    ]
	});
	function evaluateProperties(serializedProperties, styleLayerProperties, feature, featureState, availableImages) {
	    return mapObject(serializedProperties, (property, key) => {
	        const prop = styleLayerProperties instanceof PossiblyEvaluated ? styleLayerProperties.get(key) : null;
	        return prop && prop.evaluate ? prop.evaluate(feature, featureState, availableImages) : prop;
	    });
	}
	function topDownFeatureComparator(a, b) {
	    return b - a;
	}

	const glyphPadding = 1;
	const localGlyphPadding = glyphPadding * SDF_SCALE;
	class GlyphAtlas {
	    constructor(stacks) {
	        const positions = {};
	        const bins = [];
	        for (const stack in stacks) {
	            const glyphData = stacks[stack];
	            const glyphPositionMap = positions[stack] = {};
	            for (const id in glyphData.glyphs) {
	                const src = glyphData.glyphs[+id];
	                if (!src || src.bitmap.width === 0 || src.bitmap.height === 0)
	                    continue;
	                const padding = src.metrics.localGlyph ? localGlyphPadding : glyphPadding;
	                const bin = {
	                    x: 0,
	                    y: 0,
	                    w: src.bitmap.width + 2 * padding,
	                    h: src.bitmap.height + 2 * padding
	                };
	                bins.push(bin);
	                glyphPositionMap[id] = bin;
	            }
	        }
	        const {w, h} = potpack(bins);
	        const image = new AlphaImage({
	            width: w || 1,
	            height: h || 1
	        });
	        for (const stack in stacks) {
	            const glyphData = stacks[stack];
	            for (const id in glyphData.glyphs) {
	                const src = glyphData.glyphs[+id];
	                if (!src || src.bitmap.width === 0 || src.bitmap.height === 0)
	                    continue;
	                const bin = positions[stack][id];
	                const padding = src.metrics.localGlyph ? localGlyphPadding : glyphPadding;
	                AlphaImage.copy(src.bitmap, image, {
	                    x: 0,
	                    y: 0
	                }, {
	                    x: bin.x + padding,
	                    y: bin.y + padding
	                }, src.bitmap);
	            }
	        }
	        this.image = image;
	        this.positions = positions;
	    }
	}
	register(GlyphAtlas, 'GlyphAtlas');

	class WorkerTile {
	    constructor(params) {
	        this.tileID = new OverscaledTileID(params.tileID.overscaledZ, params.tileID.wrap, params.tileID.canonical.z, params.tileID.canonical.x, params.tileID.canonical.y);
	        this.tileZoom = params.tileZoom;
	        this.uid = params.uid;
	        this.zoom = params.zoom;
	        this.canonical = params.tileID.canonical;
	        this.pixelRatio = params.pixelRatio;
	        this.tileSize = params.tileSize;
	        this.source = params.source;
	        this.overscaling = this.tileID.overscaleFactor();
	        this.showCollisionBoxes = params.showCollisionBoxes;
	        this.collectResourceTiming = !!params.collectResourceTiming;
	        this.returnDependencies = !!params.returnDependencies;
	        this.promoteId = params.promoteId;
	        this.enableTerrain = !!params.enableTerrain;
	        this.isSymbolTile = params.isSymbolTile;
	        this.tileTransform = tileTransform(params.tileID.canonical, params.projection);
	        this.projection = params.projection;
	    }
	    parse(data, layerIndex, availableImages, actor, callback) {
	        this.status = 'parsing';
	        this.data = data;
	        this.collisionBoxArray = new CollisionBoxArray();
	        const sourceLayerCoder = new DictionaryCoder(Object.keys(data.layers).sort());
	        const featureIndex = new FeatureIndex(this.tileID, this.promoteId);
	        featureIndex.bucketLayerIDs = [];
	        const buckets = {};
	        const lineAtlas = new LineAtlas(256, 256);
	        const options = {
	            featureIndex,
	            iconDependencies: {},
	            patternDependencies: {},
	            glyphDependencies: {},
	            lineAtlas,
	            availableImages
	        };
	        const layerFamilies = layerIndex.familiesBySource[this.source];
	        for (const sourceLayerId in layerFamilies) {
	            const sourceLayer = data.layers[sourceLayerId];
	            if (!sourceLayer) {
	                continue;
	            }
	            let anySymbolLayers = false;
	            let anyOtherLayers = false;
	            for (const family of layerFamilies[sourceLayerId]) {
	                if (family[0].type === 'symbol') {
	                    anySymbolLayers = true;
	                } else {
	                    anyOtherLayers = true;
	                }
	            }
	            if (this.isSymbolTile === true && !anySymbolLayers) {
	                continue;
	            } else if (this.isSymbolTile === false && !anyOtherLayers) {
	                continue;
	            }
	            if (sourceLayer.version === 1) {
	                warnOnce(`Vector tile source "${ this.source }" layer "${ sourceLayerId }" ` + `does not use vector tile spec v2 and therefore may have some rendering errors.`);
	            }
	            const sourceLayerIndex = sourceLayerCoder.encode(sourceLayerId);
	            const features = [];
	            for (let index = 0; index < sourceLayer.length; index++) {
	                const feature = sourceLayer.feature(index);
	                const id = featureIndex.getId(feature, sourceLayerId);
	                features.push({
	                    feature,
	                    id,
	                    index,
	                    sourceLayerIndex
	                });
	            }
	            for (const family of layerFamilies[sourceLayerId]) {
	                const layer = family[0];
	                if (this.isSymbolTile !== undefined && layer.type === 'symbol' !== this.isSymbolTile)
	                    continue;
	                if (layer.minzoom && this.zoom < Math.floor(layer.minzoom))
	                    continue;
	                if (layer.maxzoom && this.zoom >= layer.maxzoom)
	                    continue;
	                if (layer.visibility === 'none')
	                    continue;
	                recalculateLayers(family, this.zoom, availableImages);
	                const bucket = buckets[layer.id] = layer.createBucket({
	                    index: featureIndex.bucketLayerIDs.length,
	                    layers: family,
	                    zoom: this.zoom,
	                    canonical: this.canonical,
	                    pixelRatio: this.pixelRatio,
	                    overscaling: this.overscaling,
	                    collisionBoxArray: this.collisionBoxArray,
	                    sourceLayerIndex,
	                    sourceID: this.source,
	                    enableTerrain: this.enableTerrain,
	                    projection: this.projection.spec,
	                    availableImages
	                });
	                bucket.populate(features, options, this.tileID.canonical, this.tileTransform);
	                featureIndex.bucketLayerIDs.push(family.map(l => l.id));
	            }
	        }
	        lineAtlas.trim();
	        let error;
	        let glyphMap;
	        let iconMap;
	        let patternMap;
	        const taskMetadata = {
	            type: 'maybePrepare',
	            isSymbolTile: this.isSymbolTile,
	            zoom: this.zoom
	        };
	        const stacks = mapObject(options.glyphDependencies, glyphs => Object.keys(glyphs).map(Number));
	        if (Object.keys(stacks).length) {
	            actor.send('getGlyphs', {
	                uid: this.uid,
	                stacks
	            }, (err, result) => {
	                if (!error) {
	                    error = err;
	                    glyphMap = result;
	                    maybePrepare.call(this);
	                }
	            }, undefined, false, taskMetadata);
	        } else {
	            glyphMap = {};
	        }
	        const icons = Object.keys(options.iconDependencies);
	        if (icons.length) {
	            actor.send('getImages', {
	                icons,
	                source: this.source,
	                tileID: this.tileID,
	                type: 'icons'
	            }, (err, result) => {
	                if (!error) {
	                    error = err;
	                    iconMap = result;
	                    maybePrepare.call(this);
	                }
	            }, undefined, false, taskMetadata);
	        } else {
	            iconMap = {};
	        }
	        const patterns = Object.keys(options.patternDependencies);
	        if (patterns.length) {
	            actor.send('getImages', {
	                icons: patterns,
	                source: this.source,
	                tileID: this.tileID,
	                type: 'patterns'
	            }, (err, result) => {
	                if (!error) {
	                    error = err;
	                    patternMap = result;
	                    maybePrepare.call(this);
	                }
	            }, undefined, false, taskMetadata);
	        } else {
	            patternMap = {};
	        }
	        maybePrepare.call(this);
	        function maybePrepare() {
	            if (error) {
	                return callback(error);
	            } else if (glyphMap && iconMap && patternMap) {
	                const glyphAtlas = new GlyphAtlas(glyphMap);
	                const imageAtlas = new ImageAtlas(iconMap, patternMap);
	                for (const key in buckets) {
	                    const bucket = buckets[key];
	                    if (bucket instanceof SymbolBucket) {
	                        recalculateLayers(bucket.layers, this.zoom, availableImages);
	                        performSymbolLayout(bucket, glyphMap, glyphAtlas.positions, iconMap, imageAtlas.iconPositions, this.showCollisionBoxes, availableImages, this.tileID.canonical, this.tileZoom, this.projection);
	                    } else if (bucket.hasPattern && (bucket instanceof LineBucket || bucket instanceof FillBucket || bucket instanceof FillExtrusionBucket)) {
	                        recalculateLayers(bucket.layers, this.zoom, availableImages);
	                        const imagePositions = imageAtlas.patternPositions;
	                        bucket.addFeatures(options, this.tileID.canonical, imagePositions, availableImages, this.tileTransform);
	                    }
	                }
	                this.status = 'done';
	                callback(null, {
	                    buckets: values(buckets).filter(b => !b.isEmpty()),
	                    featureIndex,
	                    collisionBoxArray: this.collisionBoxArray,
	                    glyphAtlasImage: glyphAtlas.image,
	                    lineAtlas,
	                    imageAtlas,
	                    glyphMap: this.returnDependencies ? glyphMap : null,
	                    iconMap: this.returnDependencies ? iconMap : null,
	                    glyphPositions: this.returnDependencies ? glyphAtlas.positions : null
	                });
	            }
	        }
	    }
	}
	function recalculateLayers(layers, zoom, availableImages) {
	    const parameters = new EvaluationParameters(zoom);
	    for (const layer of layers) {
	        layer.recalculate(parameters, availableImages);
	    }
	}

	class DedupedRequest {
	    constructor(scheduler) {
	        this.entries = {};
	        this.scheduler = scheduler;
	    }
	    request(key, metadata, request, callback) {
	        const entry = this.entries[key] = this.entries[key] || { callbacks: [] };
	        if (entry.result) {
	            const [err, result] = entry.result;
	            if (this.scheduler) {
	                this.scheduler.add(() => {
	                    callback(err, result);
	                }, metadata);
	            } else {
	                callback(err, result);
	            }
	            return () => {
	            };
	        }
	        entry.callbacks.push(callback);
	        if (!entry.cancel) {
	            entry.cancel = request((err, result) => {
	                entry.result = [
	                    err,
	                    result
	                ];
	                for (const cb of entry.callbacks) {
	                    if (this.scheduler) {
	                        this.scheduler.add(() => {
	                            cb(err, result);
	                        }, metadata);
	                    } else {
	                        cb(err, result);
	                    }
	                }
	                setTimeout(() => delete this.entries[key], 1000 * 3);
	            });
	        }
	        return () => {
	            if (entry.result)
	                return;
	            entry.callbacks = entry.callbacks.filter(cb => cb !== callback);
	            if (!entry.callbacks.length) {
	                entry.cancel();
	                delete this.entries[key];
	            }
	        };
	    }
	}
	function loadVectorTile(params, callback, skipParse) {
	    const key = JSON.stringify(params.request);
	    const makeRequest = callback => {
	        const request = getArrayBuffer(params.request, (err, data, cacheControl, expires) => {
	            if (err) {
	                callback(err);
	            } else if (data) {
	                callback(null, {
	                    vectorTile: skipParse ? undefined : new vectorTile.VectorTile(new pbf(data)),
	                    rawData: data,
	                    cacheControl,
	                    expires
	                });
	            }
	        });
	        return () => {
	            request.cancel();
	            callback();
	        };
	    };
	    if (params.data) {
	        this.deduped.entries[key] = {
	            result: [
	                null,
	                params.data
	            ]
	        };
	    }
	    const callbackMetadata = {
	        type: 'parseTile',
	        isSymbolTile: params.isSymbolTile,
	        zoom: params.tileZoom
	    };
	    return this.deduped.request(key, callbackMetadata, makeRequest, callback);
	}
	class VectorTileWorkerSource extends Evented {
	    constructor(actor, layerIndex, availableImages, isSpriteLoaded, loadVectorData) {
	        super();
	        this.actor = actor;
	        this.layerIndex = layerIndex;
	        this.availableImages = availableImages;
	        this.loadVectorData = loadVectorData || loadVectorTile;
	        this.loading = {};
	        this.loaded = {};
	        this.deduped = new DedupedRequest(actor.scheduler);
	        this.isSpriteLoaded = isSpriteLoaded;
	        this.scheduler = actor.scheduler;
	    }
	    loadTile(params, callback) {
	        const uid = params.uid;
	        const requestParam = params && params.request;
	        const perf = requestParam && requestParam.collectResourceTiming;
	        const workerTile = this.loading[uid] = new WorkerTile(params);
	        workerTile.abort = this.loadVectorData(params, (err, response) => {
	            const aborted = !this.loading[uid];
	            delete this.loading[uid];
	            if (aborted || err || !response) {
	                workerTile.status = 'done';
	                if (!aborted)
	                    this.loaded[uid] = workerTile;
	                return callback(err);
	            }
	            const rawTileData = response.rawData;
	            const cacheControl = {};
	            if (response.expires)
	                cacheControl.expires = response.expires;
	            if (response.cacheControl)
	                cacheControl.cacheControl = response.cacheControl;
	            workerTile.vectorTile = response.vectorTile || new vectorTile.VectorTile(new pbf(rawTileData));
	            const parseTile = () => {
	                workerTile.parse(workerTile.vectorTile, this.layerIndex, this.availableImages, this.actor, (err, result) => {
	                    if (err || !result)
	                        return callback(err);
	                    const resourceTiming = {};
	                    if (perf) {
	                        const resourceTimingData = getPerformanceMeasurement(requestParam);
	                        if (resourceTimingData.length > 0) {
	                            resourceTiming.resourceTiming = JSON.parse(JSON.stringify(resourceTimingData));
	                        }
	                    }
	                    callback(null, extend$1({ rawTileData: rawTileData.slice(0) }, result, cacheControl, resourceTiming));
	                });
	            };
	            if (this.isSpriteLoaded) {
	                parseTile();
	            } else {
	                this.once('isSpriteLoaded', () => {
	                    if (this.scheduler) {
	                        const metadata = {
	                            type: 'parseTile',
	                            isSymbolTile: params.isSymbolTile,
	                            zoom: params.tileZoom
	                        };
	                        this.scheduler.add(parseTile, metadata);
	                    } else {
	                        parseTile();
	                    }
	                });
	            }
	            this.loaded = this.loaded || {};
	            this.loaded[uid] = workerTile;
	        });
	    }
	    reloadTile(params, callback) {
	        const loaded = this.loaded, uid = params.uid, vtSource = this;
	        if (loaded && loaded[uid]) {
	            const workerTile = loaded[uid];
	            workerTile.showCollisionBoxes = params.showCollisionBoxes;
	            workerTile.enableTerrain = !!params.enableTerrain;
	            workerTile.projection = params.projection;
	            workerTile.tileTransform = tileTransform(params.tileID.canonical, params.projection);
	            const done = (err, data) => {
	                const reloadCallback = workerTile.reloadCallback;
	                if (reloadCallback) {
	                    delete workerTile.reloadCallback;
	                    workerTile.parse(workerTile.vectorTile, vtSource.layerIndex, this.availableImages, vtSource.actor, reloadCallback);
	                }
	                callback(err, data);
	            };
	            if (workerTile.status === 'parsing') {
	                workerTile.reloadCallback = done;
	            } else if (workerTile.status === 'done') {
	                if (workerTile.vectorTile) {
	                    workerTile.parse(workerTile.vectorTile, this.layerIndex, this.availableImages, this.actor, done);
	                } else {
	                    done();
	                }
	            }
	        }
	    }
	    abortTile(params, callback) {
	        const uid = params.uid;
	        const tile = this.loading[uid];
	        if (tile) {
	            if (tile.abort)
	                tile.abort();
	            delete this.loading[uid];
	        }
	        callback();
	    }
	    removeTile(params, callback) {
	        const loaded = this.loaded, uid = params.uid;
	        if (loaded && loaded[uid]) {
	            delete loaded[uid];
	        }
	        callback();
	    }
	}

	var refProperties = [
	    'type',
	    'source',
	    'source-layer',
	    'minzoom',
	    'maxzoom',
	    'filter',
	    'layout'
	];

	exports.ARRAY_TYPE = ARRAY_TYPE;
	exports.AUTH_ERR_MSG = AUTH_ERR_MSG;
	exports.Aabb = Aabb;
	exports.Actor = Actor;
	exports.CanonicalTileID = CanonicalTileID;
	exports.Color = Color$1;
	exports.ColorMode = ColorMode;
	exports.CullFaceMode = CullFaceMode;
	exports.DEMData = DEMData;
	exports.DataConstantProperty = DataConstantProperty;
	exports.DedupedRequest = DedupedRequest;
	exports.DepthMode = DepthMode;
	exports.EXTENT = EXTENT;
	exports.Elevation = Elevation;
	exports.ErrorEvent = ErrorEvent;
	exports.EvaluationParameters = EvaluationParameters;
	exports.Event = Event;
	exports.Evented = Evented;
	exports.FillExtrusionBucket = FillExtrusionBucket;
	exports.Frustum = Frustum;
	exports.FrustumCorners = FrustumCorners;
	exports.GLOBE_METERS_TO_ECEF = GLOBE_METERS_TO_ECEF;
	exports.GLOBE_RADIUS = GLOBE_RADIUS;
	exports.GLOBE_SCALE_MATCH_LATITUDE = GLOBE_SCALE_MATCH_LATITUDE;
	exports.GLOBE_ZOOM_THRESHOLD_MAX = GLOBE_ZOOM_THRESHOLD_MAX;
	exports.GLOBE_ZOOM_THRESHOLD_MIN = GLOBE_ZOOM_THRESHOLD_MIN;
	exports.GlobeSharedBuffers = GlobeSharedBuffers;
	exports.GlyphManager = GlyphManager;
	exports.ImagePosition = ImagePosition;
	exports.LineAtlas = LineAtlas;
	exports.LngLat = LngLat;
	exports.LngLatBounds = LngLatBounds;
	exports.LocalGlyphMode = LocalGlyphMode;
	exports.MAX_MERCATOR_LATITUDE = MAX_MERCATOR_LATITUDE;
	exports.MercatorCoordinate = MercatorCoordinate;
	exports.ONE_EM = ONE_EM;
	exports.OverscaledTileID = OverscaledTileID;
	exports.Properties = Properties;
	exports.RGBAImage = RGBAImage;
	exports.Ray = Ray;
	exports.RequestManager = RequestManager;
	exports.ResourceType = ResourceType;
	exports.SegmentVector = SegmentVector;
	exports.SourceCache = SourceCache;
	exports.StencilMode = StencilMode;
	exports.StructArrayLayout1ui2 = StructArrayLayout1ui2;
	exports.StructArrayLayout2f1f2i16 = StructArrayLayout2f1f2i16;
	exports.StructArrayLayout2i4 = StructArrayLayout2i4;
	exports.StructArrayLayout2ui4 = StructArrayLayout2ui4;
	exports.StructArrayLayout3f12 = StructArrayLayout3f12;
	exports.StructArrayLayout3ui6 = StructArrayLayout3ui6;
	exports.StructArrayLayout4i8 = StructArrayLayout4i8;
	exports.StructArrayLayout5f20 = StructArrayLayout5f20;
	exports.Texture = Texture;
	exports.Tile = Tile;
	exports.Transitionable = Transitionable;
	exports.Uniform1f = Uniform1f;
	exports.Uniform1i = Uniform1i;
	exports.Uniform2f = Uniform2f;
	exports.Uniform3f = Uniform3f;
	exports.Uniform4f = Uniform4f;
	exports.UniformColor = UniformColor;
	exports.UniformMatrix2f = UniformMatrix2f;
	exports.UniformMatrix3f = UniformMatrix3f;
	exports.UniformMatrix4f = UniformMatrix4f;
	exports.UnwrappedTileID = UnwrappedTileID;
	exports.ValidationError = ValidationError;
	exports.VectorTileWorkerSource = VectorTileWorkerSource;
	exports.WritingMode = WritingMode;
	exports.ZoomHistory = ZoomHistory;
	exports.add = add;
	exports.addDynamicAttributes = addDynamicAttributes;
	exports.adjoint = adjoint;
	exports.asyncAll = asyncAll;
	exports.bezier = bezier;
	exports.bindAll = bindAll;
	exports.boundsAttributes = boundsAttributes;
	exports.bufferConvexPolygon = bufferConvexPolygon;
	exports.cacheEntryPossiblyAdded = cacheEntryPossiblyAdded;
	exports.calculateGlobeLabelMatrix = calculateGlobeLabelMatrix;
	exports.calculateGlobeMatrix = calculateGlobeMatrix;
	exports.calculateGlobeMercatorMatrix = calculateGlobeMercatorMatrix;
	exports.circumferenceAtLatitude = circumferenceAtLatitude;
	exports.clamp = clamp;
	exports.clearTileCache = clearTileCache;
	exports.clipLine = clipLine;
	exports.clone = clone$1;
	exports.clone$1 = clone$2;
	exports.collisionCircleLayout = collisionCircleLayout;
	exports.config = config;
	exports.conjugate = conjugate;
	exports.create = create$3;
	exports.create$1 = create$4;
	exports.createExpression = createExpression;
	exports.createLayout = createLayout;
	exports.createStyleLayer = createStyleLayer;
	exports.cross = cross;
	exports.degToRad = degToRad;
	exports.distance = distance;
	exports.div = div;
	exports.dot = dot$1;
	exports.ease = ease;
	exports.easeCubicInOut = easeCubicInOut;
	exports.emitValidationErrors = emitValidationErrors;
	exports.endsWith = endsWith;
	exports.enforceCacheSizeLimit = enforceCacheSizeLimit;
	exports.evaluateSizeForFeature = evaluateSizeForFeature;
	exports.evaluateSizeForZoom = evaluateSizeForZoom;
	exports.evaluateVariableOffset = evaluateVariableOffset;
	exports.evented = evented;
	exports.exactEquals = exactEquals;
	exports.exactEquals$1 = exactEquals$2;
	exports.exported = exported$1;
	exports.exported$1 = exported;
	exports.extend = extend$1;
	exports.extend$1 = extend;
	exports.fillExtrusionHeightLift = fillExtrusionHeightLift;
	exports.filterObject = filterObject;
	exports.fromMat4 = fromMat4;
	exports.fromQuat = fromQuat;
	exports.fromRotation = fromRotation$1;
	exports.fromScaling = fromScaling;
	exports.furthestTileCorner = furthestTileCorner;
	exports.getAABBPointSquareDist = getAABBPointSquareDist;
	exports.getAnchorAlignment = getAnchorAlignment;
	exports.getAnchorJustification = getAnchorJustification;
	exports.getBounds = getBounds;
	exports.getColumn = getColumn;
	exports.getGridMatrix = getGridMatrix;
	exports.getImage = getImage;
	exports.getJSON = getJSON;
	exports.getLatitudinalLod = getLatitudinalLod;
	exports.getMapSessionAPI = getMapSessionAPI;
	exports.getPerformanceMeasurement = getPerformanceMeasurement;
	exports.getProjection = getProjection;
	exports.getRTLTextPluginStatus = getRTLTextPluginStatus;
	exports.getReferrer = getReferrer;
	exports.getTilePoint = getTilePoint;
	exports.getTileVec3 = getTileVec3;
	exports.getVideo = getVideo;
	exports.globeCenterToScreenPoint = globeCenterToScreenPoint;
	exports.globeECEFOrigin = globeECEFOrigin;
	exports.globeNormalizeECEF = globeNormalizeECEF;
	exports.globePixelsToTileUnits = globePixelsToTileUnits;
	exports.globePoleMatrixForTile = globePoleMatrixForTile;
	exports.globeTileBounds = globeTileBounds;
	exports.globeTileLatLngCorners = globeTileLatLngCorners;
	exports.globeTiltAtLngLat = globeTiltAtLngLat;
	exports.globeToMercatorTransition = globeToMercatorTransition;
	exports.globeUseCustomAntiAliasing = globeUseCustomAntiAliasing;
	exports.identity = identity$2;
	exports.identity$1 = identity$1;
	exports.invert = invert;
	exports.isLngLatBehindGlobe = isLngLatBehindGlobe;
	exports.isMapAuthenticated = isMapAuthenticated;
	exports.isMapboxURL = isMapboxURL;
	exports.isSafariWithAntialiasingBug = isSafariWithAntialiasingBug;
	exports.latFromMercatorY = latFromMercatorY;
	exports.len = len;
	exports.length = length$2;
	exports.length$1 = length;
	exports.loadVectorTile = loadVectorTile;
	exports.makeRequest = makeRequest;
	exports.mapValue = mapValue;
	exports.mercatorXfromLng = mercatorXfromLng;
	exports.mercatorYfromLat = mercatorYfromLat;
	exports.mercatorZfromAltitude = mercatorZfromAltitude;
	exports.mul = mul$2;
	exports.mul$1 = mul$1;
	exports.multiply = multiply$2;
	exports.multiply$1 = multiply$3;
	exports.multiply$2 = multiply$1;
	exports.nextPowerOfTwo = nextPowerOfTwo;
	exports.normalize = normalize$2;
	exports.normalize$1 = normalize;
	exports.number = number;
	exports.ortho = ortho;
	exports.pbf = pbf;
	exports.perspective = perspective;
	exports.pick = pick;
	exports.plugin = plugin;
	exports.pointGeometry = pointGeometry;
	exports.polygonContainsPoint = polygonContainsPoint;
	exports.polygonIntersectsBox = polygonIntersectsBox;
	exports.polygonIntersectsPolygon = polygonIntersectsPolygon;
	exports.polygonizeBounds = polygonizeBounds;
	exports.posAttributes = posAttributes;
	exports.postMapLoadEvent = postMapLoadEvent;
	exports.postTurnstileEvent = postTurnstileEvent;
	exports.potpack = potpack;
	exports.prevPowerOfTwo = prevPowerOfTwo;
	exports.radToDeg = radToDeg;
	exports.refProperties = refProperties;
	exports.registerForPluginStateChange = registerForPluginStateChange;
	exports.removeAuthState = removeAuthState;
	exports.renderColorRamp = renderColorRamp;
	exports.resample = resample$1;
	exports.rotateX = rotateX$1;
	exports.rotateX$1 = rotateX;
	exports.rotateY = rotateY$1;
	exports.rotateY$1 = rotateY;
	exports.rotateZ = rotateZ$1;
	exports.rotateZ$1 = rotateZ;
	exports.scale = scale$2;
	exports.scale$1 = scale;
	exports.scale$2 = scale$1;
	exports.scaleAndAdd = scaleAndAdd;
	exports.setCacheLimits = setCacheLimits;
	exports.setColumn = setColumn;
	exports.setRTLTextPlugin = setRTLTextPlugin;
	exports.smoothstep = smoothstep;
	exports.spec = spec;
	exports.storeAuthState = storeAuthState;
	exports.sub = sub;
	exports.subtract = subtract;
	exports.symbolSize = symbolSize;
	exports.tileAABB = tileAABB;
	exports.tileTransform = tileTransform;
	exports.transformMat3 = transformMat3;
	exports.transformMat4 = transformMat4$1;
	exports.transformMat4$1 = transformMat4;
	exports.transformQuat = transformQuat;
	exports.translate = translate;
	exports.transpose = transpose;
	exports.triggerPluginCompletionEvent = triggerPluginCompletionEvent;
	exports.uniqueId = uniqueId;
	exports.updateGlobeVertexNormal = updateGlobeVertexNormal;
	exports.validateCustomStyleLayer = validateCustomStyleLayer;
	exports.validateFilter = validateFilter;
	exports.validateFog = validateFog;
	exports.validateLayer = validateLayer;
	exports.validateLight = validateLight;
	exports.validateSource = validateSource;
	exports.validateStyle = validateStyle;
	exports.validateTerrain = validateTerrain;
	exports.values = values;
	exports.vectorTile = vectorTile;
	exports.version = version;
	exports.warnOnce = warnOnce;
	exports.window = window$1;
	exports.wrap = wrap;

	}));

	define(['./shared'], (function (ref_properties) {
	function stringify(obj) {
	    if (typeof obj === 'number' || typeof obj === 'boolean' || typeof obj === 'string' || obj === undefined || obj === null)
	        return JSON.stringify(obj);
	    if (Array.isArray(obj)) {
	        let str = '[';
	        for (const val of obj) {
	            str += `${ stringify(val) },`;
	        }
	        return `${ str }]`;
	    }
	    let str = '{';
	    for (const key of Object.keys(obj).sort()) {
	        str += `${ key }:${ stringify(obj[key]) },`;
	    }
	    return `${ str }}`;
	}
	function getKey(layer) {
	    let key = '';
	    for (const k of ref_properties.refProperties) {
	        key += `/${ stringify(layer[k]) }`;
	    }
	    return key;
	}
	function groupByLayout(layers, cachedKeys) {
	    const groups = {};
	    for (let i = 0; i < layers.length; i++) {
	        const k = cachedKeys && cachedKeys[layers[i].id] || getKey(layers[i]);
	        if (cachedKeys)
	            cachedKeys[layers[i].id] = k;
	        let group = groups[k];
	        if (!group) {
	            group = groups[k] = [];
	        }
	        group.push(layers[i]);
	    }
	    const result = [];
	    for (const k in groups) {
	        result.push(groups[k]);
	    }
	    return result;
	}

	class StyleLayerIndex {
	    constructor(layerConfigs) {
	        this.keyCache = {};
	        if (layerConfigs) {
	            this.replace(layerConfigs);
	        }
	    }
	    replace(layerConfigs) {
	        this._layerConfigs = {};
	        this._layers = {};
	        this.update(layerConfigs, []);
	    }
	    update(layerConfigs, removedIds) {
	        for (const layerConfig of layerConfigs) {
	            this._layerConfigs[layerConfig.id] = layerConfig;
	            const layer = this._layers[layerConfig.id] = ref_properties.createStyleLayer(layerConfig);
	            layer.compileFilter();
	            if (this.keyCache[layerConfig.id])
	                delete this.keyCache[layerConfig.id];
	        }
	        for (const id of removedIds) {
	            delete this.keyCache[id];
	            delete this._layerConfigs[id];
	            delete this._layers[id];
	        }
	        this.familiesBySource = {};
	        const groups = groupByLayout(ref_properties.values(this._layerConfigs), this.keyCache);
	        for (const layerConfigs of groups) {
	            const layers = layerConfigs.map(layerConfig => this._layers[layerConfig.id]);
	            const layer = layers[0];
	            if (layer.visibility === 'none') {
	                continue;
	            }
	            const sourceId = layer.source || '';
	            let sourceGroup = this.familiesBySource[sourceId];
	            if (!sourceGroup) {
	                sourceGroup = this.familiesBySource[sourceId] = {};
	            }
	            const sourceLayerId = layer.sourceLayer || '_geojsonTileLayer';
	            let sourceLayerFamilies = sourceGroup[sourceLayerId];
	            if (!sourceLayerFamilies) {
	                sourceLayerFamilies = sourceGroup[sourceLayerId] = [];
	            }
	            sourceLayerFamilies.push(layers);
	        }
	    }
	}

	class RasterDEMTileWorkerSource {
	    loadTile(params, callback) {
	        const {uid, encoding, rawImageData, padding, buildQuadTree} = params;
	        const imagePixels = ref_properties.window.ImageBitmap && rawImageData instanceof ref_properties.window.ImageBitmap ? this.getImageData(rawImageData, padding) : rawImageData;
	        const dem = new ref_properties.DEMData(uid, imagePixels, encoding, padding < 1, buildQuadTree);
	        callback(null, dem);
	    }
	    getImageData(imgBitmap, padding) {
	        if (!this.offscreenCanvas || !this.offscreenCanvasContext) {
	            this.offscreenCanvas = new OffscreenCanvas(imgBitmap.width, imgBitmap.height);
	            this.offscreenCanvasContext = this.offscreenCanvas.getContext('2d');
	        }
	        this.offscreenCanvas.width = imgBitmap.width;
	        this.offscreenCanvas.height = imgBitmap.height;
	        this.offscreenCanvasContext.drawImage(imgBitmap, 0, 0, imgBitmap.width, imgBitmap.height);
	        const imgData = this.offscreenCanvasContext.getImageData(-padding, -padding, imgBitmap.width + 2 * padding, imgBitmap.height + 2 * padding);
	        this.offscreenCanvasContext.clearRect(0, 0, this.offscreenCanvas.width, this.offscreenCanvas.height);
	        return imgData;
	    }
	}

	var geojsonRewind = rewind$1;
	function rewind$1(gj, outer) {
	    var type = gj && gj.type, i;
	    if (type === 'FeatureCollection') {
	        for (i = 0; i < gj.features.length; i++)
	            rewind$1(gj.features[i], outer);
	    } else if (type === 'GeometryCollection') {
	        for (i = 0; i < gj.geometries.length; i++)
	            rewind$1(gj.geometries[i], outer);
	    } else if (type === 'Feature') {
	        rewind$1(gj.geometry, outer);
	    } else if (type === 'Polygon') {
	        rewindRings(gj.coordinates, outer);
	    } else if (type === 'MultiPolygon') {
	        for (i = 0; i < gj.coordinates.length; i++)
	            rewindRings(gj.coordinates[i], outer);
	    }
	    return gj;
	}
	function rewindRings(rings, outer) {
	    if (rings.length === 0)
	        return;
	    rewindRing(rings[0], outer);
	    for (var i = 1; i < rings.length; i++) {
	        rewindRing(rings[i], !outer);
	    }
	}
	function rewindRing(ring, dir) {
	    var area = 0, err = 0;
	    for (var i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
	        var k = (ring[i][0] - ring[j][0]) * (ring[j][1] + ring[i][1]);
	        var m = area + k;
	        err += Math.abs(area) >= Math.abs(k) ? area - m + k : k - m + area;
	        area = m;
	    }
	    if (area + err >= 0 !== !!dir)
	        ring.reverse();
	}

	const toGeoJSON = ref_properties.vectorTile.VectorTileFeature.prototype.toGeoJSON;
	class FeatureWrapper$1 {
	    constructor(feature) {
	        this._feature = feature;
	        this.extent = ref_properties.EXTENT;
	        this.type = feature.type;
	        this.properties = feature.tags;
	        if ('id' in feature && !isNaN(feature.id)) {
	            this.id = parseInt(feature.id, 10);
	        }
	    }
	    loadGeometry() {
	        if (this._feature.type === 1) {
	            const geometry = [];
	            for (const point of this._feature.geometry) {
	                geometry.push([new ref_properties.pointGeometry(point[0], point[1])]);
	            }
	            return geometry;
	        } else {
	            const geometry = [];
	            for (const ring of this._feature.geometry) {
	                const newRing = [];
	                for (const point of ring) {
	                    newRing.push(new ref_properties.pointGeometry(point[0], point[1]));
	                }
	                geometry.push(newRing);
	            }
	            return geometry;
	        }
	    }
	    toGeoJSON(x, y, z) {
	        return toGeoJSON.call(this, x, y, z);
	    }
	}
	class GeoJSONWrapper$1 {
	    constructor(features) {
	        this.layers = { '_geojsonTileLayer': this };
	        this.name = '_geojsonTileLayer';
	        this.extent = ref_properties.EXTENT;
	        this.length = features.length;
	        this._features = features;
	    }
	    feature(i) {
	        return new FeatureWrapper$1(this._features[i]);
	    }
	}

	var VectorTileFeature = ref_properties.vectorTile.VectorTileFeature;
	var geojson_wrapper = GeoJSONWrapper;
	function GeoJSONWrapper(features, options) {
	    this.options = options || {};
	    this.features = features;
	    this.length = features.length;
	}
	GeoJSONWrapper.prototype.feature = function (i) {
	    return new FeatureWrapper(this.features[i], this.options.extent);
	};
	function FeatureWrapper(feature, extent) {
	    this.id = typeof feature.id === 'number' ? feature.id : undefined;
	    this.type = feature.type;
	    this.rawGeometry = feature.type === 1 ? [feature.geometry] : feature.geometry;
	    this.properties = feature.tags;
	    this.extent = extent || 4096;
	}
	FeatureWrapper.prototype.loadGeometry = function () {
	    var rings = this.rawGeometry;
	    this.geometry = [];
	    for (var i = 0; i < rings.length; i++) {
	        var ring = rings[i];
	        var newRing = [];
	        for (var j = 0; j < ring.length; j++) {
	            newRing.push(new ref_properties.pointGeometry(ring[j][0], ring[j][1]));
	        }
	        this.geometry.push(newRing);
	    }
	    return this.geometry;
	};
	FeatureWrapper.prototype.bbox = function () {
	    if (!this.geometry)
	        this.loadGeometry();
	    var rings = this.geometry;
	    var x1 = Infinity;
	    var x2 = -Infinity;
	    var y1 = Infinity;
	    var y2 = -Infinity;
	    for (var i = 0; i < rings.length; i++) {
	        var ring = rings[i];
	        for (var j = 0; j < ring.length; j++) {
	            var coord = ring[j];
	            x1 = Math.min(x1, coord.x);
	            x2 = Math.max(x2, coord.x);
	            y1 = Math.min(y1, coord.y);
	            y2 = Math.max(y2, coord.y);
	        }
	    }
	    return [
	        x1,
	        y1,
	        x2,
	        y2
	    ];
	};
	FeatureWrapper.prototype.toGeoJSON = VectorTileFeature.prototype.toGeoJSON;

	var vtPbf = fromVectorTileJs;
	var fromVectorTileJs_1 = fromVectorTileJs;
	var fromGeojsonVt_1 = fromGeojsonVt;
	var GeoJSONWrapper_1 = geojson_wrapper;
	function fromVectorTileJs(tile) {
	    var out = new ref_properties.pbf();
	    writeTile(tile, out);
	    return out.finish();
	}
	function fromGeojsonVt(layers, options) {
	    options = options || {};
	    var l = {};
	    for (var k in layers) {
	        l[k] = new geojson_wrapper(layers[k].features, options);
	        l[k].name = k;
	        l[k].version = options.version;
	        l[k].extent = options.extent;
	    }
	    return fromVectorTileJs({ layers: l });
	}
	function writeTile(tile, pbf) {
	    for (var key in tile.layers) {
	        pbf.writeMessage(3, writeLayer, tile.layers[key]);
	    }
	}
	function writeLayer(layer, pbf) {
	    pbf.writeVarintField(15, layer.version || 1);
	    pbf.writeStringField(1, layer.name || '');
	    pbf.writeVarintField(5, layer.extent || 4096);
	    var i;
	    var context = {
	        keys: [],
	        values: [],
	        keycache: {},
	        valuecache: {}
	    };
	    for (i = 0; i < layer.length; i++) {
	        context.feature = layer.feature(i);
	        pbf.writeMessage(2, writeFeature, context);
	    }
	    var keys = context.keys;
	    for (i = 0; i < keys.length; i++) {
	        pbf.writeStringField(3, keys[i]);
	    }
	    var values = context.values;
	    for (i = 0; i < values.length; i++) {
	        pbf.writeMessage(4, writeValue, values[i]);
	    }
	}
	function writeFeature(context, pbf) {
	    var feature = context.feature;
	    if (feature.id !== undefined) {
	        pbf.writeVarintField(1, feature.id);
	    }
	    pbf.writeMessage(2, writeProperties, context);
	    pbf.writeVarintField(3, feature.type);
	    pbf.writeMessage(4, writeGeometry, feature);
	}
	function writeProperties(context, pbf) {
	    var feature = context.feature;
	    var keys = context.keys;
	    var values = context.values;
	    var keycache = context.keycache;
	    var valuecache = context.valuecache;
	    for (var key in feature.properties) {
	        var value = feature.properties[key];
	        var keyIndex = keycache[key];
	        if (value === null)
	            continue;
	        if (typeof keyIndex === 'undefined') {
	            keys.push(key);
	            keyIndex = keys.length - 1;
	            keycache[key] = keyIndex;
	        }
	        pbf.writeVarint(keyIndex);
	        var type = typeof value;
	        if (type !== 'string' && type !== 'boolean' && type !== 'number') {
	            value = JSON.stringify(value);
	        }
	        var valueKey = type + ':' + value;
	        var valueIndex = valuecache[valueKey];
	        if (typeof valueIndex === 'undefined') {
	            values.push(value);
	            valueIndex = values.length - 1;
	            valuecache[valueKey] = valueIndex;
	        }
	        pbf.writeVarint(valueIndex);
	    }
	}
	function command(cmd, length) {
	    return (length << 3) + (cmd & 7);
	}
	function zigzag(num) {
	    return num << 1 ^ num >> 31;
	}
	function writeGeometry(feature, pbf) {
	    var geometry = feature.loadGeometry();
	    var type = feature.type;
	    var x = 0;
	    var y = 0;
	    var rings = geometry.length;
	    for (var r = 0; r < rings; r++) {
	        var ring = geometry[r];
	        var count = 1;
	        if (type === 1) {
	            count = ring.length;
	        }
	        pbf.writeVarint(command(1, count));
	        var lineCount = type === 3 ? ring.length - 1 : ring.length;
	        for (var i = 0; i < lineCount; i++) {
	            if (i === 1 && type !== 1) {
	                pbf.writeVarint(command(2, lineCount - 1));
	            }
	            var dx = ring[i].x - x;
	            var dy = ring[i].y - y;
	            pbf.writeVarint(zigzag(dx));
	            pbf.writeVarint(zigzag(dy));
	            x += dx;
	            y += dy;
	        }
	        if (type === 3) {
	            pbf.writeVarint(command(7, 1));
	        }
	    }
	}
	function writeValue(value, pbf) {
	    var type = typeof value;
	    if (type === 'string') {
	        pbf.writeStringField(1, value);
	    } else if (type === 'boolean') {
	        pbf.writeBooleanField(7, value);
	    } else if (type === 'number') {
	        if (value % 1 !== 0) {
	            pbf.writeDoubleField(3, value);
	        } else if (value < 0) {
	            pbf.writeSVarintField(6, value);
	        } else {
	            pbf.writeVarintField(5, value);
	        }
	    }
	}
	vtPbf.fromVectorTileJs = fromVectorTileJs_1;
	vtPbf.fromGeojsonVt = fromGeojsonVt_1;
	vtPbf.GeoJSONWrapper = GeoJSONWrapper_1;

	function sortKD(ids, coords, nodeSize, left, right, depth) {
	    if (right - left <= nodeSize)
	        return;
	    const m = left + right >> 1;
	    select(ids, coords, m, left, right, depth % 2);
	    sortKD(ids, coords, nodeSize, left, m - 1, depth + 1);
	    sortKD(ids, coords, nodeSize, m + 1, right, depth + 1);
	}
	function select(ids, coords, k, left, right, inc) {
	    while (right > left) {
	        if (right - left > 600) {
	            const n = right - left + 1;
	            const m = k - left + 1;
	            const z = Math.log(n);
	            const s = 0.5 * Math.exp(2 * z / 3);
	            const sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
	            const newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
	            const newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
	            select(ids, coords, k, newLeft, newRight, inc);
	        }
	        const t = coords[2 * k + inc];
	        let i = left;
	        let j = right;
	        swapItem(ids, coords, left, k);
	        if (coords[2 * right + inc] > t)
	            swapItem(ids, coords, left, right);
	        while (i < j) {
	            swapItem(ids, coords, i, j);
	            i++;
	            j--;
	            while (coords[2 * i + inc] < t)
	                i++;
	            while (coords[2 * j + inc] > t)
	                j--;
	        }
	        if (coords[2 * left + inc] === t)
	            swapItem(ids, coords, left, j);
	        else {
	            j++;
	            swapItem(ids, coords, j, right);
	        }
	        if (j <= k)
	            left = j + 1;
	        if (k <= j)
	            right = j - 1;
	    }
	}
	function swapItem(ids, coords, i, j) {
	    swap(ids, i, j);
	    swap(coords, 2 * i, 2 * j);
	    swap(coords, 2 * i + 1, 2 * j + 1);
	}
	function swap(arr, i, j) {
	    const tmp = arr[i];
	    arr[i] = arr[j];
	    arr[j] = tmp;
	}

	function range(ids, coords, minX, minY, maxX, maxY, nodeSize) {
	    const stack = [
	        0,
	        ids.length - 1,
	        0
	    ];
	    const result = [];
	    let x, y;
	    while (stack.length) {
	        const axis = stack.pop();
	        const right = stack.pop();
	        const left = stack.pop();
	        if (right - left <= nodeSize) {
	            for (let i = left; i <= right; i++) {
	                x = coords[2 * i];
	                y = coords[2 * i + 1];
	                if (x >= minX && x <= maxX && y >= minY && y <= maxY)
	                    result.push(ids[i]);
	            }
	            continue;
	        }
	        const m = Math.floor((left + right) / 2);
	        x = coords[2 * m];
	        y = coords[2 * m + 1];
	        if (x >= minX && x <= maxX && y >= minY && y <= maxY)
	            result.push(ids[m]);
	        const nextAxis = (axis + 1) % 2;
	        if (axis === 0 ? minX <= x : minY <= y) {
	            stack.push(left);
	            stack.push(m - 1);
	            stack.push(nextAxis);
	        }
	        if (axis === 0 ? maxX >= x : maxY >= y) {
	            stack.push(m + 1);
	            stack.push(right);
	            stack.push(nextAxis);
	        }
	    }
	    return result;
	}

	function within(ids, coords, qx, qy, r, nodeSize) {
	    const stack = [
	        0,
	        ids.length - 1,
	        0
	    ];
	    const result = [];
	    const r2 = r * r;
	    while (stack.length) {
	        const axis = stack.pop();
	        const right = stack.pop();
	        const left = stack.pop();
	        if (right - left <= nodeSize) {
	            for (let i = left; i <= right; i++) {
	                if (sqDist(coords[2 * i], coords[2 * i + 1], qx, qy) <= r2)
	                    result.push(ids[i]);
	            }
	            continue;
	        }
	        const m = Math.floor((left + right) / 2);
	        const x = coords[2 * m];
	        const y = coords[2 * m + 1];
	        if (sqDist(x, y, qx, qy) <= r2)
	            result.push(ids[m]);
	        const nextAxis = (axis + 1) % 2;
	        if (axis === 0 ? qx - r <= x : qy - r <= y) {
	            stack.push(left);
	            stack.push(m - 1);
	            stack.push(nextAxis);
	        }
	        if (axis === 0 ? qx + r >= x : qy + r >= y) {
	            stack.push(m + 1);
	            stack.push(right);
	            stack.push(nextAxis);
	        }
	    }
	    return result;
	}
	function sqDist(ax, ay, bx, by) {
	    const dx = ax - bx;
	    const dy = ay - by;
	    return dx * dx + dy * dy;
	}

	const defaultGetX = p => p[0];
	const defaultGetY = p => p[1];
	class KDBush {
	    constructor(points, getX = defaultGetX, getY = defaultGetY, nodeSize = 64, ArrayType = Float64Array) {
	        this.nodeSize = nodeSize;
	        this.points = points;
	        const IndexArrayType = points.length < 65536 ? Uint16Array : Uint32Array;
	        const ids = this.ids = new IndexArrayType(points.length);
	        const coords = this.coords = new ArrayType(points.length * 2);
	        for (let i = 0; i < points.length; i++) {
	            ids[i] = i;
	            coords[2 * i] = getX(points[i]);
	            coords[2 * i + 1] = getY(points[i]);
	        }
	        sortKD(ids, coords, nodeSize, 0, ids.length - 1, 0);
	    }
	    range(minX, minY, maxX, maxY) {
	        return range(this.ids, this.coords, minX, minY, maxX, maxY, this.nodeSize);
	    }
	    within(x, y, r) {
	        return within(this.ids, this.coords, x, y, r, this.nodeSize);
	    }
	}

	const defaultOptions = {
	    minZoom: 0,
	    maxZoom: 16,
	    minPoints: 2,
	    radius: 40,
	    extent: 512,
	    nodeSize: 64,
	    log: false,
	    generateId: false,
	    reduce: null,
	    map: props => props
	};
	const fround = Math.fround || (tmp => x => {
	    tmp[0] = +x;
	    return tmp[0];
	})(new Float32Array(1));
	class Supercluster {
	    constructor(options) {
	        this.options = extend$1(Object.create(defaultOptions), options);
	        this.trees = new Array(this.options.maxZoom + 1);
	    }
	    load(points) {
	        const {log, minZoom, maxZoom, nodeSize} = this.options;
	        if (log)
	            console.time('total time');
	        const timerId = `prepare ${ points.length } points`;
	        if (log)
	            console.time(timerId);
	        this.points = points;
	        let clusters = [];
	        for (let i = 0; i < points.length; i++) {
	            if (!points[i].geometry)
	                continue;
	            clusters.push(createPointCluster(points[i], i));
	        }
	        this.trees[maxZoom + 1] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);
	        if (log)
	            console.timeEnd(timerId);
	        for (let z = maxZoom; z >= minZoom; z--) {
	            const now = +Date.now();
	            clusters = this._cluster(clusters, z);
	            this.trees[z] = new KDBush(clusters, getX, getY, nodeSize, Float32Array);
	            if (log)
	                console.log('z%d: %d clusters in %dms', z, clusters.length, +Date.now() - now);
	        }
	        if (log)
	            console.timeEnd('total time');
	        return this;
	    }
	    getClusters(bbox, zoom) {
	        let minLng = ((bbox[0] + 180) % 360 + 360) % 360 - 180;
	        const minLat = Math.max(-90, Math.min(90, bbox[1]));
	        let maxLng = bbox[2] === 180 ? 180 : ((bbox[2] + 180) % 360 + 360) % 360 - 180;
	        const maxLat = Math.max(-90, Math.min(90, bbox[3]));
	        if (bbox[2] - bbox[0] >= 360) {
	            minLng = -180;
	            maxLng = 180;
	        } else if (minLng > maxLng) {
	            const easternHem = this.getClusters([
	                minLng,
	                minLat,
	                180,
	                maxLat
	            ], zoom);
	            const westernHem = this.getClusters([
	                -180,
	                minLat,
	                maxLng,
	                maxLat
	            ], zoom);
	            return easternHem.concat(westernHem);
	        }
	        const tree = this.trees[this._limitZoom(zoom)];
	        const ids = tree.range(lngX(minLng), latY(maxLat), lngX(maxLng), latY(minLat));
	        const clusters = [];
	        for (const id of ids) {
	            const c = tree.points[id];
	            clusters.push(c.numPoints ? getClusterJSON(c) : this.points[c.index]);
	        }
	        return clusters;
	    }
	    getChildren(clusterId) {
	        const originId = this._getOriginId(clusterId);
	        const originZoom = this._getOriginZoom(clusterId);
	        const errorMsg = 'No cluster with the specified id.';
	        const index = this.trees[originZoom];
	        if (!index)
	            throw new Error(errorMsg);
	        const origin = index.points[originId];
	        if (!origin)
	            throw new Error(errorMsg);
	        const r = this.options.radius / (this.options.extent * Math.pow(2, originZoom - 1));
	        const ids = index.within(origin.x, origin.y, r);
	        const children = [];
	        for (const id of ids) {
	            const c = index.points[id];
	            if (c.parentId === clusterId) {
	                children.push(c.numPoints ? getClusterJSON(c) : this.points[c.index]);
	            }
	        }
	        if (children.length === 0)
	            throw new Error(errorMsg);
	        return children;
	    }
	    getLeaves(clusterId, limit, offset) {
	        limit = limit || 10;
	        offset = offset || 0;
	        const leaves = [];
	        this._appendLeaves(leaves, clusterId, limit, offset, 0);
	        return leaves;
	    }
	    getTile(z, x, y) {
	        const tree = this.trees[this._limitZoom(z)];
	        const z2 = Math.pow(2, z);
	        const {extent, radius} = this.options;
	        const p = radius / extent;
	        const top = (y - p) / z2;
	        const bottom = (y + 1 + p) / z2;
	        const tile = { features: [] };
	        this._addTileFeatures(tree.range((x - p) / z2, top, (x + 1 + p) / z2, bottom), tree.points, x, y, z2, tile);
	        if (x === 0) {
	            this._addTileFeatures(tree.range(1 - p / z2, top, 1, bottom), tree.points, z2, y, z2, tile);
	        }
	        if (x === z2 - 1) {
	            this._addTileFeatures(tree.range(0, top, p / z2, bottom), tree.points, -1, y, z2, tile);
	        }
	        return tile.features.length ? tile : null;
	    }
	    getClusterExpansionZoom(clusterId) {
	        let expansionZoom = this._getOriginZoom(clusterId) - 1;
	        while (expansionZoom <= this.options.maxZoom) {
	            const children = this.getChildren(clusterId);
	            expansionZoom++;
	            if (children.length !== 1)
	                break;
	            clusterId = children[0].properties.cluster_id;
	        }
	        return expansionZoom;
	    }
	    _appendLeaves(result, clusterId, limit, offset, skipped) {
	        const children = this.getChildren(clusterId);
	        for (const child of children) {
	            const props = child.properties;
	            if (props && props.cluster) {
	                if (skipped + props.point_count <= offset) {
	                    skipped += props.point_count;
	                } else {
	                    skipped = this._appendLeaves(result, props.cluster_id, limit, offset, skipped);
	                }
	            } else if (skipped < offset) {
	                skipped++;
	            } else {
	                result.push(child);
	            }
	            if (result.length === limit)
	                break;
	        }
	        return skipped;
	    }
	    _addTileFeatures(ids, points, x, y, z2, tile) {
	        for (const i of ids) {
	            const c = points[i];
	            const isCluster = c.numPoints;
	            let tags, px, py;
	            if (isCluster) {
	                tags = getClusterProperties(c);
	                px = c.x;
	                py = c.y;
	            } else {
	                const p = this.points[c.index];
	                tags = p.properties;
	                px = lngX(p.geometry.coordinates[0]);
	                py = latY(p.geometry.coordinates[1]);
	            }
	            const f = {
	                type: 1,
	                geometry: [[
	                        Math.round(this.options.extent * (px * z2 - x)),
	                        Math.round(this.options.extent * (py * z2 - y))
	                    ]],
	                tags
	            };
	            let id;
	            if (isCluster) {
	                id = c.id;
	            } else if (this.options.generateId) {
	                id = c.index;
	            } else if (this.points[c.index].id) {
	                id = this.points[c.index].id;
	            }
	            if (id !== undefined)
	                f.id = id;
	            tile.features.push(f);
	        }
	    }
	    _limitZoom(z) {
	        return Math.max(this.options.minZoom, Math.min(+z, this.options.maxZoom + 1));
	    }
	    _cluster(points, zoom) {
	        const clusters = [];
	        const {radius, extent, reduce, minPoints} = this.options;
	        const r = radius / (extent * Math.pow(2, zoom));
	        for (let i = 0; i < points.length; i++) {
	            const p = points[i];
	            if (p.zoom <= zoom)
	                continue;
	            p.zoom = zoom;
	            const tree = this.trees[zoom + 1];
	            const neighborIds = tree.within(p.x, p.y, r);
	            const numPointsOrigin = p.numPoints || 1;
	            let numPoints = numPointsOrigin;
	            for (const neighborId of neighborIds) {
	                const b = tree.points[neighborId];
	                if (b.zoom > zoom)
	                    numPoints += b.numPoints || 1;
	            }
	            if (numPoints > numPointsOrigin && numPoints >= minPoints) {
	                let wx = p.x * numPointsOrigin;
	                let wy = p.y * numPointsOrigin;
	                let clusterProperties = reduce && numPointsOrigin > 1 ? this._map(p, true) : null;
	                const id = (i << 5) + (zoom + 1) + this.points.length;
	                for (const neighborId of neighborIds) {
	                    const b = tree.points[neighborId];
	                    if (b.zoom <= zoom)
	                        continue;
	                    b.zoom = zoom;
	                    const numPoints2 = b.numPoints || 1;
	                    wx += b.x * numPoints2;
	                    wy += b.y * numPoints2;
	                    b.parentId = id;
	                    if (reduce) {
	                        if (!clusterProperties)
	                            clusterProperties = this._map(p, true);
	                        reduce(clusterProperties, this._map(b));
	                    }
	                }
	                p.parentId = id;
	                clusters.push(createCluster(wx / numPoints, wy / numPoints, id, numPoints, clusterProperties));
	            } else {
	                clusters.push(p);
	                if (numPoints > 1) {
	                    for (const neighborId of neighborIds) {
	                        const b = tree.points[neighborId];
	                        if (b.zoom <= zoom)
	                            continue;
	                        b.zoom = zoom;
	                        clusters.push(b);
	                    }
	                }
	            }
	        }
	        return clusters;
	    }
	    _getOriginId(clusterId) {
	        return clusterId - this.points.length >> 5;
	    }
	    _getOriginZoom(clusterId) {
	        return (clusterId - this.points.length) % 32;
	    }
	    _map(point, clone) {
	        if (point.numPoints) {
	            return clone ? extend$1({}, point.properties) : point.properties;
	        }
	        const original = this.points[point.index].properties;
	        const result = this.options.map(original);
	        return clone && result === original ? extend$1({}, result) : result;
	    }
	}
	function createCluster(x, y, id, numPoints, properties) {
	    return {
	        x: fround(x),
	        y: fround(y),
	        zoom: Infinity,
	        id,
	        parentId: -1,
	        numPoints,
	        properties
	    };
	}
	function createPointCluster(p, id) {
	    const [x, y] = p.geometry.coordinates;
	    return {
	        x: fround(lngX(x)),
	        y: fround(latY(y)),
	        zoom: Infinity,
	        index: id,
	        parentId: -1
	    };
	}
	function getClusterJSON(cluster) {
	    return {
	        type: 'Feature',
	        id: cluster.id,
	        properties: getClusterProperties(cluster),
	        geometry: {
	            type: 'Point',
	            coordinates: [
	                xLng(cluster.x),
	                yLat(cluster.y)
	            ]
	        }
	    };
	}
	function getClusterProperties(cluster) {
	    const count = cluster.numPoints;
	    const abbrev = count >= 10000 ? `${ Math.round(count / 1000) }k` : count >= 1000 ? `${ Math.round(count / 100) / 10 }k` : count;
	    return extend$1(extend$1({}, cluster.properties), {
	        cluster: true,
	        cluster_id: cluster.id,
	        point_count: count,
	        point_count_abbreviated: abbrev
	    });
	}
	function lngX(lng) {
	    return lng / 360 + 0.5;
	}
	function latY(lat) {
	    const sin = Math.sin(lat * Math.PI / 180);
	    const y = 0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI;
	    return y < 0 ? 0 : y > 1 ? 1 : y;
	}
	function xLng(x) {
	    return (x - 0.5) * 360;
	}
	function yLat(y) {
	    const y2 = (180 - y * 360) * Math.PI / 180;
	    return 360 * Math.atan(Math.exp(y2)) / Math.PI - 90;
	}
	function extend$1(dest, src) {
	    for (const id in src)
	        dest[id] = src[id];
	    return dest;
	}
	function getX(p) {
	    return p.x;
	}
	function getY(p) {
	    return p.y;
	}

	function simplify(coords, first, last, sqTolerance) {
	    var maxSqDist = sqTolerance;
	    var mid = last - first >> 1;
	    var minPosToMid = last - first;
	    var index;
	    var ax = coords[first];
	    var ay = coords[first + 1];
	    var bx = coords[last];
	    var by = coords[last + 1];
	    for (var i = first + 3; i < last; i += 3) {
	        var d = getSqSegDist(coords[i], coords[i + 1], ax, ay, bx, by);
	        if (d > maxSqDist) {
	            index = i;
	            maxSqDist = d;
	        } else if (d === maxSqDist) {
	            var posToMid = Math.abs(i - mid);
	            if (posToMid < minPosToMid) {
	                index = i;
	                minPosToMid = posToMid;
	            }
	        }
	    }
	    if (maxSqDist > sqTolerance) {
	        if (index - first > 3)
	            simplify(coords, first, index, sqTolerance);
	        coords[index + 2] = maxSqDist;
	        if (last - index > 3)
	            simplify(coords, index, last, sqTolerance);
	    }
	}
	function getSqSegDist(px, py, x, y, bx, by) {
	    var dx = bx - x;
	    var dy = by - y;
	    if (dx !== 0 || dy !== 0) {
	        var t = ((px - x) * dx + (py - y) * dy) / (dx * dx + dy * dy);
	        if (t > 1) {
	            x = bx;
	            y = by;
	        } else if (t > 0) {
	            x += dx * t;
	            y += dy * t;
	        }
	    }
	    dx = px - x;
	    dy = py - y;
	    return dx * dx + dy * dy;
	}

	function createFeature(id, type, geom, tags) {
	    var feature = {
	        id: typeof id === 'undefined' ? null : id,
	        type: type,
	        geometry: geom,
	        tags: tags,
	        minX: Infinity,
	        minY: Infinity,
	        maxX: -Infinity,
	        maxY: -Infinity
	    };
	    calcBBox(feature);
	    return feature;
	}
	function calcBBox(feature) {
	    var geom = feature.geometry;
	    var type = feature.type;
	    if (type === 'Point' || type === 'MultiPoint' || type === 'LineString') {
	        calcLineBBox(feature, geom);
	    } else if (type === 'Polygon' || type === 'MultiLineString') {
	        for (var i = 0; i < geom.length; i++) {
	            calcLineBBox(feature, geom[i]);
	        }
	    } else if (type === 'MultiPolygon') {
	        for (i = 0; i < geom.length; i++) {
	            for (var j = 0; j < geom[i].length; j++) {
	                calcLineBBox(feature, geom[i][j]);
	            }
	        }
	    }
	}
	function calcLineBBox(feature, geom) {
	    for (var i = 0; i < geom.length; i += 3) {
	        feature.minX = Math.min(feature.minX, geom[i]);
	        feature.minY = Math.min(feature.minY, geom[i + 1]);
	        feature.maxX = Math.max(feature.maxX, geom[i]);
	        feature.maxY = Math.max(feature.maxY, geom[i + 1]);
	    }
	}

	function convert(data, options) {
	    var features = [];
	    if (data.type === 'FeatureCollection') {
	        for (var i = 0; i < data.features.length; i++) {
	            convertFeature(features, data.features[i], options, i);
	        }
	    } else if (data.type === 'Feature') {
	        convertFeature(features, data, options);
	    } else {
	        convertFeature(features, { geometry: data }, options);
	    }
	    return features;
	}
	function convertFeature(features, geojson, options, index) {
	    if (!geojson.geometry)
	        return;
	    var coords = geojson.geometry.coordinates;
	    var type = geojson.geometry.type;
	    var tolerance = Math.pow(options.tolerance / ((1 << options.maxZoom) * options.extent), 2);
	    var geometry = [];
	    var id = geojson.id;
	    if (options.promoteId) {
	        id = geojson.properties[options.promoteId];
	    } else if (options.generateId) {
	        id = index || 0;
	    }
	    if (type === 'Point') {
	        convertPoint(coords, geometry);
	    } else if (type === 'MultiPoint') {
	        for (var i = 0; i < coords.length; i++) {
	            convertPoint(coords[i], geometry);
	        }
	    } else if (type === 'LineString') {
	        convertLine(coords, geometry, tolerance, false);
	    } else if (type === 'MultiLineString') {
	        if (options.lineMetrics) {
	            for (i = 0; i < coords.length; i++) {
	                geometry = [];
	                convertLine(coords[i], geometry, tolerance, false);
	                features.push(createFeature(id, 'LineString', geometry, geojson.properties));
	            }
	            return;
	        } else {
	            convertLines(coords, geometry, tolerance, false);
	        }
	    } else if (type === 'Polygon') {
	        convertLines(coords, geometry, tolerance, true);
	    } else if (type === 'MultiPolygon') {
	        for (i = 0; i < coords.length; i++) {
	            var polygon = [];
	            convertLines(coords[i], polygon, tolerance, true);
	            geometry.push(polygon);
	        }
	    } else if (type === 'GeometryCollection') {
	        for (i = 0; i < geojson.geometry.geometries.length; i++) {
	            convertFeature(features, {
	                id: id,
	                geometry: geojson.geometry.geometries[i],
	                properties: geojson.properties
	            }, options, index);
	        }
	        return;
	    } else {
	        throw new Error('Input data is not a valid GeoJSON object.');
	    }
	    features.push(createFeature(id, type, geometry, geojson.properties));
	}
	function convertPoint(coords, out) {
	    out.push(projectX(coords[0]));
	    out.push(projectY(coords[1]));
	    out.push(0);
	}
	function convertLine(ring, out, tolerance, isPolygon) {
	    var x0, y0;
	    var size = 0;
	    for (var j = 0; j < ring.length; j++) {
	        var x = projectX(ring[j][0]);
	        var y = projectY(ring[j][1]);
	        out.push(x);
	        out.push(y);
	        out.push(0);
	        if (j > 0) {
	            if (isPolygon) {
	                size += (x0 * y - x * y0) / 2;
	            } else {
	                size += Math.sqrt(Math.pow(x - x0, 2) + Math.pow(y - y0, 2));
	            }
	        }
	        x0 = x;
	        y0 = y;
	    }
	    var last = out.length - 3;
	    out[2] = 1;
	    simplify(out, 0, last, tolerance);
	    out[last + 2] = 1;
	    out.size = Math.abs(size);
	    out.start = 0;
	    out.end = out.size;
	}
	function convertLines(rings, out, tolerance, isPolygon) {
	    for (var i = 0; i < rings.length; i++) {
	        var geom = [];
	        convertLine(rings[i], geom, tolerance, isPolygon);
	        out.push(geom);
	    }
	}
	function projectX(x) {
	    return x / 360 + 0.5;
	}
	function projectY(y) {
	    var sin = Math.sin(y * Math.PI / 180);
	    var y2 = 0.5 - 0.25 * Math.log((1 + sin) / (1 - sin)) / Math.PI;
	    return y2 < 0 ? 0 : y2 > 1 ? 1 : y2;
	}

	function clip(features, scale, k1, k2, axis, minAll, maxAll, options) {
	    k1 /= scale;
	    k2 /= scale;
	    if (minAll >= k1 && maxAll < k2)
	        return features;
	    else if (maxAll < k1 || minAll >= k2)
	        return null;
	    var clipped = [];
	    for (var i = 0; i < features.length; i++) {
	        var feature = features[i];
	        var geometry = feature.geometry;
	        var type = feature.type;
	        var min = axis === 0 ? feature.minX : feature.minY;
	        var max = axis === 0 ? feature.maxX : feature.maxY;
	        if (min >= k1 && max < k2) {
	            clipped.push(feature);
	            continue;
	        } else if (max < k1 || min >= k2) {
	            continue;
	        }
	        var newGeometry = [];
	        if (type === 'Point' || type === 'MultiPoint') {
	            clipPoints(geometry, newGeometry, k1, k2, axis);
	        } else if (type === 'LineString') {
	            clipLine(geometry, newGeometry, k1, k2, axis, false, options.lineMetrics);
	        } else if (type === 'MultiLineString') {
	            clipLines(geometry, newGeometry, k1, k2, axis, false);
	        } else if (type === 'Polygon') {
	            clipLines(geometry, newGeometry, k1, k2, axis, true);
	        } else if (type === 'MultiPolygon') {
	            for (var j = 0; j < geometry.length; j++) {
	                var polygon = [];
	                clipLines(geometry[j], polygon, k1, k2, axis, true);
	                if (polygon.length) {
	                    newGeometry.push(polygon);
	                }
	            }
	        }
	        if (newGeometry.length) {
	            if (options.lineMetrics && type === 'LineString') {
	                for (j = 0; j < newGeometry.length; j++) {
	                    clipped.push(createFeature(feature.id, type, newGeometry[j], feature.tags));
	                }
	                continue;
	            }
	            if (type === 'LineString' || type === 'MultiLineString') {
	                if (newGeometry.length === 1) {
	                    type = 'LineString';
	                    newGeometry = newGeometry[0];
	                } else {
	                    type = 'MultiLineString';
	                }
	            }
	            if (type === 'Point' || type === 'MultiPoint') {
	                type = newGeometry.length === 3 ? 'Point' : 'MultiPoint';
	            }
	            clipped.push(createFeature(feature.id, type, newGeometry, feature.tags));
	        }
	    }
	    return clipped.length ? clipped : null;
	}
	function clipPoints(geom, newGeom, k1, k2, axis) {
	    for (var i = 0; i < geom.length; i += 3) {
	        var a = geom[i + axis];
	        if (a >= k1 && a <= k2) {
	            newGeom.push(geom[i]);
	            newGeom.push(geom[i + 1]);
	            newGeom.push(geom[i + 2]);
	        }
	    }
	}
	function clipLine(geom, newGeom, k1, k2, axis, isPolygon, trackMetrics) {
	    var slice = newSlice(geom);
	    var intersect = axis === 0 ? intersectX : intersectY;
	    var len = geom.start;
	    var segLen, t;
	    for (var i = 0; i < geom.length - 3; i += 3) {
	        var ax = geom[i];
	        var ay = geom[i + 1];
	        var az = geom[i + 2];
	        var bx = geom[i + 3];
	        var by = geom[i + 4];
	        var a = axis === 0 ? ax : ay;
	        var b = axis === 0 ? bx : by;
	        var exited = false;
	        if (trackMetrics)
	            segLen = Math.sqrt(Math.pow(ax - bx, 2) + Math.pow(ay - by, 2));
	        if (a < k1) {
	            if (b > k1) {
	                t = intersect(slice, ax, ay, bx, by, k1);
	                if (trackMetrics)
	                    slice.start = len + segLen * t;
	            }
	        } else if (a > k2) {
	            if (b < k2) {
	                t = intersect(slice, ax, ay, bx, by, k2);
	                if (trackMetrics)
	                    slice.start = len + segLen * t;
	            }
	        } else {
	            addPoint(slice, ax, ay, az);
	        }
	        if (b < k1 && a >= k1) {
	            t = intersect(slice, ax, ay, bx, by, k1);
	            exited = true;
	        }
	        if (b > k2 && a <= k2) {
	            t = intersect(slice, ax, ay, bx, by, k2);
	            exited = true;
	        }
	        if (!isPolygon && exited) {
	            if (trackMetrics)
	                slice.end = len + segLen * t;
	            newGeom.push(slice);
	            slice = newSlice(geom);
	        }
	        if (trackMetrics)
	            len += segLen;
	    }
	    var last = geom.length - 3;
	    ax = geom[last];
	    ay = geom[last + 1];
	    az = geom[last + 2];
	    a = axis === 0 ? ax : ay;
	    if (a >= k1 && a <= k2)
	        addPoint(slice, ax, ay, az);
	    last = slice.length - 3;
	    if (isPolygon && last >= 3 && (slice[last] !== slice[0] || slice[last + 1] !== slice[1])) {
	        addPoint(slice, slice[0], slice[1], slice[2]);
	    }
	    if (slice.length) {
	        newGeom.push(slice);
	    }
	}
	function newSlice(line) {
	    var slice = [];
	    slice.size = line.size;
	    slice.start = line.start;
	    slice.end = line.end;
	    return slice;
	}
	function clipLines(geom, newGeom, k1, k2, axis, isPolygon) {
	    for (var i = 0; i < geom.length; i++) {
	        clipLine(geom[i], newGeom, k1, k2, axis, isPolygon, false);
	    }
	}
	function addPoint(out, x, y, z) {
	    out.push(x);
	    out.push(y);
	    out.push(z);
	}
	function intersectX(out, ax, ay, bx, by, x) {
	    var t = (x - ax) / (bx - ax);
	    out.push(x);
	    out.push(ay + (by - ay) * t);
	    out.push(1);
	    return t;
	}
	function intersectY(out, ax, ay, bx, by, y) {
	    var t = (y - ay) / (by - ay);
	    out.push(ax + (bx - ax) * t);
	    out.push(y);
	    out.push(1);
	    return t;
	}

	function wrap(features, options) {
	    var buffer = options.buffer / options.extent;
	    var merged = features;
	    var left = clip(features, 1, -1 - buffer, buffer, 0, -1, 2, options);
	    var right = clip(features, 1, 1 - buffer, 2 + buffer, 0, -1, 2, options);
	    if (left || right) {
	        merged = clip(features, 1, -buffer, 1 + buffer, 0, -1, 2, options) || [];
	        if (left)
	            merged = shiftFeatureCoords(left, 1).concat(merged);
	        if (right)
	            merged = merged.concat(shiftFeatureCoords(right, -1));
	    }
	    return merged;
	}
	function shiftFeatureCoords(features, offset) {
	    var newFeatures = [];
	    for (var i = 0; i < features.length; i++) {
	        var feature = features[i], type = feature.type;
	        var newGeometry;
	        if (type === 'Point' || type === 'MultiPoint' || type === 'LineString') {
	            newGeometry = shiftCoords(feature.geometry, offset);
	        } else if (type === 'MultiLineString' || type === 'Polygon') {
	            newGeometry = [];
	            for (var j = 0; j < feature.geometry.length; j++) {
	                newGeometry.push(shiftCoords(feature.geometry[j], offset));
	            }
	        } else if (type === 'MultiPolygon') {
	            newGeometry = [];
	            for (j = 0; j < feature.geometry.length; j++) {
	                var newPolygon = [];
	                for (var k = 0; k < feature.geometry[j].length; k++) {
	                    newPolygon.push(shiftCoords(feature.geometry[j][k], offset));
	                }
	                newGeometry.push(newPolygon);
	            }
	        }
	        newFeatures.push(createFeature(feature.id, type, newGeometry, feature.tags));
	    }
	    return newFeatures;
	}
	function shiftCoords(points, offset) {
	    var newPoints = [];
	    newPoints.size = points.size;
	    if (points.start !== undefined) {
	        newPoints.start = points.start;
	        newPoints.end = points.end;
	    }
	    for (var i = 0; i < points.length; i += 3) {
	        newPoints.push(points[i] + offset, points[i + 1], points[i + 2]);
	    }
	    return newPoints;
	}

	function transformTile(tile, extent) {
	    if (tile.transformed)
	        return tile;
	    var z2 = 1 << tile.z, tx = tile.x, ty = tile.y, i, j, k;
	    for (i = 0; i < tile.features.length; i++) {
	        var feature = tile.features[i], geom = feature.geometry, type = feature.type;
	        feature.geometry = [];
	        if (type === 1) {
	            for (j = 0; j < geom.length; j += 2) {
	                feature.geometry.push(transformPoint(geom[j], geom[j + 1], extent, z2, tx, ty));
	            }
	        } else {
	            for (j = 0; j < geom.length; j++) {
	                var ring = [];
	                for (k = 0; k < geom[j].length; k += 2) {
	                    ring.push(transformPoint(geom[j][k], geom[j][k + 1], extent, z2, tx, ty));
	                }
	                feature.geometry.push(ring);
	            }
	        }
	    }
	    tile.transformed = true;
	    return tile;
	}
	function transformPoint(x, y, extent, z2, tx, ty) {
	    return [
	        Math.round(extent * (x * z2 - tx)),
	        Math.round(extent * (y * z2 - ty))
	    ];
	}

	function createTile(features, z, tx, ty, options) {
	    var tolerance = z === options.maxZoom ? 0 : options.tolerance / ((1 << z) * options.extent);
	    var tile = {
	        features: [],
	        numPoints: 0,
	        numSimplified: 0,
	        numFeatures: 0,
	        source: null,
	        x: tx,
	        y: ty,
	        z: z,
	        transformed: false,
	        minX: 2,
	        minY: 1,
	        maxX: -1,
	        maxY: 0
	    };
	    for (var i = 0; i < features.length; i++) {
	        tile.numFeatures++;
	        addFeature(tile, features[i], tolerance, options);
	        var minX = features[i].minX;
	        var minY = features[i].minY;
	        var maxX = features[i].maxX;
	        var maxY = features[i].maxY;
	        if (minX < tile.minX)
	            tile.minX = minX;
	        if (minY < tile.minY)
	            tile.minY = minY;
	        if (maxX > tile.maxX)
	            tile.maxX = maxX;
	        if (maxY > tile.maxY)
	            tile.maxY = maxY;
	    }
	    return tile;
	}
	function addFeature(tile, feature, tolerance, options) {
	    var geom = feature.geometry, type = feature.type, simplified = [];
	    if (type === 'Point' || type === 'MultiPoint') {
	        for (var i = 0; i < geom.length; i += 3) {
	            simplified.push(geom[i]);
	            simplified.push(geom[i + 1]);
	            tile.numPoints++;
	            tile.numSimplified++;
	        }
	    } else if (type === 'LineString') {
	        addLine(simplified, geom, tile, tolerance, false, false);
	    } else if (type === 'MultiLineString' || type === 'Polygon') {
	        for (i = 0; i < geom.length; i++) {
	            addLine(simplified, geom[i], tile, tolerance, type === 'Polygon', i === 0);
	        }
	    } else if (type === 'MultiPolygon') {
	        for (var k = 0; k < geom.length; k++) {
	            var polygon = geom[k];
	            for (i = 0; i < polygon.length; i++) {
	                addLine(simplified, polygon[i], tile, tolerance, true, i === 0);
	            }
	        }
	    }
	    if (simplified.length) {
	        var tags = feature.tags || null;
	        if (type === 'LineString' && options.lineMetrics) {
	            tags = {};
	            for (var key in feature.tags)
	                tags[key] = feature.tags[key];
	            tags['mapbox_clip_start'] = geom.start / geom.size;
	            tags['mapbox_clip_end'] = geom.end / geom.size;
	        }
	        var tileFeature = {
	            geometry: simplified,
	            type: type === 'Polygon' || type === 'MultiPolygon' ? 3 : type === 'LineString' || type === 'MultiLineString' ? 2 : 1,
	            tags: tags
	        };
	        if (feature.id !== null) {
	            tileFeature.id = feature.id;
	        }
	        tile.features.push(tileFeature);
	    }
	}
	function addLine(result, geom, tile, tolerance, isPolygon, isOuter) {
	    var sqTolerance = tolerance * tolerance;
	    if (tolerance > 0 && geom.size < (isPolygon ? sqTolerance : tolerance)) {
	        tile.numPoints += geom.length / 3;
	        return;
	    }
	    var ring = [];
	    for (var i = 0; i < geom.length; i += 3) {
	        if (tolerance === 0 || geom[i + 2] > sqTolerance) {
	            tile.numSimplified++;
	            ring.push(geom[i]);
	            ring.push(geom[i + 1]);
	        }
	        tile.numPoints++;
	    }
	    if (isPolygon)
	        rewind(ring, isOuter);
	    result.push(ring);
	}
	function rewind(ring, clockwise) {
	    var area = 0;
	    for (var i = 0, len = ring.length, j = len - 2; i < len; j = i, i += 2) {
	        area += (ring[i] - ring[j]) * (ring[i + 1] + ring[j + 1]);
	    }
	    if (area > 0 === clockwise) {
	        for (i = 0, len = ring.length; i < len / 2; i += 2) {
	            var x = ring[i];
	            var y = ring[i + 1];
	            ring[i] = ring[len - 2 - i];
	            ring[i + 1] = ring[len - 1 - i];
	            ring[len - 2 - i] = x;
	            ring[len - 1 - i] = y;
	        }
	    }
	}

	function geojsonvt(data, options) {
	    return new GeoJSONVT(data, options);
	}
	function GeoJSONVT(data, options) {
	    options = this.options = extend(Object.create(this.options), options);
	    var debug = options.debug;
	    if (debug)
	        console.time('preprocess data');
	    if (options.maxZoom < 0 || options.maxZoom > 24)
	        throw new Error('maxZoom should be in the 0-24 range');
	    if (options.promoteId && options.generateId)
	        throw new Error('promoteId and generateId cannot be used together.');
	    var features = convert(data, options);
	    this.tiles = {};
	    this.tileCoords = [];
	    if (debug) {
	        console.timeEnd('preprocess data');
	        console.log('index: maxZoom: %d, maxPoints: %d', options.indexMaxZoom, options.indexMaxPoints);
	        console.time('generate tiles');
	        this.stats = {};
	        this.total = 0;
	    }
	    features = wrap(features, options);
	    if (features.length)
	        this.splitTile(features, 0, 0, 0);
	    if (debug) {
	        if (features.length)
	            console.log('features: %d, points: %d', this.tiles[0].numFeatures, this.tiles[0].numPoints);
	        console.timeEnd('generate tiles');
	        console.log('tiles generated:', this.total, JSON.stringify(this.stats));
	    }
	}
	GeoJSONVT.prototype.options = {
	    maxZoom: 14,
	    indexMaxZoom: 5,
	    indexMaxPoints: 100000,
	    tolerance: 3,
	    extent: 4096,
	    buffer: 64,
	    lineMetrics: false,
	    promoteId: null,
	    generateId: false,
	    debug: 0
	};
	GeoJSONVT.prototype.splitTile = function (features, z, x, y, cz, cx, cy) {
	    var stack = [
	            features,
	            z,
	            x,
	            y
	        ], options = this.options, debug = options.debug;
	    while (stack.length) {
	        y = stack.pop();
	        x = stack.pop();
	        z = stack.pop();
	        features = stack.pop();
	        var z2 = 1 << z, id = toID(z, x, y), tile = this.tiles[id];
	        if (!tile) {
	            if (debug > 1)
	                console.time('creation');
	            tile = this.tiles[id] = createTile(features, z, x, y, options);
	            this.tileCoords.push({
	                z: z,
	                x: x,
	                y: y
	            });
	            if (debug) {
	                if (debug > 1) {
	                    console.log('tile z%d-%d-%d (features: %d, points: %d, simplified: %d)', z, x, y, tile.numFeatures, tile.numPoints, tile.numSimplified);
	                    console.timeEnd('creation');
	                }
	                var key = 'z' + z;
	                this.stats[key] = (this.stats[key] || 0) + 1;
	                this.total++;
	            }
	        }
	        tile.source = features;
	        if (!cz) {
	            if (z === options.indexMaxZoom || tile.numPoints <= options.indexMaxPoints)
	                continue;
	        } else {
	            if (z === options.maxZoom || z === cz)
	                continue;
	            var m = 1 << cz - z;
	            if (x !== Math.floor(cx / m) || y !== Math.floor(cy / m))
	                continue;
	        }
	        tile.source = null;
	        if (features.length === 0)
	            continue;
	        if (debug > 1)
	            console.time('clipping');
	        var k1 = 0.5 * options.buffer / options.extent, k2 = 0.5 - k1, k3 = 0.5 + k1, k4 = 1 + k1, tl, bl, tr, br, left, right;
	        tl = bl = tr = br = null;
	        left = clip(features, z2, x - k1, x + k3, 0, tile.minX, tile.maxX, options);
	        right = clip(features, z2, x + k2, x + k4, 0, tile.minX, tile.maxX, options);
	        features = null;
	        if (left) {
	            tl = clip(left, z2, y - k1, y + k3, 1, tile.minY, tile.maxY, options);
	            bl = clip(left, z2, y + k2, y + k4, 1, tile.minY, tile.maxY, options);
	            left = null;
	        }
	        if (right) {
	            tr = clip(right, z2, y - k1, y + k3, 1, tile.minY, tile.maxY, options);
	            br = clip(right, z2, y + k2, y + k4, 1, tile.minY, tile.maxY, options);
	            right = null;
	        }
	        if (debug > 1)
	            console.timeEnd('clipping');
	        stack.push(tl || [], z + 1, x * 2, y * 2);
	        stack.push(bl || [], z + 1, x * 2, y * 2 + 1);
	        stack.push(tr || [], z + 1, x * 2 + 1, y * 2);
	        stack.push(br || [], z + 1, x * 2 + 1, y * 2 + 1);
	    }
	};
	GeoJSONVT.prototype.getTile = function (z, x, y) {
	    var options = this.options, extent = options.extent, debug = options.debug;
	    if (z < 0 || z > 24)
	        return null;
	    var z2 = 1 << z;
	    x = (x % z2 + z2) % z2;
	    var id = toID(z, x, y);
	    if (this.tiles[id])
	        return transformTile(this.tiles[id], extent);
	    if (debug > 1)
	        console.log('drilling down to z%d-%d-%d', z, x, y);
	    var z0 = z, x0 = x, y0 = y, parent;
	    while (!parent && z0 > 0) {
	        z0--;
	        x0 = Math.floor(x0 / 2);
	        y0 = Math.floor(y0 / 2);
	        parent = this.tiles[toID(z0, x0, y0)];
	    }
	    if (!parent || !parent.source)
	        return null;
	    if (debug > 1)
	        console.log('found parent tile z%d-%d-%d', z0, x0, y0);
	    if (debug > 1)
	        console.time('drilling down');
	    this.splitTile(parent.source, z0, x0, y0, z, x, y);
	    if (debug > 1)
	        console.timeEnd('drilling down');
	    return this.tiles[id] ? transformTile(this.tiles[id], extent) : null;
	};
	function toID(z, x, y) {
	    return ((1 << z) * y + x) * 32 + z;
	}
	function extend(dest, src) {
	    for (var i in src)
	        dest[i] = src[i];
	    return dest;
	}

	function loadGeoJSONTile(params, callback) {
	    const canonical = params.tileID.canonical;
	    if (!this._geoJSONIndex) {
	        return callback(null, null);
	    }
	    const geoJSONTile = this._geoJSONIndex.getTile(canonical.z, canonical.x, canonical.y);
	    if (!geoJSONTile) {
	        return callback(null, null);
	    }
	    const geojsonWrapper = new GeoJSONWrapper$1(geoJSONTile.features);
	    let pbf = vtPbf(geojsonWrapper);
	    if (pbf.byteOffset !== 0 || pbf.byteLength !== pbf.buffer.byteLength) {
	        pbf = new Uint8Array(pbf);
	    }
	    callback(null, {
	        vectorTile: geojsonWrapper,
	        rawData: pbf.buffer
	    });
	}
	class GeoJSONWorkerSource extends ref_properties.VectorTileWorkerSource {
	    constructor(actor, layerIndex, availableImages, isSpriteLoaded, loadGeoJSON) {
	        super(actor, layerIndex, availableImages, isSpriteLoaded, loadGeoJSONTile);
	        if (loadGeoJSON) {
	            this.loadGeoJSON = loadGeoJSON;
	        }
	    }
	    loadData(params, callback) {
	        const requestParam = params && params.request;
	        const perf = requestParam && requestParam.collectResourceTiming;
	        this.loadGeoJSON(params, (err, data) => {
	            if (err || !data) {
	                return callback(err);
	            } else if (typeof data !== 'object') {
	                return callback(new Error(`Input data given to '${ params.source }' is not a valid GeoJSON object.`));
	            } else {
	                geojsonRewind(data, true);
	                try {
	                    if (params.filter) {
	                        const compiled = ref_properties.createExpression(params.filter, {
	                            type: 'boolean',
	                            'property-type': 'data-driven',
	                            overridable: false,
	                            transition: false
	                        });
	                        if (compiled.result === 'error')
	                            throw new Error(compiled.value.map(err => `${ err.key }: ${ err.message }`).join(', '));
	                        const features = data.features.filter(feature => compiled.value.evaluate({ zoom: 0 }, feature));
	                        data = {
	                            type: 'FeatureCollection',
	                            features
	                        };
	                    }
	                    this._geoJSONIndex = params.cluster ? new Supercluster(getSuperclusterOptions(params)).load(data.features) : geojsonvt(data, params.geojsonVtOptions);
	                } catch (err) {
	                    return callback(err);
	                }
	                this.loaded = {};
	                const result = {};
	                if (perf) {
	                    const resourceTimingData = ref_properties.getPerformanceMeasurement(requestParam);
	                    if (resourceTimingData) {
	                        result.resourceTiming = {};
	                        result.resourceTiming[params.source] = JSON.parse(JSON.stringify(resourceTimingData));
	                    }
	                }
	                callback(null, result);
	            }
	        });
	    }
	    reloadTile(params, callback) {
	        const loaded = this.loaded, uid = params.uid;
	        if (loaded && loaded[uid]) {
	            return super.reloadTile(params, callback);
	        } else {
	            return this.loadTile(params, callback);
	        }
	    }
	    loadGeoJSON(params, callback) {
	        if (params.request) {
	            ref_properties.getJSON(params.request, callback);
	        } else if (typeof params.data === 'string') {
	            try {
	                return callback(null, JSON.parse(params.data));
	            } catch (e) {
	                return callback(new Error(`Input data given to '${ params.source }' is not a valid GeoJSON object.`));
	            }
	        } else {
	            return callback(new Error(`Input data given to '${ params.source }' is not a valid GeoJSON object.`));
	        }
	    }
	    getClusterExpansionZoom(params, callback) {
	        try {
	            callback(null, this._geoJSONIndex.getClusterExpansionZoom(params.clusterId));
	        } catch (e) {
	            callback(e);
	        }
	    }
	    getClusterChildren(params, callback) {
	        try {
	            callback(null, this._geoJSONIndex.getChildren(params.clusterId));
	        } catch (e) {
	            callback(e);
	        }
	    }
	    getClusterLeaves(params, callback) {
	        try {
	            callback(null, this._geoJSONIndex.getLeaves(params.clusterId, params.limit, params.offset));
	        } catch (e) {
	            callback(e);
	        }
	    }
	}
	function getSuperclusterOptions({superclusterOptions, clusterProperties}) {
	    if (!clusterProperties || !superclusterOptions)
	        return superclusterOptions;
	    const mapExpressions = {};
	    const reduceExpressions = {};
	    const globals = {
	        accumulated: null,
	        zoom: 0
	    };
	    const feature = { properties: null };
	    const propertyNames = Object.keys(clusterProperties);
	    for (const key of propertyNames) {
	        const [operator, mapExpression] = clusterProperties[key];
	        const mapExpressionParsed = ref_properties.createExpression(mapExpression);
	        const reduceExpressionParsed = ref_properties.createExpression(typeof operator === 'string' ? [
	            operator,
	            ['accumulated'],
	            [
	                'get',
	                key
	            ]
	        ] : operator);
	        mapExpressions[key] = mapExpressionParsed.value;
	        reduceExpressions[key] = reduceExpressionParsed.value;
	    }
	    superclusterOptions.map = pointProperties => {
	        feature.properties = pointProperties;
	        const properties = {};
	        for (const key of propertyNames) {
	            properties[key] = mapExpressions[key].evaluate(globals, feature);
	        }
	        return properties;
	    };
	    superclusterOptions.reduce = (accumulated, clusterProperties) => {
	        feature.properties = clusterProperties;
	        for (const key of propertyNames) {
	            globals.accumulated = accumulated[key];
	            accumulated[key] = reduceExpressions[key].evaluate(globals, feature);
	        }
	    };
	    return superclusterOptions;
	}

	class Worker {
	    constructor(self) {
	        this.self = self;
	        this.actor = new ref_properties.Actor(self, this);
	        this.layerIndexes = {};
	        this.availableImages = {};
	        this.isSpriteLoaded = {};
	        this.projections = {};
	        this.defaultProjection = ref_properties.getProjection({ name: 'mercator' });
	        this.workerSourceTypes = {
	            vector: ref_properties.VectorTileWorkerSource,
	            geojson: GeoJSONWorkerSource
	        };
	        this.workerSources = {};
	        this.demWorkerSources = {};
	        this.self.registerWorkerSource = (name, WorkerSource) => {
	            if (this.workerSourceTypes[name]) {
	                throw new Error(`Worker source with name "${ name }" already registered.`);
	            }
	            this.workerSourceTypes[name] = WorkerSource;
	        };
	        this.self.registerRTLTextPlugin = rtlTextPlugin => {
	            if (ref_properties.plugin.isParsed()) {
	                throw new Error('RTL text plugin already registered.');
	            }
	            ref_properties.plugin['applyArabicShaping'] = rtlTextPlugin.applyArabicShaping;
	            ref_properties.plugin['processBidirectionalText'] = rtlTextPlugin.processBidirectionalText;
	            ref_properties.plugin['processStyledBidirectionalText'] = rtlTextPlugin.processStyledBidirectionalText;
	        };
	    }
	    clearCaches(mapId, unused, callback) {
	        delete this.layerIndexes[mapId];
	        delete this.availableImages[mapId];
	        delete this.workerSources[mapId];
	        delete this.demWorkerSources[mapId];
	        callback();
	    }
	    checkIfReady(mapID, unused, callback) {
	        callback();
	    }
	    setReferrer(mapID, referrer) {
	        this.referrer = referrer;
	    }
	    spriteLoaded(mapId, bool) {
	        this.isSpriteLoaded[mapId] = bool;
	        for (const workerSource in this.workerSources[mapId]) {
	            const ws = this.workerSources[mapId][workerSource];
	            for (const source in ws) {
	                if (ws[source] instanceof ref_properties.VectorTileWorkerSource) {
	                    ws[source].isSpriteLoaded = bool;
	                    ws[source].fire(new ref_properties.Event('isSpriteLoaded'));
	                }
	            }
	        }
	    }
	    setImages(mapId, images, callback) {
	        this.availableImages[mapId] = images;
	        for (const workerSource in this.workerSources[mapId]) {
	            const ws = this.workerSources[mapId][workerSource];
	            for (const source in ws) {
	                ws[source].availableImages = images;
	            }
	        }
	        callback();
	    }
	    enableTerrain(mapId, enable, callback) {
	        this.terrain = enable;
	        callback();
	    }
	    setProjection(mapId, config) {
	        this.projections[mapId] = ref_properties.getProjection(config);
	    }
	    setLayers(mapId, layers, callback) {
	        this.getLayerIndex(mapId).replace(layers);
	        callback();
	    }
	    updateLayers(mapId, params, callback) {
	        this.getLayerIndex(mapId).update(params.layers, params.removedIds);
	        callback();
	    }
	    loadTile(mapId, params, callback) {
	        const p = this.enableTerrain ? ref_properties.extend({ enableTerrain: this.terrain }, params) : params;
	        p.projection = this.projections[mapId] || this.defaultProjection;
	        this.getWorkerSource(mapId, params.type, params.source).loadTile(p, callback);
	    }
	    loadDEMTile(mapId, params, callback) {
	        const p = this.enableTerrain ? ref_properties.extend({ buildQuadTree: this.terrain }, params) : params;
	        this.getDEMWorkerSource(mapId, params.source).loadTile(p, callback);
	    }
	    reloadTile(mapId, params, callback) {
	        const p = this.enableTerrain ? ref_properties.extend({ enableTerrain: this.terrain }, params) : params;
	        p.projection = this.projections[mapId] || this.defaultProjection;
	        this.getWorkerSource(mapId, params.type, params.source).reloadTile(p, callback);
	    }
	    abortTile(mapId, params, callback) {
	        this.getWorkerSource(mapId, params.type, params.source).abortTile(params, callback);
	    }
	    removeTile(mapId, params, callback) {
	        this.getWorkerSource(mapId, params.type, params.source).removeTile(params, callback);
	    }
	    removeSource(mapId, params, callback) {
	        if (!this.workerSources[mapId] || !this.workerSources[mapId][params.type] || !this.workerSources[mapId][params.type][params.source]) {
	            return;
	        }
	        const worker = this.workerSources[mapId][params.type][params.source];
	        delete this.workerSources[mapId][params.type][params.source];
	        if (worker.removeSource !== undefined) {
	            worker.removeSource(params, callback);
	        } else {
	            callback();
	        }
	    }
	    loadWorkerSource(map, params, callback) {
	        try {
	            this.self.importScripts(params.url);
	            callback();
	        } catch (e) {
	            callback(e.toString());
	        }
	    }
	    syncRTLPluginState(map, state, callback) {
	        try {
	            ref_properties.plugin.setState(state);
	            const pluginURL = ref_properties.plugin.getPluginURL();
	            if (ref_properties.plugin.isLoaded() && !ref_properties.plugin.isParsed() && pluginURL != null) {
	                this.self.importScripts(pluginURL);
	                const complete = ref_properties.plugin.isParsed();
	                const error = complete ? undefined : new Error(`RTL Text Plugin failed to import scripts from ${ pluginURL }`);
	                callback(error, complete);
	            }
	        } catch (e) {
	            callback(e.toString());
	        }
	    }
	    getAvailableImages(mapId) {
	        let availableImages = this.availableImages[mapId];
	        if (!availableImages) {
	            availableImages = [];
	        }
	        return availableImages;
	    }
	    getLayerIndex(mapId) {
	        let layerIndexes = this.layerIndexes[mapId];
	        if (!layerIndexes) {
	            layerIndexes = this.layerIndexes[mapId] = new StyleLayerIndex();
	        }
	        return layerIndexes;
	    }
	    getWorkerSource(mapId, type, source) {
	        if (!this.workerSources[mapId])
	            this.workerSources[mapId] = {};
	        if (!this.workerSources[mapId][type])
	            this.workerSources[mapId][type] = {};
	        if (!this.workerSources[mapId][type][source]) {
	            const actor = {
	                send: (type, data, callback, _, mustQueue, metadata) => {
	                    this.actor.send(type, data, callback, mapId, mustQueue, metadata);
	                },
	                scheduler: this.actor.scheduler
	            };
	            this.workerSources[mapId][type][source] = new this.workerSourceTypes[type](actor, this.getLayerIndex(mapId), this.getAvailableImages(mapId), this.isSpriteLoaded[mapId]);
	        }
	        return this.workerSources[mapId][type][source];
	    }
	    getDEMWorkerSource(mapId, source) {
	        if (!this.demWorkerSources[mapId])
	            this.demWorkerSources[mapId] = {};
	        if (!this.demWorkerSources[mapId][source]) {
	            this.demWorkerSources[mapId][source] = new RasterDEMTileWorkerSource();
	        }
	        return this.demWorkerSources[mapId][source];
	    }
	    enforceCacheSizeLimit(mapId, limit) {
	        ref_properties.enforceCacheSizeLimit(limit);
	    }
	    getWorkerPerformanceMetrics(mapId, params, callback) {
	        callback(undefined, void 0);
	    }
	}
	if (typeof WorkerGlobalScope !== 'undefined' && typeof self !== 'undefined' && self instanceof WorkerGlobalScope) {
	    self.worker = new Worker(self);
	}

	return Worker;

	}));

	define(['./shared'], (function (ref_properties) {
	function deepEqual(a, b) {
	    if (Array.isArray(a)) {
	        if (!Array.isArray(b) || a.length !== b.length)
	            return false;
	        for (let i = 0; i < a.length; i++) {
	            if (!deepEqual(a[i], b[i]))
	                return false;
	        }
	        return true;
	    }
	    if (typeof a === 'object' && a !== null && b !== null) {
	        if (!(typeof b === 'object'))
	            return false;
	        const keys = Object.keys(a);
	        if (keys.length !== Object.keys(b).length)
	            return false;
	        for (const key in a) {
	            if (!deepEqual(a[key], b[key]))
	                return false;
	        }
	        return true;
	    }
	    return a === b;
	}

	var supported = isSupported;
	function isSupported(options) {
	    return !notSupportedReason(options);
	}
	function notSupportedReason(options) {
	    if (!isBrowser())
	        return 'not a browser';
	    if (!isArraySupported())
	        return 'insufficent Array support';
	    if (!isFunctionSupported())
	        return 'insufficient Function support';
	    if (!isObjectSupported())
	        return 'insufficient Object support';
	    if (!isJSONSupported())
	        return 'insufficient JSON support';
	    if (!isWorkerSupported())
	        return 'insufficient worker support';
	    if (!isUint8ClampedArraySupported())
	        return 'insufficient Uint8ClampedArray support';
	    if (!isArrayBufferSupported())
	        return 'insufficient ArrayBuffer support';
	    if (!isCanvasGetImageDataSupported())
	        return 'insufficient Canvas/getImageData support';
	    if (!isWebGLSupportedCached(options && options.failIfMajorPerformanceCaveat))
	        return 'insufficient WebGL support';
	    if (!isNotIE())
	        return 'insufficient ECMAScript 6 support';
	}
	function isBrowser() {
	    return typeof window !== 'undefined' && typeof document !== 'undefined';
	}
	function isArraySupported() {
	    return Array.prototype && Array.prototype.every && Array.prototype.filter && Array.prototype.forEach && Array.prototype.indexOf && Array.prototype.lastIndexOf && Array.prototype.map && Array.prototype.some && Array.prototype.reduce && Array.prototype.reduceRight && Array.isArray;
	}
	function isFunctionSupported() {
	    return Function.prototype && Function.prototype.bind;
	}
	function isObjectSupported() {
	    return Object.keys && Object.create && Object.getPrototypeOf && Object.getOwnPropertyNames && Object.isSealed && Object.isFrozen && Object.isExtensible && Object.getOwnPropertyDescriptor && Object.defineProperty && Object.defineProperties && Object.seal && Object.freeze && Object.preventExtensions;
	}
	function isJSONSupported() {
	    return 'JSON' in window && 'parse' in JSON && 'stringify' in JSON;
	}
	function isWorkerSupported() {
	    if (!('Worker' in window && 'Blob' in window && 'URL' in window)) {
	        return false;
	    }
	    var blob = new Blob([''], { type: 'text/javascript' });
	    var workerURL = URL.createObjectURL(blob);
	    var supported;
	    var worker;
	    try {
	        worker = new Worker(workerURL);
	        supported = true;
	    } catch (e) {
	        supported = false;
	    }
	    if (worker) {
	        worker.terminate();
	    }
	    URL.revokeObjectURL(workerURL);
	    return supported;
	}
	function isUint8ClampedArraySupported() {
	    return 'Uint8ClampedArray' in window;
	}
	function isArrayBufferSupported() {
	    return ArrayBuffer.isView;
	}
	function isCanvasGetImageDataSupported() {
	    var canvas = document.createElement('canvas');
	    canvas.width = canvas.height = 1;
	    var context = canvas.getContext('2d');
	    if (!context) {
	        return false;
	    }
	    var imageData = context.getImageData(0, 0, 1, 1);
	    return imageData && imageData.width === canvas.width;
	}
	var isWebGLSupportedCache = {};
	function isWebGLSupportedCached(failIfMajorPerformanceCaveat) {
	    if (isWebGLSupportedCache[failIfMajorPerformanceCaveat] === undefined) {
	        isWebGLSupportedCache[failIfMajorPerformanceCaveat] = isWebGLSupported(failIfMajorPerformanceCaveat);
	    }
	    return isWebGLSupportedCache[failIfMajorPerformanceCaveat];
	}
	isSupported.webGLContextAttributes = {
	    antialias: false,
	    alpha: true,
	    stencil: true,
	    depth: true
	};
	function getWebGLContext(failIfMajorPerformanceCaveat) {
	    var canvas = document.createElement('canvas');
	    var attributes = Object.create(isSupported.webGLContextAttributes);
	    attributes.failIfMajorPerformanceCaveat = failIfMajorPerformanceCaveat;
	    return canvas.getContext('webgl', attributes) || canvas.getContext('experimental-webgl', attributes);
	}
	function isWebGLSupported(failIfMajorPerformanceCaveat) {
	    var gl = getWebGLContext(failIfMajorPerformanceCaveat);
	    if (!gl) {
	        return false;
	    }
	    var shader;
	    try {
	        shader = gl.createShader(gl.VERTEX_SHADER);
	    } catch (e) {
	        return false;
	    }
	    if (!shader || gl.isContextLost()) {
	        return false;
	    }
	    gl.shaderSource(shader, 'void main() {}');
	    gl.compileShader(shader);
	    return gl.getShaderParameter(shader, gl.COMPILE_STATUS) === true;
	}
	function isNotIE() {
	    return !document.documentMode;
	}

	function create$2(tagName, className, container) {
	    const el = ref_properties.window.document.createElement(tagName);
	    if (className !== undefined)
	        el.className = className;
	    if (container)
	        container.appendChild(el);
	    return el;
	}
	function createSVG(tagName, attributes, container) {
	    const el = ref_properties.window.document.createElementNS('http://www.w3.org/2000/svg', tagName);
	    for (const name of Object.keys(attributes)) {
	        el.setAttributeNS(null, name, attributes[name]);
	    }
	    if (container)
	        container.appendChild(el);
	    return el;
	}
	const docStyle = ref_properties.window.document && ref_properties.window.document.documentElement.style;
	const selectProp = docStyle && docStyle.userSelect !== undefined ? 'userSelect' : 'WebkitUserSelect';
	let userSelect;
	function disableDrag() {
	    if (docStyle && selectProp) {
	        userSelect = docStyle[selectProp];
	        docStyle[selectProp] = 'none';
	    }
	}
	function enableDrag() {
	    if (docStyle && selectProp) {
	        docStyle[selectProp] = userSelect;
	    }
	}
	function suppressClickListener(e) {
	    e.preventDefault();
	    e.stopPropagation();
	    ref_properties.window.removeEventListener('click', suppressClickListener, true);
	}
	function suppressClick() {
	    ref_properties.window.addEventListener('click', suppressClickListener, true);
	    ref_properties.window.setTimeout(() => {
	        ref_properties.window.removeEventListener('click', suppressClickListener, true);
	    }, 0);
	}
	function mousePos(el, e) {
	    const rect = el.getBoundingClientRect();
	    return getScaledPoint(el, rect, e);
	}
	function touchPos(el, touches) {
	    const rect = el.getBoundingClientRect(), points = [];
	    for (let i = 0; i < touches.length; i++) {
	        points.push(getScaledPoint(el, rect, touches[i]));
	    }
	    return points;
	}
	function mouseButton(e) {
	    if (typeof ref_properties.window.InstallTrigger !== 'undefined' && e.button === 2 && e.ctrlKey && ref_properties.window.navigator.platform.toUpperCase().indexOf('MAC') >= 0) {
	        return 0;
	    }
	    return e.button;
	}
	function getScaledPoint(el, rect, e) {
	    const scaling = el.offsetWidth === rect.width ? 1 : el.offsetWidth / rect.width;
	    return new ref_properties.pointGeometry((e.clientX - rect.left) * scaling, (e.clientY - rect.top) * scaling);
	}

	function create$1() {
	    var out = new ref_properties.ARRAY_TYPE(4);
	    if (ref_properties.ARRAY_TYPE != Float32Array) {
	        out[1] = 0;
	        out[2] = 0;
	    }
	    out[0] = 1;
	    out[3] = 1;
	    return out;
	}
	function invert(out, a) {
	    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
	    var det = a0 * a3 - a2 * a1;
	    if (!det) {
	        return null;
	    }
	    det = 1 / det;
	    out[0] = a3 * det;
	    out[1] = -a1 * det;
	    out[2] = -a2 * det;
	    out[3] = a0 * det;
	    return out;
	}
	function rotate$1(out, a, rad) {
	    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
	    var s = Math.sin(rad);
	    var c = Math.cos(rad);
	    out[0] = a0 * c + a2 * s;
	    out[1] = a1 * c + a3 * s;
	    out[2] = a0 * -s + a2 * c;
	    out[3] = a1 * -s + a3 * c;
	    return out;
	}
	function scale(out, a, v) {
	    var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
	    var v0 = v[0], v1 = v[1];
	    out[0] = a0 * v0;
	    out[1] = a1 * v0;
	    out[2] = a2 * v1;
	    out[3] = a3 * v1;
	    return out;
	}

	function loadSprite (baseURL, requestManager, callback) {
	    let json, image, error;
	    const format = ref_properties.exported.devicePixelRatio > 1 ? '@2x' : '';
	    let jsonRequest = ref_properties.getJSON(requestManager.transformRequest(requestManager.normalizeSpriteURL(baseURL, format, '.json'), ref_properties.ResourceType.SpriteJSON), (err, data) => {
	        jsonRequest = null;
	        if (!error) {
	            error = err;
	            json = data;
	            maybeComplete();
	        }
	    });
	    let imageRequest = ref_properties.getImage(requestManager.transformRequest(requestManager.normalizeSpriteURL(baseURL, format, '.png'), ref_properties.ResourceType.SpriteImage), (err, img) => {
	        imageRequest = null;
	        if (!error) {
	            error = err;
	            image = img;
	            maybeComplete();
	        }
	    });
	    function maybeComplete() {
	        if (error) {
	            callback(error);
	        } else if (json && image) {
	            const imageData = ref_properties.exported.getImageData(image);
	            const result = {};
	            for (const id in json) {
	                const {width, height, x, y, sdf, pixelRatio, stretchX, stretchY, content} = json[id];
	                const data = new ref_properties.RGBAImage({
	                    width,
	                    height
	                });
	                ref_properties.RGBAImage.copy(imageData, data, {
	                    x,
	                    y
	                }, {
	                    x: 0,
	                    y: 0
	                }, {
	                    width,
	                    height
	                });
	                result[id] = {
	                    data,
	                    pixelRatio,
	                    sdf,
	                    stretchX,
	                    stretchY,
	                    content
	                };
	            }
	            callback(null, result);
	        }
	    }
	    return {
	        cancel() {
	            if (jsonRequest) {
	                jsonRequest.cancel();
	                jsonRequest = null;
	            }
	            if (imageRequest) {
	                imageRequest.cancel();
	                imageRequest = null;
	            }
	        }
	    };
	}

	function renderStyleImage(image) {
	    const {userImage} = image;
	    if (userImage && userImage.render) {
	        const updated = userImage.render();
	        if (updated) {
	            image.data.replace(new Uint8Array(userImage.data.buffer));
	            return true;
	        }
	    }
	    return false;
	}

	const padding = 1;
	class ImageManager extends ref_properties.Evented {
	    constructor() {
	        super();
	        this.images = {};
	        this.updatedImages = {};
	        this.callbackDispatchedThisFrame = {};
	        this.loaded = false;
	        this.requestors = [];
	        this.patterns = {};
	        this.atlasImage = new ref_properties.RGBAImage({
	            width: 1,
	            height: 1
	        });
	        this.dirty = true;
	    }
	    isLoaded() {
	        return this.loaded;
	    }
	    setLoaded(loaded) {
	        if (this.loaded === loaded) {
	            return;
	        }
	        this.loaded = loaded;
	        if (loaded) {
	            for (const {ids, callback} of this.requestors) {
	                this._notify(ids, callback);
	            }
	            this.requestors = [];
	        }
	    }
	    hasImage(id) {
	        return !!this.getImage(id);
	    }
	    getImage(id) {
	        return this.images[id];
	    }
	    addImage(id, image) {
	        if (this._validate(id, image)) {
	            this.images[id] = image;
	        }
	    }
	    _validate(id, image) {
	        let valid = true;
	        if (!this._validateStretch(image.stretchX, image.data && image.data.width)) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`Image "${ id }" has invalid "stretchX" value`)));
	            valid = false;
	        }
	        if (!this._validateStretch(image.stretchY, image.data && image.data.height)) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`Image "${ id }" has invalid "stretchY" value`)));
	            valid = false;
	        }
	        if (!this._validateContent(image.content, image)) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`Image "${ id }" has invalid "content" value`)));
	            valid = false;
	        }
	        return valid;
	    }
	    _validateStretch(stretch, size) {
	        if (!stretch)
	            return true;
	        let last = 0;
	        for (const part of stretch) {
	            if (part[0] < last || part[1] < part[0] || size < part[1])
	                return false;
	            last = part[1];
	        }
	        return true;
	    }
	    _validateContent(content, image) {
	        if (!content)
	            return true;
	        if (content.length !== 4)
	            return false;
	        if (content[0] < 0 || image.data.width < content[0])
	            return false;
	        if (content[1] < 0 || image.data.height < content[1])
	            return false;
	        if (content[2] < 0 || image.data.width < content[2])
	            return false;
	        if (content[3] < 0 || image.data.height < content[3])
	            return false;
	        if (content[2] < content[0])
	            return false;
	        if (content[3] < content[1])
	            return false;
	        return true;
	    }
	    updateImage(id, image) {
	        const oldImage = this.images[id];
	        image.version = oldImage.version + 1;
	        this.images[id] = image;
	        this.updatedImages[id] = true;
	    }
	    removeImage(id) {
	        const image = this.images[id];
	        delete this.images[id];
	        delete this.patterns[id];
	        if (image.userImage && image.userImage.onRemove) {
	            image.userImage.onRemove();
	        }
	    }
	    listImages() {
	        return Object.keys(this.images);
	    }
	    getImages(ids, callback) {
	        let hasAllDependencies = true;
	        if (!this.isLoaded()) {
	            for (const id of ids) {
	                if (!this.images[id]) {
	                    hasAllDependencies = false;
	                }
	            }
	        }
	        if (this.isLoaded() || hasAllDependencies) {
	            this._notify(ids, callback);
	        } else {
	            this.requestors.push({
	                ids,
	                callback
	            });
	        }
	    }
	    _notify(ids, callback) {
	        const response = {};
	        for (const id of ids) {
	            if (!this.images[id]) {
	                this.fire(new ref_properties.Event('styleimagemissing', { id }));
	            }
	            const image = this.images[id];
	            if (image) {
	                response[id] = {
	                    data: image.data.clone(),
	                    pixelRatio: image.pixelRatio,
	                    sdf: image.sdf,
	                    version: image.version,
	                    stretchX: image.stretchX,
	                    stretchY: image.stretchY,
	                    content: image.content,
	                    hasRenderCallback: Boolean(image.userImage && image.userImage.render)
	                };
	            } else {
	                ref_properties.warnOnce(`Image "${ id }" could not be loaded. Please make sure you have added the image with map.addImage() or a "sprite" property in your style. You can provide missing images by listening for the "styleimagemissing" map event.`);
	            }
	        }
	        callback(null, response);
	    }
	    getPixelSize() {
	        const {width, height} = this.atlasImage;
	        return {
	            width,
	            height
	        };
	    }
	    getPattern(id) {
	        const pattern = this.patterns[id];
	        const image = this.getImage(id);
	        if (!image) {
	            return null;
	        }
	        if (pattern && pattern.position.version === image.version) {
	            return pattern.position;
	        }
	        if (!pattern) {
	            const w = image.data.width + padding * 2;
	            const h = image.data.height + padding * 2;
	            const bin = {
	                w,
	                h,
	                x: 0,
	                y: 0
	            };
	            const position = new ref_properties.ImagePosition(bin, image);
	            this.patterns[id] = {
	                bin,
	                position
	            };
	        } else {
	            pattern.position.version = image.version;
	        }
	        this._updatePatternAtlas();
	        return this.patterns[id].position;
	    }
	    bind(context) {
	        const gl = context.gl;
	        if (!this.atlasTexture) {
	            this.atlasTexture = new ref_properties.Texture(context, this.atlasImage, gl.RGBA);
	        } else if (this.dirty) {
	            this.atlasTexture.update(this.atlasImage);
	            this.dirty = false;
	        }
	        this.atlasTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	    }
	    _updatePatternAtlas() {
	        const bins = [];
	        for (const id in this.patterns) {
	            bins.push(this.patterns[id].bin);
	        }
	        const {w, h} = ref_properties.potpack(bins);
	        const dst = this.atlasImage;
	        dst.resize({
	            width: w || 1,
	            height: h || 1
	        });
	        for (const id in this.patterns) {
	            const {bin} = this.patterns[id];
	            const x = bin.x + padding;
	            const y = bin.y + padding;
	            const src = this.images[id].data;
	            const w = src.width;
	            const h = src.height;
	            ref_properties.RGBAImage.copy(src, dst, {
	                x: 0,
	                y: 0
	            }, {
	                x,
	                y
	            }, {
	                width: w,
	                height: h
	            });
	            ref_properties.RGBAImage.copy(src, dst, {
	                x: 0,
	                y: h - 1
	            }, {
	                x,
	                y: y - 1
	            }, {
	                width: w,
	                height: 1
	            });
	            ref_properties.RGBAImage.copy(src, dst, {
	                x: 0,
	                y: 0
	            }, {
	                x,
	                y: y + h
	            }, {
	                width: w,
	                height: 1
	            });
	            ref_properties.RGBAImage.copy(src, dst, {
	                x: w - 1,
	                y: 0
	            }, {
	                x: x - 1,
	                y
	            }, {
	                width: 1,
	                height: h
	            });
	            ref_properties.RGBAImage.copy(src, dst, {
	                x: 0,
	                y: 0
	            }, {
	                x: x + w,
	                y
	            }, {
	                width: 1,
	                height: h
	            });
	        }
	        this.dirty = true;
	    }
	    beginFrame() {
	        this.callbackDispatchedThisFrame = {};
	    }
	    dispatchRenderCallbacks(ids) {
	        for (const id of ids) {
	            if (this.callbackDispatchedThisFrame[id])
	                continue;
	            this.callbackDispatchedThisFrame[id] = true;
	            const image = this.images[id];
	            const updated = renderStyleImage(image);
	            if (updated) {
	                this.updateImage(id, image);
	            }
	        }
	    }
	}

	function sphericalToCartesian([r, azimuthal, polar]) {
	    const a = ref_properties.degToRad(azimuthal + 90), p = ref_properties.degToRad(polar);
	    return {
	        x: r * Math.cos(a) * Math.sin(p),
	        y: r * Math.sin(a) * Math.sin(p),
	        z: r * Math.cos(p),
	        azimuthal,
	        polar
	    };
	}
	class LightPositionProperty {
	    constructor() {
	        this.specification = ref_properties.spec.light.position;
	    }
	    possiblyEvaluate(value, parameters) {
	        return sphericalToCartesian(value.expression.evaluate(parameters));
	    }
	    interpolate(a, b, t) {
	        return {
	            x: ref_properties.number(a.x, b.x, t),
	            y: ref_properties.number(a.y, b.y, t),
	            z: ref_properties.number(a.z, b.z, t),
	            azimuthal: ref_properties.number(a.azimuthal, b.azimuthal, t),
	            polar: ref_properties.number(a.polar, b.polar, t)
	        };
	    }
	}
	const properties$1 = new ref_properties.Properties({
	    'anchor': new ref_properties.DataConstantProperty(ref_properties.spec.light.anchor),
	    'position': new LightPositionProperty(),
	    'color': new ref_properties.DataConstantProperty(ref_properties.spec.light.color),
	    'intensity': new ref_properties.DataConstantProperty(ref_properties.spec.light.intensity)
	});
	const TRANSITION_SUFFIX$2 = '-transition';
	class Light extends ref_properties.Evented {
	    constructor(lightOptions) {
	        super();
	        this._transitionable = new ref_properties.Transitionable(properties$1);
	        this.setLight(lightOptions);
	        this._transitioning = this._transitionable.untransitioned();
	    }
	    getLight() {
	        return this._transitionable.serialize();
	    }
	    setLight(light, options = {}) {
	        if (this._validate(ref_properties.validateLight, light, options)) {
	            return;
	        }
	        for (const name in light) {
	            const value = light[name];
	            if (ref_properties.endsWith(name, TRANSITION_SUFFIX$2)) {
	                this._transitionable.setTransition(name.slice(0, -TRANSITION_SUFFIX$2.length), value);
	            } else {
	                this._transitionable.setValue(name, value);
	            }
	        }
	    }
	    updateTransitions(parameters) {
	        this._transitioning = this._transitionable.transitioned(parameters, this._transitioning);
	    }
	    hasTransition() {
	        return this._transitioning.hasTransition();
	    }
	    recalculate(parameters) {
	        this.properties = this._transitioning.possiblyEvaluate(parameters);
	    }
	    _validate(validate, value, options) {
	        if (options && options.validate === false) {
	            return false;
	        }
	        return ref_properties.emitValidationErrors(this, validate.call(ref_properties.validateStyle, ref_properties.extend({
	            value,
	            style: {
	                glyphs: true,
	                sprite: true
	            },
	            styleSpec: ref_properties.spec
	        })));
	    }
	}

	const DrapeRenderMode = {
	    deferred: 0,
	    elevated: 1
	};
	const properties = new ref_properties.Properties({
	    'source': new ref_properties.DataConstantProperty(ref_properties.spec.terrain.source),
	    'exaggeration': new ref_properties.DataConstantProperty(ref_properties.spec.terrain.exaggeration)
	});
	const TRANSITION_SUFFIX$1 = '-transition';
	class Terrain$1 extends ref_properties.Evented {
	    constructor(terrainOptions, drapeRenderMode) {
	        super();
	        this._transitionable = new ref_properties.Transitionable(properties);
	        this.set(terrainOptions);
	        this._transitioning = this._transitionable.untransitioned();
	        this.drapeRenderMode = drapeRenderMode;
	    }
	    get() {
	        return this._transitionable.serialize();
	    }
	    set(terrain) {
	        for (const name in terrain) {
	            const value = terrain[name];
	            if (ref_properties.endsWith(name, TRANSITION_SUFFIX$1)) {
	                this._transitionable.setTransition(name.slice(0, -TRANSITION_SUFFIX$1.length), value);
	            } else {
	                this._transitionable.setValue(name, value);
	            }
	        }
	    }
	    updateTransitions(parameters) {
	        this._transitioning = this._transitionable.transitioned(parameters, this._transitioning);
	    }
	    hasTransition() {
	        return this._transitioning.hasTransition();
	    }
	    recalculate(parameters) {
	        this.properties = this._transitioning.possiblyEvaluate(parameters);
	    }
	}

	const FOG_PITCH_START = 45;
	const FOG_PITCH_END = 65;
	const FOG_SYMBOL_CLIPPING_THRESHOLD = 0.9;
	function getFogOpacity(state, pos, pitch, fov) {
	    const fogPitchOpacity = ref_properties.smoothstep(FOG_PITCH_START, FOG_PITCH_END, pitch);
	    const [start, end] = getFovAdjustedFogRange(state, fov);
	    const decay = 6;
	    const depth = ref_properties.length(pos);
	    const fogRange = (depth - start) / (end - start);
	    let falloff = 1 - Math.min(1, Math.exp(-decay * fogRange));
	    falloff *= falloff * falloff;
	    falloff = Math.min(1, 1.00747 * falloff);
	    return falloff * fogPitchOpacity * state.alpha;
	}
	function getFovAdjustedFogRange(state, fov) {
	    const shift = 0.5 / Math.tan(fov * 0.5);
	    return [
	        state.range[0] + shift,
	        state.range[1] + shift
	    ];
	}
	function getFogOpacityAtTileCoord(state, x, y, z, tileId, transform) {
	    const mat = transform.calculateFogTileMatrix(tileId);
	    const pos = [
	        x,
	        y,
	        z
	    ];
	    ref_properties.transformMat4(pos, pos, mat);
	    return getFogOpacity(state, pos, transform.pitch, transform._fov);
	}
	function getFogOpacityAtLngLat(state, lngLat, transform) {
	    const meters = ref_properties.MercatorCoordinate.fromLngLat(lngLat);
	    const elevation = transform.elevation ? transform.elevation.getAtPointOrZero(meters) : 0;
	    const pos = [
	        meters.x,
	        meters.y,
	        elevation
	    ];
	    ref_properties.transformMat4(pos, pos, transform.mercatorFogMatrix);
	    return getFogOpacity(state, pos, transform.pitch, transform._fov);
	}

	const fogProperties = new ref_properties.Properties({
	    'range': new ref_properties.DataConstantProperty(ref_properties.spec.fog.range),
	    'color': new ref_properties.DataConstantProperty(ref_properties.spec.fog.color),
	    'high-color': new ref_properties.DataConstantProperty(ref_properties.spec.fog['high-color']),
	    'space-color': new ref_properties.DataConstantProperty(ref_properties.spec.fog['space-color']),
	    'horizon-blend': new ref_properties.DataConstantProperty(ref_properties.spec.fog['horizon-blend']),
	    'star-intensity': new ref_properties.DataConstantProperty(ref_properties.spec.fog['star-intensity'])
	});
	const TRANSITION_SUFFIX = '-transition';
	class Fog extends ref_properties.Evented {
	    constructor(fogOptions, transform) {
	        super();
	        this._transitionable = new ref_properties.Transitionable(fogProperties);
	        this.set(fogOptions);
	        this._transitioning = this._transitionable.untransitioned();
	        this._transform = transform;
	    }
	    get state() {
	        const tr = this._transform;
	        const isGlobe = tr.projection.name === 'globe';
	        const transitionT = ref_properties.globeToMercatorTransition(tr.zoom);
	        const range = this.properties.get('range');
	        const globeFixedFogRange = [
	            0.5,
	            3
	        ];
	        return {
	            range: isGlobe ? [
	                ref_properties.number(globeFixedFogRange[0], range[0], transitionT),
	                ref_properties.number(globeFixedFogRange[1], range[1], transitionT)
	            ] : range,
	            horizonBlend: this.properties.get('horizon-blend'),
	            alpha: this.properties.get('color').a
	        };
	    }
	    get() {
	        return this._transitionable.serialize();
	    }
	    set(fog, options = {}) {
	        if (this._validate(ref_properties.validateFog, fog, options)) {
	            return;
	        }
	        for (const name of Object.keys(ref_properties.spec.fog)) {
	            if (fog && fog[name] === undefined) {
	                fog[name] = ref_properties.spec.fog[name].default;
	            }
	        }
	        for (const name in fog) {
	            const value = fog[name];
	            if (ref_properties.endsWith(name, TRANSITION_SUFFIX)) {
	                this._transitionable.setTransition(name.slice(0, -TRANSITION_SUFFIX.length), value);
	            } else {
	                this._transitionable.setValue(name, value);
	            }
	        }
	    }
	    getOpacity(pitch) {
	        if (!this._transform.projection.supportsFog)
	            return 0;
	        const fogColor = this.properties && this.properties.get('color') || 1;
	        const isGlobe = this._transform.projection.name === 'globe';
	        const pitchFactor = isGlobe ? 1 : ref_properties.smoothstep(FOG_PITCH_START, FOG_PITCH_END, pitch);
	        return pitchFactor * fogColor.a;
	    }
	    getOpacityAtLatLng(lngLat, transform) {
	        if (!this._transform.projection.supportsFog)
	            return 0;
	        return getFogOpacityAtLngLat(this.state, lngLat, transform);
	    }
	    getFovAdjustedRange(fov) {
	        if (!this._transform.projection.supportsFog)
	            return [
	                0,
	                1
	            ];
	        return getFovAdjustedFogRange(this.state, fov);
	    }
	    updateTransitions(parameters) {
	        this._transitioning = this._transitionable.transitioned(parameters, this._transitioning);
	    }
	    hasTransition() {
	        return this._transitioning.hasTransition();
	    }
	    recalculate(parameters) {
	        this.properties = this._transitioning.possiblyEvaluate(parameters);
	    }
	    _validate(validate, value, options) {
	        if (options && options.validate === false) {
	            return false;
	        }
	        return ref_properties.emitValidationErrors(this, validate.call(ref_properties.validateStyle, ref_properties.extend({
	            value,
	            style: {
	                glyphs: true,
	                sprite: true
	            },
	            styleSpec: ref_properties.spec
	        })));
	    }
	}

	class Dispatcher {
	    constructor(workerPool, parent) {
	        this.workerPool = workerPool;
	        this.actors = [];
	        this.currentActor = 0;
	        this.id = ref_properties.uniqueId();
	        const workers = this.workerPool.acquire(this.id);
	        for (let i = 0; i < workers.length; i++) {
	            const worker = workers[i];
	            const actor = new Dispatcher.Actor(worker, parent, this.id);
	            actor.name = `Worker ${ i }`;
	            this.actors.push(actor);
	        }
	        this.ready = false;
	        this.broadcast('checkIfReady', null, () => {
	            this.ready = true;
	        });
	    }
	    broadcast(type, data, cb) {
	        cb = cb || function () {
	        };
	        ref_properties.asyncAll(this.actors, (actor, done) => {
	            actor.send(type, data, done);
	        }, cb);
	    }
	    getActor() {
	        this.currentActor = (this.currentActor + 1) % this.actors.length;
	        return this.actors[this.currentActor];
	    }
	    remove() {
	        this.actors.forEach(actor => {
	            actor.remove();
	        });
	        this.actors = [];
	        this.workerPool.release(this.id);
	    }
	}
	Dispatcher.Actor = ref_properties.Actor;

	function pixelsToTileUnits (tile, pixelValue, z) {
	    return pixelValue * (ref_properties.EXTENT / (tile.tileSize * Math.pow(2, z - tile.tileID.overscaledZ)));
	}
	function getPixelsToTileUnitsMatrix(tile, transform) {
	    const {scale: scale$1} = tile.tileTransform;
	    const s = scale$1 * ref_properties.EXTENT / (tile.tileSize * Math.pow(2, transform.zoom - tile.tileID.overscaledZ + tile.tileID.canonical.z));
	    return scale(new Float32Array(4), transform.inverseAdjustmentMatrix, [
	        s,
	        s
	    ]);
	}

	class QueryGeometry {
	    constructor(screenBounds, cameraPoint, aboveHorizon, transform) {
	        this.screenBounds = screenBounds;
	        this.cameraPoint = cameraPoint;
	        this._screenRaycastCache = {};
	        this._cameraRaycastCache = {};
	        this.isAboveHorizon = aboveHorizon;
	        this.screenGeometry = this.bufferedScreenGeometry(0);
	        this.screenGeometryMercator = this._bufferedScreenMercator(0, transform);
	    }
	    static createFromScreenPoints(geometry, transform) {
	        let screenGeometry;
	        let aboveHorizon;
	        if (geometry instanceof ref_properties.pointGeometry || typeof geometry[0] === 'number') {
	            const pt = ref_properties.pointGeometry.convert(geometry);
	            screenGeometry = [ref_properties.pointGeometry.convert(geometry)];
	            aboveHorizon = transform.isPointAboveHorizon(pt);
	        } else {
	            const tl = ref_properties.pointGeometry.convert(geometry[0]);
	            const br = ref_properties.pointGeometry.convert(geometry[1]);
	            screenGeometry = [
	                tl,
	                br
	            ];
	            aboveHorizon = ref_properties.polygonizeBounds(tl, br).every(p => transform.isPointAboveHorizon(p));
	        }
	        return new QueryGeometry(screenGeometry, transform.getCameraPoint(), aboveHorizon, transform);
	    }
	    isPointQuery() {
	        return this.screenBounds.length === 1;
	    }
	    bufferedScreenGeometry(buffer) {
	        return ref_properties.polygonizeBounds(this.screenBounds[0], this.screenBounds.length === 1 ? this.screenBounds[0] : this.screenBounds[1], buffer);
	    }
	    bufferedCameraGeometry(buffer) {
	        const min = this.screenBounds[0];
	        const max = this.screenBounds.length === 1 ? this.screenBounds[0].add(new ref_properties.pointGeometry(1, 1)) : this.screenBounds[1];
	        const cameraPolygon = ref_properties.polygonizeBounds(min, max, 0, false);
	        if (this.cameraPoint.y > max.y) {
	            if (this.cameraPoint.x > min.x && this.cameraPoint.x < max.x) {
	                cameraPolygon.splice(3, 0, this.cameraPoint);
	            } else if (this.cameraPoint.x >= max.x) {
	                cameraPolygon[2] = this.cameraPoint;
	            } else if (this.cameraPoint.x <= min.x) {
	                cameraPolygon[3] = this.cameraPoint;
	            }
	        }
	        return ref_properties.bufferConvexPolygon(cameraPolygon, buffer);
	    }
	    bufferedCameraGeometryGlobe(buffer) {
	        const min = this.screenBounds[0];
	        const max = this.screenBounds.length === 1 ? this.screenBounds[0].add(new ref_properties.pointGeometry(1, 1)) : this.screenBounds[1];
	        const cameraPolygon = ref_properties.polygonizeBounds(min, max, buffer);
	        const camPos = this.cameraPoint.clone();
	        const column = (camPos.x > min.x) + (camPos.x > max.x);
	        const row = (camPos.y > min.y) + (camPos.y > max.y);
	        const sector = row * 3 + column;
	        switch (sector) {
	        case 0:
	            cameraPolygon[0] = camPos;
	            cameraPolygon[4] = camPos.clone();
	            break;
	        case 1:
	            cameraPolygon.splice(1, 0, camPos);
	            break;
	        case 2:
	            cameraPolygon[1] = camPos;
	            break;
	        case 3:
	            cameraPolygon.splice(4, 0, camPos);
	            break;
	        case 5:
	            cameraPolygon.splice(2, 0, camPos);
	            break;
	        case 6:
	            cameraPolygon[3] = camPos;
	            break;
	        case 7:
	            cameraPolygon.splice(3, 0, camPos);
	            break;
	        case 8:
	            cameraPolygon[2] = camPos;
	            break;
	        }
	        return cameraPolygon;
	    }
	    containsTile(tile, transform, use3D, cameraWrap = 0) {
	        const bias = 1;
	        const padding = tile.queryPadding / transform._projectionScaler + bias;
	        const cachedQuery = use3D ? this._bufferedCameraMercator(padding, transform) : this._bufferedScreenMercator(padding, transform);
	        let wrap = tile.tileID.wrap + (cachedQuery.unwrapped ? cameraWrap : 0);
	        const geometryForTileCheck = cachedQuery.polygon.map(p => ref_properties.getTilePoint(tile.tileTransform, p, wrap));
	        if (!ref_properties.polygonIntersectsBox(geometryForTileCheck, 0, 0, ref_properties.EXTENT, ref_properties.EXTENT)) {
	            return undefined;
	        }
	        wrap = tile.tileID.wrap + (this.screenGeometryMercator.unwrapped ? cameraWrap : 0);
	        const tilespaceVec3s = this.screenGeometryMercator.polygon.map(p => ref_properties.getTileVec3(tile.tileTransform, p, wrap));
	        const tilespaceGeometry = tilespaceVec3s.map(v => new ref_properties.pointGeometry(v[0], v[1]));
	        const cameraMercator = transform.getFreeCameraOptions().position || new ref_properties.MercatorCoordinate(0, 0, 0);
	        const tilespaceCameraPosition = ref_properties.getTileVec3(tile.tileTransform, cameraMercator, wrap);
	        const tilespaceRays = tilespaceVec3s.map(tileVec => {
	            const dir = ref_properties.sub(tileVec, tileVec, tilespaceCameraPosition);
	            ref_properties.normalize(dir, dir);
	            return new ref_properties.Ray(tilespaceCameraPosition, dir);
	        });
	        const pixelToTileUnitsFactor = pixelsToTileUnits(tile, 1, transform.zoom) * transform._projectionScaler;
	        return {
	            queryGeometry: this,
	            tilespaceGeometry,
	            tilespaceRays,
	            bufferedTilespaceGeometry: geometryForTileCheck,
	            bufferedTilespaceBounds: clampBoundsToTileExtents(ref_properties.getBounds(geometryForTileCheck)),
	            tile,
	            tileID: tile.tileID,
	            pixelToTileUnitsFactor
	        };
	    }
	    _bufferedScreenMercator(padding, transform) {
	        const key = cacheKey(padding);
	        if (this._screenRaycastCache[key]) {
	            return this._screenRaycastCache[key];
	        } else {
	            let poly;
	            if (transform.projection.name === 'globe') {
	                poly = this._projectAndResample(this.bufferedScreenGeometry(padding), transform);
	            } else {
	                poly = {
	                    polygon: this.bufferedScreenGeometry(padding).map(p => transform.pointCoordinate3D(p)),
	                    unwrapped: true
	                };
	            }
	            this._screenRaycastCache[key] = poly;
	            return poly;
	        }
	    }
	    _bufferedCameraMercator(padding, transform) {
	        const key = cacheKey(padding);
	        if (this._cameraRaycastCache[key]) {
	            return this._cameraRaycastCache[key];
	        } else {
	            let poly;
	            if (transform.projection.name === 'globe') {
	                poly = this._projectAndResample(this.bufferedCameraGeometryGlobe(padding), transform);
	            } else {
	                poly = {
	                    polygon: this.bufferedCameraGeometry(padding).map(p => transform.pointCoordinate3D(p)),
	                    unwrapped: true
	                };
	            }
	            this._cameraRaycastCache[key] = poly;
	            return poly;
	        }
	    }
	    _projectAndResample(polygon, transform) {
	        const polePolygon = projectPolygonCoveringPoles(polygon, transform);
	        if (polePolygon) {
	            return polePolygon;
	        }
	        const resampled = unwrapQueryPolygon(resamplePolygon(polygon, transform).map(p => new ref_properties.pointGeometry(wrap(p.x), p.y)), transform);
	        return {
	            polygon: resampled.polygon.map(p => new ref_properties.MercatorCoordinate(p.x, p.y)),
	            unwrapped: resampled.unwrapped
	        };
	    }
	}
	function unwrapQueryPolygon(polygon, tr) {
	    let unwrapped = false;
	    let maxX = -Infinity;
	    let startEdge = 0;
	    for (let e = 0; e < polygon.length - 1; e++) {
	        if (polygon[e].x > maxX) {
	            maxX = polygon[e].x;
	            startEdge = e;
	        }
	    }
	    for (let i = 0; i < polygon.length - 1; i++) {
	        const edge = (startEdge + i) % (polygon.length - 1);
	        const a = polygon[edge];
	        const b = polygon[edge + 1];
	        if (Math.abs(a.x - b.x) > 0.5) {
	            if (a.x < b.x) {
	                a.x += 1;
	                if (edge === 0) {
	                    polygon[polygon.length - 1].x += 1;
	                }
	            } else {
	                b.x += 1;
	                if (edge + 1 === polygon.length - 1) {
	                    polygon[0].x += 1;
	                }
	            }
	            unwrapped = true;
	        }
	    }
	    const cameraX = ref_properties.mercatorXfromLng(tr.center.lng);
	    if (unwrapped && cameraX < Math.abs(cameraX - 1)) {
	        polygon.forEach(p => {
	            p.x -= 1;
	        });
	    }
	    return {
	        polygon,
	        unwrapped
	    };
	}
	function projectPolygonCoveringPoles(polygon, tr) {
	    const matrix = ref_properties.multiply([], tr.pixelMatrix, tr.globeMatrix);
	    const northPole = [
	        0,
	        -ref_properties.GLOBE_RADIUS,
	        0,
	        1
	    ];
	    const southPole = [
	        0,
	        ref_properties.GLOBE_RADIUS,
	        0,
	        1
	    ];
	    const center = [
	        0,
	        0,
	        0,
	        1
	    ];
	    ref_properties.transformMat4$1(northPole, northPole, matrix);
	    ref_properties.transformMat4$1(southPole, southPole, matrix);
	    ref_properties.transformMat4$1(center, center, matrix);
	    const screenNp = new ref_properties.pointGeometry(northPole[0] / northPole[3], northPole[1] / northPole[3]);
	    const screenSp = new ref_properties.pointGeometry(southPole[0] / southPole[3], southPole[1] / southPole[3]);
	    const containsNp = ref_properties.polygonContainsPoint(polygon, screenNp) && northPole[3] < center[3];
	    const containsSp = ref_properties.polygonContainsPoint(polygon, screenSp) && southPole[3] < center[3];
	    if (!containsNp && !containsSp) {
	        return null;
	    }
	    const result = findEdgeCrossingAntimeridian(polygon, tr, containsNp ? -1 : 1);
	    if (!result) {
	        return null;
	    }
	    const {idx, t} = result;
	    let partA = idx > 1 ? resamplePolygon(polygon.slice(0, idx), tr) : [];
	    let partB = idx < polygon.length ? resamplePolygon(polygon.slice(idx), tr) : [];
	    partA = partA.map(p => new ref_properties.pointGeometry(wrap(p.x), p.y));
	    partB = partB.map(p => new ref_properties.pointGeometry(wrap(p.x), p.y));
	    const resampled = [...partA];
	    if (resampled.length === 0) {
	        resampled.push(partB[partB.length - 1]);
	    }
	    const a = resampled[resampled.length - 1];
	    const b = partB.length === 0 ? partA[0] : partB[0];
	    const intersectionY = ref_properties.number(a.y, b.y, t);
	    let mid;
	    if (containsNp) {
	        mid = [
	            new ref_properties.pointGeometry(0, intersectionY),
	            new ref_properties.pointGeometry(0, 0),
	            new ref_properties.pointGeometry(1, 0),
	            new ref_properties.pointGeometry(1, intersectionY)
	        ];
	    } else {
	        mid = [
	            new ref_properties.pointGeometry(1, intersectionY),
	            new ref_properties.pointGeometry(1, 1),
	            new ref_properties.pointGeometry(0, 1),
	            new ref_properties.pointGeometry(0, intersectionY)
	        ];
	    }
	    resampled.push(...mid);
	    if (partB.length === 0) {
	        resampled.push(partA[0]);
	    } else {
	        resampled.push(...partB);
	    }
	    return {
	        polygon: resampled.map(p => new ref_properties.MercatorCoordinate(p.x, p.y)),
	        unwrapped: false
	    };
	}
	function resamplePolygon(polygon, transform) {
	    const tolerance = 1 / 256;
	    return ref_properties.resample(polygon, p => {
	        const mc = transform.pointCoordinate3D(p);
	        p.x = mc.x;
	        p.y = mc.y;
	    }, tolerance);
	}
	function wrap(mercatorX) {
	    return mercatorX < 0 ? 1 + mercatorX % 1 : mercatorX % 1;
	}
	function findEdgeCrossingAntimeridian(polygon, tr, direction) {
	    for (let i = 1; i < polygon.length; i++) {
	        const a = wrap(tr.pointCoordinate3D(polygon[i - 1]).x);
	        const b = wrap(tr.pointCoordinate3D(polygon[i]).x);
	        if (direction < 0) {
	            if (a < b) {
	                return {
	                    idx: i,
	                    t: -a / (b - 1 - a)
	                };
	            }
	        } else {
	            if (b < a) {
	                return {
	                    idx: i,
	                    t: (1 - a) / (b + 1 - a)
	                };
	            }
	        }
	    }
	    return null;
	}
	function cacheKey(padding) {
	    return padding * 100 | 0;
	}
	function clampBoundsToTileExtents(bounds) {
	    bounds.min.x = ref_properties.clamp(bounds.min.x, 0, ref_properties.EXTENT);
	    bounds.min.y = ref_properties.clamp(bounds.min.y, 0, ref_properties.EXTENT);
	    bounds.max.x = ref_properties.clamp(bounds.max.x, 0, ref_properties.EXTENT);
	    bounds.max.y = ref_properties.clamp(bounds.max.y, 0, ref_properties.EXTENT);
	    return bounds;
	}

	function loadTileJSON (options, requestManager, language, worldview, callback) {
	    const loaded = function (err, tileJSON) {
	        if (err) {
	            return callback(err);
	        } else if (tileJSON) {
	            const result = ref_properties.pick(ref_properties.extend(tileJSON, options), [
	                'tiles',
	                'minzoom',
	                'maxzoom',
	                'attribution',
	                'mapbox_logo',
	                'bounds',
	                'scheme',
	                'tileSize',
	                'encoding'
	            ]);
	            if (tileJSON.vector_layers) {
	                result.vectorLayers = tileJSON.vector_layers;
	                result.vectorLayerIds = result.vectorLayers.map(layer => {
	                    return layer.id;
	                });
	            }
	            if (tileJSON.language_options) {
	                result.languageOptions = tileJSON.language_options;
	            }
	            if (tileJSON.language && tileJSON.language[tileJSON.id]) {
	                result.language = tileJSON.language[tileJSON.id];
	            }
	            if (tileJSON.worldview_options) {
	                result.worldviewOptions = tileJSON.worldview_options;
	            }
	            if (tileJSON.worldview) {
	                result.worldview = tileJSON.worldview[tileJSON.id];
	            } else if (tileJSON.worldview_default) {
	                result.worldview = tileJSON.worldview_default;
	            }
	            result.tiles = requestManager.canonicalizeTileset(result, options.url);
	            callback(null, result);
	        }
	    };
	    if (options.url) {
	        return ref_properties.getJSON(requestManager.transformRequest(requestManager.normalizeSourceURL(options.url, null, language, worldview), ref_properties.ResourceType.Source), loaded);
	    } else {
	        return ref_properties.exported.frame(() => loaded(null, options));
	    }
	}

	class TileBounds {
	    constructor(bounds, minzoom, maxzoom) {
	        this.bounds = ref_properties.LngLatBounds.convert(this.validateBounds(bounds));
	        this.minzoom = minzoom || 0;
	        this.maxzoom = maxzoom || 24;
	    }
	    validateBounds(bounds) {
	        if (!Array.isArray(bounds) || bounds.length !== 4)
	            return [
	                -180,
	                -90,
	                180,
	                90
	            ];
	        return [
	            Math.max(-180, bounds[0]),
	            Math.max(-90, bounds[1]),
	            Math.min(180, bounds[2]),
	            Math.min(90, bounds[3])
	        ];
	    }
	    contains(tileID) {
	        const worldSize = Math.pow(2, tileID.z);
	        const level = {
	            minX: Math.floor(ref_properties.mercatorXfromLng(this.bounds.getWest()) * worldSize),
	            minY: Math.floor(ref_properties.mercatorYfromLat(this.bounds.getNorth()) * worldSize),
	            maxX: Math.ceil(ref_properties.mercatorXfromLng(this.bounds.getEast()) * worldSize),
	            maxY: Math.ceil(ref_properties.mercatorYfromLat(this.bounds.getSouth()) * worldSize)
	        };
	        const hit = tileID.x >= level.minX && tileID.x < level.maxX && tileID.y >= level.minY && tileID.y < level.maxY;
	        return hit;
	    }
	}

	class IndexBuffer {
	    constructor(context, array, dynamicDraw) {
	        this.context = context;
	        const gl = context.gl;
	        this.buffer = gl.createBuffer();
	        this.dynamicDraw = Boolean(dynamicDraw);
	        this.context.unbindVAO();
	        context.bindElementBuffer.set(this.buffer);
	        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, array.arrayBuffer, this.dynamicDraw ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW);
	        if (!this.dynamicDraw) {
	            array.destroy();
	        }
	    }
	    bind() {
	        this.context.bindElementBuffer.set(this.buffer);
	    }
	    updateData(array) {
	        const gl = this.context.gl;
	        this.context.unbindVAO();
	        this.bind();
	        gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, array.arrayBuffer);
	    }
	    destroy() {
	        const gl = this.context.gl;
	        if (this.buffer) {
	            gl.deleteBuffer(this.buffer);
	            delete this.buffer;
	        }
	    }
	}

	const AttributeType = {
	    Int8: 'BYTE',
	    Uint8: 'UNSIGNED_BYTE',
	    Int16: 'SHORT',
	    Uint16: 'UNSIGNED_SHORT',
	    Int32: 'INT',
	    Uint32: 'UNSIGNED_INT',
	    Float32: 'FLOAT'
	};
	class VertexBuffer {
	    constructor(context, array, attributes, dynamicDraw) {
	        this.length = array.length;
	        this.attributes = attributes;
	        this.itemSize = array.bytesPerElement;
	        this.dynamicDraw = dynamicDraw;
	        this.context = context;
	        const gl = context.gl;
	        this.buffer = gl.createBuffer();
	        context.bindVertexBuffer.set(this.buffer);
	        gl.bufferData(gl.ARRAY_BUFFER, array.arrayBuffer, this.dynamicDraw ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW);
	        if (!this.dynamicDraw) {
	            array.destroy();
	        }
	    }
	    bind() {
	        this.context.bindVertexBuffer.set(this.buffer);
	    }
	    updateData(array) {
	        const gl = this.context.gl;
	        this.bind();
	        gl.bufferSubData(gl.ARRAY_BUFFER, 0, array.arrayBuffer);
	    }
	    enableAttributes(gl, program) {
	        for (let j = 0; j < this.attributes.length; j++) {
	            const member = this.attributes[j];
	            const attribIndex = program.attributes[member.name];
	            if (attribIndex !== undefined) {
	                gl.enableVertexAttribArray(attribIndex);
	            }
	        }
	    }
	    setVertexAttribPointers(gl, program, vertexOffset) {
	        for (let j = 0; j < this.attributes.length; j++) {
	            const member = this.attributes[j];
	            const attribIndex = program.attributes[member.name];
	            if (attribIndex !== undefined) {
	                gl.vertexAttribPointer(attribIndex, member.components, gl[AttributeType[member.type]], false, this.itemSize, member.offset + this.itemSize * (vertexOffset || 0));
	            }
	        }
	    }
	    destroy() {
	        const gl = this.context.gl;
	        if (this.buffer) {
	            gl.deleteBuffer(this.buffer);
	            delete this.buffer;
	        }
	    }
	}

	class BaseValue {
	    constructor(context) {
	        this.gl = context.gl;
	        this.default = this.getDefault();
	        this.current = this.default;
	        this.dirty = false;
	    }
	    get() {
	        return this.current;
	    }
	    set(value) {
	    }
	    getDefault() {
	        return this.default;
	    }
	    setDefault() {
	        this.set(this.default);
	    }
	}
	class ClearColor extends BaseValue {
	    getDefault() {
	        return ref_properties.Color.transparent;
	    }
	    set(v) {
	        const c = this.current;
	        if (v.r === c.r && v.g === c.g && v.b === c.b && v.a === c.a && !this.dirty)
	            return;
	        this.gl.clearColor(v.r, v.g, v.b, v.a);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class ClearDepth extends BaseValue {
	    getDefault() {
	        return 1;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        this.gl.clearDepth(v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class ClearStencil extends BaseValue {
	    getDefault() {
	        return 0;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        this.gl.clearStencil(v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class ColorMask extends BaseValue {
	    getDefault() {
	        return [
	            true,
	            true,
	            true,
	            true
	        ];
	    }
	    set(v) {
	        const c = this.current;
	        if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && v[3] === c[3] && !this.dirty)
	            return;
	        this.gl.colorMask(v[0], v[1], v[2], v[3]);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class DepthMask extends BaseValue {
	    getDefault() {
	        return true;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        this.gl.depthMask(v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class StencilMask extends BaseValue {
	    getDefault() {
	        return 255;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        this.gl.stencilMask(v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class StencilFunc extends BaseValue {
	    getDefault() {
	        return {
	            func: this.gl.ALWAYS,
	            ref: 0,
	            mask: 255
	        };
	    }
	    set(v) {
	        const c = this.current;
	        if (v.func === c.func && v.ref === c.ref && v.mask === c.mask && !this.dirty)
	            return;
	        this.gl.stencilFunc(v.func, v.ref, v.mask);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class StencilOp extends BaseValue {
	    getDefault() {
	        const gl = this.gl;
	        return [
	            gl.KEEP,
	            gl.KEEP,
	            gl.KEEP
	        ];
	    }
	    set(v) {
	        const c = this.current;
	        if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && !this.dirty)
	            return;
	        this.gl.stencilOp(v[0], v[1], v[2]);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class StencilTest extends BaseValue {
	    getDefault() {
	        return false;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        const gl = this.gl;
	        if (v) {
	            gl.enable(gl.STENCIL_TEST);
	        } else {
	            gl.disable(gl.STENCIL_TEST);
	        }
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class DepthRange extends BaseValue {
	    getDefault() {
	        return [
	            0,
	            1
	        ];
	    }
	    set(v) {
	        const c = this.current;
	        if (v[0] === c[0] && v[1] === c[1] && !this.dirty)
	            return;
	        this.gl.depthRange(v[0], v[1]);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class DepthTest extends BaseValue {
	    getDefault() {
	        return false;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        const gl = this.gl;
	        if (v) {
	            gl.enable(gl.DEPTH_TEST);
	        } else {
	            gl.disable(gl.DEPTH_TEST);
	        }
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class DepthFunc extends BaseValue {
	    getDefault() {
	        return this.gl.LESS;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        this.gl.depthFunc(v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class Blend extends BaseValue {
	    getDefault() {
	        return false;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        const gl = this.gl;
	        if (v) {
	            gl.enable(gl.BLEND);
	        } else {
	            gl.disable(gl.BLEND);
	        }
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class BlendFunc extends BaseValue {
	    getDefault() {
	        const gl = this.gl;
	        return [
	            gl.ONE,
	            gl.ZERO
	        ];
	    }
	    set(v) {
	        const c = this.current;
	        if (v[0] === c[0] && v[1] === c[1] && !this.dirty)
	            return;
	        this.gl.blendFunc(v[0], v[1]);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class BlendColor extends BaseValue {
	    getDefault() {
	        return ref_properties.Color.transparent;
	    }
	    set(v) {
	        const c = this.current;
	        if (v.r === c.r && v.g === c.g && v.b === c.b && v.a === c.a && !this.dirty)
	            return;
	        this.gl.blendColor(v.r, v.g, v.b, v.a);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class BlendEquation extends BaseValue {
	    getDefault() {
	        return this.gl.FUNC_ADD;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        this.gl.blendEquation(v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class CullFace extends BaseValue {
	    getDefault() {
	        return false;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        const gl = this.gl;
	        if (v) {
	            gl.enable(gl.CULL_FACE);
	        } else {
	            gl.disable(gl.CULL_FACE);
	        }
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class CullFaceSide extends BaseValue {
	    getDefault() {
	        return this.gl.BACK;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        this.gl.cullFace(v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class FrontFace extends BaseValue {
	    getDefault() {
	        return this.gl.CCW;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        this.gl.frontFace(v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class Program$1 extends BaseValue {
	    getDefault() {
	        return null;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        this.gl.useProgram(v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class ActiveTextureUnit extends BaseValue {
	    getDefault() {
	        return this.gl.TEXTURE0;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        this.gl.activeTexture(v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class Viewport extends BaseValue {
	    getDefault() {
	        const gl = this.gl;
	        return [
	            0,
	            0,
	            gl.drawingBufferWidth,
	            gl.drawingBufferHeight
	        ];
	    }
	    set(v) {
	        const c = this.current;
	        if (v[0] === c[0] && v[1] === c[1] && v[2] === c[2] && v[3] === c[3] && !this.dirty)
	            return;
	        this.gl.viewport(v[0], v[1], v[2], v[3]);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class BindFramebuffer extends BaseValue {
	    getDefault() {
	        return null;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        const gl = this.gl;
	        gl.bindFramebuffer(gl.FRAMEBUFFER, v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class BindRenderbuffer extends BaseValue {
	    getDefault() {
	        return null;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        const gl = this.gl;
	        gl.bindRenderbuffer(gl.RENDERBUFFER, v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class BindTexture extends BaseValue {
	    getDefault() {
	        return null;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        const gl = this.gl;
	        gl.bindTexture(gl.TEXTURE_2D, v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class BindVertexBuffer extends BaseValue {
	    getDefault() {
	        return null;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        const gl = this.gl;
	        gl.bindBuffer(gl.ARRAY_BUFFER, v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class BindElementBuffer extends BaseValue {
	    getDefault() {
	        return null;
	    }
	    set(v) {
	        const gl = this.gl;
	        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class BindVertexArrayOES extends BaseValue {
	    constructor(context) {
	        super(context);
	        this.vao = context.extVertexArrayObject;
	    }
	    getDefault() {
	        return null;
	    }
	    set(v) {
	        if (!this.vao || v === this.current && !this.dirty)
	            return;
	        this.vao.bindVertexArrayOES(v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class PixelStoreUnpack extends BaseValue {
	    getDefault() {
	        return 4;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        const gl = this.gl;
	        gl.pixelStorei(gl.UNPACK_ALIGNMENT, v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class PixelStoreUnpackPremultiplyAlpha extends BaseValue {
	    getDefault() {
	        return false;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        const gl = this.gl;
	        gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class PixelStoreUnpackFlipY extends BaseValue {
	    getDefault() {
	        return false;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        const gl = this.gl;
	        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class FramebufferAttachment extends BaseValue {
	    constructor(context, parent) {
	        super(context);
	        this.context = context;
	        this.parent = parent;
	    }
	    getDefault() {
	        return null;
	    }
	}
	class ColorAttachment extends FramebufferAttachment {
	    setDirty() {
	        this.dirty = true;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        this.context.bindFramebuffer.set(this.parent);
	        const gl = this.gl;
	        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, v, 0);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class DepthAttachment extends FramebufferAttachment {
	    attachment() {
	        return this.gl.DEPTH_ATTACHMENT;
	    }
	    set(v) {
	        if (v === this.current && !this.dirty)
	            return;
	        this.context.bindFramebuffer.set(this.parent);
	        const gl = this.gl;
	        gl.framebufferRenderbuffer(gl.FRAMEBUFFER, this.attachment(), gl.RENDERBUFFER, v);
	        this.current = v;
	        this.dirty = false;
	    }
	}
	class DepthStencilAttachment extends DepthAttachment {
	    attachment() {
	        return this.gl.DEPTH_STENCIL_ATTACHMENT;
	    }
	}

	class Framebuffer {
	    constructor(context, width, height, hasDepth) {
	        this.context = context;
	        this.width = width;
	        this.height = height;
	        const gl = context.gl;
	        const fbo = this.framebuffer = gl.createFramebuffer();
	        this.colorAttachment = new ColorAttachment(context, fbo);
	        if (hasDepth) {
	            this.depthAttachment = new DepthAttachment(context, fbo);
	        }
	    }
	    destroy() {
	        const gl = this.context.gl;
	        const texture = this.colorAttachment.get();
	        if (texture)
	            gl.deleteTexture(texture);
	        if (this.depthAttachment) {
	            const renderbuffer = this.depthAttachment.get();
	            if (renderbuffer)
	                gl.deleteRenderbuffer(renderbuffer);
	        }
	        gl.deleteFramebuffer(this.framebuffer);
	    }
	}

	class Context {
	    constructor(gl) {
	        this.gl = gl;
	        this.extVertexArrayObject = this.gl.getExtension('OES_vertex_array_object');
	        this.clearColor = new ClearColor(this);
	        this.clearDepth = new ClearDepth(this);
	        this.clearStencil = new ClearStencil(this);
	        this.colorMask = new ColorMask(this);
	        this.depthMask = new DepthMask(this);
	        this.stencilMask = new StencilMask(this);
	        this.stencilFunc = new StencilFunc(this);
	        this.stencilOp = new StencilOp(this);
	        this.stencilTest = new StencilTest(this);
	        this.depthRange = new DepthRange(this);
	        this.depthTest = new DepthTest(this);
	        this.depthFunc = new DepthFunc(this);
	        this.blend = new Blend(this);
	        this.blendFunc = new BlendFunc(this);
	        this.blendColor = new BlendColor(this);
	        this.blendEquation = new BlendEquation(this);
	        this.cullFace = new CullFace(this);
	        this.cullFaceSide = new CullFaceSide(this);
	        this.frontFace = new FrontFace(this);
	        this.program = new Program$1(this);
	        this.activeTexture = new ActiveTextureUnit(this);
	        this.viewport = new Viewport(this);
	        this.bindFramebuffer = new BindFramebuffer(this);
	        this.bindRenderbuffer = new BindRenderbuffer(this);
	        this.bindTexture = new BindTexture(this);
	        this.bindVertexBuffer = new BindVertexBuffer(this);
	        this.bindElementBuffer = new BindElementBuffer(this);
	        this.bindVertexArrayOES = this.extVertexArrayObject && new BindVertexArrayOES(this);
	        this.pixelStoreUnpack = new PixelStoreUnpack(this);
	        this.pixelStoreUnpackPremultiplyAlpha = new PixelStoreUnpackPremultiplyAlpha(this);
	        this.pixelStoreUnpackFlipY = new PixelStoreUnpackFlipY(this);
	        this.extTextureFilterAnisotropic = gl.getExtension('EXT_texture_filter_anisotropic') || gl.getExtension('MOZ_EXT_texture_filter_anisotropic') || gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic');
	        if (this.extTextureFilterAnisotropic) {
	            this.extTextureFilterAnisotropicMax = gl.getParameter(this.extTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT);
	        }
	        this.extTextureFilterAnisotropicForceOff = false;
	        this.extStandardDerivativesForceOff = false;
	        this.extTextureHalfFloat = gl.getExtension('OES_texture_half_float');
	        if (this.extTextureHalfFloat) {
	            gl.getExtension('OES_texture_half_float_linear');
	            this.extRenderToTextureHalfFloat = gl.getExtension('EXT_color_buffer_half_float');
	        }
	        this.extStandardDerivatives = gl.getExtension('OES_standard_derivatives');
	        this.extTimerQuery = gl.getExtension('EXT_disjoint_timer_query');
	        this.maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
	    }
	    setDefault() {
	        this.unbindVAO();
	        this.clearColor.setDefault();
	        this.clearDepth.setDefault();
	        this.clearStencil.setDefault();
	        this.colorMask.setDefault();
	        this.depthMask.setDefault();
	        this.stencilMask.setDefault();
	        this.stencilFunc.setDefault();
	        this.stencilOp.setDefault();
	        this.stencilTest.setDefault();
	        this.depthRange.setDefault();
	        this.depthTest.setDefault();
	        this.depthFunc.setDefault();
	        this.blend.setDefault();
	        this.blendFunc.setDefault();
	        this.blendColor.setDefault();
	        this.blendEquation.setDefault();
	        this.cullFace.setDefault();
	        this.cullFaceSide.setDefault();
	        this.frontFace.setDefault();
	        this.program.setDefault();
	        this.activeTexture.setDefault();
	        this.bindFramebuffer.setDefault();
	        this.pixelStoreUnpack.setDefault();
	        this.pixelStoreUnpackPremultiplyAlpha.setDefault();
	        this.pixelStoreUnpackFlipY.setDefault();
	    }
	    setDirty() {
	        this.clearColor.dirty = true;
	        this.clearDepth.dirty = true;
	        this.clearStencil.dirty = true;
	        this.colorMask.dirty = true;
	        this.depthMask.dirty = true;
	        this.stencilMask.dirty = true;
	        this.stencilFunc.dirty = true;
	        this.stencilOp.dirty = true;
	        this.stencilTest.dirty = true;
	        this.depthRange.dirty = true;
	        this.depthTest.dirty = true;
	        this.depthFunc.dirty = true;
	        this.blend.dirty = true;
	        this.blendFunc.dirty = true;
	        this.blendColor.dirty = true;
	        this.blendEquation.dirty = true;
	        this.cullFace.dirty = true;
	        this.cullFaceSide.dirty = true;
	        this.frontFace.dirty = true;
	        this.program.dirty = true;
	        this.activeTexture.dirty = true;
	        this.viewport.dirty = true;
	        this.bindFramebuffer.dirty = true;
	        this.bindRenderbuffer.dirty = true;
	        this.bindTexture.dirty = true;
	        this.bindVertexBuffer.dirty = true;
	        this.bindElementBuffer.dirty = true;
	        if (this.extVertexArrayObject) {
	            this.bindVertexArrayOES.dirty = true;
	        }
	        this.pixelStoreUnpack.dirty = true;
	        this.pixelStoreUnpackPremultiplyAlpha.dirty = true;
	        this.pixelStoreUnpackFlipY.dirty = true;
	    }
	    createIndexBuffer(array, dynamicDraw) {
	        return new IndexBuffer(this, array, dynamicDraw);
	    }
	    createVertexBuffer(array, attributes, dynamicDraw) {
	        return new VertexBuffer(this, array, attributes, dynamicDraw);
	    }
	    createRenderbuffer(storageFormat, width, height) {
	        const gl = this.gl;
	        const rbo = gl.createRenderbuffer();
	        this.bindRenderbuffer.set(rbo);
	        gl.renderbufferStorage(gl.RENDERBUFFER, storageFormat, width, height);
	        this.bindRenderbuffer.set(null);
	        return rbo;
	    }
	    createFramebuffer(width, height, hasDepth) {
	        return new Framebuffer(this, width, height, hasDepth);
	    }
	    clear({color, depth, stencil}) {
	        const gl = this.gl;
	        let mask = 0;
	        if (color) {
	            mask |= gl.COLOR_BUFFER_BIT;
	            this.clearColor.set(color);
	            this.colorMask.set([
	                true,
	                true,
	                true,
	                true
	            ]);
	        }
	        if (typeof depth !== 'undefined') {
	            mask |= gl.DEPTH_BUFFER_BIT;
	            this.depthRange.set([
	                0,
	                1
	            ]);
	            this.clearDepth.set(depth);
	            this.depthMask.set(true);
	        }
	        if (typeof stencil !== 'undefined') {
	            mask |= gl.STENCIL_BUFFER_BIT;
	            this.clearStencil.set(stencil);
	            this.stencilMask.set(255);
	        }
	        gl.clear(mask);
	    }
	    setCullFace(cullFaceMode) {
	        if (cullFaceMode.enable === false) {
	            this.cullFace.set(false);
	        } else {
	            this.cullFace.set(true);
	            this.cullFaceSide.set(cullFaceMode.mode);
	            this.frontFace.set(cullFaceMode.frontFace);
	        }
	    }
	    setDepthMode(depthMode) {
	        if (depthMode.func === this.gl.ALWAYS && !depthMode.mask) {
	            this.depthTest.set(false);
	        } else {
	            this.depthTest.set(true);
	            this.depthFunc.set(depthMode.func);
	            this.depthMask.set(depthMode.mask);
	            this.depthRange.set(depthMode.range);
	        }
	    }
	    setStencilMode(stencilMode) {
	        if (stencilMode.test.func === this.gl.ALWAYS && !stencilMode.mask) {
	            this.stencilTest.set(false);
	        } else {
	            this.stencilTest.set(true);
	            this.stencilMask.set(stencilMode.mask);
	            this.stencilOp.set([
	                stencilMode.fail,
	                stencilMode.depthFail,
	                stencilMode.pass
	            ]);
	            this.stencilFunc.set({
	                func: stencilMode.test.func,
	                ref: stencilMode.ref,
	                mask: stencilMode.test.mask
	            });
	        }
	    }
	    setColorMode(colorMode) {
	        if (deepEqual(colorMode.blendFunction, ref_properties.ColorMode.Replace)) {
	            this.blend.set(false);
	        } else {
	            this.blend.set(true);
	            this.blendFunc.set(colorMode.blendFunction);
	            this.blendColor.set(colorMode.blendColor);
	        }
	        this.colorMask.set(colorMode.mask);
	    }
	    unbindVAO() {
	        if (this.extVertexArrayObject) {
	            this.bindVertexArrayOES.set(null);
	        }
	    }
	}

	class VectorTileSource extends ref_properties.Evented {
	    constructor(id, options, dispatcher, eventedParent) {
	        super();
	        this.id = id;
	        this.dispatcher = dispatcher;
	        this.type = 'vector';
	        this.minzoom = 0;
	        this.maxzoom = 22;
	        this.scheme = 'xyz';
	        this.tileSize = 512;
	        this.reparseOverscaled = true;
	        this.isTileClipped = true;
	        this._loaded = false;
	        ref_properties.extend(this, ref_properties.pick(options, [
	            'url',
	            'scheme',
	            'tileSize',
	            'promoteId'
	        ]));
	        this._options = ref_properties.extend({ type: 'vector' }, options);
	        this._collectResourceTiming = options.collectResourceTiming;
	        if (this.tileSize !== 512) {
	            throw new Error('vector tile sources must have a tileSize of 512');
	        }
	        this.setEventedParent(eventedParent);
	        this._tileWorkers = {};
	        this._deduped = new ref_properties.DedupedRequest();
	    }
	    load(callback) {
	        this._loaded = false;
	        this.fire(new ref_properties.Event('dataloading', { dataType: 'source' }));
	        const language = this.language || this.map._language;
	        const worldview = this.worldview || this.map._worldview;
	        this._tileJSONRequest = loadTileJSON(this._options, this.map._requestManager, language, worldview, (err, tileJSON) => {
	            this._tileJSONRequest = null;
	            this._loaded = true;
	            if (err) {
	                if (language)
	                    console.warn(`Ensure that your requested language string is a valid BCP-47 code. Found: ${ language }`);
	                if (worldview && worldview.length !== 2)
	                    console.warn(`Requested worldview strings must be a valid ISO alpha-2 code. Found: ${ worldview }`);
	                this.fire(new ref_properties.ErrorEvent(err));
	            } else if (tileJSON) {
	                ref_properties.extend(this, tileJSON);
	                if (tileJSON.bounds)
	                    this.tileBounds = new TileBounds(tileJSON.bounds, this.minzoom, this.maxzoom);
	                ref_properties.postTurnstileEvent(tileJSON.tiles, this.map._requestManager._customAccessToken);
	                this.fire(new ref_properties.Event('data', {
	                    dataType: 'source',
	                    sourceDataType: 'metadata'
	                }));
	                this.fire(new ref_properties.Event('data', {
	                    dataType: 'source',
	                    sourceDataType: 'content'
	                }));
	            }
	            if (callback)
	                callback(err);
	        });
	    }
	    loaded() {
	        return this._loaded;
	    }
	    hasTile(tileID) {
	        return !this.tileBounds || this.tileBounds.contains(tileID.canonical);
	    }
	    onAdd(map) {
	        this.map = map;
	        this.load();
	    }
	    setSourceProperty(callback) {
	        if (this._tileJSONRequest) {
	            this._tileJSONRequest.cancel();
	        }
	        callback();
	        this.load(() => {
	            const sourceCaches = this.map.style._getSourceCaches(this.id);
	            for (const sourceCache of sourceCaches) {
	                sourceCache.clearTiles();
	            }
	        });
	    }
	    setTiles(tiles) {
	        this.setSourceProperty(() => {
	            this._options.tiles = tiles;
	        });
	        return this;
	    }
	    setUrl(url) {
	        this.setSourceProperty(() => {
	            this.url = url;
	            this._options.url = url;
	        });
	        return this;
	    }
	    _setLanguage(language) {
	        if (language === this.language)
	            return this;
	        this.setSourceProperty(() => {
	            this.language = language;
	        });
	        return this;
	    }
	    _setWorldview(worldview) {
	        if (worldview === this.worldview)
	            return this;
	        if (this.worldviewOptions && worldview && !this.worldviewOptions[worldview]) {
	            console.warn(`Vector tile source "${ this.id }" does not support worldview "${ worldview }".`);
	            return this;
	        }
	        this.setSourceProperty(() => {
	            this.worldview = worldview;
	        });
	        return this;
	    }
	    onRemove() {
	        if (this._tileJSONRequest) {
	            this._tileJSONRequest.cancel();
	            this._tileJSONRequest = null;
	        }
	    }
	    serialize() {
	        return ref_properties.extend({}, this._options);
	    }
	    loadTile(tile, callback) {
	        const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme));
	        const request = this.map._requestManager.transformRequest(url, ref_properties.ResourceType.Tile);
	        const params = {
	            request,
	            data: undefined,
	            uid: tile.uid,
	            tileID: tile.tileID,
	            tileZoom: tile.tileZoom,
	            zoom: tile.tileID.overscaledZ,
	            tileSize: this.tileSize * tile.tileID.overscaleFactor(),
	            type: this.type,
	            source: this.id,
	            pixelRatio: ref_properties.exported.devicePixelRatio,
	            showCollisionBoxes: this.map.showCollisionBoxes,
	            promoteId: this.promoteId,
	            isSymbolTile: tile.isSymbolTile
	        };
	        params.request.collectResourceTiming = this._collectResourceTiming;
	        if (!tile.actor || tile.state === 'expired') {
	            tile.actor = this._tileWorkers[url] = this._tileWorkers[url] || this.dispatcher.getActor();
	            if (!this.dispatcher.ready) {
	                const cancel = ref_properties.loadVectorTile.call({ deduped: this._deduped }, params, (err, data) => {
	                    if (err || !data) {
	                        done.call(this, err);
	                    } else {
	                        params.data = {
	                            cacheControl: data.cacheControl,
	                            expires: data.expires,
	                            rawData: data.rawData.slice(0)
	                        };
	                        if (tile.actor)
	                            tile.actor.send('loadTile', params, done.bind(this), undefined, true);
	                    }
	                }, true);
	                tile.request = { cancel };
	            } else {
	                tile.request = tile.actor.send('loadTile', params, done.bind(this), undefined, true);
	            }
	        } else if (tile.state === 'loading') {
	            tile.reloadCallback = callback;
	        } else {
	            tile.request = tile.actor.send('reloadTile', params, done.bind(this));
	        }
	        function done(err, data) {
	            delete tile.request;
	            if (tile.aborted)
	                return callback(null);
	            if (err && err.status !== 404) {
	                return callback(err);
	            }
	            if (data && data.resourceTiming)
	                tile.resourceTiming = data.resourceTiming;
	            if (this.map._refreshExpiredTiles && data)
	                tile.setExpiryData(data);
	            tile.loadVectorData(data, this.map.painter);
	            ref_properties.cacheEntryPossiblyAdded(this.dispatcher);
	            callback(null);
	            if (tile.reloadCallback) {
	                this.loadTile(tile, tile.reloadCallback);
	                tile.reloadCallback = null;
	            }
	        }
	    }
	    abortTile(tile) {
	        if (tile.request) {
	            tile.request.cancel();
	            delete tile.request;
	        }
	        if (tile.actor) {
	            tile.actor.send('abortTile', {
	                uid: tile.uid,
	                type: this.type,
	                source: this.id
	            });
	        }
	    }
	    unloadTile(tile) {
	        tile.unloadVectorData();
	        if (tile.actor) {
	            tile.actor.send('removeTile', {
	                uid: tile.uid,
	                type: this.type,
	                source: this.id
	            });
	        }
	    }
	    hasTransition() {
	        return false;
	    }
	    afterUpdate() {
	        this._tileWorkers = {};
	    }
	}

	class RasterTileSource extends ref_properties.Evented {
	    constructor(id, options, dispatcher, eventedParent) {
	        super();
	        this.id = id;
	        this.dispatcher = dispatcher;
	        this.setEventedParent(eventedParent);
	        this.type = 'raster';
	        this.minzoom = 0;
	        this.maxzoom = 22;
	        this.roundZoom = true;
	        this.scheme = 'xyz';
	        this.tileSize = 512;
	        this._loaded = false;
	        this._options = ref_properties.extend({ type: 'raster' }, options);
	        ref_properties.extend(this, ref_properties.pick(options, [
	            'url',
	            'scheme',
	            'tileSize'
	        ]));
	    }
	    load() {
	        this._loaded = false;
	        this.fire(new ref_properties.Event('dataloading', { dataType: 'source' }));
	        this._tileJSONRequest = loadTileJSON(this._options, this.map._requestManager, null, null, (err, tileJSON) => {
	            this._tileJSONRequest = null;
	            this._loaded = true;
	            if (err) {
	                this.fire(new ref_properties.ErrorEvent(err));
	            } else if (tileJSON) {
	                ref_properties.extend(this, tileJSON);
	                if (tileJSON.bounds)
	                    this.tileBounds = new TileBounds(tileJSON.bounds, this.minzoom, this.maxzoom);
	                ref_properties.postTurnstileEvent(tileJSON.tiles);
	                this.fire(new ref_properties.Event('data', {
	                    dataType: 'source',
	                    sourceDataType: 'metadata'
	                }));
	                this.fire(new ref_properties.Event('data', {
	                    dataType: 'source',
	                    sourceDataType: 'content'
	                }));
	            }
	        });
	    }
	    loaded() {
	        return this._loaded;
	    }
	    onAdd(map) {
	        this.map = map;
	        this.load();
	    }
	    onRemove() {
	        if (this._tileJSONRequest) {
	            this._tileJSONRequest.cancel();
	            this._tileJSONRequest = null;
	        }
	    }
	    serialize() {
	        return ref_properties.extend({}, this._options);
	    }
	    hasTile(tileID) {
	        return !this.tileBounds || this.tileBounds.contains(tileID.canonical);
	    }
	    loadTile(tile, callback) {
	        const use2x = ref_properties.exported.devicePixelRatio >= 2;
	        const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme), use2x, this.tileSize);
	        tile.request = ref_properties.getImage(this.map._requestManager.transformRequest(url, ref_properties.ResourceType.Tile), (error, data, cacheControl, expires) => {
	            delete tile.request;
	            if (tile.aborted) {
	                tile.state = 'unloaded';
	                return callback(null);
	            }
	            if (error) {
	                tile.state = 'errored';
	                return callback(error);
	            }
	            if (!data)
	                return callback(null);
	            if (this.map._refreshExpiredTiles)
	                tile.setExpiryData({
	                    cacheControl,
	                    expires
	                });
	            tile.setTexture(data, this.map.painter);
	            tile.state = 'loaded';
	            ref_properties.cacheEntryPossiblyAdded(this.dispatcher);
	            callback(null);
	        });
	    }
	    static loadTileData(tile, data, painter) {
	        tile.setTexture(data, painter);
	    }
	    static unloadTileData(tile, painter) {
	        if (tile.texture) {
	            painter.saveTileTexture(tile.texture);
	        }
	    }
	    abortTile(tile, callback) {
	        if (tile.request) {
	            tile.request.cancel();
	            delete tile.request;
	        }
	        callback();
	    }
	    unloadTile(tile, callback) {
	        if (tile.texture)
	            this.map.painter.saveTileTexture(tile.texture);
	        callback();
	    }
	    hasTransition() {
	        return false;
	    }
	}

	let supportsOffscreenCanvas;
	function offscreenCanvasSupported() {
	    if (supportsOffscreenCanvas == null) {
	        supportsOffscreenCanvas = ref_properties.window.OffscreenCanvas && new ref_properties.window.OffscreenCanvas(1, 1).getContext('2d') && typeof ref_properties.window.createImageBitmap === 'function';
	    }
	    return supportsOffscreenCanvas;
	}

	class RasterDEMTileSource extends RasterTileSource {
	    constructor(id, options, dispatcher, eventedParent) {
	        super(id, options, dispatcher, eventedParent);
	        this.type = 'raster-dem';
	        this.maxzoom = 22;
	        this._options = ref_properties.extend({ type: 'raster-dem' }, options);
	        this.encoding = options.encoding || 'mapbox';
	    }
	    loadTile(tile, callback) {
	        const url = this.map._requestManager.normalizeTileURL(tile.tileID.canonical.url(this.tiles, this.scheme), false, this.tileSize);
	        tile.request = ref_properties.getImage(this.map._requestManager.transformRequest(url, ref_properties.ResourceType.Tile), imageLoaded.bind(this));
	        function imageLoaded(err, img, cacheControl, expires) {
	            delete tile.request;
	            if (tile.aborted) {
	                tile.state = 'unloaded';
	                callback(null);
	            } else if (err) {
	                tile.state = 'errored';
	                callback(err);
	            } else if (img) {
	                if (this.map._refreshExpiredTiles)
	                    tile.setExpiryData({
	                        cacheControl,
	                        expires
	                    });
	                const transfer = ref_properties.window.ImageBitmap && img instanceof ref_properties.window.ImageBitmap && offscreenCanvasSupported();
	                const buffer = (img.width - ref_properties.prevPowerOfTwo(img.width)) / 2;
	                const padding = 1 - buffer;
	                const borderReady = padding < 1;
	                if (!borderReady && !tile.neighboringTiles) {
	                    tile.neighboringTiles = this._getNeighboringTiles(tile.tileID);
	                }
	                const rawImageData = transfer ? img : ref_properties.exported.getImageData(img, padding);
	                const params = {
	                    uid: tile.uid,
	                    coord: tile.tileID,
	                    source: this.id,
	                    rawImageData,
	                    encoding: this.encoding,
	                    padding
	                };
	                if (!tile.actor || tile.state === 'expired') {
	                    tile.actor = this.dispatcher.getActor();
	                    tile.actor.send('loadDEMTile', params, done.bind(this), undefined, true);
	                }
	            }
	        }
	        function done(err, dem) {
	            if (err) {
	                tile.state = 'errored';
	                callback(err);
	            }
	            if (dem) {
	                tile.dem = dem;
	                tile.dem.onDeserialize();
	                tile.needsHillshadePrepare = true;
	                tile.needsDEMTextureUpload = true;
	                tile.state = 'loaded';
	                callback(null);
	            }
	        }
	    }
	    _getNeighboringTiles(tileID) {
	        const canonical = tileID.canonical;
	        const dim = Math.pow(2, canonical.z);
	        const px = (canonical.x - 1 + dim) % dim;
	        const pxw = canonical.x === 0 ? tileID.wrap - 1 : tileID.wrap;
	        const nx = (canonical.x + 1 + dim) % dim;
	        const nxw = canonical.x + 1 === dim ? tileID.wrap + 1 : tileID.wrap;
	        const neighboringTiles = {};
	        neighboringTiles[new ref_properties.OverscaledTileID(tileID.overscaledZ, pxw, canonical.z, px, canonical.y).key] = { backfilled: false };
	        neighboringTiles[new ref_properties.OverscaledTileID(tileID.overscaledZ, nxw, canonical.z, nx, canonical.y).key] = { backfilled: false };
	        if (canonical.y > 0) {
	            neighboringTiles[new ref_properties.OverscaledTileID(tileID.overscaledZ, pxw, canonical.z, px, canonical.y - 1).key] = { backfilled: false };
	            neighboringTiles[new ref_properties.OverscaledTileID(tileID.overscaledZ, tileID.wrap, canonical.z, canonical.x, canonical.y - 1).key] = { backfilled: false };
	            neighboringTiles[new ref_properties.OverscaledTileID(tileID.overscaledZ, nxw, canonical.z, nx, canonical.y - 1).key] = { backfilled: false };
	        }
	        if (canonical.y + 1 < dim) {
	            neighboringTiles[new ref_properties.OverscaledTileID(tileID.overscaledZ, pxw, canonical.z, px, canonical.y + 1).key] = { backfilled: false };
	            neighboringTiles[new ref_properties.OverscaledTileID(tileID.overscaledZ, tileID.wrap, canonical.z, canonical.x, canonical.y + 1).key] = { backfilled: false };
	            neighboringTiles[new ref_properties.OverscaledTileID(tileID.overscaledZ, nxw, canonical.z, nx, canonical.y + 1).key] = { backfilled: false };
	        }
	        return neighboringTiles;
	    }
	    unloadTile(tile) {
	        if (tile.demTexture)
	            this.map.painter.saveTileTexture(tile.demTexture);
	        if (tile.fbo) {
	            tile.fbo.destroy();
	            delete tile.fbo;
	        }
	        if (tile.dem)
	            delete tile.dem;
	        delete tile.neighboringTiles;
	        tile.state = 'unloaded';
	    }
	}

	class GeoJSONSource extends ref_properties.Evented {
	    constructor(id, options, dispatcher, eventedParent) {
	        super();
	        this.id = id;
	        this.type = 'geojson';
	        this.minzoom = 0;
	        this.maxzoom = 18;
	        this.tileSize = 512;
	        this.isTileClipped = true;
	        this.reparseOverscaled = true;
	        this._loaded = false;
	        this.actor = dispatcher.getActor();
	        this.setEventedParent(eventedParent);
	        this._data = options.data;
	        this._options = ref_properties.extend({}, options);
	        this._collectResourceTiming = options.collectResourceTiming;
	        if (options.maxzoom !== undefined)
	            this.maxzoom = options.maxzoom;
	        if (options.type)
	            this.type = options.type;
	        if (options.attribution)
	            this.attribution = options.attribution;
	        this.promoteId = options.promoteId;
	        const scale = ref_properties.EXTENT / this.tileSize;
	        this.workerOptions = ref_properties.extend({
	            source: this.id,
	            cluster: options.cluster || false,
	            geojsonVtOptions: {
	                buffer: (options.buffer !== undefined ? options.buffer : 128) * scale,
	                tolerance: (options.tolerance !== undefined ? options.tolerance : 0.375) * scale,
	                extent: ref_properties.EXTENT,
	                maxZoom: this.maxzoom,
	                lineMetrics: options.lineMetrics || false,
	                generateId: options.generateId || false
	            },
	            superclusterOptions: {
	                maxZoom: options.clusterMaxZoom !== undefined ? options.clusterMaxZoom : this.maxzoom - 1,
	                minPoints: Math.max(2, options.clusterMinPoints || 2),
	                extent: ref_properties.EXTENT,
	                radius: (options.clusterRadius !== undefined ? options.clusterRadius : 50) * scale,
	                log: false,
	                generateId: options.generateId || false
	            },
	            clusterProperties: options.clusterProperties,
	            filter: options.filter
	        }, options.workerOptions);
	    }
	    onAdd(map) {
	        this.map = map;
	        this.setData(this._data);
	    }
	    setData(data) {
	        this._data = data;
	        this._updateWorkerData();
	        return this;
	    }
	    getClusterExpansionZoom(clusterId, callback) {
	        this.actor.send('geojson.getClusterExpansionZoom', {
	            clusterId,
	            source: this.id
	        }, callback);
	        return this;
	    }
	    getClusterChildren(clusterId, callback) {
	        this.actor.send('geojson.getClusterChildren', {
	            clusterId,
	            source: this.id
	        }, callback);
	        return this;
	    }
	    getClusterLeaves(clusterId, limit, offset, callback) {
	        this.actor.send('geojson.getClusterLeaves', {
	            source: this.id,
	            clusterId,
	            limit,
	            offset
	        }, callback);
	        return this;
	    }
	    _updateWorkerData() {
	        if (this._pendingLoad) {
	            this._coalesce = true;
	            return;
	        }
	        this.fire(new ref_properties.Event('dataloading', { dataType: 'source' }));
	        this._loaded = false;
	        const options = ref_properties.extend({}, this.workerOptions);
	        const data = this._data;
	        if (typeof data === 'string') {
	            options.request = this.map._requestManager.transformRequest(ref_properties.exported.resolveURL(data), ref_properties.ResourceType.Source);
	            options.request.collectResourceTiming = this._collectResourceTiming;
	        } else {
	            options.data = JSON.stringify(data);
	        }
	        this._pendingLoad = this.actor.send(`${ this.type }.loadData`, options, (err, result) => {
	            this._loaded = true;
	            this._pendingLoad = null;
	            if (err) {
	                this.fire(new ref_properties.ErrorEvent(err));
	            } else {
	                const data = {
	                    dataType: 'source',
	                    sourceDataType: this._metadataFired ? 'content' : 'metadata'
	                };
	                if (this._collectResourceTiming && result && result.resourceTiming && result.resourceTiming[this.id]) {
	                    data.resourceTiming = result.resourceTiming[this.id];
	                }
	                this.fire(new ref_properties.Event('data', data));
	                this._metadataFired = true;
	            }
	            if (this._coalesce) {
	                this._updateWorkerData();
	                this._coalesce = false;
	            }
	        });
	    }
	    loaded() {
	        return this._loaded;
	    }
	    loadTile(tile, callback) {
	        const message = !tile.actor ? 'loadTile' : 'reloadTile';
	        tile.actor = this.actor;
	        const params = {
	            type: this.type,
	            uid: tile.uid,
	            tileID: tile.tileID,
	            tileZoom: tile.tileZoom,
	            zoom: tile.tileID.overscaledZ,
	            maxZoom: this.maxzoom,
	            tileSize: this.tileSize,
	            source: this.id,
	            pixelRatio: ref_properties.exported.devicePixelRatio,
	            showCollisionBoxes: this.map.showCollisionBoxes,
	            promoteId: this.promoteId
	        };
	        tile.request = this.actor.send(message, params, (err, data) => {
	            delete tile.request;
	            tile.unloadVectorData();
	            if (tile.aborted) {
	                return callback(null);
	            }
	            if (err) {
	                return callback(err);
	            }
	            tile.loadVectorData(data, this.map.painter, message === 'reloadTile');
	            return callback(null);
	        }, undefined, message === 'loadTile');
	    }
	    abortTile(tile) {
	        if (tile.request) {
	            tile.request.cancel();
	            delete tile.request;
	        }
	        tile.aborted = true;
	    }
	    unloadTile(tile) {
	        tile.unloadVectorData();
	        this.actor.send('removeTile', {
	            uid: tile.uid,
	            type: this.type,
	            source: this.id
	        });
	    }
	    onRemove() {
	        if (this._pendingLoad) {
	            this._pendingLoad.cancel();
	        }
	    }
	    serialize() {
	        return ref_properties.extend({}, this._options, {
	            type: this.type,
	            data: this._data
	        });
	    }
	    hasTransition() {
	        return false;
	    }
	}

	function basisToPoints(x1, y1, x2, y2, x3, y3, x4, y4) {
	    const m = [
	        x1,
	        x2,
	        x3,
	        y1,
	        y2,
	        y3,
	        1,
	        1,
	        1
	    ];
	    const s = [
	        x4,
	        y4,
	        1
	    ];
	    const ma = ref_properties.adjoint([], m);
	    const [sx, sy, sz] = ref_properties.transformMat3(s, s, ref_properties.transpose(ma, ma));
	    return ref_properties.multiply$1(m, [
	        sx,
	        0,
	        0,
	        0,
	        sy,
	        0,
	        0,
	        0,
	        sz
	    ], m);
	}
	function getPerspectiveTransform(w, h, x1, y1, x2, y2, x3, y3, x4, y4) {
	    const s = basisToPoints(0, 0, w, 0, 0, h, w, h);
	    const m = basisToPoints(x1, y1, x2, y2, x3, y3, x4, y4);
	    ref_properties.multiply$1(m, ref_properties.adjoint(s, s), m);
	    return [
	        m[6] / m[8] * w / ref_properties.EXTENT,
	        m[7] / m[8] * h / ref_properties.EXTENT
	    ];
	}
	class ImageSource extends ref_properties.Evented {
	    constructor(id, options, dispatcher, eventedParent) {
	        super();
	        this.id = id;
	        this.dispatcher = dispatcher;
	        this.coordinates = options.coordinates;
	        this.type = 'image';
	        this.minzoom = 0;
	        this.maxzoom = 22;
	        this.tileSize = 512;
	        this.tiles = {};
	        this._loaded = false;
	        this.setEventedParent(eventedParent);
	        this.options = options;
	    }
	    load(newCoordinates, loaded) {
	        this._loaded = loaded || false;
	        this.fire(new ref_properties.Event('dataloading', { dataType: 'source' }));
	        this.url = this.options.url;
	        ref_properties.getImage(this.map._requestManager.transformRequest(this.url, ref_properties.ResourceType.Image), (err, image) => {
	            this._loaded = true;
	            if (err) {
	                this.fire(new ref_properties.ErrorEvent(err));
	            } else if (image) {
	                const {HTMLImageElement} = ref_properties.window;
	                if (image instanceof HTMLImageElement) {
	                    this.image = ref_properties.exported.getImageData(image);
	                } else {
	                    this.image = image;
	                }
	                this.width = this.image.width;
	                this.height = this.image.height;
	                if (newCoordinates) {
	                    this.coordinates = newCoordinates;
	                }
	                this._finishLoading();
	            }
	        });
	    }
	    loaded() {
	        return this._loaded;
	    }
	    updateImage(options) {
	        if (!this.image || !options.url) {
	            return this;
	        }
	        this.options.url = options.url;
	        this.load(options.coordinates, this._loaded);
	        return this;
	    }
	    _finishLoading() {
	        if (this.map) {
	            this.setCoordinates(this.coordinates);
	            this.fire(new ref_properties.Event('data', {
	                dataType: 'source',
	                sourceDataType: 'metadata'
	            }));
	        }
	    }
	    onAdd(map) {
	        this.map = map;
	        this.load();
	    }
	    onRemove() {
	        if (this.texture)
	            this.texture.destroy();
	    }
	    setCoordinates(coordinates) {
	        this.coordinates = coordinates;
	        this._boundsArray = undefined;
	        const cornerCoords = coordinates.map(ref_properties.MercatorCoordinate.fromLngLat);
	        this.tileID = getCoordinatesCenterTileID(cornerCoords);
	        this.minzoom = this.maxzoom = this.tileID.z;
	        this.fire(new ref_properties.Event('data', {
	            dataType: 'source',
	            sourceDataType: 'content'
	        }));
	        return this;
	    }
	    _clear() {
	        this._boundsArray = undefined;
	    }
	    _prepareData(context) {
	        for (const w in this.tiles) {
	            const tile = this.tiles[w];
	            if (tile.state !== 'loaded') {
	                tile.state = 'loaded';
	                tile.texture = this.texture;
	            }
	        }
	        if (this._boundsArray)
	            return;
	        const tileTr = ref_properties.tileTransform(this.tileID, this.map.transform.projection);
	        const [tl, tr, br, bl] = this.coordinates.map(coord => {
	            const projectedCoord = tileTr.projection.project(coord[0], coord[1]);
	            return ref_properties.getTilePoint(tileTr, projectedCoord)._round();
	        });
	        this.perspectiveTransform = getPerspectiveTransform(this.width, this.height, tl.x, tl.y, tr.x, tr.y, bl.x, bl.y, br.x, br.y);
	        const boundsArray = this._boundsArray = new ref_properties.StructArrayLayout4i8();
	        boundsArray.emplaceBack(tl.x, tl.y, 0, 0);
	        boundsArray.emplaceBack(tr.x, tr.y, ref_properties.EXTENT, 0);
	        boundsArray.emplaceBack(bl.x, bl.y, 0, ref_properties.EXTENT);
	        boundsArray.emplaceBack(br.x, br.y, ref_properties.EXTENT, ref_properties.EXTENT);
	        if (this.boundsBuffer) {
	            this.boundsBuffer.destroy();
	        }
	        this.boundsBuffer = context.createVertexBuffer(boundsArray, ref_properties.boundsAttributes.members);
	        this.boundsSegments = ref_properties.SegmentVector.simpleSegment(0, 0, 4, 2);
	    }
	    prepare() {
	        if (Object.keys(this.tiles).length === 0 || !this.image)
	            return;
	        const context = this.map.painter.context;
	        const gl = context.gl;
	        if (!this.texture) {
	            this.texture = new ref_properties.Texture(context, this.image, gl.RGBA);
	            this.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	        } else {
	            this.texture.update(this.image);
	        }
	        this._prepareData(context);
	    }
	    loadTile(tile, callback) {
	        if (this.tileID && this.tileID.equals(tile.tileID.canonical)) {
	            this.tiles[String(tile.tileID.wrap)] = tile;
	            tile.buckets = {};
	            callback(null);
	        } else {
	            tile.state = 'errored';
	            callback(null);
	        }
	    }
	    serialize() {
	        return {
	            type: 'image',
	            url: this.options.url,
	            coordinates: this.coordinates
	        };
	    }
	    hasTransition() {
	        return false;
	    }
	}
	function getCoordinatesCenterTileID(coords) {
	    let minX = Infinity;
	    let minY = Infinity;
	    let maxX = -Infinity;
	    let maxY = -Infinity;
	    for (const coord of coords) {
	        minX = Math.min(minX, coord.x);
	        minY = Math.min(minY, coord.y);
	        maxX = Math.max(maxX, coord.x);
	        maxY = Math.max(maxY, coord.y);
	    }
	    const dx = maxX - minX;
	    const dy = maxY - minY;
	    const dMax = Math.max(dx, dy);
	    const zoom = Math.max(0, Math.floor(-Math.log(dMax) / Math.LN2));
	    const tilesAtZoom = Math.pow(2, zoom);
	    return new ref_properties.CanonicalTileID(zoom, Math.floor((minX + maxX) / 2 * tilesAtZoom), Math.floor((minY + maxY) / 2 * tilesAtZoom));
	}

	class VideoSource extends ImageSource {
	    constructor(id, options, dispatcher, eventedParent) {
	        super(id, options, dispatcher, eventedParent);
	        this.roundZoom = true;
	        this.type = 'video';
	        this.options = options;
	    }
	    load() {
	        this._loaded = false;
	        const options = this.options;
	        this.urls = [];
	        for (const url of options.urls) {
	            this.urls.push(this.map._requestManager.transformRequest(url, ref_properties.ResourceType.Source).url);
	        }
	        ref_properties.getVideo(this.urls, (err, video) => {
	            this._loaded = true;
	            if (err) {
	                this.fire(new ref_properties.ErrorEvent(err));
	            } else if (video) {
	                this.video = video;
	                this.video.loop = true;
	                this.video.setAttribute('playsinline', '');
	                this.video.addEventListener('playing', () => {
	                    this.map.triggerRepaint();
	                });
	                if (this.map) {
	                    this.video.play();
	                }
	                this._finishLoading();
	            }
	        });
	    }
	    pause() {
	        if (this.video) {
	            this.video.pause();
	        }
	    }
	    play() {
	        if (this.video) {
	            this.video.play();
	        }
	    }
	    seek(seconds) {
	        if (this.video) {
	            const seekableRange = this.video.seekable;
	            if (seconds < seekableRange.start(0) || seconds > seekableRange.end(0)) {
	                this.fire(new ref_properties.ErrorEvent(new ref_properties.ValidationError(`sources.${ this.id }`, null, `Playback for this video can be set only between the ${ seekableRange.start(0) } and ${ seekableRange.end(0) }-second mark.`)));
	            } else
	                this.video.currentTime = seconds;
	        }
	    }
	    getVideo() {
	        return this.video;
	    }
	    onAdd(map) {
	        if (this.map)
	            return;
	        this.map = map;
	        this.load();
	        if (this.video) {
	            this.video.play();
	            this.setCoordinates(this.coordinates);
	        }
	    }
	    prepare() {
	        if (Object.keys(this.tiles).length === 0 || this.video.readyState < 2) {
	            return;
	        }
	        const context = this.map.painter.context;
	        const gl = context.gl;
	        if (!this.texture) {
	            this.texture = new ref_properties.Texture(context, this.video, gl.RGBA);
	            this.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	            this.width = this.video.videoWidth;
	            this.height = this.video.videoHeight;
	        } else if (!this.video.paused) {
	            this.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	            gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, this.video);
	        }
	        this._prepareData(context);
	    }
	    serialize() {
	        return {
	            type: 'video',
	            urls: this.urls,
	            coordinates: this.coordinates
	        };
	    }
	    hasTransition() {
	        return this.video && !this.video.paused;
	    }
	}

	class CanvasSource extends ImageSource {
	    constructor(id, options, dispatcher, eventedParent) {
	        super(id, options, dispatcher, eventedParent);
	        if (!options.coordinates) {
	            this.fire(new ref_properties.ErrorEvent(new ref_properties.ValidationError(`sources.${ id }`, null, 'missing required property "coordinates"')));
	        } else if (!Array.isArray(options.coordinates) || options.coordinates.length !== 4 || options.coordinates.some(c => !Array.isArray(c) || c.length !== 2 || c.some(l => typeof l !== 'number'))) {
	            this.fire(new ref_properties.ErrorEvent(new ref_properties.ValidationError(`sources.${ id }`, null, '"coordinates" property must be an array of 4 longitude/latitude array pairs')));
	        }
	        if (options.animate && typeof options.animate !== 'boolean') {
	            this.fire(new ref_properties.ErrorEvent(new ref_properties.ValidationError(`sources.${ id }`, null, 'optional "animate" property must be a boolean value')));
	        }
	        if (!options.canvas) {
	            this.fire(new ref_properties.ErrorEvent(new ref_properties.ValidationError(`sources.${ id }`, null, 'missing required property "canvas"')));
	        } else if (typeof options.canvas !== 'string' && !(options.canvas instanceof ref_properties.window.HTMLCanvasElement)) {
	            this.fire(new ref_properties.ErrorEvent(new ref_properties.ValidationError(`sources.${ id }`, null, '"canvas" must be either a string representing the ID of the canvas element from which to read, or an HTMLCanvasElement instance')));
	        }
	        this.options = options;
	        this.animate = options.animate !== undefined ? options.animate : true;
	    }
	    load() {
	        this._loaded = true;
	        if (!this.canvas) {
	            this.canvas = this.options.canvas instanceof ref_properties.window.HTMLCanvasElement ? this.options.canvas : ref_properties.window.document.getElementById(this.options.canvas);
	        }
	        this.width = this.canvas.width;
	        this.height = this.canvas.height;
	        if (this._hasInvalidDimensions()) {
	            this.fire(new ref_properties.ErrorEvent(new Error('Canvas dimensions cannot be less than or equal to zero.')));
	            return;
	        }
	        this.play = function () {
	            this._playing = true;
	            this.map.triggerRepaint();
	        };
	        this.pause = function () {
	            if (this._playing) {
	                this.prepare();
	                this._playing = false;
	            }
	        };
	        this._finishLoading();
	    }
	    getCanvas() {
	        return this.canvas;
	    }
	    onAdd(map) {
	        this.map = map;
	        this.load();
	        if (this.canvas) {
	            if (this.animate)
	                this.play();
	        }
	    }
	    onRemove() {
	        this.pause();
	    }
	    prepare() {
	        let resize = false;
	        if (this.canvas.width !== this.width) {
	            this.width = this.canvas.width;
	            resize = true;
	        }
	        if (this.canvas.height !== this.height) {
	            this.height = this.canvas.height;
	            resize = true;
	        }
	        if (this._hasInvalidDimensions())
	            return;
	        if (Object.keys(this.tiles).length === 0)
	            return;
	        const context = this.map.painter.context;
	        if (!this.texture) {
	            this.texture = new ref_properties.Texture(context, this.canvas, context.gl.RGBA, { premultiply: true });
	        } else if (resize || this._playing) {
	            this.texture.update(this.canvas, { premultiply: true });
	        }
	        this._prepareData(context);
	    }
	    serialize() {
	        return {
	            type: 'canvas',
	            coordinates: this.coordinates
	        };
	    }
	    hasTransition() {
	        return this._playing;
	    }
	    _hasInvalidDimensions() {
	        for (const x of [
	                this.canvas.width,
	                this.canvas.height
	            ]) {
	            if (isNaN(x) || x <= 0)
	                return true;
	        }
	        return false;
	    }
	}

	function isRaster(data) {
	    return data instanceof ref_properties.window.ImageData || data instanceof ref_properties.window.ImageBitmap || data instanceof ref_properties.window.HTMLCanvasElement;
	}
	class CustomSource extends ref_properties.Evented {
	    constructor(id, implementation, dispatcher, eventedParent) {
	        super();
	        this.id = id;
	        this.type = 'custom';
	        this._dataType = 'raster';
	        this._dispatcher = dispatcher;
	        this._implementation = implementation;
	        this.setEventedParent(eventedParent);
	        this.scheme = 'xyz';
	        this.minzoom = 0;
	        this.maxzoom = 22;
	        this.tileSize = 512;
	        this._loaded = false;
	        this.roundZoom = true;
	        if (!this._implementation) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`Missing implementation for ${ this.id } custom source`)));
	        }
	        if (!this._implementation.loadTile) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`Missing loadTile implementation for ${ this.id } custom source`)));
	        }
	        if (this._implementation.bounds) {
	            this.tileBounds = new TileBounds(this._implementation.bounds, this.minzoom, this.maxzoom);
	        }
	        implementation.update = this._update.bind(this);
	        implementation.coveringTiles = this._coveringTiles.bind(this);
	        ref_properties.extend(this, ref_properties.pick(implementation, [
	            'dataType',
	            'scheme',
	            'minzoom',
	            'maxzoom',
	            'tileSize',
	            'attribution',
	            'minTileCacheSize',
	            'maxTileCacheSize'
	        ]));
	    }
	    serialize() {
	        return ref_properties.pick(this, [
	            'type',
	            'scheme',
	            'minzoom',
	            'maxzoom',
	            'tileSize',
	            'attribution'
	        ]);
	    }
	    load() {
	        this._loaded = true;
	        this.fire(new ref_properties.Event('data', {
	            dataType: 'source',
	            sourceDataType: 'metadata'
	        }));
	        this.fire(new ref_properties.Event('data', {
	            dataType: 'source',
	            sourceDataType: 'content'
	        }));
	    }
	    loaded() {
	        return this._loaded;
	    }
	    onAdd(map) {
	        this._map = map;
	        this._loaded = false;
	        this.fire(new ref_properties.Event('dataloading', { dataType: 'source' }));
	        if (this._implementation.onAdd)
	            this._implementation.onAdd(map);
	        this.load();
	    }
	    onRemove(map) {
	        if (this._implementation.onRemove) {
	            this._implementation.onRemove(map);
	        }
	    }
	    hasTile(tileID) {
	        if (this._implementation.hasTile) {
	            const {x, y, z} = tileID.canonical;
	            return this._implementation.hasTile({
	                x,
	                y,
	                z
	            });
	        }
	        return !this.tileBounds || this.tileBounds.contains(tileID.canonical);
	    }
	    loadTile(tile, callback) {
	        const {x, y, z} = tile.tileID.canonical;
	        const controller = new ref_properties.window.AbortController();
	        const signal = controller.signal;
	        const request = this._implementation.loadTile({
	            x,
	            y,
	            z
	        }, { signal });
	        if (!request) {
	            const emptyImage = {
	                width: this.tileSize,
	                height: this.tileSize,
	                data: null
	            };
	            this.loadTileData(tile, emptyImage);
	            tile.state = 'loaded';
	            return callback(null);
	        }
	        request.cancel = () => controller.abort();
	        tile.request = request.then(tileLoaded.bind(this)).catch(error => {
	            if (error.code === 20)
	                return;
	            tile.state = 'errored';
	            callback(error);
	        });
	        function tileLoaded(data) {
	            delete tile.request;
	            if (tile.aborted) {
	                tile.state = 'unloaded';
	                return callback(null);
	            }
	            if (!data) {
	                const emptyImage = {
	                    width: this.tileSize,
	                    height: this.tileSize,
	                    data: null
	                };
	                this.loadTileData(tile, emptyImage);
	                tile.state = 'loaded';
	                return callback(null);
	            }
	            if (!isRaster(data)) {
	                tile.state = 'errored';
	                return callback(new Error(`Can't infer data type for ${ this.id }, only raster data supported at the moment`));
	            }
	            this.loadTileData(tile, data);
	            tile.state = 'loaded';
	            callback(null);
	        }
	    }
	    loadTileData(tile, data) {
	        RasterTileSource.loadTileData(tile, data, this._map.painter);
	    }
	    unloadTileData(tile) {
	        RasterTileSource.unloadTileData(tile, this._map.painter);
	    }
	    prepareTile(tile) {
	        if (!this._implementation.prepareTile)
	            return null;
	        const {x, y, z} = tile.tileID.canonical;
	        const data = this._implementation.prepareTile({
	            x,
	            y,
	            z
	        });
	        if (!data)
	            return null;
	        this.loadTileData(tile, data);
	        tile.state = 'loaded';
	        return data;
	    }
	    unloadTile(tile, callback) {
	        this.unloadTileData(tile);
	        if (this._implementation.unloadTile) {
	            const {x, y, z} = tile.tileID.canonical;
	            this._implementation.unloadTile({
	                x,
	                y,
	                z
	            });
	        }
	        callback();
	    }
	    abortTile(tile, callback) {
	        if (tile.request && tile.request.cancel) {
	            tile.request.cancel();
	            delete tile.request;
	        }
	        callback();
	    }
	    hasTransition() {
	        return false;
	    }
	    _coveringTiles() {
	        const tileIDs = this._map.transform.coveringTiles({
	            tileSize: this.tileSize,
	            minzoom: this.minzoom,
	            maxzoom: this.maxzoom,
	            roundZoom: this.roundZoom
	        });
	        return tileIDs.map(tileID => ({
	            x: tileID.canonical.x,
	            y: tileID.canonical.y,
	            z: tileID.canonical.z
	        }));
	    }
	    _update() {
	        this.fire(new ref_properties.Event('data', {
	            dataType: 'source',
	            sourceDataType: 'content'
	        }));
	    }
	}

	const sourceTypes = {
	    vector: VectorTileSource,
	    raster: RasterTileSource,
	    'raster-dem': RasterDEMTileSource,
	    geojson: GeoJSONSource,
	    video: VideoSource,
	    image: ImageSource,
	    canvas: CanvasSource,
	    custom: CustomSource
	};
	const create = function (id, specification, dispatcher, eventedParent) {
	    const source = new sourceTypes[specification.type](id, specification, dispatcher, eventedParent);
	    if (source.id !== id) {
	        throw new Error(`Expected Source id to be ${ id } instead of ${ source.id }`);
	    }
	    ref_properties.bindAll([
	        'load',
	        'abort',
	        'unload',
	        'serialize',
	        'prepare'
	    ], source);
	    return source;
	};
	const getType = function (name) {
	    return sourceTypes[name];
	};
	const setType = function (name, type) {
	    sourceTypes[name] = type;
	};

	function getPixelPosMatrix(transform, tileID) {
	    const t = ref_properties.identity([]);
	    ref_properties.scale(t, t, [
	        transform.width * 0.5,
	        -transform.height * 0.5,
	        1
	    ]);
	    ref_properties.translate(t, t, [
	        1,
	        -1,
	        0
	    ]);
	    ref_properties.multiply(t, t, transform.calculateProjMatrix(tileID.toUnwrapped()));
	    return Float32Array.from(t);
	}
	function queryRenderedFeatures(sourceCache, styleLayers, serializedLayers, queryGeometry, params, transform, use3DQuery, visualizeQueryGeometry = false) {
	    const tileResults = sourceCache.tilesIn(queryGeometry, use3DQuery, visualizeQueryGeometry);
	    tileResults.sort(sortTilesIn);
	    const renderedFeatureLayers = [];
	    for (const tileResult of tileResults) {
	        renderedFeatureLayers.push({
	            wrappedTileID: tileResult.tile.tileID.wrapped().key,
	            queryResults: tileResult.tile.queryRenderedFeatures(styleLayers, serializedLayers, sourceCache._state, tileResult, params, transform, getPixelPosMatrix(sourceCache.transform, tileResult.tile.tileID), visualizeQueryGeometry)
	        });
	    }
	    const result = mergeRenderedFeatureLayers(renderedFeatureLayers);
	    for (const layerID in result) {
	        result[layerID].forEach(featureWrapper => {
	            const feature = featureWrapper.feature;
	            const layer = feature.layer;
	            if (!layer || layer.type === 'background' || layer.type === 'sky')
	                return;
	            feature.source = layer.source;
	            if (layer['source-layer']) {
	                feature.sourceLayer = layer['source-layer'];
	            }
	            feature.state = feature.id !== undefined ? sourceCache.getFeatureState(layer['source-layer'], feature.id) : {};
	        });
	    }
	    return result;
	}
	function queryRenderedSymbols(styleLayers, serializedLayers, getLayerSourceCache, queryGeometry, params, collisionIndex, retainedQueryData) {
	    const result = {};
	    const renderedSymbols = collisionIndex.queryRenderedSymbols(queryGeometry);
	    const bucketQueryData = [];
	    for (const bucketInstanceId of Object.keys(renderedSymbols).map(Number)) {
	        bucketQueryData.push(retainedQueryData[bucketInstanceId]);
	    }
	    bucketQueryData.sort(sortTilesIn);
	    for (const queryData of bucketQueryData) {
	        const bucketSymbols = queryData.featureIndex.lookupSymbolFeatures(renderedSymbols[queryData.bucketInstanceId], serializedLayers, queryData.bucketIndex, queryData.sourceLayerIndex, params.filter, params.layers, params.availableImages, styleLayers);
	        for (const layerID in bucketSymbols) {
	            const resultFeatures = result[layerID] = result[layerID] || [];
	            const layerSymbols = bucketSymbols[layerID];
	            layerSymbols.sort((a, b) => {
	                const featureSortOrder = queryData.featureSortOrder;
	                if (featureSortOrder) {
	                    const sortedA = featureSortOrder.indexOf(a.featureIndex);
	                    const sortedB = featureSortOrder.indexOf(b.featureIndex);
	                    return sortedB - sortedA;
	                } else {
	                    return b.featureIndex - a.featureIndex;
	                }
	            });
	            for (const symbolFeature of layerSymbols) {
	                resultFeatures.push(symbolFeature);
	            }
	        }
	    }
	    for (const layerName in result) {
	        result[layerName].forEach(featureWrapper => {
	            const feature = featureWrapper.feature;
	            const layer = styleLayers[layerName];
	            const sourceCache = getLayerSourceCache(layer);
	            const state = sourceCache.getFeatureState(feature.layer['source-layer'], feature.id);
	            feature.source = feature.layer.source;
	            if (feature.layer['source-layer']) {
	                feature.sourceLayer = feature.layer['source-layer'];
	            }
	            feature.state = state;
	        });
	    }
	    return result;
	}
	function querySourceFeatures(sourceCache, params) {
	    const tiles = sourceCache.getRenderableIds().map(id => {
	        return sourceCache.getTileByID(id);
	    });
	    const result = [];
	    const dataTiles = {};
	    for (let i = 0; i < tiles.length; i++) {
	        const tile = tiles[i];
	        const dataID = tile.tileID.canonical.key;
	        if (!dataTiles[dataID]) {
	            dataTiles[dataID] = true;
	            tile.querySourceFeatures(result, params);
	        }
	    }
	    return result;
	}
	function sortTilesIn(a, b) {
	    const idA = a.tileID;
	    const idB = b.tileID;
	    return idA.overscaledZ - idB.overscaledZ || idA.canonical.y - idB.canonical.y || idA.wrap - idB.wrap || idA.canonical.x - idB.canonical.x;
	}
	function mergeRenderedFeatureLayers(tiles) {
	    const result = {};
	    const wrappedIDLayerMap = {};
	    for (const tile of tiles) {
	        const queryResults = tile.queryResults;
	        const wrappedID = tile.wrappedTileID;
	        const wrappedIDLayers = wrappedIDLayerMap[wrappedID] = wrappedIDLayerMap[wrappedID] || {};
	        for (const layerID in queryResults) {
	            const tileFeatures = queryResults[layerID];
	            const wrappedIDFeatures = wrappedIDLayers[layerID] = wrappedIDLayers[layerID] || {};
	            const resultFeatures = result[layerID] = result[layerID] || [];
	            for (const tileFeature of tileFeatures) {
	                if (!wrappedIDFeatures[tileFeature.featureIndex]) {
	                    wrappedIDFeatures[tileFeature.featureIndex] = true;
	                    resultFeatures.push(tileFeature);
	                }
	            }
	        }
	    }
	    return result;
	}

	function WebWorker () {
	    return exported.workerClass != null ? new exported.workerClass() : new ref_properties.window.Worker(exported.workerUrl);
	}

	const PRELOAD_POOL_ID = 'mapboxgl_preloaded_worker_pool';
	class WorkerPool {
	    constructor() {
	        this.active = {};
	    }
	    acquire(mapId) {
	        if (!this.workers) {
	            this.workers = [];
	            while (this.workers.length < WorkerPool.workerCount) {
	                this.workers.push(new WebWorker());
	            }
	        }
	        this.active[mapId] = true;
	        return this.workers.slice();
	    }
	    release(mapId) {
	        delete this.active[mapId];
	        if (this.numActive() === 0) {
	            this.workers.forEach(w => {
	                w.terminate();
	            });
	            this.workers = null;
	        }
	    }
	    isPreloaded() {
	        return !!this.active[PRELOAD_POOL_ID];
	    }
	    numActive() {
	        return Object.keys(this.active).length;
	    }
	}
	WorkerPool.workerCount = 2;

	let globalWorkerPool;
	function getGlobalWorkerPool() {
	    if (!globalWorkerPool) {
	        globalWorkerPool = new WorkerPool();
	    }
	    return globalWorkerPool;
	}
	function prewarm() {
	    const workerPool = getGlobalWorkerPool();
	    workerPool.acquire(PRELOAD_POOL_ID);
	}
	function clearPrewarmedResources() {
	    const pool = globalWorkerPool;
	    if (pool) {
	        if (pool.isPreloaded() && pool.numActive() === 1) {
	            pool.release(PRELOAD_POOL_ID);
	            globalWorkerPool = null;
	        } else {
	            console.warn('Could not clear WebWorkers since there are active Map instances that still reference it. The pre-warmed WebWorker pool can only be cleared when all map instances have been removed with map.remove()');
	        }
	    }
	}

	function deref(layer, parent) {
	    const result = {};
	    for (const k in layer) {
	        if (k !== 'ref') {
	            result[k] = layer[k];
	        }
	    }
	    ref_properties.refProperties.forEach(k => {
	        if (k in parent) {
	            result[k] = parent[k];
	        }
	    });
	    return result;
	}
	function derefLayers(layers) {
	    layers = layers.slice();
	    const map = Object.create(null);
	    for (let i = 0; i < layers.length; i++) {
	        map[layers[i].id] = layers[i];
	    }
	    for (let i = 0; i < layers.length; i++) {
	        if ('ref' in layers[i]) {
	            layers[i] = deref(layers[i], map[layers[i].ref]);
	        }
	    }
	    return layers;
	}

	function emptyStyle() {
	    return {
	        version: 8,
	        layers: [],
	        sources: {}
	    };
	}

	const operations = {
	    setStyle: 'setStyle',
	    addLayer: 'addLayer',
	    removeLayer: 'removeLayer',
	    setPaintProperty: 'setPaintProperty',
	    setLayoutProperty: 'setLayoutProperty',
	    setFilter: 'setFilter',
	    addSource: 'addSource',
	    removeSource: 'removeSource',
	    setGeoJSONSourceData: 'setGeoJSONSourceData',
	    setLayerZoomRange: 'setLayerZoomRange',
	    setLayerProperty: 'setLayerProperty',
	    setCenter: 'setCenter',
	    setZoom: 'setZoom',
	    setBearing: 'setBearing',
	    setPitch: 'setPitch',
	    setSprite: 'setSprite',
	    setGlyphs: 'setGlyphs',
	    setTransition: 'setTransition',
	    setLight: 'setLight',
	    setTerrain: 'setTerrain',
	    setFog: 'setFog',
	    setProjection: 'setProjection'
	};
	function addSource(sourceId, after, commands) {
	    commands.push({
	        command: operations.addSource,
	        args: [
	            sourceId,
	            after[sourceId]
	        ]
	    });
	}
	function removeSource(sourceId, commands, sourcesRemoved) {
	    commands.push({
	        command: operations.removeSource,
	        args: [sourceId]
	    });
	    sourcesRemoved[sourceId] = true;
	}
	function updateSource(sourceId, after, commands, sourcesRemoved) {
	    removeSource(sourceId, commands, sourcesRemoved);
	    addSource(sourceId, after, commands);
	}
	function canUpdateGeoJSON(before, after, sourceId) {
	    let prop;
	    for (prop in before[sourceId]) {
	        if (!before[sourceId].hasOwnProperty(prop))
	            continue;
	        if (prop !== 'data' && !deepEqual(before[sourceId][prop], after[sourceId][prop])) {
	            return false;
	        }
	    }
	    for (prop in after[sourceId]) {
	        if (!after[sourceId].hasOwnProperty(prop))
	            continue;
	        if (prop !== 'data' && !deepEqual(before[sourceId][prop], after[sourceId][prop])) {
	            return false;
	        }
	    }
	    return true;
	}
	function diffSources(before, after, commands, sourcesRemoved) {
	    before = before || {};
	    after = after || {};
	    let sourceId;
	    for (sourceId in before) {
	        if (!before.hasOwnProperty(sourceId))
	            continue;
	        if (!after.hasOwnProperty(sourceId)) {
	            removeSource(sourceId, commands, sourcesRemoved);
	        }
	    }
	    for (sourceId in after) {
	        if (!after.hasOwnProperty(sourceId))
	            continue;
	        if (!before.hasOwnProperty(sourceId)) {
	            addSource(sourceId, after, commands);
	        } else if (!deepEqual(before[sourceId], after[sourceId])) {
	            if (before[sourceId].type === 'geojson' && after[sourceId].type === 'geojson' && canUpdateGeoJSON(before, after, sourceId)) {
	                commands.push({
	                    command: operations.setGeoJSONSourceData,
	                    args: [
	                        sourceId,
	                        after[sourceId].data
	                    ]
	                });
	            } else {
	                updateSource(sourceId, after, commands, sourcesRemoved);
	            }
	        }
	    }
	}
	function diffLayerPropertyChanges(before, after, commands, layerId, klass, command) {
	    before = before || {};
	    after = after || {};
	    let prop;
	    for (prop in before) {
	        if (!before.hasOwnProperty(prop))
	            continue;
	        if (!deepEqual(before[prop], after[prop])) {
	            commands.push({
	                command,
	                args: [
	                    layerId,
	                    prop,
	                    after[prop],
	                    klass
	                ]
	            });
	        }
	    }
	    for (prop in after) {
	        if (!after.hasOwnProperty(prop) || before.hasOwnProperty(prop))
	            continue;
	        if (!deepEqual(before[prop], after[prop])) {
	            commands.push({
	                command,
	                args: [
	                    layerId,
	                    prop,
	                    after[prop],
	                    klass
	                ]
	            });
	        }
	    }
	}
	function pluckId(layer) {
	    return layer.id;
	}
	function indexById(group, layer) {
	    group[layer.id] = layer;
	    return group;
	}
	function diffLayers(before, after, commands) {
	    before = before || [];
	    after = after || [];
	    const beforeOrder = before.map(pluckId);
	    const afterOrder = after.map(pluckId);
	    const beforeIndex = before.reduce(indexById, {});
	    const afterIndex = after.reduce(indexById, {});
	    const tracker = beforeOrder.slice();
	    const clean = Object.create(null);
	    let i, d, layerId, beforeLayer, afterLayer, insertBeforeLayerId, prop;
	    for (i = 0, d = 0; i < beforeOrder.length; i++) {
	        layerId = beforeOrder[i];
	        if (!afterIndex.hasOwnProperty(layerId)) {
	            commands.push({
	                command: operations.removeLayer,
	                args: [layerId]
	            });
	            tracker.splice(tracker.indexOf(layerId, d), 1);
	        } else {
	            d++;
	        }
	    }
	    for (i = 0, d = 0; i < afterOrder.length; i++) {
	        layerId = afterOrder[afterOrder.length - 1 - i];
	        if (tracker[tracker.length - 1 - i] === layerId)
	            continue;
	        if (beforeIndex.hasOwnProperty(layerId)) {
	            commands.push({
	                command: operations.removeLayer,
	                args: [layerId]
	            });
	            tracker.splice(tracker.lastIndexOf(layerId, tracker.length - d), 1);
	        } else {
	            d++;
	        }
	        insertBeforeLayerId = tracker[tracker.length - i];
	        commands.push({
	            command: operations.addLayer,
	            args: [
	                afterIndex[layerId],
	                insertBeforeLayerId
	            ]
	        });
	        tracker.splice(tracker.length - i, 0, layerId);
	        clean[layerId] = true;
	    }
	    for (i = 0; i < afterOrder.length; i++) {
	        layerId = afterOrder[i];
	        beforeLayer = beforeIndex[layerId];
	        afterLayer = afterIndex[layerId];
	        if (clean[layerId] || deepEqual(beforeLayer, afterLayer))
	            continue;
	        if (!deepEqual(beforeLayer.source, afterLayer.source) || !deepEqual(beforeLayer['source-layer'], afterLayer['source-layer']) || !deepEqual(beforeLayer.type, afterLayer.type)) {
	            commands.push({
	                command: operations.removeLayer,
	                args: [layerId]
	            });
	            insertBeforeLayerId = tracker[tracker.lastIndexOf(layerId) + 1];
	            commands.push({
	                command: operations.addLayer,
	                args: [
	                    afterLayer,
	                    insertBeforeLayerId
	                ]
	            });
	            continue;
	        }
	        diffLayerPropertyChanges(beforeLayer.layout, afterLayer.layout, commands, layerId, null, operations.setLayoutProperty);
	        diffLayerPropertyChanges(beforeLayer.paint, afterLayer.paint, commands, layerId, null, operations.setPaintProperty);
	        if (!deepEqual(beforeLayer.filter, afterLayer.filter)) {
	            commands.push({
	                command: operations.setFilter,
	                args: [
	                    layerId,
	                    afterLayer.filter
	                ]
	            });
	        }
	        if (!deepEqual(beforeLayer.minzoom, afterLayer.minzoom) || !deepEqual(beforeLayer.maxzoom, afterLayer.maxzoom)) {
	            commands.push({
	                command: operations.setLayerZoomRange,
	                args: [
	                    layerId,
	                    afterLayer.minzoom,
	                    afterLayer.maxzoom
	                ]
	            });
	        }
	        for (prop in beforeLayer) {
	            if (!beforeLayer.hasOwnProperty(prop))
	                continue;
	            if (prop === 'layout' || prop === 'paint' || prop === 'filter' || prop === 'metadata' || prop === 'minzoom' || prop === 'maxzoom')
	                continue;
	            if (prop.indexOf('paint.') === 0) {
	                diffLayerPropertyChanges(beforeLayer[prop], afterLayer[prop], commands, layerId, prop.slice(6), operations.setPaintProperty);
	            } else if (!deepEqual(beforeLayer[prop], afterLayer[prop])) {
	                commands.push({
	                    command: operations.setLayerProperty,
	                    args: [
	                        layerId,
	                        prop,
	                        afterLayer[prop]
	                    ]
	                });
	            }
	        }
	        for (prop in afterLayer) {
	            if (!afterLayer.hasOwnProperty(prop) || beforeLayer.hasOwnProperty(prop))
	                continue;
	            if (prop === 'layout' || prop === 'paint' || prop === 'filter' || prop === 'metadata' || prop === 'minzoom' || prop === 'maxzoom')
	                continue;
	            if (prop.indexOf('paint.') === 0) {
	                diffLayerPropertyChanges(beforeLayer[prop], afterLayer[prop], commands, layerId, prop.slice(6), operations.setPaintProperty);
	            } else if (!deepEqual(beforeLayer[prop], afterLayer[prop])) {
	                commands.push({
	                    command: operations.setLayerProperty,
	                    args: [
	                        layerId,
	                        prop,
	                        afterLayer[prop]
	                    ]
	                });
	            }
	        }
	    }
	}
	function diffStyles(before, after) {
	    if (!before)
	        return [{
	                command: operations.setStyle,
	                args: [after]
	            }];
	    let commands = [];
	    try {
	        if (!deepEqual(before.version, after.version)) {
	            return [{
	                    command: operations.setStyle,
	                    args: [after]
	                }];
	        }
	        if (!deepEqual(before.center, after.center)) {
	            commands.push({
	                command: operations.setCenter,
	                args: [after.center]
	            });
	        }
	        if (!deepEqual(before.zoom, after.zoom)) {
	            commands.push({
	                command: operations.setZoom,
	                args: [after.zoom]
	            });
	        }
	        if (!deepEqual(before.bearing, after.bearing)) {
	            commands.push({
	                command: operations.setBearing,
	                args: [after.bearing]
	            });
	        }
	        if (!deepEqual(before.pitch, after.pitch)) {
	            commands.push({
	                command: operations.setPitch,
	                args: [after.pitch]
	            });
	        }
	        if (!deepEqual(before.sprite, after.sprite)) {
	            commands.push({
	                command: operations.setSprite,
	                args: [after.sprite]
	            });
	        }
	        if (!deepEqual(before.glyphs, after.glyphs)) {
	            commands.push({
	                command: operations.setGlyphs,
	                args: [after.glyphs]
	            });
	        }
	        if (!deepEqual(before.transition, after.transition)) {
	            commands.push({
	                command: operations.setTransition,
	                args: [after.transition]
	            });
	        }
	        if (!deepEqual(before.light, after.light)) {
	            commands.push({
	                command: operations.setLight,
	                args: [after.light]
	            });
	        }
	        if (!deepEqual(before.fog, after.fog)) {
	            commands.push({
	                command: operations.setFog,
	                args: [after.fog]
	            });
	        }
	        if (!deepEqual(before.projection, after.projection)) {
	            commands.push({
	                command: operations.setProjection,
	                args: [after.projection]
	            });
	        }
	        const sourcesRemoved = {};
	        const removeOrAddSourceCommands = [];
	        diffSources(before.sources, after.sources, removeOrAddSourceCommands, sourcesRemoved);
	        const beforeLayers = [];
	        if (before.layers) {
	            before.layers.forEach(layer => {
	                if (layer.source && sourcesRemoved[layer.source]) {
	                    commands.push({
	                        command: operations.removeLayer,
	                        args: [layer.id]
	                    });
	                } else {
	                    beforeLayers.push(layer);
	                }
	            });
	        }
	        let beforeTerrain = before.terrain;
	        if (beforeTerrain) {
	            if (sourcesRemoved[beforeTerrain.source]) {
	                commands.push({
	                    command: operations.setTerrain,
	                    args: [undefined]
	                });
	                beforeTerrain = undefined;
	            }
	        }
	        commands = commands.concat(removeOrAddSourceCommands);
	        if (!deepEqual(beforeTerrain, after.terrain)) {
	            commands.push({
	                command: operations.setTerrain,
	                args: [after.terrain]
	            });
	        }
	        diffLayers(beforeLayers, after.layers, commands);
	    } catch (e) {
	        console.warn('Unable to compute style diff:', e);
	        commands = [{
	                command: operations.setStyle,
	                args: [after]
	            }];
	    }
	    return commands;
	}

	class PathInterpolator {
	    constructor(points_, padding_) {
	        this.reset(points_, padding_);
	    }
	    reset(points_, padding_) {
	        this.points = points_ || [];
	        this._distances = [0];
	        for (let i = 1; i < this.points.length; i++) {
	            this._distances[i] = this._distances[i - 1] + this.points[i].dist(this.points[i - 1]);
	        }
	        this.length = this._distances[this._distances.length - 1];
	        this.padding = Math.min(padding_ || 0, this.length * 0.5);
	        this.paddedLength = this.length - this.padding * 2;
	    }
	    lerp(t) {
	        if (this.points.length === 1) {
	            return this.points[0];
	        }
	        t = ref_properties.clamp(t, 0, 1);
	        let currentIndex = 1;
	        let distOfCurrentIdx = this._distances[currentIndex];
	        const distToTarget = t * this.paddedLength + this.padding;
	        while (distOfCurrentIdx < distToTarget && currentIndex < this._distances.length) {
	            distOfCurrentIdx = this._distances[++currentIndex];
	        }
	        const idxOfPrevPoint = currentIndex - 1;
	        const distOfPrevIdx = this._distances[idxOfPrevPoint];
	        const segmentLength = distOfCurrentIdx - distOfPrevIdx;
	        const segmentT = segmentLength > 0 ? (distToTarget - distOfPrevIdx) / segmentLength : 0;
	        return this.points[idxOfPrevPoint].mult(1 - segmentT).add(this.points[currentIndex].mult(segmentT));
	    }
	}

	class GridIndex {
	    constructor(width, height, cellSize) {
	        const boxCells = this.boxCells = [];
	        const circleCells = this.circleCells = [];
	        this.xCellCount = Math.ceil(width / cellSize);
	        this.yCellCount = Math.ceil(height / cellSize);
	        for (let i = 0; i < this.xCellCount * this.yCellCount; i++) {
	            boxCells.push([]);
	            circleCells.push([]);
	        }
	        this.circleKeys = [];
	        this.boxKeys = [];
	        this.bboxes = [];
	        this.circles = [];
	        this.width = width;
	        this.height = height;
	        this.xScale = this.xCellCount / width;
	        this.yScale = this.yCellCount / height;
	        this.boxUid = 0;
	        this.circleUid = 0;
	    }
	    keysLength() {
	        return this.boxKeys.length + this.circleKeys.length;
	    }
	    insert(key, x1, y1, x2, y2) {
	        this._forEachCell(x1, y1, x2, y2, this._insertBoxCell, this.boxUid++);
	        this.boxKeys.push(key);
	        this.bboxes.push(x1);
	        this.bboxes.push(y1);
	        this.bboxes.push(x2);
	        this.bboxes.push(y2);
	    }
	    insertCircle(key, x, y, radius) {
	        this._forEachCell(x - radius, y - radius, x + radius, y + radius, this._insertCircleCell, this.circleUid++);
	        this.circleKeys.push(key);
	        this.circles.push(x);
	        this.circles.push(y);
	        this.circles.push(radius);
	    }
	    _insertBoxCell(x1, y1, x2, y2, cellIndex, uid) {
	        this.boxCells[cellIndex].push(uid);
	    }
	    _insertCircleCell(x1, y1, x2, y2, cellIndex, uid) {
	        this.circleCells[cellIndex].push(uid);
	    }
	    _query(x1, y1, x2, y2, hitTest, predicate) {
	        if (x2 < 0 || x1 > this.width || y2 < 0 || y1 > this.height) {
	            return hitTest ? false : [];
	        }
	        const result = [];
	        if (x1 <= 0 && y1 <= 0 && this.width <= x2 && this.height <= y2) {
	            if (hitTest) {
	                return true;
	            }
	            for (let boxUid = 0; boxUid < this.boxKeys.length; boxUid++) {
	                result.push({
	                    key: this.boxKeys[boxUid],
	                    x1: this.bboxes[boxUid * 4],
	                    y1: this.bboxes[boxUid * 4 + 1],
	                    x2: this.bboxes[boxUid * 4 + 2],
	                    y2: this.bboxes[boxUid * 4 + 3]
	                });
	            }
	            for (let circleUid = 0; circleUid < this.circleKeys.length; circleUid++) {
	                const x = this.circles[circleUid * 3];
	                const y = this.circles[circleUid * 3 + 1];
	                const radius = this.circles[circleUid * 3 + 2];
	                result.push({
	                    key: this.circleKeys[circleUid],
	                    x1: x - radius,
	                    y1: y - radius,
	                    x2: x + radius,
	                    y2: y + radius
	                });
	            }
	            return predicate ? result.filter(predicate) : result;
	        } else {
	            const queryArgs = {
	                hitTest,
	                seenUids: {
	                    box: {},
	                    circle: {}
	                }
	            };
	            this._forEachCell(x1, y1, x2, y2, this._queryCell, result, queryArgs, predicate);
	            return hitTest ? result.length > 0 : result;
	        }
	    }
	    _queryCircle(x, y, radius, hitTest, predicate) {
	        const x1 = x - radius;
	        const x2 = x + radius;
	        const y1 = y - radius;
	        const y2 = y + radius;
	        if (x2 < 0 || x1 > this.width || y2 < 0 || y1 > this.height) {
	            return hitTest ? false : [];
	        }
	        const result = [];
	        const queryArgs = {
	            hitTest,
	            circle: {
	                x,
	                y,
	                radius
	            },
	            seenUids: {
	                box: {},
	                circle: {}
	            }
	        };
	        this._forEachCell(x1, y1, x2, y2, this._queryCellCircle, result, queryArgs, predicate);
	        return hitTest ? result.length > 0 : result;
	    }
	    query(x1, y1, x2, y2, predicate) {
	        return this._query(x1, y1, x2, y2, false, predicate);
	    }
	    hitTest(x1, y1, x2, y2, predicate) {
	        return this._query(x1, y1, x2, y2, true, predicate);
	    }
	    hitTestCircle(x, y, radius, predicate) {
	        return this._queryCircle(x, y, radius, true, predicate);
	    }
	    _queryCell(x1, y1, x2, y2, cellIndex, result, queryArgs, predicate) {
	        const seenUids = queryArgs.seenUids;
	        const boxCell = this.boxCells[cellIndex];
	        if (boxCell !== null) {
	            const bboxes = this.bboxes;
	            for (const boxUid of boxCell) {
	                if (!seenUids.box[boxUid]) {
	                    seenUids.box[boxUid] = true;
	                    const offset = boxUid * 4;
	                    if (x1 <= bboxes[offset + 2] && y1 <= bboxes[offset + 3] && x2 >= bboxes[offset + 0] && y2 >= bboxes[offset + 1] && (!predicate || predicate(this.boxKeys[boxUid]))) {
	                        if (queryArgs.hitTest) {
	                            result.push(true);
	                            return true;
	                        } else {
	                            result.push({
	                                key: this.boxKeys[boxUid],
	                                x1: bboxes[offset],
	                                y1: bboxes[offset + 1],
	                                x2: bboxes[offset + 2],
	                                y2: bboxes[offset + 3]
	                            });
	                        }
	                    }
	                }
	            }
	        }
	        const circleCell = this.circleCells[cellIndex];
	        if (circleCell !== null) {
	            const circles = this.circles;
	            for (const circleUid of circleCell) {
	                if (!seenUids.circle[circleUid]) {
	                    seenUids.circle[circleUid] = true;
	                    const offset = circleUid * 3;
	                    if (this._circleAndRectCollide(circles[offset], circles[offset + 1], circles[offset + 2], x1, y1, x2, y2) && (!predicate || predicate(this.circleKeys[circleUid]))) {
	                        if (queryArgs.hitTest) {
	                            result.push(true);
	                            return true;
	                        } else {
	                            const x = circles[offset];
	                            const y = circles[offset + 1];
	                            const radius = circles[offset + 2];
	                            result.push({
	                                key: this.circleKeys[circleUid],
	                                x1: x - radius,
	                                y1: y - radius,
	                                x2: x + radius,
	                                y2: y + radius
	                            });
	                        }
	                    }
	                }
	            }
	        }
	    }
	    _queryCellCircle(x1, y1, x2, y2, cellIndex, result, queryArgs, predicate) {
	        const circle = queryArgs.circle;
	        const seenUids = queryArgs.seenUids;
	        const boxCell = this.boxCells[cellIndex];
	        if (boxCell !== null) {
	            const bboxes = this.bboxes;
	            for (const boxUid of boxCell) {
	                if (!seenUids.box[boxUid]) {
	                    seenUids.box[boxUid] = true;
	                    const offset = boxUid * 4;
	                    if (this._circleAndRectCollide(circle.x, circle.y, circle.radius, bboxes[offset + 0], bboxes[offset + 1], bboxes[offset + 2], bboxes[offset + 3]) && (!predicate || predicate(this.boxKeys[boxUid]))) {
	                        result.push(true);
	                        return true;
	                    }
	                }
	            }
	        }
	        const circleCell = this.circleCells[cellIndex];
	        if (circleCell !== null) {
	            const circles = this.circles;
	            for (const circleUid of circleCell) {
	                if (!seenUids.circle[circleUid]) {
	                    seenUids.circle[circleUid] = true;
	                    const offset = circleUid * 3;
	                    if (this._circlesCollide(circles[offset], circles[offset + 1], circles[offset + 2], circle.x, circle.y, circle.radius) && (!predicate || predicate(this.circleKeys[circleUid]))) {
	                        result.push(true);
	                        return true;
	                    }
	                }
	            }
	        }
	    }
	    _forEachCell(x1, y1, x2, y2, fn, arg1, arg2, predicate) {
	        const cx1 = this._convertToXCellCoord(x1);
	        const cy1 = this._convertToYCellCoord(y1);
	        const cx2 = this._convertToXCellCoord(x2);
	        const cy2 = this._convertToYCellCoord(y2);
	        for (let x = cx1; x <= cx2; x++) {
	            for (let y = cy1; y <= cy2; y++) {
	                const cellIndex = this.xCellCount * y + x;
	                if (fn.call(this, x1, y1, x2, y2, cellIndex, arg1, arg2, predicate))
	                    return;
	            }
	        }
	    }
	    _convertToXCellCoord(x) {
	        return Math.max(0, Math.min(this.xCellCount - 1, Math.floor(x * this.xScale)));
	    }
	    _convertToYCellCoord(y) {
	        return Math.max(0, Math.min(this.yCellCount - 1, Math.floor(y * this.yScale)));
	    }
	    _circlesCollide(x1, y1, r1, x2, y2, r2) {
	        const dx = x2 - x1;
	        const dy = y2 - y1;
	        const bothRadii = r1 + r2;
	        return bothRadii * bothRadii > dx * dx + dy * dy;
	    }
	    _circleAndRectCollide(circleX, circleY, radius, x1, y1, x2, y2) {
	        const halfRectWidth = (x2 - x1) / 2;
	        const distX = Math.abs(circleX - (x1 + halfRectWidth));
	        if (distX > halfRectWidth + radius) {
	            return false;
	        }
	        const halfRectHeight = (y2 - y1) / 2;
	        const distY = Math.abs(circleY - (y1 + halfRectHeight));
	        if (distY > halfRectHeight + radius) {
	            return false;
	        }
	        if (distX <= halfRectWidth || distY <= halfRectHeight) {
	            return true;
	        }
	        const dx = distX - halfRectWidth;
	        const dy = distY - halfRectHeight;
	        return dx * dx + dy * dy <= radius * radius;
	    }
	}

	const FlipState = {
	    unknown: 0,
	    flipRequired: 1,
	    flipNotRequired: 2
	};
	const maxTangent = Math.tan(85 * Math.PI / 180);
	function getLabelPlaneMatrixForRendering(posMatrix, tileID, pitchWithMap, rotateWithMap, transform, projection, pixelsToTileUnits) {
	    const m = ref_properties.create();
	    if (pitchWithMap) {
	        if (projection.name === 'globe') {
	            const lm = ref_properties.calculateGlobeLabelMatrix(transform, tileID);
	            ref_properties.multiply(m, m, lm);
	        } else {
	            const s = invert([], pixelsToTileUnits);
	            m[0] = s[0];
	            m[1] = s[1];
	            m[4] = s[2];
	            m[5] = s[3];
	            if (!rotateWithMap) {
	                ref_properties.rotateZ(m, m, transform.angle);
	            }
	        }
	    } else {
	        ref_properties.multiply(m, transform.labelPlaneMatrix, posMatrix);
	    }
	    return m;
	}
	function getLabelPlaneMatrixForPlacement(posMatrix, tileID, pitchWithMap, rotateWithMap, transform, projection, pixelsToTileUnits) {
	    const m = getLabelPlaneMatrixForRendering(posMatrix, tileID, pitchWithMap, rotateWithMap, transform, projection, pixelsToTileUnits);
	    if (projection.name !== 'globe' || !pitchWithMap) {
	        m[2] = m[6] = m[10] = m[14] = 0;
	    }
	    return m;
	}
	function getGlCoordMatrix(posMatrix, tileID, pitchWithMap, rotateWithMap, transform, projection, pixelsToTileUnits) {
	    if (pitchWithMap) {
	        if (projection.name === 'globe') {
	            const m = getLabelPlaneMatrixForRendering(posMatrix, tileID, pitchWithMap, rotateWithMap, transform, projection, pixelsToTileUnits);
	            ref_properties.invert(m, m);
	            ref_properties.multiply(m, posMatrix, m);
	            return m;
	        } else {
	            const m = ref_properties.clone(posMatrix);
	            const s = ref_properties.identity([]);
	            s[0] = pixelsToTileUnits[0];
	            s[1] = pixelsToTileUnits[1];
	            s[4] = pixelsToTileUnits[2];
	            s[5] = pixelsToTileUnits[3];
	            ref_properties.multiply(m, m, s);
	            if (!rotateWithMap) {
	                ref_properties.rotateZ(m, m, -transform.angle);
	            }
	            return m;
	        }
	    } else {
	        return transform.glCoordMatrix;
	    }
	}
	function project(point, matrix, elevation = 0) {
	    const pos = [
	        point.x,
	        point.y,
	        elevation,
	        1
	    ];
	    if (elevation) {
	        ref_properties.transformMat4$1(pos, pos, matrix);
	    } else {
	        xyTransformMat4(pos, pos, matrix);
	    }
	    const w = pos[3];
	    return {
	        point: [
	            pos[0] / w,
	            pos[1] / w,
	            pos[2] / w
	        ],
	        signedDistanceFromCamera: w
	    };
	}
	function projectVector(point, matrix) {
	    const pos = [
	        point[0],
	        point[1],
	        point[2],
	        1
	    ];
	    ref_properties.transformMat4$1(pos, pos, matrix);
	    const w = pos[3];
	    return {
	        point: [
	            pos[0] / w,
	            pos[1] / w,
	            pos[2] / w
	        ],
	        signedDistanceFromCamera: w
	    };
	}
	function projectClamped(point, matrix) {
	    const pos = [
	        point[0],
	        point[1],
	        point[2],
	        1
	    ];
	    ref_properties.transformMat4$1(pos, pos, matrix);
	    const w = Math.max(pos[3], 0.000001);
	    return [
	        pos[0] / w,
	        pos[1] / w,
	        pos[2] / w,
	        w
	    ];
	}
	function getPerspectiveRatio(cameraToCenterDistance, signedDistanceFromCamera) {
	    return Math.min(0.5 + 0.5 * (cameraToCenterDistance / signedDistanceFromCamera), 1.5);
	}
	function isVisible(anchorPos, clippingBuffer) {
	    const x = anchorPos[0] / anchorPos[3];
	    const y = anchorPos[1] / anchorPos[3];
	    const inPaddedViewport = x >= -clippingBuffer[0] && x <= clippingBuffer[0] && y >= -clippingBuffer[1] && y <= clippingBuffer[1];
	    return inPaddedViewport;
	}
	function updateLineLabels(bucket, posMatrix, painter, isText, labelPlaneMatrix, glCoordMatrix, pitchWithMap, keepUpright, getElevation, tileID) {
	    const tr = painter.transform;
	    const sizeData = isText ? bucket.textSizeData : bucket.iconSizeData;
	    const partiallyEvaluatedSize = ref_properties.evaluateSizeForZoom(sizeData, painter.transform.zoom);
	    const isGlobe = tr.projection.name === 'globe';
	    const clippingBuffer = [
	        256 / painter.width * 2 + 1,
	        256 / painter.height * 2 + 1
	    ];
	    const dynamicLayoutVertexArray = isText ? bucket.text.dynamicLayoutVertexArray : bucket.icon.dynamicLayoutVertexArray;
	    dynamicLayoutVertexArray.clear();
	    let globeExtVertexArray = null;
	    if (isGlobe) {
	        globeExtVertexArray = isText ? bucket.text.globeExtVertexArray : bucket.icon.globeExtVertexArray;
	    }
	    const lineVertexArray = bucket.lineVertexArray;
	    const placedSymbols = isText ? bucket.text.placedSymbolArray : bucket.icon.placedSymbolArray;
	    const aspectRatio = painter.transform.width / painter.transform.height;
	    let useVertical = false;
	    for (let s = 0; s < placedSymbols.length; s++) {
	        const symbol = placedSymbols.get(s);
	        if (symbol.writingMode === ref_properties.WritingMode.vertical && !useVertical) {
	            if (s === 0 || placedSymbols.get(s - 1).writingMode !== ref_properties.WritingMode.horizontal) {
	                useVertical = true;
	            }
	        }
	        if ((symbol.hidden || symbol.writingMode === ref_properties.WritingMode.vertical) && !useVertical) {
	            hideGlyphs(symbol.numGlyphs, dynamicLayoutVertexArray);
	            continue;
	        }
	        useVertical = false;
	        const tileAnchorPoint = new ref_properties.pointGeometry(symbol.tileAnchorX, symbol.tileAnchorY);
	        const elevation = getElevation ? getElevation(tileAnchorPoint) : [
	            0,
	            0,
	            0
	        ];
	        const projectedAnchor = tr.projection.projectTilePoint(tileAnchorPoint.x, tileAnchorPoint.y, tileID.canonical);
	        const elevatedAnchor = [
	            projectedAnchor.x + elevation[0],
	            projectedAnchor.y + elevation[1],
	            projectedAnchor.z + elevation[2]
	        ];
	        const anchorPos = [
	            ...elevatedAnchor,
	            1
	        ];
	        ref_properties.transformMat4$1(anchorPos, anchorPos, posMatrix);
	        if (!isVisible(anchorPos, clippingBuffer)) {
	            hideGlyphs(symbol.numGlyphs, dynamicLayoutVertexArray);
	            continue;
	        }
	        const cameraToAnchorDistance = anchorPos[3];
	        const perspectiveRatio = getPerspectiveRatio(painter.transform.cameraToCenterDistance, cameraToAnchorDistance);
	        const fontSize = ref_properties.evaluateSizeForFeature(sizeData, partiallyEvaluatedSize, symbol);
	        const pitchScaledFontSize = pitchWithMap ? fontSize / perspectiveRatio : fontSize * perspectiveRatio;
	        const labelPlaneAnchorPoint = project(new ref_properties.pointGeometry(elevatedAnchor[0], elevatedAnchor[1]), labelPlaneMatrix, elevatedAnchor[2]);
	        if (labelPlaneAnchorPoint.signedDistanceFromCamera <= 0) {
	            hideGlyphs(symbol.numGlyphs, dynamicLayoutVertexArray);
	            continue;
	        }
	        let projectionCache = {};
	        const getElevationForPlacement = pitchWithMap ? null : getElevation;
	        const placeUnflipped = placeGlyphsAlongLine(symbol, pitchScaledFontSize, false, keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, bucket.glyphOffsetArray, lineVertexArray, dynamicLayoutVertexArray, globeExtVertexArray, labelPlaneAnchorPoint.point, tileAnchorPoint, projectionCache, aspectRatio, getElevationForPlacement, tr.projection, tileID, pitchWithMap);
	        useVertical = placeUnflipped.useVertical;
	        if (getElevationForPlacement && placeUnflipped.needsFlipping)
	            projectionCache = {};
	        if (placeUnflipped.notEnoughRoom || useVertical || placeUnflipped.needsFlipping && placeGlyphsAlongLine(symbol, pitchScaledFontSize, true, keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, bucket.glyphOffsetArray, lineVertexArray, dynamicLayoutVertexArray, globeExtVertexArray, labelPlaneAnchorPoint.point, tileAnchorPoint, projectionCache, aspectRatio, getElevationForPlacement, tr.projection, tileID, pitchWithMap).notEnoughRoom) {
	            hideGlyphs(symbol.numGlyphs, dynamicLayoutVertexArray);
	        }
	    }
	    if (isText) {
	        bucket.text.dynamicLayoutVertexBuffer.updateData(dynamicLayoutVertexArray);
	        if (globeExtVertexArray) {
	            bucket.text.globeExtVertexBuffer.updateData(globeExtVertexArray);
	        }
	    } else {
	        bucket.icon.dynamicLayoutVertexBuffer.updateData(dynamicLayoutVertexArray);
	        if (globeExtVertexArray) {
	            bucket.icon.globeExtVertexBuffer.updateData(globeExtVertexArray);
	        }
	    }
	}
	function placeFirstAndLastGlyph(fontScale, glyphOffsetArray, lineOffsetX, lineOffsetY, flip, anchorPoint, tileAnchorPoint, symbol, lineVertexArray, labelPlaneMatrix, projectionCache, getElevation, returnPathInTileCoords, projection, tileID, pitchWithMap) {
	    const glyphEndIndex = symbol.glyphStartIndex + symbol.numGlyphs;
	    const lineStartIndex = symbol.lineStartIndex;
	    const lineEndIndex = symbol.lineStartIndex + symbol.lineLength;
	    const firstGlyphOffset = glyphOffsetArray.getoffsetX(symbol.glyphStartIndex);
	    const lastGlyphOffset = glyphOffsetArray.getoffsetX(glyphEndIndex - 1);
	    const firstPlacedGlyph = placeGlyphAlongLine(fontScale * firstGlyphOffset, lineOffsetX, lineOffsetY, flip, anchorPoint, tileAnchorPoint, symbol.segment, lineStartIndex, lineEndIndex, lineVertexArray, labelPlaneMatrix, projectionCache, getElevation, returnPathInTileCoords, true, projection, tileID, pitchWithMap);
	    if (!firstPlacedGlyph)
	        return null;
	    const lastPlacedGlyph = placeGlyphAlongLine(fontScale * lastGlyphOffset, lineOffsetX, lineOffsetY, flip, anchorPoint, tileAnchorPoint, symbol.segment, lineStartIndex, lineEndIndex, lineVertexArray, labelPlaneMatrix, projectionCache, getElevation, returnPathInTileCoords, true, projection, tileID, pitchWithMap);
	    if (!lastPlacedGlyph)
	        return null;
	    return {
	        first: firstPlacedGlyph,
	        last: lastPlacedGlyph
	    };
	}
	function isInFlipRetainRange(firstPoint, lastPoint, aspectRatio) {
	    const deltaY = lastPoint.y - firstPoint.y;
	    const deltaX = (lastPoint.x - firstPoint.x) * aspectRatio;
	    if (deltaX === 0) {
	        return true;
	    }
	    const absTangent = Math.abs(deltaY / deltaX);
	    return absTangent > maxTangent;
	}
	function requiresOrientationChange(symbol, firstPoint, lastPoint, aspectRatio) {
	    if (symbol.writingMode === ref_properties.WritingMode.horizontal) {
	        const rise = Math.abs(lastPoint.y - firstPoint.y);
	        const run = Math.abs(lastPoint.x - firstPoint.x) * aspectRatio;
	        if (rise > run) {
	            return { useVertical: true };
	        }
	    }
	    if (symbol.writingMode === ref_properties.WritingMode.vertical) {
	        return firstPoint.y < lastPoint.y ? { needsFlipping: true } : null;
	    }
	    if (symbol.flipState !== FlipState.unknown && isInFlipRetainRange(firstPoint, lastPoint, aspectRatio)) {
	        return symbol.flipState === FlipState.flipRequired ? { needsFlipping: true } : null;
	    }
	    return firstPoint.x > lastPoint.x ? { needsFlipping: true } : null;
	}
	function placeGlyphsAlongLine(symbol, fontSize, flip, keepUpright, posMatrix, labelPlaneMatrix, glCoordMatrix, glyphOffsetArray, lineVertexArray, dynamicLayoutVertexArray, globeExtVertexArray, anchorPoint, tileAnchorPoint, projectionCache, aspectRatio, getElevation, projection, tileID, pitchWithMap) {
	    const fontScale = fontSize / 24;
	    const lineOffsetX = symbol.lineOffsetX * fontScale;
	    const lineOffsetY = symbol.lineOffsetY * fontScale;
	    let placedGlyphs;
	    if (symbol.numGlyphs > 1) {
	        const glyphEndIndex = symbol.glyphStartIndex + symbol.numGlyphs;
	        const lineStartIndex = symbol.lineStartIndex;
	        const lineEndIndex = symbol.lineStartIndex + symbol.lineLength;
	        const firstAndLastGlyph = placeFirstAndLastGlyph(fontScale, glyphOffsetArray, lineOffsetX, lineOffsetY, flip, anchorPoint, tileAnchorPoint, symbol, lineVertexArray, labelPlaneMatrix, projectionCache, getElevation, false, projection, tileID, pitchWithMap);
	        if (!firstAndLastGlyph) {
	            return { notEnoughRoom: true };
	        }
	        const firstVec = projectVector(firstAndLastGlyph.first.point, glCoordMatrix).point;
	        const lastVec = projectVector(firstAndLastGlyph.last.point, glCoordMatrix).point;
	        const firstPoint = new ref_properties.pointGeometry(firstVec[0], firstVec[1]);
	        const lastPoint = new ref_properties.pointGeometry(lastVec[0], lastVec[1]);
	        if (keepUpright && !flip) {
	            const orientationChange = requiresOrientationChange(symbol, firstPoint, lastPoint, aspectRatio);
	            symbol.flipState = orientationChange && orientationChange.needsFlipping ? FlipState.flipRequired : FlipState.flipNotRequired;
	            if (orientationChange) {
	                return orientationChange;
	            }
	        }
	        placedGlyphs = [firstAndLastGlyph.first];
	        for (let glyphIndex = symbol.glyphStartIndex + 1; glyphIndex < glyphEndIndex - 1; glyphIndex++) {
	            placedGlyphs.push(placeGlyphAlongLine(fontScale * glyphOffsetArray.getoffsetX(glyphIndex), lineOffsetX, lineOffsetY, flip, anchorPoint, tileAnchorPoint, symbol.segment, lineStartIndex, lineEndIndex, lineVertexArray, labelPlaneMatrix, projectionCache, getElevation, false, false, projection, tileID, pitchWithMap));
	        }
	        placedGlyphs.push(firstAndLastGlyph.last);
	    } else {
	        if (keepUpright && !flip) {
	            const a = project(tileAnchorPoint, posMatrix).point;
	            const tileVertexIndex = symbol.lineStartIndex + symbol.segment + 1;
	            const tileSegmentEnd = new ref_properties.pointGeometry(lineVertexArray.getx(tileVertexIndex), lineVertexArray.gety(tileVertexIndex));
	            const projectedVertex = project(tileSegmentEnd, posMatrix);
	            const b = projectedVertex.signedDistanceFromCamera > 0 ? projectedVertex.point : projectTruncatedLineSegment(tileAnchorPoint, tileSegmentEnd, a, 1, posMatrix, undefined, projection, tileID.canonical);
	            const orientationChange = requiresOrientationChange(symbol, new ref_properties.pointGeometry(a[0], a[1]), new ref_properties.pointGeometry(b[0], b[1]), aspectRatio);
	            symbol.flipState = orientationChange && orientationChange.needsFlipping ? FlipState.flipRequired : FlipState.flipNotRequired;
	            if (orientationChange) {
	                return orientationChange;
	            }
	        }
	        const singleGlyph = placeGlyphAlongLine(fontScale * glyphOffsetArray.getoffsetX(symbol.glyphStartIndex), lineOffsetX, lineOffsetY, flip, anchorPoint, tileAnchorPoint, symbol.segment, symbol.lineStartIndex, symbol.lineStartIndex + symbol.lineLength, lineVertexArray, labelPlaneMatrix, projectionCache, getElevation, false, false, projection, tileID, pitchWithMap);
	        if (!singleGlyph)
	            return { notEnoughRoom: true };
	        placedGlyphs = [singleGlyph];
	    }
	    if (globeExtVertexArray) {
	        for (const glyph of placedGlyphs) {
	            ref_properties.updateGlobeVertexNormal(globeExtVertexArray, dynamicLayoutVertexArray.length + 0, glyph.up[0], glyph.up[1], glyph.up[2]);
	            ref_properties.updateGlobeVertexNormal(globeExtVertexArray, dynamicLayoutVertexArray.length + 1, glyph.up[0], glyph.up[1], glyph.up[2]);
	            ref_properties.updateGlobeVertexNormal(globeExtVertexArray, dynamicLayoutVertexArray.length + 2, glyph.up[0], glyph.up[1], glyph.up[2]);
	            ref_properties.updateGlobeVertexNormal(globeExtVertexArray, dynamicLayoutVertexArray.length + 3, glyph.up[0], glyph.up[1], glyph.up[2]);
	            ref_properties.addDynamicAttributes(dynamicLayoutVertexArray, glyph.point[0], glyph.point[1], glyph.point[2], glyph.angle);
	        }
	    } else {
	        for (const glyph of placedGlyphs) {
	            ref_properties.addDynamicAttributes(dynamicLayoutVertexArray, glyph.point[0], glyph.point[1], glyph.point[2], glyph.angle);
	        }
	    }
	    return {};
	}
	function elevatePointAndProject(p, tileID, posMatrix, projection, getElevation) {
	    const point = projection.projectTilePoint(p.x, p.y, tileID);
	    if (!getElevation) {
	        return project(point, posMatrix, point.z);
	    }
	    const elevation = getElevation(p);
	    return project(new ref_properties.pointGeometry(point.x + elevation[0], point.y + elevation[1]), posMatrix, point.z + elevation[2]);
	}
	function projectTruncatedLineSegment(previousTilePoint, currentTilePoint, previousProjectedPoint, minimumLength, projectionMatrix, getElevation, projection, tileID) {
	    const unitVertex = previousTilePoint.add(previousTilePoint.sub(currentTilePoint)._unit());
	    const projectedUnitVertex = elevatePointAndProject(unitVertex, tileID, projectionMatrix, projection, getElevation).point;
	    const projectedUnitSegment = ref_properties.sub([], previousProjectedPoint, projectedUnitVertex);
	    return ref_properties.scaleAndAdd([], previousProjectedPoint, projectedUnitSegment, minimumLength / ref_properties.length(projectedUnitSegment));
	}
	function placeGlyphAlongLine(offsetX, lineOffsetX, lineOffsetY, flip, anchorPoint, tileAnchorPoint, anchorSegment, lineStartIndex, lineEndIndex, lineVertexArray, labelPlaneMatrix, projectionCache, getElevation, returnPathInTileCoords, endGlyph, reprojection, tileID, pitchWithMap) {
	    const combinedOffsetX = flip ? offsetX - lineOffsetX : offsetX + lineOffsetX;
	    let dir = combinedOffsetX > 0 ? 1 : -1;
	    let angle = 0;
	    if (flip) {
	        dir *= -1;
	        angle = Math.PI;
	    }
	    if (dir < 0)
	        angle += Math.PI;
	    let currentIndex = dir > 0 ? lineStartIndex + anchorSegment : lineStartIndex + anchorSegment + 1;
	    let current = anchorPoint;
	    let prev = anchorPoint;
	    let distanceToPrev = 0;
	    let currentSegmentDistance = 0;
	    const absOffsetX = Math.abs(combinedOffsetX);
	    const pathVertices = [];
	    const tilePath = [];
	    let currentVertex = tileAnchorPoint;
	    const previousTilePoint = () => {
	        const previousLineVertexIndex = currentIndex - dir;
	        return distanceToPrev === 0 ? tileAnchorPoint : new ref_properties.pointGeometry(lineVertexArray.getx(previousLineVertexIndex), lineVertexArray.gety(previousLineVertexIndex));
	    };
	    const getTruncatedLineSegment = () => {
	        return projectTruncatedLineSegment(previousTilePoint(), currentVertex, prev, absOffsetX - distanceToPrev + 1, labelPlaneMatrix, getElevation, reprojection, tileID.canonical);
	    };
	    while (distanceToPrev + currentSegmentDistance <= absOffsetX) {
	        currentIndex += dir;
	        if (currentIndex < lineStartIndex || currentIndex >= lineEndIndex)
	            return null;
	        prev = current;
	        pathVertices.push(current);
	        if (returnPathInTileCoords)
	            tilePath.push(currentVertex || previousTilePoint());
	        current = projectionCache[currentIndex];
	        if (current === undefined) {
	            currentVertex = new ref_properties.pointGeometry(lineVertexArray.getx(currentIndex), lineVertexArray.gety(currentIndex));
	            const projection = elevatePointAndProject(currentVertex, tileID.canonical, labelPlaneMatrix, reprojection, getElevation);
	            if (projection.signedDistanceFromCamera > 0) {
	                current = projectionCache[currentIndex] = projection.point;
	            } else {
	                current = getTruncatedLineSegment();
	            }
	        } else {
	            currentVertex = null;
	        }
	        distanceToPrev += currentSegmentDistance;
	        currentSegmentDistance = ref_properties.distance(prev, current);
	    }
	    currentVertex = currentVertex || new ref_properties.pointGeometry(lineVertexArray.getx(currentIndex), lineVertexArray.gety(currentIndex));
	    const prevVertex = previousTilePoint();
	    if (endGlyph && getElevation) {
	        projectionCache[currentIndex] = current = projectionCache[currentIndex] === undefined ? current : getTruncatedLineSegment();
	        currentSegmentDistance = ref_properties.distance(prev, current);
	    }
	    const segmentInterpolationT = (absOffsetX - distanceToPrev) / currentSegmentDistance;
	    const tilePoint = currentVertex.sub(prevVertex).mult(segmentInterpolationT)._add(prevVertex);
	    const prevToCurrent = ref_properties.sub([], current, prev);
	    const labelPlanePoint = ref_properties.scaleAndAdd([], prev, prevToCurrent, segmentInterpolationT);
	    let axisZ = [
	        0,
	        0,
	        1
	    ];
	    let diffX = prevToCurrent[0];
	    let diffY = prevToCurrent[1];
	    if (pitchWithMap) {
	        axisZ = reprojection.upVector(tileID.canonical, tilePoint.x, tilePoint.y);
	        if (axisZ[0] !== 0 || axisZ[1] !== 0 || axisZ[2] !== 1) {
	            const axisX = [
	                1,
	                0,
	                0
	            ];
	            const axisY = [
	                0,
	                1,
	                0
	            ];
	            axisX[0] = axisZ[2];
	            axisX[1] = 0;
	            axisX[2] = -axisZ[0];
	            ref_properties.cross(axisY, axisZ, axisX);
	            ref_properties.normalize(axisX, axisX);
	            ref_properties.normalize(axisY, axisY);
	            diffX = ref_properties.dot(prevToCurrent, axisX);
	            diffY = ref_properties.dot(prevToCurrent, axisY);
	        }
	    }
	    if (lineOffsetY) {
	        const offsetDir = ref_properties.cross([], axisZ, prevToCurrent);
	        ref_properties.normalize(offsetDir, offsetDir);
	        ref_properties.scaleAndAdd(labelPlanePoint, labelPlanePoint, offsetDir, lineOffsetY * dir);
	    }
	    const segmentAngle = angle + Math.atan2(diffY, diffX);
	    pathVertices.push(labelPlanePoint);
	    if (returnPathInTileCoords) {
	        tilePath.push(tilePoint);
	    }
	    return {
	        point: labelPlanePoint,
	        angle: segmentAngle,
	        path: pathVertices,
	        tilePath,
	        up: axisZ
	    };
	}
	const hiddenGlyphAttributes = new Float32Array([
	    -Infinity,
	    -Infinity,
	    0,
	    -Infinity,
	    -Infinity,
	    0,
	    -Infinity,
	    -Infinity,
	    0,
	    -Infinity,
	    -Infinity,
	    0,
	    -Infinity,
	    -Infinity,
	    0
	]);
	function hideGlyphs(num, dynamicLayoutVertexArray) {
	    for (let i = 0; i < num; i++) {
	        const offset = dynamicLayoutVertexArray.length;
	        dynamicLayoutVertexArray.resize(offset + 4);
	        dynamicLayoutVertexArray.float32.set(hiddenGlyphAttributes, offset * 4);
	    }
	}
	function xyTransformMat4(out, a, m) {
	    const x = a[0], y = a[1];
	    out[0] = m[0] * x + m[4] * y + m[12];
	    out[1] = m[1] * x + m[5] * y + m[13];
	    out[3] = m[3] * x + m[7] * y + m[15];
	    return out;
	}

	const viewportPadding = 100;
	class CollisionIndex {
	    constructor(transform, fogState, grid = new GridIndex(transform.width + 2 * viewportPadding, transform.height + 2 * viewportPadding, 25), ignoredGrid = new GridIndex(transform.width + 2 * viewportPadding, transform.height + 2 * viewportPadding, 25)) {
	        this.transform = transform;
	        this.grid = grid;
	        this.ignoredGrid = ignoredGrid;
	        this.pitchfactor = Math.cos(transform._pitch) * transform.cameraToCenterDistance;
	        this.screenRightBoundary = transform.width + viewportPadding;
	        this.screenBottomBoundary = transform.height + viewportPadding;
	        this.gridRightBoundary = transform.width + 2 * viewportPadding;
	        this.gridBottomBoundary = transform.height + 2 * viewportPadding;
	        this.fogState = fogState;
	    }
	    placeCollisionBox(bucket, scale, collisionBox, shift, allowOverlap, textPixelRatio, posMatrix, collisionGroupPredicate) {
	        let anchorX = collisionBox.projectedAnchorX;
	        let anchorY = collisionBox.projectedAnchorY;
	        let anchorZ = collisionBox.projectedAnchorZ;
	        const elevation = collisionBox.elevation;
	        const tileID = collisionBox.tileID;
	        if (elevation && tileID) {
	            const up = bucket.getProjection().upVector(tileID.canonical, collisionBox.tileAnchorX, collisionBox.tileAnchorY);
	            const upScale = bucket.getProjection().upVectorScale(tileID.canonical, this.transform.center.lat, this.transform.worldSize).metersToTile;
	            anchorX += up[0] * elevation * upScale;
	            anchorY += up[1] * elevation * upScale;
	            anchorZ += up[2] * elevation * upScale;
	        }
	        const checkOcclusion = bucket.projection.name === 'globe' || !!elevation || this.transform.pitch > 0;
	        const projectedPoint = this.projectAndGetPerspectiveRatio(posMatrix, [
	            anchorX,
	            anchorY,
	            anchorZ
	        ], collisionBox.tileID, checkOcclusion, bucket.getProjection());
	        const tileToViewport = textPixelRatio * projectedPoint.perspectiveRatio;
	        const tlX = (collisionBox.x1 * scale + shift.x - collisionBox.padding) * tileToViewport + projectedPoint.point.x;
	        const tlY = (collisionBox.y1 * scale + shift.y - collisionBox.padding) * tileToViewport + projectedPoint.point.y;
	        const brX = (collisionBox.x2 * scale + shift.x + collisionBox.padding) * tileToViewport + projectedPoint.point.x;
	        const brY = (collisionBox.y2 * scale + shift.y + collisionBox.padding) * tileToViewport + projectedPoint.point.y;
	        const minPerspectiveRatio = 0.55;
	        const isClipped = projectedPoint.perspectiveRatio <= minPerspectiveRatio || projectedPoint.occluded;
	        if (!this.isInsideGrid(tlX, tlY, brX, brY) || !allowOverlap && this.grid.hitTest(tlX, tlY, brX, brY, collisionGroupPredicate) || isClipped) {
	            return {
	                box: [],
	                offscreen: false,
	                occluded: projectedPoint.occluded
	            };
	        }
	        return {
	            box: [
	                tlX,
	                tlY,
	                brX,
	                brY
	            ],
	            offscreen: this.isOffscreen(tlX, tlY, brX, brY),
	            occluded: false
	        };
	    }
	    placeCollisionCircles(bucket, allowOverlap, symbol, lineVertexArray, glyphOffsetArray, fontSize, posMatrix, labelPlaneMatrix, labelToScreenMatrix, showCollisionCircles, pitchWithMap, collisionGroupPredicate, circlePixelDiameter, textPixelPadding, tileID) {
	        const placedCollisionCircles = [];
	        const elevation = this.transform.elevation;
	        const getElevation = elevation ? elevation.getAtTileOffsetFunc(tileID, this.transform.center.lat, this.transform.worldSize, bucket.getProjection()) : _ => [
	            0,
	            0,
	            0
	        ];
	        const tileUnitAnchorPoint = new ref_properties.pointGeometry(symbol.tileAnchorX, symbol.tileAnchorY);
	        const projectedAnchor = bucket.getProjection().projectTilePoint(symbol.tileAnchorX, symbol.tileAnchorY, tileID.canonical);
	        const anchorElevation = getElevation(tileUnitAnchorPoint);
	        const elevatedAnchor = [
	            projectedAnchor.x + anchorElevation[0],
	            projectedAnchor.y + anchorElevation[1],
	            projectedAnchor.z + anchorElevation[2]
	        ];
	        const isGlobe = bucket.projection.name === 'globe';
	        const checkOcclusion = isGlobe || !!elevation || this.transform.pitch > 0;
	        const screenAnchorPoint = this.projectAndGetPerspectiveRatio(posMatrix, [
	            elevatedAnchor[0],
	            elevatedAnchor[1],
	            elevatedAnchor[2]
	        ], tileID, checkOcclusion, bucket.getProjection());
	        const {perspectiveRatio} = screenAnchorPoint;
	        const labelPlaneFontSize = pitchWithMap ? fontSize / perspectiveRatio : fontSize * perspectiveRatio;
	        const labelPlaneFontScale = labelPlaneFontSize / ref_properties.ONE_EM;
	        const labelPlaneAnchorPoint = project(new ref_properties.pointGeometry(elevatedAnchor[0], elevatedAnchor[1]), labelPlaneMatrix, elevatedAnchor[2]).point;
	        const projectionCache = {};
	        const lineOffsetX = symbol.lineOffsetX * labelPlaneFontScale;
	        const lineOffsetY = symbol.lineOffsetY * labelPlaneFontScale;
	        const firstAndLastGlyph = screenAnchorPoint.signedDistanceFromCamera > 0 ? placeFirstAndLastGlyph(labelPlaneFontScale, glyphOffsetArray, lineOffsetX, lineOffsetY, false, labelPlaneAnchorPoint, tileUnitAnchorPoint, symbol, lineVertexArray, labelPlaneMatrix, projectionCache, elevation && !pitchWithMap ? getElevation : null, pitchWithMap && !!elevation, bucket.getProjection(), tileID, pitchWithMap) : null;
	        let collisionDetected = false;
	        let inGrid = false;
	        let entirelyOffscreen = true;
	        if (firstAndLastGlyph && !screenAnchorPoint.occluded) {
	            const radius = circlePixelDiameter * 0.5 * perspectiveRatio + textPixelPadding;
	            const screenPlaneMin = new ref_properties.pointGeometry(-viewportPadding, -viewportPadding);
	            const screenPlaneMax = new ref_properties.pointGeometry(this.screenRightBoundary, this.screenBottomBoundary);
	            const interpolator = new PathInterpolator();
	            const first = firstAndLastGlyph.first;
	            const last = firstAndLastGlyph.last;
	            let projectedPath = [];
	            for (let i = first.path.length - 1; i >= 1; i--) {
	                projectedPath.push(first.path[i]);
	            }
	            for (let i = 1; i < last.path.length; i++) {
	                projectedPath.push(last.path[i]);
	            }
	            const circleDist = radius * 2.5;
	            if (labelToScreenMatrix) {
	                const screenSpacePath = elevation && !isGlobe ? projectedPath.map((p, index) => {
	                    const elevation = getElevation(index < first.path.length - 1 ? first.tilePath[first.path.length - 1 - index] : last.tilePath[index - first.path.length + 2]);
	                    p[2] = elevation[2];
	                    return projectVector(p, labelToScreenMatrix);
	                }) : projectedPath.map(p => projectVector(p, labelToScreenMatrix));
	                if (screenSpacePath.some(point => point.signedDistanceFromCamera <= 0)) {
	                    projectedPath = [];
	                } else {
	                    projectedPath = screenSpacePath.map(p => p.point);
	                }
	            }
	            let segments = [];
	            if (projectedPath.length > 0) {
	                const screenSpacePath = projectedPath.map(p => new ref_properties.pointGeometry(p[0], p[1]));
	                let minx = Infinity;
	                let maxx = -Infinity;
	                let miny = Infinity;
	                let maxy = -Infinity;
	                for (let i = 0; i < screenSpacePath.length; i++) {
	                    minx = Math.min(minx, screenSpacePath[i].x);
	                    miny = Math.min(miny, screenSpacePath[i].y);
	                    maxx = Math.max(maxx, screenSpacePath[i].x);
	                    maxy = Math.max(maxy, screenSpacePath[i].y);
	                }
	                if (minx >= screenPlaneMin.x && maxx <= screenPlaneMax.x && miny >= screenPlaneMin.y && maxy <= screenPlaneMax.y) {
	                    segments = [screenSpacePath];
	                } else if (maxx < screenPlaneMin.x || minx > screenPlaneMax.x || maxy < screenPlaneMin.y || miny > screenPlaneMax.y) {
	                    segments = [];
	                } else {
	                    segments = ref_properties.clipLine([screenSpacePath], screenPlaneMin.x, screenPlaneMin.y, screenPlaneMax.x, screenPlaneMax.y);
	                }
	            }
	            for (const seg of segments) {
	                interpolator.reset(seg, radius * 0.25);
	                let numCircles = 0;
	                if (interpolator.length <= 0.5 * radius) {
	                    numCircles = 1;
	                } else {
	                    numCircles = Math.ceil(interpolator.paddedLength / circleDist) + 1;
	                }
	                for (let i = 0; i < numCircles; i++) {
	                    const t = i / Math.max(numCircles - 1, 1);
	                    const circlePosition = interpolator.lerp(t);
	                    const centerX = circlePosition.x + viewportPadding;
	                    const centerY = circlePosition.y + viewportPadding;
	                    placedCollisionCircles.push(centerX, centerY, radius, 0);
	                    const x1 = centerX - radius;
	                    const y1 = centerY - radius;
	                    const x2 = centerX + radius;
	                    const y2 = centerY + radius;
	                    entirelyOffscreen = entirelyOffscreen && this.isOffscreen(x1, y1, x2, y2);
	                    inGrid = inGrid || this.isInsideGrid(x1, y1, x2, y2);
	                    if (!allowOverlap) {
	                        if (this.grid.hitTestCircle(centerX, centerY, radius, collisionGroupPredicate)) {
	                            collisionDetected = true;
	                            if (!showCollisionCircles) {
	                                return {
	                                    circles: [],
	                                    offscreen: false,
	                                    collisionDetected,
	                                    occluded: false
	                                };
	                            }
	                        }
	                    }
	                }
	            }
	        }
	        return {
	            circles: !showCollisionCircles && collisionDetected || !inGrid ? [] : placedCollisionCircles,
	            offscreen: entirelyOffscreen,
	            collisionDetected,
	            occluded: screenAnchorPoint.occluded
	        };
	    }
	    queryRenderedSymbols(viewportQueryGeometry) {
	        if (viewportQueryGeometry.length === 0 || this.grid.keysLength() === 0 && this.ignoredGrid.keysLength() === 0) {
	            return {};
	        }
	        const query = [];
	        let minX = Infinity;
	        let minY = Infinity;
	        let maxX = -Infinity;
	        let maxY = -Infinity;
	        for (const point of viewportQueryGeometry) {
	            const gridPoint = new ref_properties.pointGeometry(point.x + viewportPadding, point.y + viewportPadding);
	            minX = Math.min(minX, gridPoint.x);
	            minY = Math.min(minY, gridPoint.y);
	            maxX = Math.max(maxX, gridPoint.x);
	            maxY = Math.max(maxY, gridPoint.y);
	            query.push(gridPoint);
	        }
	        const features = this.grid.query(minX, minY, maxX, maxY).concat(this.ignoredGrid.query(minX, minY, maxX, maxY));
	        const seenFeatures = {};
	        const result = {};
	        for (const feature of features) {
	            const featureKey = feature.key;
	            if (seenFeatures[featureKey.bucketInstanceId] === undefined) {
	                seenFeatures[featureKey.bucketInstanceId] = {};
	            }
	            if (seenFeatures[featureKey.bucketInstanceId][featureKey.featureIndex]) {
	                continue;
	            }
	            const bbox = [
	                new ref_properties.pointGeometry(feature.x1, feature.y1),
	                new ref_properties.pointGeometry(feature.x2, feature.y1),
	                new ref_properties.pointGeometry(feature.x2, feature.y2),
	                new ref_properties.pointGeometry(feature.x1, feature.y2)
	            ];
	            if (!ref_properties.polygonIntersectsPolygon(query, bbox)) {
	                continue;
	            }
	            seenFeatures[featureKey.bucketInstanceId][featureKey.featureIndex] = true;
	            if (result[featureKey.bucketInstanceId] === undefined) {
	                result[featureKey.bucketInstanceId] = [];
	            }
	            result[featureKey.bucketInstanceId].push(featureKey.featureIndex);
	        }
	        return result;
	    }
	    insertCollisionBox(collisionBox, ignorePlacement, bucketInstanceId, featureIndex, collisionGroupID) {
	        const grid = ignorePlacement ? this.ignoredGrid : this.grid;
	        const key = {
	            bucketInstanceId,
	            featureIndex,
	            collisionGroupID
	        };
	        grid.insert(key, collisionBox[0], collisionBox[1], collisionBox[2], collisionBox[3]);
	    }
	    insertCollisionCircles(collisionCircles, ignorePlacement, bucketInstanceId, featureIndex, collisionGroupID) {
	        const grid = ignorePlacement ? this.ignoredGrid : this.grid;
	        const key = {
	            bucketInstanceId,
	            featureIndex,
	            collisionGroupID
	        };
	        for (let k = 0; k < collisionCircles.length; k += 4) {
	            grid.insertCircle(key, collisionCircles[k], collisionCircles[k + 1], collisionCircles[k + 2]);
	        }
	    }
	    projectAndGetPerspectiveRatio(posMatrix, point, tileID, checkOcclusion, bucketProjection) {
	        const p = [
	            point[0],
	            point[1],
	            point[2],
	            1
	        ];
	        let behindFog = false;
	        if (point[2] || this.transform.pitch > 0) {
	            ref_properties.transformMat4$1(p, p, posMatrix);
	            const isGlobe = bucketProjection.name === 'globe';
	            if (this.fogState && tileID && !isGlobe) {
	                const fogOpacity = getFogOpacityAtTileCoord(this.fogState, point[0], point[1], point[2], tileID.toUnwrapped(), this.transform);
	                behindFog = fogOpacity > FOG_SYMBOL_CLIPPING_THRESHOLD;
	            }
	        } else {
	            xyTransformMat4(p, p, posMatrix);
	        }
	        const a = new ref_properties.pointGeometry((p[0] / p[3] + 1) / 2 * this.transform.width + viewportPadding, (-p[1] / p[3] + 1) / 2 * this.transform.height + viewportPadding);
	        return {
	            point: a,
	            perspectiveRatio: Math.min(0.5 + 0.5 * (this.transform.getCameraToCenterDistance(bucketProjection) / p[3]), 1.5),
	            signedDistanceFromCamera: p[3],
	            occluded: checkOcclusion && p[2] > p[3] || behindFog
	        };
	    }
	    isOffscreen(x1, y1, x2, y2) {
	        return x2 < viewportPadding || x1 >= this.screenRightBoundary || y2 < viewportPadding || y1 > this.screenBottomBoundary;
	    }
	    isInsideGrid(x1, y1, x2, y2) {
	        return x2 >= 0 && x1 < this.gridRightBoundary && y2 >= 0 && y1 < this.gridBottomBoundary;
	    }
	    getViewportMatrix() {
	        const m = ref_properties.identity([]);
	        ref_properties.translate(m, m, [
	            -viewportPadding,
	            -viewportPadding,
	            0
	        ]);
	        return m;
	    }
	}

	function reconstructTileMatrix(transform, projection, coord) {
	    const tileMatrix = projection.createTileMatrix(transform, transform.worldSize, coord.toUnwrapped());
	    return ref_properties.multiply(new Float32Array(16), transform.projMatrix, tileMatrix);
	}
	function getCollisionDebugTileProjectionMatrix(coord, bucket, transform) {
	    if (bucket.projection.name === transform.projection.name) {
	        return coord.projMatrix;
	    }
	    const tr = transform.clone();
	    tr.setProjection(bucket.projection);
	    return reconstructTileMatrix(tr, bucket.getProjection(), coord);
	}
	function getSymbolTileProjectionMatrix(coord, bucketProjection, transform) {
	    if (bucketProjection.name === transform.projection.name) {
	        return coord.projMatrix;
	    }
	    return reconstructTileMatrix(transform, bucketProjection, coord);
	}
	function getSymbolPlacementTileProjectionMatrix(coord, bucketProjection, transform, runtimeProjection) {
	    if (bucketProjection.name === runtimeProjection) {
	        return transform.calculateProjMatrix(coord.toUnwrapped());
	    }
	    return reconstructTileMatrix(transform, bucketProjection, coord);
	}

	class OpacityState {
	    constructor(prevState, increment, placed, skipFade) {
	        if (prevState) {
	            this.opacity = Math.max(0, Math.min(1, prevState.opacity + (prevState.placed ? increment : -increment)));
	        } else {
	            this.opacity = skipFade && placed ? 1 : 0;
	        }
	        this.placed = placed;
	    }
	    isHidden() {
	        return this.opacity === 0 && !this.placed;
	    }
	}
	class JointOpacityState {
	    constructor(prevState, increment, placedText, placedIcon, skipFade, clipped = false) {
	        this.text = new OpacityState(prevState ? prevState.text : null, increment, placedText, skipFade);
	        this.icon = new OpacityState(prevState ? prevState.icon : null, increment, placedIcon, skipFade);
	        this.clipped = clipped;
	    }
	    isHidden() {
	        return this.text.isHidden() && this.icon.isHidden();
	    }
	}
	class JointPlacement {
	    constructor(text, icon, skipFade, clipped = false) {
	        this.text = text;
	        this.icon = icon;
	        this.skipFade = skipFade;
	        this.clipped = clipped;
	    }
	}
	class CollisionCircleArray {
	    constructor() {
	        this.invProjMatrix = ref_properties.create();
	        this.viewportMatrix = ref_properties.create();
	        this.circles = [];
	    }
	}
	class RetainedQueryData {
	    constructor(bucketInstanceId, featureIndex, sourceLayerIndex, bucketIndex, tileID) {
	        this.bucketInstanceId = bucketInstanceId;
	        this.featureIndex = featureIndex;
	        this.sourceLayerIndex = sourceLayerIndex;
	        this.bucketIndex = bucketIndex;
	        this.tileID = tileID;
	    }
	}
	class CollisionGroups {
	    constructor(crossSourceCollisions) {
	        this.crossSourceCollisions = crossSourceCollisions;
	        this.maxGroupID = 0;
	        this.collisionGroups = {};
	    }
	    get(sourceID) {
	        if (!this.crossSourceCollisions) {
	            if (!this.collisionGroups[sourceID]) {
	                const nextGroupID = ++this.maxGroupID;
	                this.collisionGroups[sourceID] = {
	                    ID: nextGroupID,
	                    predicate: key => {
	                        return key.collisionGroupID === nextGroupID;
	                    }
	                };
	            }
	            return this.collisionGroups[sourceID];
	        } else {
	            return {
	                ID: 0,
	                predicate: null
	            };
	        }
	    }
	}
	function calculateVariableLayoutShift(anchor, width, height, textOffset, textScale) {
	    const {horizontalAlign, verticalAlign} = ref_properties.getAnchorAlignment(anchor);
	    const shiftX = -(horizontalAlign - 0.5) * width;
	    const shiftY = -(verticalAlign - 0.5) * height;
	    const offset = ref_properties.evaluateVariableOffset(anchor, textOffset);
	    return new ref_properties.pointGeometry(shiftX + offset[0] * textScale, shiftY + offset[1] * textScale);
	}
	function offsetShift(shiftX, shiftY, rotateWithMap, pitchWithMap, angle) {
	    const shift = new ref_properties.pointGeometry(shiftX, shiftY);
	    if (rotateWithMap) {
	        shift._rotate(pitchWithMap ? angle : -angle);
	    }
	    return shift;
	}
	class Placement {
	    constructor(transform, fadeDuration, crossSourceCollisions, prevPlacement, fogState) {
	        this.transform = transform.clone();
	        this.projection = transform.projection.name;
	        this.collisionIndex = new CollisionIndex(this.transform, fogState);
	        this.placements = {};
	        this.opacities = {};
	        this.variableOffsets = {};
	        this.stale = false;
	        this.commitTime = 0;
	        this.fadeDuration = fadeDuration;
	        this.retainedQueryData = {};
	        this.collisionGroups = new CollisionGroups(crossSourceCollisions);
	        this.collisionCircleArrays = {};
	        this.prevPlacement = prevPlacement;
	        if (prevPlacement) {
	            prevPlacement.prevPlacement = undefined;
	        }
	        this.placedOrientations = {};
	    }
	    getBucketParts(results, styleLayer, tile, sortAcrossTiles) {
	        const symbolBucket = tile.getBucket(styleLayer);
	        const bucketFeatureIndex = tile.latestFeatureIndex;
	        if (!symbolBucket || !bucketFeatureIndex || styleLayer.id !== symbolBucket.layerIds[0])
	            return;
	        const layout = symbolBucket.layers[0].layout;
	        const collisionBoxArray = tile.collisionBoxArray;
	        const scale = Math.pow(2, this.transform.zoom - tile.tileID.overscaledZ);
	        const textPixelRatio = tile.tileSize / ref_properties.EXTENT;
	        const unwrappedTileID = tile.tileID.toUnwrapped();
	        this.transform.setProjection(symbolBucket.projection);
	        const posMatrix = getSymbolPlacementTileProjectionMatrix(tile.tileID, symbolBucket.getProjection(), this.transform, this.projection);
	        const pitchWithMap = layout.get('text-pitch-alignment') === 'map';
	        const rotateWithMap = layout.get('text-rotation-alignment') === 'map';
	        styleLayer.compileFilter();
	        const dynamicFilter = styleLayer.dynamicFilter();
	        const dynamicFilterNeedsFeature = styleLayer.dynamicFilterNeedsFeature();
	        const pixelsToTiles = this.transform.calculatePixelsToTileUnitsMatrix(tile);
	        const textLabelPlaneMatrix = getLabelPlaneMatrixForPlacement(posMatrix, tile.tileID.canonical, pitchWithMap, rotateWithMap, this.transform, symbolBucket.getProjection(), pixelsToTiles);
	        let labelToScreenMatrix = null;
	        if (pitchWithMap) {
	            const glMatrix = getGlCoordMatrix(posMatrix, tile.tileID.canonical, pitchWithMap, rotateWithMap, this.transform, symbolBucket.getProjection(), pixelsToTiles);
	            labelToScreenMatrix = ref_properties.multiply([], this.transform.labelPlaneMatrix, glMatrix);
	        }
	        let clippingData = null;
	        if (!!dynamicFilter && tile.latestFeatureIndex) {
	            clippingData = {
	                unwrappedTileID,
	                dynamicFilter,
	                dynamicFilterNeedsFeature,
	                featureIndex: tile.latestFeatureIndex
	            };
	        }
	        this.retainedQueryData[symbolBucket.bucketInstanceId] = new RetainedQueryData(symbolBucket.bucketInstanceId, bucketFeatureIndex, symbolBucket.sourceLayerIndex, symbolBucket.index, tile.tileID);
	        const parameters = {
	            bucket: symbolBucket,
	            layout,
	            posMatrix,
	            textLabelPlaneMatrix,
	            labelToScreenMatrix,
	            clippingData,
	            scale,
	            textPixelRatio,
	            holdingForFade: tile.holdingForFade(),
	            collisionBoxArray,
	            partiallyEvaluatedTextSize: ref_properties.evaluateSizeForZoom(symbolBucket.textSizeData, this.transform.zoom),
	            partiallyEvaluatedIconSize: ref_properties.evaluateSizeForZoom(symbolBucket.iconSizeData, this.transform.zoom),
	            collisionGroup: this.collisionGroups.get(symbolBucket.sourceID)
	        };
	        if (sortAcrossTiles) {
	            for (const range of symbolBucket.sortKeyRanges) {
	                const {sortKey, symbolInstanceStart, symbolInstanceEnd} = range;
	                results.push({
	                    sortKey,
	                    symbolInstanceStart,
	                    symbolInstanceEnd,
	                    parameters
	                });
	            }
	        } else {
	            results.push({
	                symbolInstanceStart: 0,
	                symbolInstanceEnd: symbolBucket.symbolInstances.length,
	                parameters
	            });
	        }
	    }
	    attemptAnchorPlacement(anchor, textBox, width, height, textScale, rotateWithMap, pitchWithMap, textPixelRatio, posMatrix, collisionGroup, textAllowOverlap, symbolInstance, symbolIndex, bucket, orientation, iconBox, textSize, iconSize) {
	        const textOffset = [
	            symbolInstance.textOffset0,
	            symbolInstance.textOffset1
	        ];
	        const shift = calculateVariableLayoutShift(anchor, width, height, textOffset, textScale);
	        const placedGlyphBoxes = this.collisionIndex.placeCollisionBox(bucket, textScale, textBox, offsetShift(shift.x, shift.y, rotateWithMap, pitchWithMap, this.transform.angle), textAllowOverlap, textPixelRatio, posMatrix, collisionGroup.predicate);
	        if (iconBox) {
	            const placedIconBoxes = this.collisionIndex.placeCollisionBox(bucket, bucket.getSymbolInstanceIconSize(iconSize, this.transform.zoom, symbolIndex), iconBox, offsetShift(shift.x, shift.y, rotateWithMap, pitchWithMap, this.transform.angle), textAllowOverlap, textPixelRatio, posMatrix, collisionGroup.predicate);
	            if (placedIconBoxes.box.length === 0)
	                return;
	        }
	        if (placedGlyphBoxes.box.length > 0) {
	            let prevAnchor;
	            if (this.prevPlacement && this.prevPlacement.variableOffsets[symbolInstance.crossTileID] && this.prevPlacement.placements[symbolInstance.crossTileID] && this.prevPlacement.placements[symbolInstance.crossTileID].text) {
	                prevAnchor = this.prevPlacement.variableOffsets[symbolInstance.crossTileID].anchor;
	            }
	            this.variableOffsets[symbolInstance.crossTileID] = {
	                textOffset,
	                width,
	                height,
	                anchor,
	                textScale,
	                prevAnchor
	            };
	            this.markUsedJustification(bucket, anchor, symbolInstance, orientation);
	            if (bucket.allowVerticalPlacement) {
	                this.markUsedOrientation(bucket, orientation, symbolInstance);
	                this.placedOrientations[symbolInstance.crossTileID] = orientation;
	            }
	            return {
	                shift,
	                placedGlyphBoxes
	            };
	        }
	    }
	    placeLayerBucketPart(bucketPart, seenCrossTileIDs, showCollisionBoxes, updateCollisionBoxIfNecessary) {
	        const {bucket, layout, posMatrix, textLabelPlaneMatrix, labelToScreenMatrix, clippingData, textPixelRatio, holdingForFade, collisionBoxArray, partiallyEvaluatedTextSize, partiallyEvaluatedIconSize, collisionGroup} = bucketPart.parameters;
	        const textOptional = layout.get('text-optional');
	        const iconOptional = layout.get('icon-optional');
	        const textAllowOverlap = layout.get('text-allow-overlap');
	        const iconAllowOverlap = layout.get('icon-allow-overlap');
	        const rotateWithMap = layout.get('text-rotation-alignment') === 'map';
	        const pitchWithMap = layout.get('text-pitch-alignment') === 'map';
	        const hasIconTextFit = layout.get('icon-text-fit') !== 'none';
	        const zOrderByViewportY = layout.get('symbol-z-order') === 'viewport-y';
	        this.transform.setProjection(bucket.projection);
	        let alwaysShowText = textAllowOverlap && (iconAllowOverlap || !bucket.hasIconData() || iconOptional);
	        let alwaysShowIcon = iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || textOptional);
	        if (!bucket.collisionArrays && collisionBoxArray) {
	            bucket.deserializeCollisionBoxes(collisionBoxArray);
	        }
	        if (showCollisionBoxes && updateCollisionBoxIfNecessary) {
	            bucket.updateCollisionDebugBuffers(this.transform.zoom, collisionBoxArray);
	        }
	        const placeSymbol = (symbolInstance, symbolIndex, collisionArrays) => {
	            if (clippingData) {
	                const globals = {
	                    zoom: this.transform.zoom,
	                    pitch: this.transform.pitch
	                };
	                let feature = null;
	                if (clippingData.dynamicFilterNeedsFeature) {
	                    const featureIndex = clippingData.featureIndex;
	                    const retainedQueryData = this.retainedQueryData[bucket.bucketInstanceId];
	                    feature = featureIndex.loadFeature({
	                        featureIndex: symbolInstance.featureIndex,
	                        bucketIndex: retainedQueryData.bucketIndex,
	                        sourceLayerIndex: retainedQueryData.sourceLayerIndex,
	                        layoutVertexArrayOffset: 0
	                    });
	                }
	                const canonicalTileId = this.retainedQueryData[bucket.bucketInstanceId].tileID.canonical;
	                const filterFunc = clippingData.dynamicFilter;
	                const shouldClip = !filterFunc(globals, feature, canonicalTileId, new ref_properties.pointGeometry(symbolInstance.tileAnchorX, symbolInstance.tileAnchorY), this.transform.calculateDistanceTileData(clippingData.unwrappedTileID));
	                if (shouldClip) {
	                    this.placements[symbolInstance.crossTileID] = new JointPlacement(false, false, false, true);
	                    seenCrossTileIDs[symbolInstance.crossTileID] = true;
	                    return;
	                }
	            }
	            if (seenCrossTileIDs[symbolInstance.crossTileID])
	                return;
	            if (holdingForFade) {
	                this.placements[symbolInstance.crossTileID] = new JointPlacement(false, false, false);
	                return;
	            }
	            let placeText = false;
	            let placeIcon = false;
	            let offscreen = true;
	            let textOccluded = false;
	            let iconOccluded = false;
	            let shift = null;
	            let placed = {
	                box: null,
	                offscreen: null,
	                occluded: null
	            };
	            let placedVerticalText = {
	                box: null,
	                offscreen: null,
	                occluded: null
	            };
	            let placedGlyphBoxes = null;
	            let placedGlyphCircles = null;
	            let placedIconBoxes = null;
	            let textFeatureIndex = 0;
	            let verticalTextFeatureIndex = 0;
	            let iconFeatureIndex = 0;
	            if (collisionArrays.textFeatureIndex) {
	                textFeatureIndex = collisionArrays.textFeatureIndex;
	            } else if (symbolInstance.useRuntimeCollisionCircles) {
	                textFeatureIndex = symbolInstance.featureIndex;
	            }
	            if (collisionArrays.verticalTextFeatureIndex) {
	                verticalTextFeatureIndex = collisionArrays.verticalTextFeatureIndex;
	            }
	            const updateBoxData = box => {
	                box.tileID = this.retainedQueryData[bucket.bucketInstanceId].tileID;
	                if (!this.transform.elevation && !box.elevation)
	                    return;
	                box.elevation = this.transform.elevation ? this.transform.elevation.getAtTileOffset(this.retainedQueryData[bucket.bucketInstanceId].tileID, box.tileAnchorX, box.tileAnchorY) : 0;
	            };
	            const textBox = collisionArrays.textBox;
	            if (textBox) {
	                updateBoxData(textBox);
	                const updatePreviousOrientationIfNotPlaced = isPlaced => {
	                    let previousOrientation = ref_properties.WritingMode.horizontal;
	                    if (bucket.allowVerticalPlacement && !isPlaced && this.prevPlacement) {
	                        const prevPlacedOrientation = this.prevPlacement.placedOrientations[symbolInstance.crossTileID];
	                        if (prevPlacedOrientation) {
	                            this.placedOrientations[symbolInstance.crossTileID] = prevPlacedOrientation;
	                            previousOrientation = prevPlacedOrientation;
	                            this.markUsedOrientation(bucket, previousOrientation, symbolInstance);
	                        }
	                    }
	                    return previousOrientation;
	                };
	                const placeTextForPlacementModes = (placeHorizontalFn, placeVerticalFn) => {
	                    if (bucket.allowVerticalPlacement && symbolInstance.numVerticalGlyphVertices > 0 && collisionArrays.verticalTextBox) {
	                        for (const placementMode of bucket.writingModes) {
	                            if (placementMode === ref_properties.WritingMode.vertical) {
	                                placed = placeVerticalFn();
	                                placedVerticalText = placed;
	                            } else {
	                                placed = placeHorizontalFn();
	                            }
	                            if (placed && placed.box && placed.box.length)
	                                break;
	                        }
	                    } else {
	                        placed = placeHorizontalFn();
	                    }
	                };
	                if (!layout.get('text-variable-anchor')) {
	                    const placeBox = (collisionTextBox, orientation) => {
	                        const textScale = bucket.getSymbolInstanceTextSize(partiallyEvaluatedTextSize, symbolInstance, this.transform.zoom, symbolIndex);
	                        const placedFeature = this.collisionIndex.placeCollisionBox(bucket, textScale, collisionTextBox, new ref_properties.pointGeometry(0, 0), textAllowOverlap, textPixelRatio, posMatrix, collisionGroup.predicate);
	                        if (placedFeature && placedFeature.box && placedFeature.box.length) {
	                            this.markUsedOrientation(bucket, orientation, symbolInstance);
	                            this.placedOrientations[symbolInstance.crossTileID] = orientation;
	                        }
	                        return placedFeature;
	                    };
	                    const placeHorizontal = () => {
	                        return placeBox(textBox, ref_properties.WritingMode.horizontal);
	                    };
	                    const placeVertical = () => {
	                        const verticalTextBox = collisionArrays.verticalTextBox;
	                        if (bucket.allowVerticalPlacement && symbolInstance.numVerticalGlyphVertices > 0 && verticalTextBox) {
	                            updateBoxData(verticalTextBox);
	                            return placeBox(verticalTextBox, ref_properties.WritingMode.vertical);
	                        }
	                        return {
	                            box: null,
	                            offscreen: null,
	                            occluded: null
	                        };
	                    };
	                    placeTextForPlacementModes(placeHorizontal, placeVertical);
	                    updatePreviousOrientationIfNotPlaced(placed && placed.box && placed.box.length);
	                } else {
	                    let anchors = layout.get('text-variable-anchor');
	                    if (this.prevPlacement && this.prevPlacement.variableOffsets[symbolInstance.crossTileID]) {
	                        const prevOffsets = this.prevPlacement.variableOffsets[symbolInstance.crossTileID];
	                        if (anchors.indexOf(prevOffsets.anchor) > 0) {
	                            anchors = anchors.filter(anchor => anchor !== prevOffsets.anchor);
	                            anchors.unshift(prevOffsets.anchor);
	                        }
	                    }
	                    const placeBoxForVariableAnchors = (collisionTextBox, collisionIconBox, orientation) => {
	                        const textScale = bucket.getSymbolInstanceTextSize(partiallyEvaluatedTextSize, symbolInstance, this.transform.zoom, symbolIndex);
	                        const width = (collisionTextBox.x2 - collisionTextBox.x1) * textScale + 2 * collisionTextBox.padding;
	                        const height = (collisionTextBox.y2 - collisionTextBox.y1) * textScale + 2 * collisionTextBox.padding;
	                        const variableIconBox = hasIconTextFit && !iconAllowOverlap ? collisionIconBox : null;
	                        if (variableIconBox)
	                            updateBoxData(variableIconBox);
	                        let placedBox = {
	                            box: [],
	                            offscreen: false,
	                            occluded: false
	                        };
	                        const placementAttempts = textAllowOverlap ? anchors.length * 2 : anchors.length;
	                        for (let i = 0; i < placementAttempts; ++i) {
	                            const anchor = anchors[i % anchors.length];
	                            const allowOverlap = i >= anchors.length;
	                            const result = this.attemptAnchorPlacement(anchor, collisionTextBox, width, height, textScale, rotateWithMap, pitchWithMap, textPixelRatio, posMatrix, collisionGroup, allowOverlap, symbolInstance, symbolIndex, bucket, orientation, variableIconBox, partiallyEvaluatedTextSize, partiallyEvaluatedIconSize);
	                            if (result) {
	                                placedBox = result.placedGlyphBoxes;
	                                if (placedBox && placedBox.box && placedBox.box.length) {
	                                    placeText = true;
	                                    shift = result.shift;
	                                    break;
	                                }
	                            }
	                        }
	                        return placedBox;
	                    };
	                    const placeHorizontal = () => {
	                        return placeBoxForVariableAnchors(textBox, collisionArrays.iconBox, ref_properties.WritingMode.horizontal);
	                    };
	                    const placeVertical = () => {
	                        const verticalTextBox = collisionArrays.verticalTextBox;
	                        if (verticalTextBox)
	                            updateBoxData(verticalTextBox);
	                        const wasPlaced = placed && placed.box && placed.box.length;
	                        if (bucket.allowVerticalPlacement && !wasPlaced && symbolInstance.numVerticalGlyphVertices > 0 && verticalTextBox) {
	                            return placeBoxForVariableAnchors(verticalTextBox, collisionArrays.verticalIconBox, ref_properties.WritingMode.vertical);
	                        }
	                        return {
	                            box: null,
	                            offscreen: null,
	                            occluded: null
	                        };
	                    };
	                    placeTextForPlacementModes(placeHorizontal, placeVertical);
	                    if (placed) {
	                        placeText = placed.box;
	                        offscreen = placed.offscreen;
	                        textOccluded = placed.occluded;
	                    }
	                    const prevOrientation = updatePreviousOrientationIfNotPlaced(placed && placed.box);
	                    if (!placeText && this.prevPlacement) {
	                        const prevOffset = this.prevPlacement.variableOffsets[symbolInstance.crossTileID];
	                        if (prevOffset) {
	                            this.variableOffsets[symbolInstance.crossTileID] = prevOffset;
	                            this.markUsedJustification(bucket, prevOffset.anchor, symbolInstance, prevOrientation);
	                        }
	                    }
	                }
	            }
	            placedGlyphBoxes = placed;
	            placeText = placedGlyphBoxes && placedGlyphBoxes.box && placedGlyphBoxes.box.length > 0;
	            offscreen = placedGlyphBoxes && placedGlyphBoxes.offscreen;
	            textOccluded = placedGlyphBoxes && placedGlyphBoxes.occluded;
	            if (symbolInstance.useRuntimeCollisionCircles) {
	                const placedSymbolIndex = symbolInstance.centerJustifiedTextSymbolIndex >= 0 ? symbolInstance.centerJustifiedTextSymbolIndex : symbolInstance.verticalPlacedTextSymbolIndex;
	                const placedSymbol = bucket.text.placedSymbolArray.get(placedSymbolIndex);
	                const fontSize = ref_properties.evaluateSizeForFeature(bucket.textSizeData, partiallyEvaluatedTextSize, placedSymbol);
	                const textPixelPadding = layout.get('text-padding');
	                const circlePixelDiameter = symbolInstance.collisionCircleDiameter * fontSize / ref_properties.ONE_EM;
	                placedGlyphCircles = this.collisionIndex.placeCollisionCircles(bucket, textAllowOverlap, placedSymbol, bucket.lineVertexArray, bucket.glyphOffsetArray, fontSize, posMatrix, textLabelPlaneMatrix, labelToScreenMatrix, showCollisionBoxes, pitchWithMap, collisionGroup.predicate, circlePixelDiameter, textPixelPadding, this.retainedQueryData[bucket.bucketInstanceId].tileID);
	                placeText = textAllowOverlap || placedGlyphCircles.circles.length > 0 && !placedGlyphCircles.collisionDetected;
	                offscreen = offscreen && placedGlyphCircles.offscreen;
	                textOccluded = placedGlyphCircles.occluded;
	            }
	            if (collisionArrays.iconFeatureIndex) {
	                iconFeatureIndex = collisionArrays.iconFeatureIndex;
	            }
	            if (collisionArrays.iconBox) {
	                const placeIconFeature = iconBox => {
	                    updateBoxData(iconBox);
	                    const shiftPoint = hasIconTextFit && shift ? offsetShift(shift.x, shift.y, rotateWithMap, pitchWithMap, this.transform.angle) : new ref_properties.pointGeometry(0, 0);
	                    const iconScale = bucket.getSymbolInstanceIconSize(partiallyEvaluatedIconSize, this.transform.zoom, symbolIndex);
	                    return this.collisionIndex.placeCollisionBox(bucket, iconScale, iconBox, shiftPoint, iconAllowOverlap, textPixelRatio, posMatrix, collisionGroup.predicate);
	                };
	                if (placedVerticalText && placedVerticalText.box && placedVerticalText.box.length && collisionArrays.verticalIconBox) {
	                    placedIconBoxes = placeIconFeature(collisionArrays.verticalIconBox);
	                    placeIcon = placedIconBoxes.box.length > 0;
	                } else {
	                    placedIconBoxes = placeIconFeature(collisionArrays.iconBox);
	                    placeIcon = placedIconBoxes.box.length > 0;
	                }
	                offscreen = offscreen && placedIconBoxes.offscreen;
	                iconOccluded = placedIconBoxes.occluded;
	            }
	            const iconWithoutText = textOptional || symbolInstance.numHorizontalGlyphVertices === 0 && symbolInstance.numVerticalGlyphVertices === 0;
	            const textWithoutIcon = iconOptional || symbolInstance.numIconVertices === 0;
	            if (!iconWithoutText && !textWithoutIcon) {
	                placeIcon = placeText = placeIcon && placeText;
	            } else if (!textWithoutIcon) {
	                placeText = placeIcon && placeText;
	            } else if (!iconWithoutText) {
	                placeIcon = placeIcon && placeText;
	            }
	            if (placeText && placedGlyphBoxes && placedGlyphBoxes.box) {
	                if (placedVerticalText && placedVerticalText.box && verticalTextFeatureIndex) {
	                    this.collisionIndex.insertCollisionBox(placedGlyphBoxes.box, layout.get('text-ignore-placement'), bucket.bucketInstanceId, verticalTextFeatureIndex, collisionGroup.ID);
	                } else {
	                    this.collisionIndex.insertCollisionBox(placedGlyphBoxes.box, layout.get('text-ignore-placement'), bucket.bucketInstanceId, textFeatureIndex, collisionGroup.ID);
	                }
	            }
	            if (placeIcon && placedIconBoxes) {
	                this.collisionIndex.insertCollisionBox(placedIconBoxes.box, layout.get('icon-ignore-placement'), bucket.bucketInstanceId, iconFeatureIndex, collisionGroup.ID);
	            }
	            if (placedGlyphCircles) {
	                if (placeText) {
	                    this.collisionIndex.insertCollisionCircles(placedGlyphCircles.circles, layout.get('text-ignore-placement'), bucket.bucketInstanceId, textFeatureIndex, collisionGroup.ID);
	                }
	                if (showCollisionBoxes) {
	                    const id = bucket.bucketInstanceId;
	                    let circleArray = this.collisionCircleArrays[id];
	                    if (circleArray === undefined)
	                        circleArray = this.collisionCircleArrays[id] = new CollisionCircleArray();
	                    for (let i = 0; i < placedGlyphCircles.circles.length; i += 4) {
	                        circleArray.circles.push(placedGlyphCircles.circles[i + 0]);
	                        circleArray.circles.push(placedGlyphCircles.circles[i + 1]);
	                        circleArray.circles.push(placedGlyphCircles.circles[i + 2]);
	                        circleArray.circles.push(placedGlyphCircles.collisionDetected ? 1 : 0);
	                    }
	                }
	            }
	            const notGlobe = bucket.projection.name !== 'globe';
	            alwaysShowText = alwaysShowText && (notGlobe || !textOccluded);
	            alwaysShowIcon = alwaysShowIcon && (notGlobe || !iconOccluded);
	            this.placements[symbolInstance.crossTileID] = new JointPlacement(placeText || alwaysShowText, placeIcon || alwaysShowIcon, offscreen || bucket.justReloaded);
	            seenCrossTileIDs[symbolInstance.crossTileID] = true;
	        };
	        if (zOrderByViewportY) {
	            const symbolIndexes = bucket.getSortedSymbolIndexes(this.transform.angle);
	            for (let i = symbolIndexes.length - 1; i >= 0; --i) {
	                const symbolIndex = symbolIndexes[i];
	                placeSymbol(bucket.symbolInstances.get(symbolIndex), symbolIndex, bucket.collisionArrays[symbolIndex]);
	            }
	        } else {
	            for (let i = bucketPart.symbolInstanceStart; i < bucketPart.symbolInstanceEnd; i++) {
	                placeSymbol(bucket.symbolInstances.get(i), i, bucket.collisionArrays[i]);
	            }
	        }
	        if (showCollisionBoxes && bucket.bucketInstanceId in this.collisionCircleArrays) {
	            const circleArray = this.collisionCircleArrays[bucket.bucketInstanceId];
	            ref_properties.invert(circleArray.invProjMatrix, posMatrix);
	            circleArray.viewportMatrix = this.collisionIndex.getViewportMatrix();
	        }
	        bucket.justReloaded = false;
	    }
	    markUsedJustification(bucket, placedAnchor, symbolInstance, orientation) {
	        const justifications = {
	            'left': symbolInstance.leftJustifiedTextSymbolIndex,
	            'center': symbolInstance.centerJustifiedTextSymbolIndex,
	            'right': symbolInstance.rightJustifiedTextSymbolIndex
	        };
	        let autoIndex;
	        if (orientation === ref_properties.WritingMode.vertical) {
	            autoIndex = symbolInstance.verticalPlacedTextSymbolIndex;
	        } else {
	            autoIndex = justifications[ref_properties.getAnchorJustification(placedAnchor)];
	        }
	        const indexes = [
	            symbolInstance.leftJustifiedTextSymbolIndex,
	            symbolInstance.centerJustifiedTextSymbolIndex,
	            symbolInstance.rightJustifiedTextSymbolIndex,
	            symbolInstance.verticalPlacedTextSymbolIndex
	        ];
	        for (const index of indexes) {
	            if (index >= 0) {
	                if (autoIndex >= 0 && index !== autoIndex) {
	                    bucket.text.placedSymbolArray.get(index).crossTileID = 0;
	                } else {
	                    bucket.text.placedSymbolArray.get(index).crossTileID = symbolInstance.crossTileID;
	                }
	            }
	        }
	    }
	    markUsedOrientation(bucket, orientation, symbolInstance) {
	        const horizontal = orientation === ref_properties.WritingMode.horizontal || orientation === ref_properties.WritingMode.horizontalOnly ? orientation : 0;
	        const vertical = orientation === ref_properties.WritingMode.vertical ? orientation : 0;
	        const horizontalIndexes = [
	            symbolInstance.leftJustifiedTextSymbolIndex,
	            symbolInstance.centerJustifiedTextSymbolIndex,
	            symbolInstance.rightJustifiedTextSymbolIndex
	        ];
	        for (const index of horizontalIndexes) {
	            bucket.text.placedSymbolArray.get(index).placedOrientation = horizontal;
	        }
	        if (symbolInstance.verticalPlacedTextSymbolIndex) {
	            bucket.text.placedSymbolArray.get(symbolInstance.verticalPlacedTextSymbolIndex).placedOrientation = vertical;
	        }
	    }
	    commit(now) {
	        this.commitTime = now;
	        this.zoomAtLastRecencyCheck = this.transform.zoom;
	        const prevPlacement = this.prevPlacement;
	        let placementChanged = false;
	        this.prevZoomAdjustment = prevPlacement ? prevPlacement.zoomAdjustment(this.transform.zoom) : 0;
	        const increment = prevPlacement ? prevPlacement.symbolFadeChange(now) : 1;
	        const prevOpacities = prevPlacement ? prevPlacement.opacities : {};
	        const prevOffsets = prevPlacement ? prevPlacement.variableOffsets : {};
	        const prevOrientations = prevPlacement ? prevPlacement.placedOrientations : {};
	        for (const crossTileID in this.placements) {
	            const jointPlacement = this.placements[crossTileID];
	            const prevOpacity = prevOpacities[crossTileID];
	            if (prevOpacity) {
	                this.opacities[crossTileID] = new JointOpacityState(prevOpacity, increment, jointPlacement.text, jointPlacement.icon, null, jointPlacement.clipped);
	                placementChanged = placementChanged || jointPlacement.text !== prevOpacity.text.placed || jointPlacement.icon !== prevOpacity.icon.placed;
	            } else {
	                this.opacities[crossTileID] = new JointOpacityState(null, increment, jointPlacement.text, jointPlacement.icon, jointPlacement.skipFade, jointPlacement.clipped);
	                placementChanged = placementChanged || jointPlacement.text || jointPlacement.icon;
	            }
	        }
	        for (const crossTileID in prevOpacities) {
	            const prevOpacity = prevOpacities[crossTileID];
	            if (!this.opacities[crossTileID]) {
	                const jointOpacity = new JointOpacityState(prevOpacity, increment, false, false);
	                if (!jointOpacity.isHidden()) {
	                    this.opacities[crossTileID] = jointOpacity;
	                    placementChanged = placementChanged || prevOpacity.text.placed || prevOpacity.icon.placed;
	                }
	            }
	        }
	        for (const crossTileID in prevOffsets) {
	            if (!this.variableOffsets[crossTileID] && this.opacities[crossTileID] && !this.opacities[crossTileID].isHidden()) {
	                this.variableOffsets[crossTileID] = prevOffsets[crossTileID];
	            }
	        }
	        for (const crossTileID in prevOrientations) {
	            if (!this.placedOrientations[crossTileID] && this.opacities[crossTileID] && !this.opacities[crossTileID].isHidden()) {
	                this.placedOrientations[crossTileID] = prevOrientations[crossTileID];
	            }
	        }
	        if (placementChanged) {
	            this.lastPlacementChangeTime = now;
	        } else if (typeof this.lastPlacementChangeTime !== 'number') {
	            this.lastPlacementChangeTime = prevPlacement ? prevPlacement.lastPlacementChangeTime : now;
	        }
	    }
	    updateLayerOpacities(styleLayer, tiles) {
	        const seenCrossTileIDs = {};
	        for (const tile of tiles) {
	            const symbolBucket = tile.getBucket(styleLayer);
	            if (symbolBucket && tile.latestFeatureIndex && styleLayer.id === symbolBucket.layerIds[0]) {
	                this.updateBucketOpacities(symbolBucket, seenCrossTileIDs, tile.collisionBoxArray);
	            }
	        }
	    }
	    updateBucketOpacities(bucket, seenCrossTileIDs, collisionBoxArray) {
	        if (bucket.hasTextData())
	            bucket.text.opacityVertexArray.clear();
	        if (bucket.hasIconData())
	            bucket.icon.opacityVertexArray.clear();
	        if (bucket.hasIconCollisionBoxData())
	            bucket.iconCollisionBox.collisionVertexArray.clear();
	        if (bucket.hasTextCollisionBoxData())
	            bucket.textCollisionBox.collisionVertexArray.clear();
	        const layout = bucket.layers[0].layout;
	        const hasClipping = !!bucket.layers[0].dynamicFilter();
	        const duplicateOpacityState = new JointOpacityState(null, 0, false, false, true);
	        const textAllowOverlap = layout.get('text-allow-overlap');
	        const iconAllowOverlap = layout.get('icon-allow-overlap');
	        const variablePlacement = layout.get('text-variable-anchor');
	        const rotateWithMap = layout.get('text-rotation-alignment') === 'map';
	        const pitchWithMap = layout.get('text-pitch-alignment') === 'map';
	        const hasIconTextFit = layout.get('icon-text-fit') !== 'none';
	        const defaultOpacityState = new JointOpacityState(null, 0, textAllowOverlap && (iconAllowOverlap || !bucket.hasIconData() || layout.get('icon-optional')), iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || layout.get('text-optional')), true);
	        if (!bucket.collisionArrays && collisionBoxArray && (bucket.hasIconCollisionBoxData() || bucket.hasTextCollisionBoxData())) {
	            bucket.deserializeCollisionBoxes(collisionBoxArray);
	        }
	        const addOpacities = (iconOrText, numVertices, opacity) => {
	            for (let i = 0; i < numVertices / 4; i++) {
	                iconOrText.opacityVertexArray.emplaceBack(opacity);
	            }
	        };
	        let visibleInstanceCount = 0;
	        for (let s = 0; s < bucket.symbolInstances.length; s++) {
	            const symbolInstance = bucket.symbolInstances.get(s);
	            const {numHorizontalGlyphVertices, numVerticalGlyphVertices, crossTileID} = symbolInstance;
	            const isDuplicate = seenCrossTileIDs[crossTileID];
	            let opacityState = this.opacities[crossTileID];
	            if (isDuplicate) {
	                opacityState = duplicateOpacityState;
	            } else if (!opacityState) {
	                opacityState = defaultOpacityState;
	                this.opacities[crossTileID] = opacityState;
	            }
	            seenCrossTileIDs[crossTileID] = true;
	            const hasText = numHorizontalGlyphVertices > 0 || numVerticalGlyphVertices > 0;
	            const hasIcon = symbolInstance.numIconVertices > 0;
	            const placedOrientation = this.placedOrientations[symbolInstance.crossTileID];
	            const horizontalHidden = placedOrientation === ref_properties.WritingMode.vertical;
	            const verticalHidden = placedOrientation === ref_properties.WritingMode.horizontal || placedOrientation === ref_properties.WritingMode.horizontalOnly;
	            if ((hasText || hasIcon) && !opacityState.isHidden())
	                visibleInstanceCount++;
	            if (hasText) {
	                const packedOpacity = packOpacity(opacityState.text);
	                const horizontalOpacity = horizontalHidden ? PACKED_HIDDEN_OPACITY : packedOpacity;
	                addOpacities(bucket.text, numHorizontalGlyphVertices, horizontalOpacity);
	                const verticalOpacity = verticalHidden ? PACKED_HIDDEN_OPACITY : packedOpacity;
	                addOpacities(bucket.text, numVerticalGlyphVertices, verticalOpacity);
	                const symbolHidden = opacityState.text.isHidden();
	                [
	                    symbolInstance.rightJustifiedTextSymbolIndex,
	                    symbolInstance.centerJustifiedTextSymbolIndex,
	                    symbolInstance.leftJustifiedTextSymbolIndex
	                ].forEach(index => {
	                    if (index >= 0) {
	                        bucket.text.placedSymbolArray.get(index).hidden = symbolHidden || horizontalHidden ? 1 : 0;
	                    }
	                });
	                if (symbolInstance.verticalPlacedTextSymbolIndex >= 0) {
	                    bucket.text.placedSymbolArray.get(symbolInstance.verticalPlacedTextSymbolIndex).hidden = symbolHidden || verticalHidden ? 1 : 0;
	                }
	                const prevOffset = this.variableOffsets[symbolInstance.crossTileID];
	                if (prevOffset) {
	                    this.markUsedJustification(bucket, prevOffset.anchor, symbolInstance, placedOrientation);
	                }
	                const prevOrientation = this.placedOrientations[symbolInstance.crossTileID];
	                if (prevOrientation) {
	                    this.markUsedJustification(bucket, 'left', symbolInstance, prevOrientation);
	                    this.markUsedOrientation(bucket, prevOrientation, symbolInstance);
	                }
	            }
	            if (hasIcon) {
	                const packedOpacity = packOpacity(opacityState.icon);
	                if (symbolInstance.placedIconSymbolIndex >= 0) {
	                    const horizontalOpacity = !horizontalHidden ? packedOpacity : PACKED_HIDDEN_OPACITY;
	                    addOpacities(bucket.icon, symbolInstance.numIconVertices, horizontalOpacity);
	                    bucket.icon.placedSymbolArray.get(symbolInstance.placedIconSymbolIndex).hidden = opacityState.icon.isHidden();
	                }
	                if (symbolInstance.verticalPlacedIconSymbolIndex >= 0) {
	                    const verticalOpacity = !verticalHidden ? packedOpacity : PACKED_HIDDEN_OPACITY;
	                    addOpacities(bucket.icon, symbolInstance.numVerticalIconVertices, verticalOpacity);
	                    bucket.icon.placedSymbolArray.get(symbolInstance.verticalPlacedIconSymbolIndex).hidden = opacityState.icon.isHidden();
	                }
	            }
	            if (bucket.hasIconCollisionBoxData() || bucket.hasTextCollisionBoxData()) {
	                const collisionArrays = bucket.collisionArrays[s];
	                if (collisionArrays) {
	                    let shift = new ref_properties.pointGeometry(0, 0);
	                    let used = true;
	                    if (collisionArrays.textBox || collisionArrays.verticalTextBox) {
	                        if (variablePlacement) {
	                            const variableOffset = this.variableOffsets[crossTileID];
	                            if (variableOffset) {
	                                shift = calculateVariableLayoutShift(variableOffset.anchor, variableOffset.width, variableOffset.height, variableOffset.textOffset, variableOffset.textScale);
	                                if (rotateWithMap) {
	                                    shift._rotate(pitchWithMap ? this.transform.angle : -this.transform.angle);
	                                }
	                            } else {
	                                used = false;
	                            }
	                        }
	                        if (hasClipping) {
	                            used = !opacityState.clipped;
	                        }
	                        if (collisionArrays.textBox) {
	                            updateCollisionVertices(bucket.textCollisionBox.collisionVertexArray, opacityState.text.placed, !used || horizontalHidden, shift.x, shift.y);
	                        }
	                        if (collisionArrays.verticalTextBox) {
	                            updateCollisionVertices(bucket.textCollisionBox.collisionVertexArray, opacityState.text.placed, !used || verticalHidden, shift.x, shift.y);
	                        }
	                    }
	                    const verticalIconUsed = used && Boolean(!verticalHidden && collisionArrays.verticalIconBox);
	                    if (collisionArrays.iconBox) {
	                        updateCollisionVertices(bucket.iconCollisionBox.collisionVertexArray, opacityState.icon.placed, verticalIconUsed, hasIconTextFit ? shift.x : 0, hasIconTextFit ? shift.y : 0);
	                    }
	                    if (collisionArrays.verticalIconBox) {
	                        updateCollisionVertices(bucket.iconCollisionBox.collisionVertexArray, opacityState.icon.placed, !verticalIconUsed, hasIconTextFit ? shift.x : 0, hasIconTextFit ? shift.y : 0);
	                    }
	                }
	            }
	        }
	        bucket.fullyClipped = visibleInstanceCount === 0;
	        bucket.sortFeatures(this.transform.angle);
	        if (this.retainedQueryData[bucket.bucketInstanceId]) {
	            this.retainedQueryData[bucket.bucketInstanceId].featureSortOrder = bucket.featureSortOrder;
	        }
	        if (bucket.hasTextData() && bucket.text.opacityVertexBuffer) {
	            bucket.text.opacityVertexBuffer.updateData(bucket.text.opacityVertexArray);
	        }
	        if (bucket.hasIconData() && bucket.icon.opacityVertexBuffer) {
	            bucket.icon.opacityVertexBuffer.updateData(bucket.icon.opacityVertexArray);
	        }
	        if (bucket.hasIconCollisionBoxData() && bucket.iconCollisionBox.collisionVertexBuffer) {
	            bucket.iconCollisionBox.collisionVertexBuffer.updateData(bucket.iconCollisionBox.collisionVertexArray);
	        }
	        if (bucket.hasTextCollisionBoxData() && bucket.textCollisionBox.collisionVertexBuffer) {
	            bucket.textCollisionBox.collisionVertexBuffer.updateData(bucket.textCollisionBox.collisionVertexArray);
	        }
	        if (bucket.bucketInstanceId in this.collisionCircleArrays) {
	            const instance = this.collisionCircleArrays[bucket.bucketInstanceId];
	            bucket.placementInvProjMatrix = instance.invProjMatrix;
	            bucket.placementViewportMatrix = instance.viewportMatrix;
	            bucket.collisionCircleArray = instance.circles;
	            delete this.collisionCircleArrays[bucket.bucketInstanceId];
	        }
	    }
	    symbolFadeChange(now) {
	        return this.fadeDuration === 0 ? 1 : (now - this.commitTime) / this.fadeDuration + this.prevZoomAdjustment;
	    }
	    zoomAdjustment(zoom) {
	        return Math.max(0, (this.transform.zoom - zoom) / 1.5);
	    }
	    hasTransitions(now) {
	        return this.stale || now - this.lastPlacementChangeTime < this.fadeDuration;
	    }
	    stillRecent(now, zoom) {
	        const durationAdjustment = this.zoomAtLastRecencyCheck === zoom ? 1 - this.zoomAdjustment(zoom) : 1;
	        this.zoomAtLastRecencyCheck = zoom;
	        return this.commitTime + this.fadeDuration * durationAdjustment > now;
	    }
	    setStale() {
	        this.stale = true;
	    }
	}
	function updateCollisionVertices(collisionVertexArray, placed, notUsed, shiftX, shiftY) {
	    collisionVertexArray.emplaceBack(placed ? 1 : 0, notUsed ? 1 : 0, shiftX || 0, shiftY || 0);
	    collisionVertexArray.emplaceBack(placed ? 1 : 0, notUsed ? 1 : 0, shiftX || 0, shiftY || 0);
	    collisionVertexArray.emplaceBack(placed ? 1 : 0, notUsed ? 1 : 0, shiftX || 0, shiftY || 0);
	    collisionVertexArray.emplaceBack(placed ? 1 : 0, notUsed ? 1 : 0, shiftX || 0, shiftY || 0);
	}
	const shift25 = Math.pow(2, 25);
	const shift24 = Math.pow(2, 24);
	const shift17 = Math.pow(2, 17);
	const shift16 = Math.pow(2, 16);
	const shift9 = Math.pow(2, 9);
	const shift8 = Math.pow(2, 8);
	const shift1 = Math.pow(2, 1);
	function packOpacity(opacityState) {
	    if (opacityState.opacity === 0 && !opacityState.placed) {
	        return 0;
	    } else if (opacityState.opacity === 1 && opacityState.placed) {
	        return 4294967295;
	    }
	    const targetBit = opacityState.placed ? 1 : 0;
	    const opacityBits = Math.floor(opacityState.opacity * 127);
	    return opacityBits * shift25 + targetBit * shift24 + opacityBits * shift17 + targetBit * shift16 + opacityBits * shift9 + targetBit * shift8 + opacityBits * shift1 + targetBit;
	}
	const PACKED_HIDDEN_OPACITY = 0;

	class LayerPlacement {
	    constructor(styleLayer) {
	        this._sortAcrossTiles = styleLayer.layout.get('symbol-z-order') !== 'viewport-y' && styleLayer.layout.get('symbol-sort-key').constantOr(1) !== undefined;
	        this._currentTileIndex = 0;
	        this._currentPartIndex = 0;
	        this._seenCrossTileIDs = {};
	        this._bucketParts = [];
	    }
	    continuePlacement(tiles, placement, showCollisionBoxes, styleLayer, shouldPausePlacement) {
	        const bucketParts = this._bucketParts;
	        while (this._currentTileIndex < tiles.length) {
	            const tile = tiles[this._currentTileIndex];
	            placement.getBucketParts(bucketParts, styleLayer, tile, this._sortAcrossTiles);
	            this._currentTileIndex++;
	            if (shouldPausePlacement()) {
	                return true;
	            }
	        }
	        if (this._sortAcrossTiles) {
	            this._sortAcrossTiles = false;
	            bucketParts.sort((a, b) => a.sortKey - b.sortKey);
	        }
	        while (this._currentPartIndex < bucketParts.length) {
	            const bucketPart = bucketParts[this._currentPartIndex];
	            placement.placeLayerBucketPart(bucketPart, this._seenCrossTileIDs, showCollisionBoxes, bucketPart.symbolInstanceStart === 0);
	            this._currentPartIndex++;
	            if (shouldPausePlacement()) {
	                return true;
	            }
	        }
	        return false;
	    }
	}
	class PauseablePlacement {
	    constructor(transform, order, forceFullPlacement, showCollisionBoxes, fadeDuration, crossSourceCollisions, prevPlacement, fogState) {
	        this.placement = new Placement(transform, fadeDuration, crossSourceCollisions, prevPlacement, fogState);
	        this._currentPlacementIndex = order.length - 1;
	        this._forceFullPlacement = forceFullPlacement;
	        this._showCollisionBoxes = showCollisionBoxes;
	        this._done = false;
	    }
	    isDone() {
	        return this._done;
	    }
	    continuePlacement(order, layers, layerTiles) {
	        const startTime = ref_properties.exported.now();
	        const shouldPausePlacement = () => {
	            const elapsedTime = ref_properties.exported.now() - startTime;
	            return this._forceFullPlacement ? false : elapsedTime > 2;
	        };
	        while (this._currentPlacementIndex >= 0) {
	            const layerId = order[this._currentPlacementIndex];
	            const layer = layers[layerId];
	            const placementZoom = this.placement.collisionIndex.transform.zoom;
	            if (layer.type === 'symbol' && (!layer.minzoom || layer.minzoom <= placementZoom) && (!layer.maxzoom || layer.maxzoom > placementZoom)) {
	                if (!this._inProgressLayer) {
	                    this._inProgressLayer = new LayerPlacement(layer);
	                }
	                const pausePlacement = this._inProgressLayer.continuePlacement(layerTiles[layer.source], this.placement, this._showCollisionBoxes, layer, shouldPausePlacement);
	                if (pausePlacement) {
	                    return;
	                }
	                delete this._inProgressLayer;
	            }
	            this._currentPlacementIndex--;
	        }
	        this._done = true;
	    }
	    commit(now) {
	        this.placement.commit(now);
	        return this.placement;
	    }
	}

	const roundingFactor = 512 / ref_properties.EXTENT / 2;
	class TileLayerIndex {
	    constructor(tileID, symbolInstances, bucketInstanceId) {
	        this.tileID = tileID;
	        this.indexedSymbolInstances = {};
	        this.bucketInstanceId = bucketInstanceId;
	        for (let i = 0; i < symbolInstances.length; i++) {
	            const symbolInstance = symbolInstances.get(i);
	            const key = symbolInstance.key;
	            if (!this.indexedSymbolInstances[key]) {
	                this.indexedSymbolInstances[key] = [];
	            }
	            this.indexedSymbolInstances[key].push({
	                crossTileID: symbolInstance.crossTileID,
	                coord: this.getScaledCoordinates(symbolInstance, tileID)
	            });
	        }
	    }
	    getScaledCoordinates(symbolInstance, childTileID) {
	        const zDifference = childTileID.canonical.z - this.tileID.canonical.z;
	        const scale = roundingFactor / Math.pow(2, zDifference);
	        return {
	            x: Math.floor((childTileID.canonical.x * ref_properties.EXTENT + symbolInstance.tileAnchorX) * scale),
	            y: Math.floor((childTileID.canonical.y * ref_properties.EXTENT + symbolInstance.tileAnchorY) * scale)
	        };
	    }
	    findMatches(symbolInstances, newTileID, zoomCrossTileIDs) {
	        const tolerance = this.tileID.canonical.z < newTileID.canonical.z ? 1 : Math.pow(2, this.tileID.canonical.z - newTileID.canonical.z);
	        for (let i = 0; i < symbolInstances.length; i++) {
	            const symbolInstance = symbolInstances.get(i);
	            if (symbolInstance.crossTileID) {
	                continue;
	            }
	            const indexedInstances = this.indexedSymbolInstances[symbolInstance.key];
	            if (!indexedInstances) {
	                continue;
	            }
	            const scaledSymbolCoord = this.getScaledCoordinates(symbolInstance, newTileID);
	            for (const thisTileSymbol of indexedInstances) {
	                if (Math.abs(thisTileSymbol.coord.x - scaledSymbolCoord.x) <= tolerance && Math.abs(thisTileSymbol.coord.y - scaledSymbolCoord.y) <= tolerance && !zoomCrossTileIDs[thisTileSymbol.crossTileID]) {
	                    zoomCrossTileIDs[thisTileSymbol.crossTileID] = true;
	                    symbolInstance.crossTileID = thisTileSymbol.crossTileID;
	                    break;
	                }
	            }
	        }
	    }
	}
	class CrossTileIDs {
	    constructor() {
	        this.maxCrossTileID = 0;
	    }
	    generate() {
	        return ++this.maxCrossTileID;
	    }
	}
	class CrossTileSymbolLayerIndex {
	    constructor() {
	        this.indexes = {};
	        this.usedCrossTileIDs = {};
	        this.lng = 0;
	    }
	    handleWrapJump(lng) {
	        const wrapDelta = Math.round((lng - this.lng) / 360);
	        if (wrapDelta !== 0) {
	            for (const zoom in this.indexes) {
	                const zoomIndexes = this.indexes[zoom];
	                const newZoomIndex = {};
	                for (const key in zoomIndexes) {
	                    const index = zoomIndexes[key];
	                    index.tileID = index.tileID.unwrapTo(index.tileID.wrap + wrapDelta);
	                    newZoomIndex[index.tileID.key] = index;
	                }
	                this.indexes[zoom] = newZoomIndex;
	            }
	        }
	        this.lng = lng;
	    }
	    addBucket(tileID, bucket, crossTileIDs) {
	        if (this.indexes[tileID.overscaledZ] && this.indexes[tileID.overscaledZ][tileID.key]) {
	            if (this.indexes[tileID.overscaledZ][tileID.key].bucketInstanceId === bucket.bucketInstanceId) {
	                return false;
	            } else {
	                this.removeBucketCrossTileIDs(tileID.overscaledZ, this.indexes[tileID.overscaledZ][tileID.key]);
	            }
	        }
	        for (let i = 0; i < bucket.symbolInstances.length; i++) {
	            const symbolInstance = bucket.symbolInstances.get(i);
	            symbolInstance.crossTileID = 0;
	        }
	        if (!this.usedCrossTileIDs[tileID.overscaledZ]) {
	            this.usedCrossTileIDs[tileID.overscaledZ] = {};
	        }
	        const zoomCrossTileIDs = this.usedCrossTileIDs[tileID.overscaledZ];
	        for (const zoom in this.indexes) {
	            const zoomIndexes = this.indexes[zoom];
	            if (Number(zoom) > tileID.overscaledZ) {
	                for (const id in zoomIndexes) {
	                    const childIndex = zoomIndexes[id];
	                    if (childIndex.tileID.isChildOf(tileID)) {
	                        childIndex.findMatches(bucket.symbolInstances, tileID, zoomCrossTileIDs);
	                    }
	                }
	            } else {
	                const parentCoord = tileID.scaledTo(Number(zoom));
	                const parentIndex = zoomIndexes[parentCoord.key];
	                if (parentIndex) {
	                    parentIndex.findMatches(bucket.symbolInstances, tileID, zoomCrossTileIDs);
	                }
	            }
	        }
	        for (let i = 0; i < bucket.symbolInstances.length; i++) {
	            const symbolInstance = bucket.symbolInstances.get(i);
	            if (!symbolInstance.crossTileID) {
	                symbolInstance.crossTileID = crossTileIDs.generate();
	                zoomCrossTileIDs[symbolInstance.crossTileID] = true;
	            }
	        }
	        if (this.indexes[tileID.overscaledZ] === undefined) {
	            this.indexes[tileID.overscaledZ] = {};
	        }
	        this.indexes[tileID.overscaledZ][tileID.key] = new TileLayerIndex(tileID, bucket.symbolInstances, bucket.bucketInstanceId);
	        return true;
	    }
	    removeBucketCrossTileIDs(zoom, removedBucket) {
	        for (const key in removedBucket.indexedSymbolInstances) {
	            for (const symbolInstance of removedBucket.indexedSymbolInstances[key]) {
	                delete this.usedCrossTileIDs[zoom][symbolInstance.crossTileID];
	            }
	        }
	    }
	    removeStaleBuckets(currentIDs) {
	        let tilesChanged = false;
	        for (const z in this.indexes) {
	            const zoomIndexes = this.indexes[z];
	            for (const tileKey in zoomIndexes) {
	                if (!currentIDs[zoomIndexes[tileKey].bucketInstanceId]) {
	                    this.removeBucketCrossTileIDs(z, zoomIndexes[tileKey]);
	                    delete zoomIndexes[tileKey];
	                    tilesChanged = true;
	                }
	            }
	        }
	        return tilesChanged;
	    }
	}
	class CrossTileSymbolIndex {
	    constructor() {
	        this.layerIndexes = {};
	        this.crossTileIDs = new CrossTileIDs();
	        this.maxBucketInstanceId = 0;
	        this.bucketsInCurrentPlacement = {};
	    }
	    addLayer(styleLayer, tiles, lng, projection) {
	        let layerIndex = this.layerIndexes[styleLayer.id];
	        if (layerIndex === undefined) {
	            layerIndex = this.layerIndexes[styleLayer.id] = new CrossTileSymbolLayerIndex();
	        }
	        let symbolBucketsChanged = false;
	        const currentBucketIDs = {};
	        if (projection.name !== 'globe') {
	            layerIndex.handleWrapJump(lng);
	        }
	        for (const tile of tiles) {
	            const symbolBucket = tile.getBucket(styleLayer);
	            if (!symbolBucket || styleLayer.id !== symbolBucket.layerIds[0])
	                continue;
	            if (!symbolBucket.bucketInstanceId) {
	                symbolBucket.bucketInstanceId = ++this.maxBucketInstanceId;
	            }
	            if (layerIndex.addBucket(tile.tileID, symbolBucket, this.crossTileIDs)) {
	                symbolBucketsChanged = true;
	            }
	            currentBucketIDs[symbolBucket.bucketInstanceId] = true;
	        }
	        if (layerIndex.removeStaleBuckets(currentBucketIDs)) {
	            symbolBucketsChanged = true;
	        }
	        return symbolBucketsChanged;
	    }
	    pruneUnusedLayers(usedLayers) {
	        const usedLayerMap = {};
	        usedLayers.forEach(usedLayer => {
	            usedLayerMap[usedLayer] = true;
	        });
	        for (const layerId in this.layerIndexes) {
	            if (!usedLayerMap[layerId]) {
	                delete this.layerIndexes[layerId];
	            }
	        }
	    }
	}

	const emitValidationErrors = (evented, errors) => ref_properties.emitValidationErrors(evented, errors && errors.filter(error => error.identifier !== 'source.canvas'));
	const supportedDiffOperations = ref_properties.pick(operations, [
	    'addLayer',
	    'removeLayer',
	    'setPaintProperty',
	    'setLayoutProperty',
	    'setFilter',
	    'addSource',
	    'removeSource',
	    'setLayerZoomRange',
	    'setLight',
	    'setTransition',
	    'setGeoJSONSourceData',
	    'setTerrain',
	    'setFog',
	    'setProjection'
	]);
	const ignoredDiffOperations = ref_properties.pick(operations, [
	    'setCenter',
	    'setZoom',
	    'setBearing',
	    'setPitch'
	]);
	const empty = emptyStyle();
	const drapedLayers = {
	    'fill': true,
	    'line': true,
	    'background': true,
	    'hillshade': true,
	    'raster': true
	};
	class Style extends ref_properties.Evented {
	    constructor(map, options = {}) {
	        super();
	        this.map = map;
	        this.dispatcher = new Dispatcher(getGlobalWorkerPool(), this);
	        this.imageManager = new ImageManager();
	        this.imageManager.setEventedParent(this);
	        this.glyphManager = new ref_properties.GlyphManager(map._requestManager, options.localFontFamily ? ref_properties.LocalGlyphMode.all : options.localIdeographFontFamily ? ref_properties.LocalGlyphMode.ideographs : ref_properties.LocalGlyphMode.none, options.localFontFamily || options.localIdeographFontFamily);
	        this.lineAtlas = new ref_properties.LineAtlas(256, 512);
	        this.crossTileSymbolIndex = new CrossTileSymbolIndex();
	        this._layers = {};
	        this._num3DLayers = 0;
	        this._numSymbolLayers = 0;
	        this._numCircleLayers = 0;
	        this._serializedLayers = {};
	        this._sourceCaches = {};
	        this._otherSourceCaches = {};
	        this._symbolSourceCaches = {};
	        this.zoomHistory = new ref_properties.ZoomHistory();
	        this._loaded = false;
	        this._availableImages = [];
	        this._order = [];
	        this._drapedFirstOrder = [];
	        this._markersNeedUpdate = false;
	        this._resetUpdates();
	        this.dispatcher.broadcast('setReferrer', ref_properties.getReferrer());
	        const self = this;
	        this._rtlTextPluginCallback = Style.registerForPluginStateChange(event => {
	            const state = {
	                pluginStatus: event.pluginStatus,
	                pluginURL: event.pluginURL
	            };
	            self.dispatcher.broadcast('syncRTLPluginState', state, (err, results) => {
	                ref_properties.triggerPluginCompletionEvent(err);
	                if (results) {
	                    const allComplete = results.every(elem => elem);
	                    if (allComplete) {
	                        for (const id in self._sourceCaches) {
	                            const sourceCache = self._sourceCaches[id];
	                            const sourceCacheType = sourceCache.getSource().type;
	                            if (sourceCacheType === 'vector' || sourceCacheType === 'geojson') {
	                                sourceCache.reload();
	                            }
	                        }
	                    }
	                }
	            });
	        });
	        this.on('data', event => {
	            if (event.dataType !== 'source' || event.sourceDataType !== 'metadata') {
	                return;
	            }
	            const source = this.getSource(event.sourceId);
	            if (!source || !source.vectorLayerIds) {
	                return;
	            }
	            for (const layerId in this._layers) {
	                const layer = this._layers[layerId];
	                if (layer.source === source.id) {
	                    this._validateLayer(layer);
	                }
	            }
	        });
	    }
	    loadURL(url, options = {}) {
	        this.fire(new ref_properties.Event('dataloading', { dataType: 'style' }));
	        const validate = typeof options.validate === 'boolean' ? options.validate : !ref_properties.isMapboxURL(url);
	        url = this.map._requestManager.normalizeStyleURL(url, options.accessToken);
	        const request = this.map._requestManager.transformRequest(url, ref_properties.ResourceType.Style);
	        this._request = ref_properties.getJSON(request, (error, json) => {
	            this._request = null;
	            if (error) {
	                this.fire(new ref_properties.ErrorEvent(error));
	            } else if (json) {
	                this._load(json, validate);
	            }
	        });
	    }
	    loadJSON(json, options = {}) {
	        this.fire(new ref_properties.Event('dataloading', { dataType: 'style' }));
	        this._request = ref_properties.exported.frame(() => {
	            this._request = null;
	            this._load(json, options.validate !== false);
	        });
	    }
	    loadEmpty() {
	        this.fire(new ref_properties.Event('dataloading', { dataType: 'style' }));
	        this._load(empty, false);
	    }
	    _updateLayerCount(layer, add) {
	        const count = add ? 1 : -1;
	        if (layer.is3D()) {
	            this._num3DLayers += count;
	        }
	        if (layer.type === 'circle') {
	            this._numCircleLayers += count;
	        }
	        if (layer.type === 'symbol') {
	            this._numSymbolLayers += count;
	        }
	    }
	    _load(json, validate) {
	        if (validate && emitValidationErrors(this, ref_properties.validateStyle(json))) {
	            return;
	        }
	        this._loaded = true;
	        this.stylesheet = ref_properties.clone$1(json);
	        this._updateMapProjection();
	        for (const id in json.sources) {
	            this.addSource(id, json.sources[id], { validate: false });
	        }
	        this._changed = false;
	        if (json.sprite) {
	            this._loadSprite(json.sprite);
	        } else {
	            this.imageManager.setLoaded(true);
	            this.dispatcher.broadcast('spriteLoaded', true);
	        }
	        this.glyphManager.setURL(json.glyphs);
	        const layers = derefLayers(this.stylesheet.layers);
	        this._order = layers.map(layer => layer.id);
	        this._layers = {};
	        this._serializedLayers = {};
	        for (let layer of layers) {
	            layer = ref_properties.createStyleLayer(layer);
	            layer.setEventedParent(this, { layer: { id: layer.id } });
	            this._layers[layer.id] = layer;
	            this._serializedLayers[layer.id] = layer.serialize();
	            this._updateLayerCount(layer, true);
	        }
	        this.dispatcher.broadcast('setLayers', this._serializeLayers(this._order));
	        this.light = new Light(this.stylesheet.light);
	        if (this.stylesheet.terrain && !this.terrainSetForDrapingOnly()) {
	            this._createTerrain(this.stylesheet.terrain, DrapeRenderMode.elevated);
	        }
	        if (this.stylesheet.fog) {
	            this._createFog(this.stylesheet.fog);
	        }
	        this._updateDrapeFirstLayers();
	        this.fire(new ref_properties.Event('data', { dataType: 'style' }));
	        this.fire(new ref_properties.Event('style.load'));
	    }
	    terrainSetForDrapingOnly() {
	        return !!this.terrain && this.terrain.drapeRenderMode === DrapeRenderMode.deferred;
	    }
	    setProjection(projection) {
	        if (projection) {
	            this.stylesheet.projection = projection;
	        } else {
	            delete this.stylesheet.projection;
	        }
	        if (!this.map._explicitProjection) {
	            this.map._updateProjection();
	        }
	    }
	    _updateMapProjection() {
	        if (!this.map._explicitProjection) {
	            this.map._updateProjection();
	        } else {
	            this.applyProjectionUpdate();
	        }
	    }
	    applyProjectionUpdate() {
	        if (!this._loaded)
	            return;
	        this.dispatcher.broadcast('setProjection', this.map.transform.projectionOptions);
	        if (this.map.transform.projection.requiresDraping) {
	            const hasTerrain = this.getTerrain() || this.stylesheet.terrain;
	            if (!hasTerrain) {
	                this.setTerrainForDraping();
	            }
	        } else if (this.terrainSetForDrapingOnly()) {
	            this.setTerrain(null);
	        }
	    }
	    _loadSprite(url) {
	        this._spriteRequest = loadSprite(url, this.map._requestManager, (err, images) => {
	            this._spriteRequest = null;
	            if (err) {
	                this.fire(new ref_properties.ErrorEvent(err));
	            } else if (images) {
	                for (const id in images) {
	                    this.imageManager.addImage(id, images[id]);
	                }
	            }
	            this.imageManager.setLoaded(true);
	            this._availableImages = this.imageManager.listImages();
	            this.dispatcher.broadcast('setImages', this._availableImages);
	            this.dispatcher.broadcast('spriteLoaded', true);
	            this.fire(new ref_properties.Event('data', { dataType: 'style' }));
	        });
	    }
	    _validateLayer(layer) {
	        const source = this.getSource(layer.source);
	        if (!source) {
	            return;
	        }
	        const sourceLayer = layer.sourceLayer;
	        if (!sourceLayer) {
	            return;
	        }
	        if (source.type === 'geojson' || source.vectorLayerIds && source.vectorLayerIds.indexOf(sourceLayer) === -1) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`Source layer "${ sourceLayer }" ` + `does not exist on source "${ source.id }" ` + `as specified by style layer "${ layer.id }"`)));
	        }
	    }
	    loaded() {
	        if (!this._loaded)
	            return false;
	        if (Object.keys(this._updatedSources).length)
	            return false;
	        for (const id in this._sourceCaches)
	            if (!this._sourceCaches[id].loaded())
	                return false;
	        if (!this.imageManager.isLoaded())
	            return false;
	        return true;
	    }
	    _serializeLayers(ids) {
	        const serializedLayers = [];
	        for (const id of ids) {
	            const layer = this._layers[id];
	            if (layer.type !== 'custom') {
	                serializedLayers.push(layer.serialize());
	            }
	        }
	        return serializedLayers;
	    }
	    hasTransitions() {
	        if (this.light && this.light.hasTransition()) {
	            return true;
	        }
	        if (this.fog && this.fog.hasTransition()) {
	            return true;
	        }
	        for (const id in this._sourceCaches) {
	            if (this._sourceCaches[id].hasTransition()) {
	                return true;
	            }
	        }
	        for (const id in this._layers) {
	            if (this._layers[id].hasTransition()) {
	                return true;
	            }
	        }
	        return false;
	    }
	    get order() {
	        if (this.map._optimizeForTerrain && this.terrain) {
	            return this._drapedFirstOrder;
	        }
	        return this._order;
	    }
	    isLayerDraped(layer) {
	        if (!this.terrain)
	            return false;
	        return drapedLayers[layer.type];
	    }
	    _checkLoaded() {
	        if (!this._loaded) {
	            throw new Error('Style is not done loading');
	        }
	    }
	    update(parameters) {
	        if (!this._loaded) {
	            return;
	        }
	        const changed = this._changed;
	        if (this._changed) {
	            const updatedIds = Object.keys(this._updatedLayers);
	            const removedIds = Object.keys(this._removedLayers);
	            if (updatedIds.length || removedIds.length) {
	                this._updateWorkerLayers(updatedIds, removedIds);
	            }
	            for (const id in this._updatedSources) {
	                const action = this._updatedSources[id];
	                if (action === 'reload') {
	                    this._reloadSource(id);
	                } else if (action === 'clear') {
	                    this._clearSource(id);
	                }
	            }
	            this._updateTilesForChangedImages();
	            for (const id in this._updatedPaintProps) {
	                this._layers[id].updateTransitions(parameters);
	            }
	            this.light.updateTransitions(parameters);
	            if (this.fog) {
	                this.fog.updateTransitions(parameters);
	            }
	            this._resetUpdates();
	        }
	        const sourcesUsedBefore = {};
	        for (const sourceId in this._sourceCaches) {
	            const sourceCache = this._sourceCaches[sourceId];
	            sourcesUsedBefore[sourceId] = sourceCache.used;
	            sourceCache.used = false;
	        }
	        for (const layerId of this._order) {
	            const layer = this._layers[layerId];
	            layer.recalculate(parameters, this._availableImages);
	            if (!layer.isHidden(parameters.zoom)) {
	                const sourceCache = this._getLayerSourceCache(layer);
	                if (sourceCache)
	                    sourceCache.used = true;
	            }
	            const painter = this.map.painter;
	            if (painter) {
	                const programIds = layer.getProgramIds();
	                if (!programIds)
	                    continue;
	                const programConfiguration = layer.getProgramConfiguration(parameters.zoom);
	                for (const programId of programIds) {
	                    painter.useProgram(programId, programConfiguration);
	                }
	            }
	        }
	        for (const sourceId in sourcesUsedBefore) {
	            const sourceCache = this._sourceCaches[sourceId];
	            if (sourcesUsedBefore[sourceId] !== sourceCache.used) {
	                sourceCache.getSource().fire(new ref_properties.Event('data', {
	                    sourceDataType: 'visibility',
	                    dataType: 'source',
	                    sourceId: sourceCache.getSource().id
	                }));
	            }
	        }
	        this.light.recalculate(parameters);
	        if (this.terrain) {
	            this.terrain.recalculate(parameters);
	        }
	        if (this.fog) {
	            this.fog.recalculate(parameters);
	        }
	        this.z = parameters.zoom;
	        if (this._markersNeedUpdate) {
	            this._updateMarkersOpacity();
	            this._markersNeedUpdate = false;
	        }
	        if (changed) {
	            this.fire(new ref_properties.Event('data', { dataType: 'style' }));
	        }
	    }
	    _updateTilesForChangedImages() {
	        const changedImages = Object.keys(this._changedImages);
	        if (changedImages.length) {
	            for (const name in this._sourceCaches) {
	                this._sourceCaches[name].reloadTilesForDependencies([
	                    'icons',
	                    'patterns'
	                ], changedImages);
	            }
	            this._changedImages = {};
	        }
	    }
	    _updateWorkerLayers(updatedIds, removedIds) {
	        this.dispatcher.broadcast('updateLayers', {
	            layers: this._serializeLayers(updatedIds),
	            removedIds
	        });
	    }
	    _resetUpdates() {
	        this._changed = false;
	        this._updatedLayers = {};
	        this._removedLayers = {};
	        this._updatedSources = {};
	        this._updatedPaintProps = {};
	        this._changedImages = {};
	    }
	    setState(nextState) {
	        this._checkLoaded();
	        if (emitValidationErrors(this, ref_properties.validateStyle(nextState)))
	            return false;
	        nextState = ref_properties.clone$1(nextState);
	        nextState.layers = derefLayers(nextState.layers);
	        const changes = diffStyles(this.serialize(), nextState).filter(op => !(op.command in ignoredDiffOperations));
	        if (changes.length === 0) {
	            return false;
	        }
	        const unimplementedOps = changes.filter(op => !(op.command in supportedDiffOperations));
	        if (unimplementedOps.length > 0) {
	            throw new Error(`Unimplemented: ${ unimplementedOps.map(op => op.command).join(', ') }.`);
	        }
	        changes.forEach(op => {
	            if (op.command === 'setTransition') {
	                return;
	            }
	            this[op.command].apply(this, op.args);
	        });
	        this.stylesheet = nextState;
	        this._updateMapProjection();
	        return true;
	    }
	    addImage(id, image) {
	        if (this.getImage(id)) {
	            return this.fire(new ref_properties.ErrorEvent(new Error('An image with this name already exists.')));
	        }
	        this.imageManager.addImage(id, image);
	        this._afterImageUpdated(id);
	        return this;
	    }
	    updateImage(id, image) {
	        this.imageManager.updateImage(id, image);
	    }
	    getImage(id) {
	        return this.imageManager.getImage(id);
	    }
	    removeImage(id) {
	        if (!this.getImage(id)) {
	            return this.fire(new ref_properties.ErrorEvent(new Error('No image with this name exists.')));
	        }
	        this.imageManager.removeImage(id);
	        this._afterImageUpdated(id);
	        return this;
	    }
	    _afterImageUpdated(id) {
	        this._availableImages = this.imageManager.listImages();
	        this._changedImages[id] = true;
	        this._changed = true;
	        this.dispatcher.broadcast('setImages', this._availableImages);
	        this.fire(new ref_properties.Event('data', { dataType: 'style' }));
	    }
	    listImages() {
	        this._checkLoaded();
	        return this._availableImages.slice();
	    }
	    addSource(id, source, options = {}) {
	        this._checkLoaded();
	        if (this.getSource(id) !== undefined) {
	            throw new Error('There is already a source with this ID');
	        }
	        if (!source.type) {
	            throw new Error(`The type property must be defined, but only the following properties were given: ${ Object.keys(source).join(', ') }.`);
	        }
	        const builtIns = [
	            'vector',
	            'raster',
	            'geojson',
	            'video',
	            'image'
	        ];
	        const shouldValidate = builtIns.indexOf(source.type) >= 0;
	        if (shouldValidate && this._validate(ref_properties.validateSource, `sources.${ id }`, source, null, options))
	            return;
	        if (this.map && this.map._collectResourceTiming)
	            source.collectResourceTiming = true;
	        const sourceInstance = create(id, source, this.dispatcher, this);
	        sourceInstance.setEventedParent(this, () => ({
	            isSourceLoaded: this._isSourceCacheLoaded(id),
	            source: sourceInstance.serialize(),
	            sourceId: id
	        }));
	        const addSourceCache = onlySymbols => {
	            const sourceCacheId = (onlySymbols ? 'symbol:' : 'other:') + id;
	            const sourceCache = this._sourceCaches[sourceCacheId] = new ref_properties.SourceCache(sourceCacheId, sourceInstance, onlySymbols);
	            (onlySymbols ? this._symbolSourceCaches : this._otherSourceCaches)[id] = sourceCache;
	            sourceCache.style = this;
	            sourceCache.onAdd(this.map);
	        };
	        addSourceCache(false);
	        if (source.type === 'vector' || source.type === 'geojson') {
	            addSourceCache(true);
	        }
	        if (sourceInstance.onAdd)
	            sourceInstance.onAdd(this.map);
	        this._changed = true;
	    }
	    removeSource(id) {
	        this._checkLoaded();
	        const source = this.getSource(id);
	        if (!source) {
	            throw new Error('There is no source with this ID');
	        }
	        for (const layerId in this._layers) {
	            if (this._layers[layerId].source === id) {
	                return this.fire(new ref_properties.ErrorEvent(new Error(`Source "${ id }" cannot be removed while layer "${ layerId }" is using it.`)));
	            }
	        }
	        if (this.terrain && this.terrain.get().source === id) {
	            return this.fire(new ref_properties.ErrorEvent(new Error(`Source "${ id }" cannot be removed while terrain is using it.`)));
	        }
	        const sourceCaches = this._getSourceCaches(id);
	        for (const sourceCache of sourceCaches) {
	            delete this._sourceCaches[sourceCache.id];
	            delete this._updatedSources[sourceCache.id];
	            sourceCache.fire(new ref_properties.Event('data', {
	                sourceDataType: 'metadata',
	                dataType: 'source',
	                sourceId: sourceCache.getSource().id
	            }));
	            sourceCache.setEventedParent(null);
	            sourceCache.clearTiles();
	        }
	        delete this._otherSourceCaches[id];
	        delete this._symbolSourceCaches[id];
	        source.setEventedParent(null);
	        if (source.onRemove) {
	            source.onRemove(this.map);
	        }
	        this._changed = true;
	        return this;
	    }
	    setGeoJSONSourceData(id, data) {
	        this._checkLoaded();
	        const geojsonSource = this.getSource(id);
	        geojsonSource.setData(data);
	        this._changed = true;
	    }
	    getSource(id) {
	        const sourceCache = this._getSourceCache(id);
	        return sourceCache && sourceCache.getSource();
	    }
	    addLayer(layerObject, before, options = {}) {
	        this._checkLoaded();
	        const id = layerObject.id;
	        if (this.getLayer(id)) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`Layer with id "${ id }" already exists on this map`)));
	            return;
	        }
	        let layer;
	        if (layerObject.type === 'custom') {
	            if (emitValidationErrors(this, ref_properties.validateCustomStyleLayer(layerObject)))
	                return;
	            layer = ref_properties.createStyleLayer(layerObject);
	        } else {
	            if (typeof layerObject.source === 'object') {
	                this.addSource(id, layerObject.source);
	                layerObject = ref_properties.clone$1(layerObject);
	                layerObject = ref_properties.extend(layerObject, { source: id });
	            }
	            if (this._validate(ref_properties.validateLayer, `layers.${ id }`, layerObject, { arrayIndex: -1 }, options))
	                return;
	            layer = ref_properties.createStyleLayer(layerObject);
	            this._validateLayer(layer);
	            layer.setEventedParent(this, { layer: { id } });
	            this._serializedLayers[layer.id] = layer.serialize();
	            this._updateLayerCount(layer, true);
	        }
	        const index = before ? this._order.indexOf(before) : this._order.length;
	        if (before && index === -1) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`Layer with id "${ before }" does not exist on this map.`)));
	            return;
	        }
	        this._order.splice(index, 0, id);
	        this._layerOrderChanged = true;
	        this._layers[id] = layer;
	        const sourceCache = this._getLayerSourceCache(layer);
	        if (this._removedLayers[id] && layer.source && sourceCache && layer.type !== 'custom') {
	            const removed = this._removedLayers[id];
	            delete this._removedLayers[id];
	            if (removed.type !== layer.type) {
	                this._updatedSources[layer.source] = 'clear';
	            } else {
	                this._updatedSources[layer.source] = 'reload';
	                sourceCache.pause();
	            }
	        }
	        this._updateLayer(layer);
	        if (layer.onAdd) {
	            layer.onAdd(this.map);
	        }
	        this._updateDrapeFirstLayers();
	    }
	    moveLayer(id, before) {
	        this._checkLoaded();
	        this._changed = true;
	        const layer = this._layers[id];
	        if (!layer) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The layer '${ id }' does not exist in the map's style and cannot be moved.`)));
	            return;
	        }
	        if (id === before) {
	            return;
	        }
	        const index = this._order.indexOf(id);
	        this._order.splice(index, 1);
	        const newIndex = before ? this._order.indexOf(before) : this._order.length;
	        if (before && newIndex === -1) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`Layer with id "${ before }" does not exist on this map.`)));
	            return;
	        }
	        this._order.splice(newIndex, 0, id);
	        this._layerOrderChanged = true;
	        this._updateDrapeFirstLayers();
	    }
	    removeLayer(id) {
	        this._checkLoaded();
	        const layer = this._layers[id];
	        if (!layer) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The layer '${ id }' does not exist in the map's style and cannot be removed.`)));
	            return;
	        }
	        layer.setEventedParent(null);
	        this._updateLayerCount(layer, false);
	        const index = this._order.indexOf(id);
	        this._order.splice(index, 1);
	        this._layerOrderChanged = true;
	        this._changed = true;
	        this._removedLayers[id] = layer;
	        delete this._layers[id];
	        delete this._serializedLayers[id];
	        delete this._updatedLayers[id];
	        delete this._updatedPaintProps[id];
	        if (layer.onRemove) {
	            layer.onRemove(this.map);
	        }
	        this._updateDrapeFirstLayers();
	    }
	    getLayer(id) {
	        return this._layers[id];
	    }
	    hasLayer(id) {
	        return id in this._layers;
	    }
	    hasLayerType(type) {
	        for (const layerId in this._layers) {
	            const layer = this._layers[layerId];
	            if (layer.type === type) {
	                return true;
	            }
	        }
	        return false;
	    }
	    setLayerZoomRange(layerId, minzoom, maxzoom) {
	        this._checkLoaded();
	        const layer = this.getLayer(layerId);
	        if (!layer) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The layer '${ layerId }' does not exist in the map's style and cannot have zoom extent.`)));
	            return;
	        }
	        if (layer.minzoom === minzoom && layer.maxzoom === maxzoom)
	            return;
	        if (minzoom != null) {
	            layer.minzoom = minzoom;
	        }
	        if (maxzoom != null) {
	            layer.maxzoom = maxzoom;
	        }
	        this._updateLayer(layer);
	    }
	    setFilter(layerId, filter, options = {}) {
	        this._checkLoaded();
	        const layer = this.getLayer(layerId);
	        if (!layer) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The layer '${ layerId }' does not exist in the map's style and cannot be filtered.`)));
	            return;
	        }
	        if (deepEqual(layer.filter, filter)) {
	            return;
	        }
	        if (filter === null || filter === undefined) {
	            layer.filter = undefined;
	            this._updateLayer(layer);
	            return;
	        }
	        if (this._validate(ref_properties.validateFilter, `layers.${ layer.id }.filter`, filter, { layerType: layer.type }, options)) {
	            return;
	        }
	        layer.filter = ref_properties.clone$1(filter);
	        this._updateLayer(layer);
	    }
	    getFilter(layerId) {
	        const layer = this.getLayer(layerId);
	        return layer && ref_properties.clone$1(layer.filter);
	    }
	    setLayoutProperty(layerId, name, value, options = {}) {
	        this._checkLoaded();
	        const layer = this.getLayer(layerId);
	        if (!layer) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The layer '${ layerId }' does not exist in the map's style and cannot be styled.`)));
	            return;
	        }
	        if (deepEqual(layer.getLayoutProperty(name), value))
	            return;
	        layer.setLayoutProperty(name, value, options);
	        this._updateLayer(layer);
	    }
	    getLayoutProperty(layerId, name) {
	        const layer = this.getLayer(layerId);
	        if (!layer) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The layer '${ layerId }' does not exist in the map's style.`)));
	            return;
	        }
	        return layer.getLayoutProperty(name);
	    }
	    setPaintProperty(layerId, name, value, options = {}) {
	        this._checkLoaded();
	        const layer = this.getLayer(layerId);
	        if (!layer) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The layer '${ layerId }' does not exist in the map's style and cannot be styled.`)));
	            return;
	        }
	        if (deepEqual(layer.getPaintProperty(name), value))
	            return;
	        const requiresRelayout = layer.setPaintProperty(name, value, options);
	        if (requiresRelayout) {
	            this._updateLayer(layer);
	        }
	        this._changed = true;
	        this._updatedPaintProps[layerId] = true;
	    }
	    getPaintProperty(layerId, name) {
	        const layer = this.getLayer(layerId);
	        return layer && layer.getPaintProperty(name);
	    }
	    setFeatureState(target, state) {
	        this._checkLoaded();
	        const sourceId = target.source;
	        const sourceLayer = target.sourceLayer;
	        const source = this.getSource(sourceId);
	        if (!source) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The source '${ sourceId }' does not exist in the map's style.`)));
	            return;
	        }
	        const sourceType = source.type;
	        if (sourceType === 'geojson' && sourceLayer) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`GeoJSON sources cannot have a sourceLayer parameter.`)));
	            return;
	        }
	        if (sourceType === 'vector' && !sourceLayer) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The sourceLayer parameter must be provided for vector source types.`)));
	            return;
	        }
	        if (target.id === undefined) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The feature id parameter must be provided.`)));
	        }
	        const sourceCaches = this._getSourceCaches(sourceId);
	        for (const sourceCache of sourceCaches) {
	            sourceCache.setFeatureState(sourceLayer, target.id, state);
	        }
	    }
	    removeFeatureState(target, key) {
	        this._checkLoaded();
	        const sourceId = target.source;
	        const source = this.getSource(sourceId);
	        if (!source) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The source '${ sourceId }' does not exist in the map's style.`)));
	            return;
	        }
	        const sourceType = source.type;
	        const sourceLayer = sourceType === 'vector' ? target.sourceLayer : undefined;
	        if (sourceType === 'vector' && !sourceLayer) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The sourceLayer parameter must be provided for vector source types.`)));
	            return;
	        }
	        if (key && (typeof target.id !== 'string' && typeof target.id !== 'number')) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`A feature id is required to remove its specific state property.`)));
	            return;
	        }
	        const sourceCaches = this._getSourceCaches(sourceId);
	        for (const sourceCache of sourceCaches) {
	            sourceCache.removeFeatureState(sourceLayer, target.id, key);
	        }
	    }
	    getFeatureState(target) {
	        this._checkLoaded();
	        const sourceId = target.source;
	        const sourceLayer = target.sourceLayer;
	        const source = this.getSource(sourceId);
	        if (!source) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The source '${ sourceId }' does not exist in the map's style.`)));
	            return;
	        }
	        const sourceType = source.type;
	        if (sourceType === 'vector' && !sourceLayer) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The sourceLayer parameter must be provided for vector source types.`)));
	            return;
	        }
	        if (target.id === undefined) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The feature id parameter must be provided.`)));
	        }
	        const sourceCaches = this._getSourceCaches(sourceId);
	        return sourceCaches[0].getFeatureState(sourceLayer, target.id);
	    }
	    getTransition() {
	        return ref_properties.extend({
	            duration: 300,
	            delay: 0
	        }, this.stylesheet && this.stylesheet.transition);
	    }
	    serialize() {
	        const sources = {};
	        for (const cacheId in this._sourceCaches) {
	            const source = this._sourceCaches[cacheId].getSource();
	            if (!sources[source.id]) {
	                sources[source.id] = source.serialize();
	            }
	        }
	        return ref_properties.filterObject({
	            version: this.stylesheet.version,
	            name: this.stylesheet.name,
	            metadata: this.stylesheet.metadata,
	            light: this.stylesheet.light,
	            terrain: this.stylesheet.terrain,
	            fog: this.stylesheet.fog,
	            center: this.stylesheet.center,
	            zoom: this.stylesheet.zoom,
	            bearing: this.stylesheet.bearing,
	            pitch: this.stylesheet.pitch,
	            sprite: this.stylesheet.sprite,
	            glyphs: this.stylesheet.glyphs,
	            transition: this.stylesheet.transition,
	            projection: this.stylesheet.projection,
	            sources,
	            layers: this._serializeLayers(this._order)
	        }, value => {
	            return value !== undefined;
	        });
	    }
	    _updateLayer(layer) {
	        this._updatedLayers[layer.id] = true;
	        const sourceCache = this._getLayerSourceCache(layer);
	        if (layer.source && !this._updatedSources[layer.source] && sourceCache && sourceCache.getSource().type !== 'raster') {
	            this._updatedSources[layer.source] = 'reload';
	            sourceCache.pause();
	        }
	        this._changed = true;
	        layer.invalidateCompiledFilter();
	    }
	    _flattenAndSortRenderedFeatures(sourceResults) {
	        const isLayer3D = layerId => this._layers[layerId].type === 'fill-extrusion';
	        const layerIndex = {};
	        const features3D = [];
	        for (let l = this._order.length - 1; l >= 0; l--) {
	            const layerId = this._order[l];
	            if (isLayer3D(layerId)) {
	                layerIndex[layerId] = l;
	                for (const sourceResult of sourceResults) {
	                    const layerFeatures = sourceResult[layerId];
	                    if (layerFeatures) {
	                        for (const featureWrapper of layerFeatures) {
	                            features3D.push(featureWrapper);
	                        }
	                    }
	                }
	            }
	        }
	        features3D.sort((a, b) => {
	            return b.intersectionZ - a.intersectionZ;
	        });
	        const features = [];
	        for (let l = this._order.length - 1; l >= 0; l--) {
	            const layerId = this._order[l];
	            if (isLayer3D(layerId)) {
	                for (let i = features3D.length - 1; i >= 0; i--) {
	                    const topmost3D = features3D[i].feature;
	                    if (layerIndex[topmost3D.layer.id] < l)
	                        break;
	                    features.push(topmost3D);
	                    features3D.pop();
	                }
	            } else {
	                for (const sourceResult of sourceResults) {
	                    const layerFeatures = sourceResult[layerId];
	                    if (layerFeatures) {
	                        for (const featureWrapper of layerFeatures) {
	                            features.push(featureWrapper.feature);
	                        }
	                    }
	                }
	            }
	        }
	        return features;
	    }
	    queryRenderedFeatures(queryGeometry, params, transform) {
	        if (params && params.filter) {
	            this._validate(ref_properties.validateFilter, 'queryRenderedFeatures.filter', params.filter, null, params);
	        }
	        const includedSources = {};
	        if (params && params.layers) {
	            if (!Array.isArray(params.layers)) {
	                this.fire(new ref_properties.ErrorEvent(new Error('parameters.layers must be an Array.')));
	                return [];
	            }
	            for (const layerId of params.layers) {
	                const layer = this._layers[layerId];
	                if (!layer) {
	                    this.fire(new ref_properties.ErrorEvent(new Error(`The layer '${ layerId }' does not exist in the map's style and cannot be queried for features.`)));
	                    return [];
	                }
	                includedSources[layer.source] = true;
	            }
	        }
	        const sourceResults = [];
	        params.availableImages = this._availableImages;
	        const has3DLayer = params && params.layers ? params.layers.some(layerId => {
	            const layer = this.getLayer(layerId);
	            return layer && layer.is3D();
	        }) : this.has3DLayers();
	        const queryGeometryStruct = QueryGeometry.createFromScreenPoints(queryGeometry, transform);
	        for (const id in this._sourceCaches) {
	            const sourceId = this._sourceCaches[id].getSource().id;
	            if (params.layers && !includedSources[sourceId])
	                continue;
	            sourceResults.push(queryRenderedFeatures(this._sourceCaches[id], this._layers, this._serializedLayers, queryGeometryStruct, params, transform, has3DLayer, !!this.map._showQueryGeometry));
	        }
	        if (this.placement) {
	            sourceResults.push(queryRenderedSymbols(this._layers, this._serializedLayers, this._getLayerSourceCache.bind(this), queryGeometryStruct.screenGeometry, params, this.placement.collisionIndex, this.placement.retainedQueryData));
	        }
	        return this._flattenAndSortRenderedFeatures(sourceResults);
	    }
	    querySourceFeatures(sourceID, params) {
	        if (params && params.filter) {
	            this._validate(ref_properties.validateFilter, 'querySourceFeatures.filter', params.filter, null, params);
	        }
	        const sourceCaches = this._getSourceCaches(sourceID);
	        let results = [];
	        for (const sourceCache of sourceCaches) {
	            results = results.concat(querySourceFeatures(sourceCache, params));
	        }
	        return results;
	    }
	    addSourceType(name, SourceType, callback) {
	        if (Style.getSourceType(name)) {
	            return callback(new Error(`A source type called "${ name }" already exists.`));
	        }
	        Style.setSourceType(name, SourceType);
	        if (!SourceType.workerSourceURL) {
	            return callback(null, null);
	        }
	        this.dispatcher.broadcast('loadWorkerSource', {
	            name,
	            url: SourceType.workerSourceURL
	        }, callback);
	    }
	    getLight() {
	        return this.light.getLight();
	    }
	    setLight(lightOptions, options = {}) {
	        this._checkLoaded();
	        const light = this.light.getLight();
	        let _update = false;
	        for (const key in lightOptions) {
	            if (!deepEqual(lightOptions[key], light[key])) {
	                _update = true;
	                break;
	            }
	        }
	        if (!_update)
	            return;
	        const parameters = this._setTransitionParameters({
	            duration: 300,
	            delay: 0
	        });
	        this.light.setLight(lightOptions, options);
	        this.light.updateTransitions(parameters);
	    }
	    getTerrain() {
	        return this.terrain && this.terrain.drapeRenderMode === DrapeRenderMode.elevated ? this.terrain.get() : null;
	    }
	    setTerrainForDraping() {
	        const mockTerrainOptions = {
	            source: '',
	            exaggeration: 0
	        };
	        this.setTerrain(mockTerrainOptions, DrapeRenderMode.deferred);
	    }
	    setTerrain(terrainOptions, drapeRenderMode = DrapeRenderMode.elevated) {
	        this._checkLoaded();
	        if (!terrainOptions) {
	            delete this.terrain;
	            delete this.stylesheet.terrain;
	            this.dispatcher.broadcast('enableTerrain', false);
	            this._force3DLayerUpdate();
	            this._markersNeedUpdate = true;
	            return;
	        }
	        if (drapeRenderMode === DrapeRenderMode.elevated) {
	            if (typeof terrainOptions.source === 'object') {
	                const id = 'terrain-dem-src';
	                this.addSource(id, terrainOptions.source);
	                terrainOptions = ref_properties.clone$1(terrainOptions);
	                terrainOptions = ref_properties.extend(terrainOptions, { source: id });
	            }
	            if (this._validate(ref_properties.validateTerrain, 'terrain', terrainOptions)) {
	                return;
	            }
	        }
	        if (!this.terrain || this.terrain && drapeRenderMode !== this.terrain.drapeRenderMode) {
	            this._createTerrain(terrainOptions, drapeRenderMode);
	        } else {
	            const terrain = this.terrain;
	            const currSpec = terrain.get();
	            for (const name of Object.keys(ref_properties.spec.terrain)) {
	                if (!terrainOptions.hasOwnProperty(name) && !!ref_properties.spec.terrain[name].default) {
	                    terrainOptions[name] = ref_properties.spec.terrain[name].default;
	                }
	            }
	            for (const key in terrainOptions) {
	                if (!deepEqual(terrainOptions[key], currSpec[key])) {
	                    terrain.set(terrainOptions);
	                    this.stylesheet.terrain = terrainOptions;
	                    const parameters = this._setTransitionParameters({ duration: 0 });
	                    terrain.updateTransitions(parameters);
	                    break;
	                }
	            }
	        }
	        this._updateDrapeFirstLayers();
	        this._markersNeedUpdate = true;
	    }
	    _createFog(fogOptions) {
	        const fog = this.fog = new Fog(fogOptions, this.map.transform);
	        this.stylesheet.fog = fogOptions;
	        const parameters = this._setTransitionParameters({ duration: 0 });
	        fog.updateTransitions(parameters);
	    }
	    _updateMarkersOpacity() {
	        if (this.map._markers.length === 0) {
	            return;
	        }
	        this.map._requestDomTask(() => {
	            for (const marker of this.map._markers) {
	                marker._evaluateOpacity();
	            }
	        });
	    }
	    getFog() {
	        return this.fog ? this.fog.get() : null;
	    }
	    setFog(fogOptions) {
	        this._checkLoaded();
	        if (!fogOptions) {
	            delete this.fog;
	            delete this.stylesheet.fog;
	            this._markersNeedUpdate = true;
	            return;
	        }
	        if (!this.fog) {
	            this._createFog(fogOptions);
	        } else {
	            const fog = this.fog;
	            const currSpec = fog.get();
	            if (Object.keys(fogOptions).length === 0)
	                fog.set(fogOptions);
	            for (const key in fogOptions) {
	                if (!deepEqual(fogOptions[key], currSpec[key])) {
	                    fog.set(fogOptions);
	                    this.stylesheet.fog = fogOptions;
	                    const parameters = this._setTransitionParameters({ duration: 0 });
	                    fog.updateTransitions(parameters);
	                    break;
	                }
	            }
	        }
	        this._markersNeedUpdate = true;
	    }
	    _setTransitionParameters(transitionOptions) {
	        return {
	            now: ref_properties.exported.now(),
	            transition: ref_properties.extend(transitionOptions, this.stylesheet.transition)
	        };
	    }
	    _updateDrapeFirstLayers() {
	        if (!this.map._optimizeForTerrain || !this.terrain) {
	            return;
	        }
	        const draped = this._order.filter(id => {
	            return this.isLayerDraped(this._layers[id]);
	        });
	        const nonDraped = this._order.filter(id => {
	            return !this.isLayerDraped(this._layers[id]);
	        });
	        this._drapedFirstOrder = [];
	        this._drapedFirstOrder.push(...draped);
	        this._drapedFirstOrder.push(...nonDraped);
	    }
	    _createTerrain(terrainOptions, drapeRenderMode) {
	        const terrain = this.terrain = new Terrain$1(terrainOptions, drapeRenderMode);
	        this.stylesheet.terrain = terrainOptions;
	        this.dispatcher.broadcast('enableTerrain', !this.terrainSetForDrapingOnly());
	        this._force3DLayerUpdate();
	        const parameters = this._setTransitionParameters({ duration: 0 });
	        terrain.updateTransitions(parameters);
	    }
	    _force3DLayerUpdate() {
	        for (const layerId in this._layers) {
	            const layer = this._layers[layerId];
	            if (layer.type === 'fill-extrusion') {
	                this._updateLayer(layer);
	            }
	        }
	    }
	    _forceSymbolLayerUpdate() {
	        for (const layerId in this._layers) {
	            const layer = this._layers[layerId];
	            if (layer.type === 'symbol') {
	                this._updateLayer(layer);
	            }
	        }
	    }
	    _validate(validate, key, value, props, options = {}) {
	        if (options && options.validate === false) {
	            return false;
	        }
	        return emitValidationErrors(this, validate.call(ref_properties.validateStyle, ref_properties.extend({
	            key,
	            style: this.serialize(),
	            value,
	            styleSpec: ref_properties.spec
	        }, props)));
	    }
	    _remove() {
	        if (this._request) {
	            this._request.cancel();
	            this._request = null;
	        }
	        if (this._spriteRequest) {
	            this._spriteRequest.cancel();
	            this._spriteRequest = null;
	        }
	        ref_properties.evented.off('pluginStateChange', this._rtlTextPluginCallback);
	        for (const layerId in this._layers) {
	            const layer = this._layers[layerId];
	            layer.setEventedParent(null);
	        }
	        for (const id in this._sourceCaches) {
	            this._sourceCaches[id].clearTiles();
	            this._sourceCaches[id].setEventedParent(null);
	        }
	        this.imageManager.setEventedParent(null);
	        this.setEventedParent(null);
	        this.dispatcher.remove();
	    }
	    _clearSource(id) {
	        const sourceCaches = this._getSourceCaches(id);
	        for (const sourceCache of sourceCaches) {
	            sourceCache.clearTiles();
	        }
	    }
	    _reloadSource(id) {
	        const sourceCaches = this._getSourceCaches(id);
	        for (const sourceCache of sourceCaches) {
	            sourceCache.resume();
	            sourceCache.reload();
	        }
	    }
	    _updateSources(transform) {
	        for (const id in this._sourceCaches) {
	            this._sourceCaches[id].update(transform);
	        }
	    }
	    _generateCollisionBoxes() {
	        for (const id in this._sourceCaches) {
	            const sourceCache = this._sourceCaches[id];
	            sourceCache.resume();
	            sourceCache.reload();
	        }
	    }
	    _updatePlacement(transform, showCollisionBoxes, fadeDuration, crossSourceCollisions, forceFullPlacement = false) {
	        let symbolBucketsChanged = false;
	        let placementCommitted = false;
	        const layerTiles = {};
	        for (const layerID of this._order) {
	            const styleLayer = this._layers[layerID];
	            if (styleLayer.type !== 'symbol')
	                continue;
	            if (!layerTiles[styleLayer.source]) {
	                const sourceCache = this._getLayerSourceCache(styleLayer);
	                if (!sourceCache)
	                    continue;
	                layerTiles[styleLayer.source] = sourceCache.getRenderableIds(true).map(id => sourceCache.getTileByID(id)).sort((a, b) => b.tileID.overscaledZ - a.tileID.overscaledZ || (a.tileID.isLessThan(b.tileID) ? -1 : 1));
	            }
	            const layerBucketsChanged = this.crossTileSymbolIndex.addLayer(styleLayer, layerTiles[styleLayer.source], transform.center.lng, transform.projection);
	            symbolBucketsChanged = symbolBucketsChanged || layerBucketsChanged;
	        }
	        this.crossTileSymbolIndex.pruneUnusedLayers(this._order);
	        forceFullPlacement = forceFullPlacement || this._layerOrderChanged || fadeDuration === 0;
	        if (this._layerOrderChanged) {
	            this.fire(new ref_properties.Event('neworder'));
	        }
	        if (forceFullPlacement || !this.pauseablePlacement || this.pauseablePlacement.isDone() && !this.placement.stillRecent(ref_properties.exported.now(), transform.zoom)) {
	            const fogState = this.fog && transform.projection.supportsFog ? this.fog.state : null;
	            this.pauseablePlacement = new PauseablePlacement(transform, this._order, forceFullPlacement, showCollisionBoxes, fadeDuration, crossSourceCollisions, this.placement, fogState);
	            this._layerOrderChanged = false;
	        }
	        if (this.pauseablePlacement.isDone()) {
	            this.placement.setStale();
	        } else {
	            this.pauseablePlacement.continuePlacement(this._order, this._layers, layerTiles);
	            if (this.pauseablePlacement.isDone()) {
	                this.placement = this.pauseablePlacement.commit(ref_properties.exported.now());
	                placementCommitted = true;
	            }
	            if (symbolBucketsChanged) {
	                this.pauseablePlacement.placement.setStale();
	            }
	        }
	        if (placementCommitted || symbolBucketsChanged) {
	            for (const layerID of this._order) {
	                const styleLayer = this._layers[layerID];
	                if (styleLayer.type !== 'symbol')
	                    continue;
	                this.placement.updateLayerOpacities(styleLayer, layerTiles[styleLayer.source]);
	            }
	        }
	        const needsRerender = !this.pauseablePlacement.isDone() || this.placement.hasTransitions(ref_properties.exported.now());
	        return needsRerender;
	    }
	    _releaseSymbolFadeTiles() {
	        for (const id in this._sourceCaches) {
	            this._sourceCaches[id].releaseSymbolFadeTiles();
	        }
	    }
	    getImages(mapId, params, callback) {
	        this.imageManager.getImages(params.icons, callback);
	        this._updateTilesForChangedImages();
	        const setDependencies = sourceCache => {
	            if (sourceCache) {
	                sourceCache.setDependencies(params.tileID.key, params.type, params.icons);
	            }
	        };
	        setDependencies(this._otherSourceCaches[params.source]);
	        setDependencies(this._symbolSourceCaches[params.source]);
	    }
	    getGlyphs(mapId, params, callback) {
	        this.glyphManager.getGlyphs(params.stacks, callback);
	    }
	    getResource(mapId, params, callback) {
	        return ref_properties.makeRequest(params, callback);
	    }
	    _getSourceCache(source) {
	        return this._otherSourceCaches[source];
	    }
	    _getLayerSourceCache(layer) {
	        return layer.type === 'symbol' ? this._symbolSourceCaches[layer.source] : this._otherSourceCaches[layer.source];
	    }
	    _getSourceCaches(source) {
	        const sourceCaches = [];
	        if (this._otherSourceCaches[source]) {
	            sourceCaches.push(this._otherSourceCaches[source]);
	        }
	        if (this._symbolSourceCaches[source]) {
	            sourceCaches.push(this._symbolSourceCaches[source]);
	        }
	        return sourceCaches;
	    }
	    _isSourceCacheLoaded(source) {
	        const sourceCaches = this._getSourceCaches(source);
	        if (sourceCaches.length === 0) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`There is no source with ID '${ source }'`)));
	            return false;
	        }
	        return sourceCaches.every(sc => sc.loaded());
	    }
	    has3DLayers() {
	        return this._num3DLayers > 0;
	    }
	    hasSymbolLayers() {
	        return this._numSymbolLayers > 0;
	    }
	    hasCircleLayers() {
	        return this._numCircleLayers > 0;
	    }
	    _clearWorkerCaches() {
	        this.dispatcher.broadcast('clearCaches');
	    }
	    destroy() {
	        this._clearWorkerCaches();
	        if (this.terrainSetForDrapingOnly()) {
	            delete this.terrain;
	            delete this.stylesheet.terrain;
	        }
	    }
	}
	Style.getSourceType = getType;
	Style.setSourceType = setType;
	Style.registerForPluginStateChange = ref_properties.registerForPluginStateChange;

	var preludeCommon = "\n#define EPSILON 0.0000001\n#define PI 3.141592653589793\n#define EXTENT 8192.0\n#define HALF_PI PI/2.0\n#define QUARTER_PI PI/4.0\n#define RAD_TO_DEG 180.0/PI\n#define DEG_TO_RAD PI/180.0\n#define GLOBE_RADIUS EXTENT/PI/2.0";

	var preludeFrag = "\nhighp vec3 hash(highp vec2 p) {highp vec3 p3=fract(p.xyx*vec3(443.8975,397.2973,491.1871));p3+=dot(p3,p3.yxz+19.19);return fract((p3.xxy+p3.yzz)*p3.zyx);}vec3 dither(vec3 color,highp vec2 seed) {vec3 rnd=hash(seed)+hash(seed+0.59374)-0.5;return color+rnd/255.0;}\n#ifdef TERRAIN\nhighp vec4 pack_depth(highp float ndc_z) {highp float depth=ndc_z*0.5+0.5;const highp vec4 bit_shift=vec4(256.0*256.0*256.0,256.0*256.0,256.0,1.0);const highp vec4 bit_mask =vec4(0.0,1.0/256.0,1.0/256.0,1.0/256.0);highp vec4 res=fract(depth*bit_shift);res-=res.xxyz*bit_mask;return res;}\n#endif";

	var preludeVert = "\nfloat wrap(float n,float min,float max) {float d=max-min;float w=mod(mod(n-min,d)+d,d)+min;return (w==min) ? max : w;}\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 mercator_tile_position(mat4 matrix,vec2 tile_anchor,vec3 tile_id,vec2 mercator_center) {\n#ifndef PROJECTED_POS_ON_VIEWPORT\nfloat tiles=tile_id.z;vec2 mercator=(tile_anchor/EXTENT+tile_id.xy)/tiles;mercator-=mercator_center;mercator.x=wrap(mercator.x,-0.5,0.5);vec4 mercator_tile=vec4(mercator.xy*EXTENT,EXTENT/(2.0*PI),1.0);mercator_tile=matrix*mercator_tile;return mercator_tile.xyz;\n#else\nreturn vec3(0.0);\n#endif\n}vec3 mix_globe_mercator(vec3 globe,vec3 mercator,float t) {return mix(globe,mercator,t);}mat3 globe_mercator_surface_vectors(vec3 pos_normal,vec3 up_dir,float zoom_transition) {vec3 normal=zoom_transition==0.0 ? pos_normal : normalize(mix(pos_normal,up_dir,zoom_transition));vec3 xAxis=normalize(vec3(normal.z,0.0,-normal.x));vec3 yAxis=normalize(cross(normal,xAxis));return mat3(xAxis,yAxis,normal);}\n#endif\nvec2 unpack_float(const float packedValue) {int packedIntValue=int(packedValue);int v0=packedIntValue/256;return vec2(v0,packedIntValue-v0*256);}vec2 unpack_opacity(const float packedOpacity) {int intOpacity=int(packedOpacity)/2;return vec2(float(intOpacity)/127.0,mod(packedOpacity,2.0));}vec4 decode_color(const vec2 encodedColor) {return vec4(\nunpack_float(encodedColor[0])/255.0,unpack_float(encodedColor[1])/255.0\n);}float unpack_mix_vec2(const vec2 packedValue,const float t) {return mix(packedValue[0],packedValue[1],t);}vec4 unpack_mix_color(const vec4 packedColors,const float t) {vec4 minColor=decode_color(vec2(packedColors[0],packedColors[1]));vec4 maxColor=decode_color(vec2(packedColors[2],packedColors[3]));return mix(minColor,maxColor,t);}vec2 get_pattern_pos(const vec2 pixel_coord_upper,const vec2 pixel_coord_lower,const vec2 pattern_size,const float tile_units_to_pixels,const vec2 pos) {vec2 offset=mod(mod(mod(pixel_coord_upper,pattern_size)*256.0,pattern_size)*256.0+pixel_coord_lower,pattern_size);return (tile_units_to_pixels*pos+offset)/pattern_size;}const vec4 AWAY=vec4(-1000.0,-1000.0,-1000.0,1);//Normalized device coordinate that is not rendered.";

	var backgroundFrag = "uniform vec4 u_color;uniform float u_opacity;void main() {vec4 out_color=u_color;\n#ifdef FOG\nout_color=fog_dither(fog_apply_premultiplied(out_color,v_fog_pos));\n#endif\ngl_FragColor=out_color*u_opacity;\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var backgroundVert = "attribute vec2 a_pos;uniform mat4 u_matrix;void main() {gl_Position=u_matrix*vec4(a_pos,0,1);\n#ifdef FOG\nv_fog_pos=fog_position(a_pos);\n#endif\n}";

	var backgroundPatternFrag = "uniform vec2 u_pattern_tl_a;uniform vec2 u_pattern_br_a;uniform vec2 u_pattern_tl_b;uniform vec2 u_pattern_br_b;uniform vec2 u_texsize;uniform float u_mix;uniform float u_opacity;uniform sampler2D u_image;varying vec2 v_pos_a;varying vec2 v_pos_b;void main() {vec2 imagecoord=mod(v_pos_a,1.0);vec2 pos=mix(u_pattern_tl_a/u_texsize,u_pattern_br_a/u_texsize,imagecoord);vec4 color1=texture2D(u_image,pos);vec2 imagecoord_b=mod(v_pos_b,1.0);vec2 pos2=mix(u_pattern_tl_b/u_texsize,u_pattern_br_b/u_texsize,imagecoord_b);vec4 color2=texture2D(u_image,pos2);vec4 out_color=mix(color1,color2,u_mix);\n#ifdef FOG\nout_color=fog_dither(fog_apply_premultiplied(out_color,v_fog_pos));\n#endif\ngl_FragColor=out_color*u_opacity;\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var backgroundPatternVert = "uniform mat4 u_matrix;uniform vec2 u_pattern_size_a;uniform vec2 u_pattern_size_b;uniform vec2 u_pixel_coord_upper;uniform vec2 u_pixel_coord_lower;uniform float u_scale_a;uniform float u_scale_b;uniform float u_tile_units_to_pixels;attribute vec2 a_pos;varying vec2 v_pos_a;varying vec2 v_pos_b;void main() {gl_Position=u_matrix*vec4(a_pos,0,1);v_pos_a=get_pattern_pos(u_pixel_coord_upper,u_pixel_coord_lower,u_scale_a*u_pattern_size_a,u_tile_units_to_pixels,a_pos);v_pos_b=get_pattern_pos(u_pixel_coord_upper,u_pixel_coord_lower,u_scale_b*u_pattern_size_b,u_tile_units_to_pixels,a_pos);\n#ifdef FOG\nv_fog_pos=fog_position(a_pos);\n#endif\n}";

	var circleFrag = "varying vec3 v_data;varying float v_visibility;\n#pragma mapbox: define highp vec4 color\n#pragma mapbox: define mediump float radius\n#pragma mapbox: define lowp float blur\n#pragma mapbox: define lowp float opacity\n#pragma mapbox: define highp vec4 stroke_color\n#pragma mapbox: define mediump float stroke_width\n#pragma mapbox: define lowp float stroke_opacity\nvoid main() {\n#pragma mapbox: initialize highp vec4 color\n#pragma mapbox: initialize mediump float radius\n#pragma mapbox: initialize lowp float blur\n#pragma mapbox: initialize lowp float opacity\n#pragma mapbox: initialize highp vec4 stroke_color\n#pragma mapbox: initialize mediump float stroke_width\n#pragma mapbox: initialize lowp float stroke_opacity\nvec2 extrude=v_data.xy;float extrude_length=length(extrude);lowp float antialiasblur=v_data.z;float antialiased_blur=-max(blur,antialiasblur);float opacity_t=smoothstep(0.0,antialiased_blur,extrude_length-1.0);float color_t=stroke_width < 0.01 ? 0.0 : smoothstep(\nantialiased_blur,0.0,extrude_length-radius/(radius+stroke_width)\n);vec4 out_color=mix(color*opacity,stroke_color*stroke_opacity,color_t);\n#ifdef FOG\nout_color=fog_apply_premultiplied(out_color,v_fog_pos);\n#endif\ngl_FragColor=out_color*(v_visibility*opacity_t);\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var circleVert = "#define NUM_VISIBILITY_RINGS 2\n#define INV_SQRT2 0.70710678\n#define ELEVATION_BIAS 0.0001\n#define NUM_SAMPLES_PER_RING 16\nuniform mat4 u_matrix;uniform mat2 u_extrude_scale;uniform lowp float u_device_pixel_ratio;uniform highp float u_camera_to_center_distance;attribute vec2 a_pos;\n#ifdef PROJECTION_GLOBE_VIEW\nattribute vec3 a_pos_3;attribute vec3 a_pos_normal_3;attribute float a_scale;uniform mat4 u_inv_rot_matrix;uniform vec2 u_merc_center;uniform vec3 u_tile_id;uniform float u_zoom_transition;uniform vec3 u_up_dir;\n#endif\nvarying vec3 v_data;varying float v_visibility;\n#pragma mapbox: define highp vec4 color\n#pragma mapbox: define mediump float radius\n#pragma mapbox: define lowp float blur\n#pragma mapbox: define lowp float opacity\n#pragma mapbox: define highp vec4 stroke_color\n#pragma mapbox: define mediump float stroke_width\n#pragma mapbox: define lowp float stroke_opacity\nvec2 calc_offset(vec2 extrusion,float radius,float stroke_width, float view_scale) {return extrusion*(radius+stroke_width)*u_extrude_scale*view_scale;}float cantilevered_elevation(vec2 pos,float radius,float stroke_width,float view_scale) {vec2 c1=pos+calc_offset(vec2(-1,-1),radius,stroke_width,view_scale);vec2 c2=pos+calc_offset(vec2(1,-1),radius,stroke_width,view_scale);vec2 c3=pos+calc_offset(vec2(1,1),radius,stroke_width,view_scale);vec2 c4=pos+calc_offset(vec2(-1,1),radius,stroke_width,view_scale);float h1=elevation(c1)+ELEVATION_BIAS;float h2=elevation(c2)+ELEVATION_BIAS;float h3=elevation(c3)+ELEVATION_BIAS;float h4=elevation(c4)+ELEVATION_BIAS;return max(h4,max(h3,max(h1,h2)));}float circle_elevation(vec2 pos) {\n#if defined(TERRAIN)\nreturn elevation(pos)+ELEVATION_BIAS;\n#else\nreturn 0.0;\n#endif\n}vec4 project_vertex(vec2 extrusion,vec4 world_center,vec4 projected_center,float radius,float stroke_width, float view_scale,mat3 surface_vectors) {vec2 sample_offset=calc_offset(extrusion,radius,stroke_width,view_scale);\n#ifdef PITCH_WITH_MAP\n#ifdef PROJECTION_GLOBE_VIEW\nreturn u_matrix*( world_center+vec4(sample_offset.x*surface_vectors[0]+sample_offset.y*surface_vectors[1],0) );\n#else\nreturn u_matrix*( world_center+vec4(sample_offset,0,0) );\n#endif\n#else\nreturn projected_center+vec4(sample_offset,0,0);\n#endif\n}float get_sample_step() {\n#ifdef PITCH_WITH_MAP\nreturn 2.0*PI/float(NUM_SAMPLES_PER_RING);\n#else\nreturn PI/float(NUM_SAMPLES_PER_RING);\n#endif\n}void main(void) {\n#pragma mapbox: initialize highp vec4 color\n#pragma mapbox: initialize mediump float radius\n#pragma mapbox: initialize lowp float blur\n#pragma mapbox: initialize lowp float opacity\n#pragma mapbox: initialize highp vec4 stroke_color\n#pragma mapbox: initialize mediump float stroke_width\n#pragma mapbox: initialize lowp float stroke_opacity\nvec2 extrude=vec2(mod(a_pos,2.0)*2.0-1.0);vec2 circle_center=floor(a_pos*0.5);\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 pos_normal_3=a_pos_normal_3/16384.0;mat3 surface_vectors=globe_mercator_surface_vectors(pos_normal_3,u_up_dir,u_zoom_transition);vec3 surface_extrusion=extrude.x*surface_vectors[0]+extrude.y*surface_vectors[1];vec3 globe_elevation=elevationVector(circle_center)*circle_elevation(circle_center);vec3 globe_pos=a_pos_3+surface_extrusion+globe_elevation;vec3 mercator_elevation=u_up_dir*u_tile_up_scale*circle_elevation(circle_center);vec3 merc_pos=mercator_tile_position(u_inv_rot_matrix,circle_center,u_tile_id,u_merc_center)+surface_extrusion+mercator_elevation;vec3 pos=mix_globe_mercator(globe_pos,merc_pos,u_zoom_transition);vec4 world_center=vec4(pos,1);\n#else \nmat3 surface_vectors=mat3(1.0);float height=circle_elevation(circle_center);vec4 world_center=vec4(circle_center,height,1);\n#endif\nvec4 projected_center=u_matrix*world_center;float view_scale=0.0;\n#ifdef PITCH_WITH_MAP\n#ifdef SCALE_WITH_MAP\nview_scale=1.0;\n#else\nview_scale=projected_center.w/u_camera_to_center_distance;\n#endif\n#else\n#ifdef SCALE_WITH_MAP\nview_scale=u_camera_to_center_distance;\n#else\nview_scale=projected_center.w;\n#endif\n#endif\ngl_Position=project_vertex(extrude,world_center,projected_center,radius,stroke_width,view_scale,surface_vectors);float visibility=0.0;\n#ifdef TERRAIN\nfloat step=get_sample_step();\n#ifdef PITCH_WITH_MAP\nfloat cantilevered_height=cantilevered_elevation(circle_center,radius,stroke_width,view_scale);vec4 occlusion_world_center=vec4(circle_center,cantilevered_height,1);vec4 occlusion_projected_center=u_matrix*occlusion_world_center;\n#else\nvec4 occlusion_world_center=world_center;vec4 occlusion_projected_center=projected_center;\n#endif\nfor(int ring=0; ring < NUM_VISIBILITY_RINGS; ring++) {float scale=(float(ring)+1.0)/float(NUM_VISIBILITY_RINGS);for(int i=0; i < NUM_SAMPLES_PER_RING; i++) {vec2 extrusion=vec2(cos(step*float(i)),-sin(step*float(i)))*scale;vec4 frag_pos=project_vertex(extrusion,occlusion_world_center,occlusion_projected_center,radius,stroke_width,view_scale,surface_vectors);visibility+=float(!isOccluded(frag_pos));}}visibility/=float(NUM_VISIBILITY_RINGS)*float(NUM_SAMPLES_PER_RING);\n#else\nvisibility=1.0;\n#endif\n#ifdef PROJECTION_GLOBE_VIEW\nvisibility=1.0;\n#endif\nv_visibility=visibility;lowp float antialiasblur=1.0/u_device_pixel_ratio/(radius+stroke_width);v_data=vec3(extrude.x,extrude.y,antialiasblur);\n#ifdef FOG\nv_fog_pos=fog_position(world_center.xyz);\n#endif\n}";

	var clippingMaskFrag = "void main() {gl_FragColor=vec4(1.0);}";

	var clippingMaskVert = "attribute vec2 a_pos;uniform mat4 u_matrix;void main() {gl_Position=u_matrix*vec4(a_pos,0,1);}";

	var heatmapFrag = "uniform highp float u_intensity;varying vec2 v_extrude;\n#pragma mapbox: define highp float weight\n#define GAUSS_COEF 0.3989422804014327\nvoid main() {\n#pragma mapbox: initialize highp float weight\nfloat d=-0.5*3.0*3.0*dot(v_extrude,v_extrude);float val=weight*u_intensity*GAUSS_COEF*exp(d);gl_FragColor=vec4(val,1.0,1.0,1.0);\n#ifdef FOG\nif (u_is_globe==0) {gl_FragColor.r*=pow(1.0-fog_opacity(v_fog_pos),2.0);}\n#endif\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var heatmapVert = "uniform mat4 u_matrix;uniform float u_extrude_scale;uniform float u_opacity;uniform float u_intensity;attribute vec2 a_pos;\n#ifdef PROJECTION_GLOBE_VIEW\nattribute vec3 a_pos_3;attribute vec3 a_pos_normal_3;uniform mat4 u_inv_rot_matrix;uniform vec2 u_merc_center;uniform vec3 u_tile_id;uniform float u_zoom_transition;uniform vec3 u_up_dir;\n#endif\nvarying vec2 v_extrude;\n#pragma mapbox: define highp float weight\n#pragma mapbox: define mediump float radius\nconst highp float ZERO=1.0/255.0/16.0;\n#define GAUSS_COEF 0.3989422804014327\nvoid main(void) {\n#pragma mapbox: initialize highp float weight\n#pragma mapbox: initialize mediump float radius\nvec2 unscaled_extrude=vec2(mod(a_pos,2.0)*2.0-1.0);float S=sqrt(-2.0*log(ZERO/weight/u_intensity/GAUSS_COEF))/3.0;v_extrude=S*unscaled_extrude;vec2 extrude=v_extrude*radius*u_extrude_scale;vec2 tilePos=floor(a_pos*0.5);\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 pos_normal_3=a_pos_normal_3/16384.0;mat3 surface_vectors=globe_mercator_surface_vectors(pos_normal_3,u_up_dir,u_zoom_transition);vec3 surface_extrusion=extrude.x*surface_vectors[0]+extrude.y*surface_vectors[1];vec3 globe_elevation=elevationVector(tilePos)*elevation(tilePos);vec3 globe_pos=a_pos_3+surface_extrusion+globe_elevation;vec3 mercator_elevation=u_up_dir*u_tile_up_scale*elevation(tilePos);vec3 merc_pos=mercator_tile_position(u_inv_rot_matrix,tilePos,u_tile_id,u_merc_center)+surface_extrusion+mercator_elevation;vec3 pos=mix_globe_mercator(globe_pos,merc_pos,u_zoom_transition);\n#else\nvec3 pos=vec3(tilePos+extrude,elevation(tilePos));\n#endif\ngl_Position=u_matrix*vec4(pos,1);\n#ifdef FOG\nv_fog_pos=fog_position(pos);\n#endif\n}";

	var heatmapTextureFrag = "uniform sampler2D u_image;uniform sampler2D u_color_ramp;uniform float u_opacity;varying vec2 v_pos;void main() {float t=texture2D(u_image,v_pos).r;vec4 color=texture2D(u_color_ramp,vec2(t,0.5));gl_FragColor=color*u_opacity;\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(0.0);\n#endif\n}";

	var heatmapTextureVert = "attribute vec2 a_pos;varying vec2 v_pos;void main() {gl_Position=vec4(a_pos,0,1);v_pos=a_pos*0.5+0.5;}";

	var collisionBoxFrag = "varying float v_placed;varying float v_notUsed;void main() {vec4 red =vec4(1.0,0.0,0.0,1.0);vec4 blue=vec4(0.0,0.0,1.0,0.5);gl_FragColor =mix(red,blue,step(0.5,v_placed))*0.5;gl_FragColor*=mix(1.0,0.1,step(0.5,v_notUsed));}";

	var collisionBoxVert = "attribute vec3 a_pos;attribute vec2 a_anchor_pos;attribute vec2 a_extrude;attribute vec2 a_placed;attribute vec2 a_shift;attribute float a_size_scale;attribute vec2 a_padding;uniform mat4 u_matrix;uniform vec2 u_extrude_scale;uniform float u_camera_to_center_distance;varying float v_placed;varying float v_notUsed;void main() {vec4 projectedPoint=u_matrix*vec4(a_pos+elevationVector(a_anchor_pos)*elevation(a_anchor_pos),1);highp float camera_to_anchor_distance=projectedPoint.w;highp float collision_perspective_ratio=clamp(\n0.5+0.5*(u_camera_to_center_distance/camera_to_anchor_distance),0.0,1.5);gl_Position=projectedPoint;gl_Position.xy+=(a_extrude*a_size_scale+a_shift+a_padding)*u_extrude_scale*gl_Position.w*collision_perspective_ratio;v_placed=a_placed.x;v_notUsed=a_placed.y;}";

	var collisionCircleFrag = "varying float v_radius;varying vec2 v_extrude;varying float v_perspective_ratio;varying float v_collision;void main() {float alpha=0.5*min(v_perspective_ratio,1.0);float stroke_radius=0.9*max(v_perspective_ratio,1.0);float distance_to_center=length(v_extrude);float distance_to_edge=abs(distance_to_center-v_radius);float opacity_t=smoothstep(-stroke_radius,0.0,-distance_to_edge);vec4 color=mix(vec4(0.0,0.0,1.0,0.5),vec4(1.0,0.0,0.0,1.0),v_collision);gl_FragColor=color*alpha*opacity_t;}";

	var collisionCircleVert = "attribute vec2 a_pos_2f;attribute float a_radius;attribute vec2 a_flags;uniform mat4 u_matrix;uniform mat4 u_inv_matrix;uniform vec2 u_viewport_size;uniform float u_camera_to_center_distance;varying float v_radius;varying vec2 v_extrude;varying float v_perspective_ratio;varying float v_collision;vec3 toTilePosition(vec2 screenPos) {vec4 rayStart=u_inv_matrix*vec4(screenPos,-1.0,1.0);vec4 rayEnd  =u_inv_matrix*vec4(screenPos, 1.0,1.0);rayStart.xyz/=rayStart.w;rayEnd.xyz  /=rayEnd.w;highp float t=(0.0-rayStart.z)/(rayEnd.z-rayStart.z);return mix(rayStart.xyz,rayEnd.xyz,t);}void main() {vec2 quadCenterPos=a_pos_2f;float radius=a_radius;float collision=a_flags.x;float vertexIdx=a_flags.y;vec2 quadVertexOffset=vec2(\nmix(-1.0,1.0,float(vertexIdx >=2.0)),mix(-1.0,1.0,float(vertexIdx >=1.0 && vertexIdx <=2.0)));vec2 quadVertexExtent=quadVertexOffset*radius;vec3 tilePos=toTilePosition(quadCenterPos);vec4 clipPos=u_matrix*vec4(tilePos,1.0);highp float camera_to_anchor_distance=clipPos.w;highp float collision_perspective_ratio=clamp(\n0.5+0.5*(u_camera_to_center_distance/camera_to_anchor_distance),0.0,4.0);float padding_factor=1.2;v_radius=radius;v_extrude=quadVertexExtent*padding_factor;v_perspective_ratio=collision_perspective_ratio;v_collision=collision;gl_Position=vec4(clipPos.xyz/clipPos.w,1.0)+vec4(quadVertexExtent*padding_factor/u_viewport_size*2.0,0.0,0.0);}";

	var debugFrag = "uniform highp vec4 u_color;uniform sampler2D u_overlay;varying vec2 v_uv;void main() {vec4 overlay_color=texture2D(u_overlay,v_uv);gl_FragColor=mix(u_color,overlay_color,overlay_color.a);}";

	var debugVert = "attribute vec2 a_pos;\n#ifdef PROJECTION_GLOBE_VIEW\nattribute vec3 a_pos_3;\n#endif\nvarying vec2 v_uv;uniform mat4 u_matrix;uniform float u_overlay_scale;void main() {float h=elevation(a_pos);v_uv=a_pos/8192.0;\n#ifdef PROJECTION_GLOBE_VIEW\ngl_Position=u_matrix*vec4(a_pos_3+elevationVector(a_pos)*h,1);\n#else\ngl_Position=u_matrix*vec4(a_pos*u_overlay_scale,h,1);\n#endif\n}";

	var fillFrag = "#pragma mapbox: define highp vec4 color\n#pragma mapbox: define lowp float opacity\nvoid main() {\n#pragma mapbox: initialize highp vec4 color\n#pragma mapbox: initialize lowp float opacity\nvec4 out_color=color;\n#ifdef FOG\nout_color=fog_dither(fog_apply_premultiplied(out_color,v_fog_pos));\n#endif\ngl_FragColor=out_color*opacity;\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var fillVert = "attribute vec2 a_pos;uniform mat4 u_matrix;\n#pragma mapbox: define highp vec4 color\n#pragma mapbox: define lowp float opacity\nvoid main() {\n#pragma mapbox: initialize highp vec4 color\n#pragma mapbox: initialize lowp float opacity\ngl_Position=u_matrix*vec4(a_pos,0,1);\n#ifdef FOG\nv_fog_pos=fog_position(a_pos);\n#endif\n}";

	var fillOutlineFrag = "varying vec2 v_pos;\n#pragma mapbox: define highp vec4 outline_color\n#pragma mapbox: define lowp float opacity\nvoid main() {\n#pragma mapbox: initialize highp vec4 outline_color\n#pragma mapbox: initialize lowp float opacity\nfloat dist=length(v_pos-gl_FragCoord.xy);float alpha=1.0-smoothstep(0.0,1.0,dist);vec4 out_color=outline_color;\n#ifdef FOG\nout_color=fog_dither(fog_apply_premultiplied(out_color,v_fog_pos));\n#endif\ngl_FragColor=out_color*(alpha*opacity);\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var fillOutlineVert = "attribute vec2 a_pos;uniform mat4 u_matrix;uniform vec2 u_world;varying vec2 v_pos;\n#pragma mapbox: define highp vec4 outline_color\n#pragma mapbox: define lowp float opacity\nvoid main() {\n#pragma mapbox: initialize highp vec4 outline_color\n#pragma mapbox: initialize lowp float opacity\ngl_Position=u_matrix*vec4(a_pos,0,1);v_pos=(gl_Position.xy/gl_Position.w+1.0)/2.0*u_world;\n#ifdef FOG\nv_fog_pos=fog_position(a_pos);\n#endif\n}";

	var fillOutlinePatternFrag = "uniform vec2 u_texsize;uniform sampler2D u_image;uniform float u_fade;varying vec2 v_pos_a;varying vec2 v_pos_b;varying vec2 v_pos;\n#pragma mapbox: define lowp float opacity\n#pragma mapbox: define lowp vec4 pattern_from\n#pragma mapbox: define lowp vec4 pattern_to\nvoid main() {\n#pragma mapbox: initialize lowp float opacity\n#pragma mapbox: initialize mediump vec4 pattern_from\n#pragma mapbox: initialize mediump vec4 pattern_to\nvec2 pattern_tl_a=pattern_from.xy;vec2 pattern_br_a=pattern_from.zw;vec2 pattern_tl_b=pattern_to.xy;vec2 pattern_br_b=pattern_to.zw;vec2 imagecoord=mod(v_pos_a,1.0);vec2 pos=mix(pattern_tl_a/u_texsize,pattern_br_a/u_texsize,imagecoord);vec4 color1=texture2D(u_image,pos);vec2 imagecoord_b=mod(v_pos_b,1.0);vec2 pos2=mix(pattern_tl_b/u_texsize,pattern_br_b/u_texsize,imagecoord_b);vec4 color2=texture2D(u_image,pos2);float dist=length(v_pos-gl_FragCoord.xy);float alpha=1.0-smoothstep(0.0,1.0,dist);vec4 out_color=mix(color1,color2,u_fade);\n#ifdef FOG\nout_color=fog_dither(fog_apply_premultiplied(out_color,v_fog_pos));\n#endif\ngl_FragColor=out_color*(alpha*opacity);\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var fillOutlinePatternVert = "uniform mat4 u_matrix;uniform vec2 u_world;uniform vec2 u_pixel_coord_upper;uniform vec2 u_pixel_coord_lower;uniform vec3 u_scale;attribute vec2 a_pos;varying vec2 v_pos_a;varying vec2 v_pos_b;varying vec2 v_pos;\n#pragma mapbox: define lowp float opacity\n#pragma mapbox: define lowp vec4 pattern_from\n#pragma mapbox: define lowp vec4 pattern_to\n#pragma mapbox: define lowp float pixel_ratio_from\n#pragma mapbox: define lowp float pixel_ratio_to\nvoid main() {\n#pragma mapbox: initialize lowp float opacity\n#pragma mapbox: initialize mediump vec4 pattern_from\n#pragma mapbox: initialize mediump vec4 pattern_to\n#pragma mapbox: initialize lowp float pixel_ratio_from\n#pragma mapbox: initialize lowp float pixel_ratio_to\nvec2 pattern_tl_a=pattern_from.xy;vec2 pattern_br_a=pattern_from.zw;vec2 pattern_tl_b=pattern_to.xy;vec2 pattern_br_b=pattern_to.zw;float tileRatio=u_scale.x;float fromScale=u_scale.y;float toScale=u_scale.z;gl_Position=u_matrix*vec4(a_pos,0,1);vec2 display_size_a=(pattern_br_a-pattern_tl_a)/pixel_ratio_from;vec2 display_size_b=(pattern_br_b-pattern_tl_b)/pixel_ratio_to;v_pos_a=get_pattern_pos(u_pixel_coord_upper,u_pixel_coord_lower,fromScale*display_size_a,tileRatio,a_pos);v_pos_b=get_pattern_pos(u_pixel_coord_upper,u_pixel_coord_lower,toScale*display_size_b,tileRatio,a_pos);v_pos=(gl_Position.xy/gl_Position.w+1.0)/2.0*u_world;\n#ifdef FOG\nv_fog_pos=fog_position(a_pos);\n#endif\n}";

	var fillPatternFrag = "uniform vec2 u_texsize;uniform float u_fade;uniform sampler2D u_image;varying vec2 v_pos_a;varying vec2 v_pos_b;\n#pragma mapbox: define lowp float opacity\n#pragma mapbox: define lowp vec4 pattern_from\n#pragma mapbox: define lowp vec4 pattern_to\nvoid main() {\n#pragma mapbox: initialize lowp float opacity\n#pragma mapbox: initialize mediump vec4 pattern_from\n#pragma mapbox: initialize mediump vec4 pattern_to\nvec2 pattern_tl_a=pattern_from.xy;vec2 pattern_br_a=pattern_from.zw;vec2 pattern_tl_b=pattern_to.xy;vec2 pattern_br_b=pattern_to.zw;vec2 imagecoord=mod(v_pos_a,1.0);vec2 pos=mix(pattern_tl_a/u_texsize,pattern_br_a/u_texsize,imagecoord);vec4 color1=texture2D(u_image,pos);vec2 imagecoord_b=mod(v_pos_b,1.0);vec2 pos2=mix(pattern_tl_b/u_texsize,pattern_br_b/u_texsize,imagecoord_b);vec4 color2=texture2D(u_image,pos2);vec4 out_color=mix(color1,color2,u_fade);\n#ifdef FOG\nout_color=fog_dither(fog_apply_premultiplied(out_color,v_fog_pos));\n#endif\ngl_FragColor=out_color*opacity;\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var fillPatternVert = "uniform mat4 u_matrix;uniform vec2 u_pixel_coord_upper;uniform vec2 u_pixel_coord_lower;uniform vec3 u_scale;attribute vec2 a_pos;varying vec2 v_pos_a;varying vec2 v_pos_b;\n#pragma mapbox: define lowp float opacity\n#pragma mapbox: define lowp vec4 pattern_from\n#pragma mapbox: define lowp vec4 pattern_to\n#pragma mapbox: define lowp float pixel_ratio_from\n#pragma mapbox: define lowp float pixel_ratio_to\nvoid main() {\n#pragma mapbox: initialize lowp float opacity\n#pragma mapbox: initialize mediump vec4 pattern_from\n#pragma mapbox: initialize mediump vec4 pattern_to\n#pragma mapbox: initialize lowp float pixel_ratio_from\n#pragma mapbox: initialize lowp float pixel_ratio_to\nvec2 pattern_tl_a=pattern_from.xy;vec2 pattern_br_a=pattern_from.zw;vec2 pattern_tl_b=pattern_to.xy;vec2 pattern_br_b=pattern_to.zw;float tileZoomRatio=u_scale.x;float fromScale=u_scale.y;float toScale=u_scale.z;vec2 display_size_a=(pattern_br_a-pattern_tl_a)/pixel_ratio_from;vec2 display_size_b=(pattern_br_b-pattern_tl_b)/pixel_ratio_to;gl_Position=u_matrix*vec4(a_pos,0,1);v_pos_a=get_pattern_pos(u_pixel_coord_upper,u_pixel_coord_lower,fromScale*display_size_a,tileZoomRatio,a_pos);v_pos_b=get_pattern_pos(u_pixel_coord_upper,u_pixel_coord_lower,toScale*display_size_b,tileZoomRatio,a_pos);\n#ifdef FOG\nv_fog_pos=fog_position(a_pos);\n#endif\n}";

	var fillExtrusionFrag = "varying vec4 v_color;void main() {vec4 color=v_color;\n#ifdef FOG\ncolor=fog_dither(fog_apply_premultiplied(color,v_fog_pos));\n#endif\ngl_FragColor=color;\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var fillExtrusionVert = "uniform mat4 u_matrix;uniform vec3 u_lightcolor;uniform lowp vec3 u_lightpos;uniform lowp float u_lightintensity;uniform float u_vertical_gradient;uniform lowp float u_opacity;attribute vec4 a_pos_normal_ed;attribute vec2 a_centroid_pos;\n#ifdef PROJECTION_GLOBE_VIEW\nattribute vec3 a_pos_3;attribute vec3 a_pos_normal_3;uniform mat4 u_inv_rot_matrix;uniform vec2 u_merc_center;uniform vec3 u_tile_id;uniform float u_zoom_transition;uniform vec3 u_up_dir;uniform float u_height_lift;\n#endif\nvarying vec4 v_color;\n#pragma mapbox: define highp float base\n#pragma mapbox: define highp float height\n#pragma mapbox: define highp vec4 color\nvoid main() {\n#pragma mapbox: initialize highp float base\n#pragma mapbox: initialize highp float height\n#pragma mapbox: initialize highp vec4 color\nvec3 pos_nx=floor(a_pos_normal_ed.xyz*0.5);mediump vec3 top_up_ny=a_pos_normal_ed.xyz-2.0*pos_nx;float x_normal=pos_nx.z/8192.0;vec3 normal=top_up_ny.y==1.0 ? vec3(0.0,0.0,1.0) : normalize(vec3(x_normal,(2.0*top_up_ny.z-1.0)*(1.0-abs(x_normal)),0.0));base=max(0.0,base);height=max(0.0,height);float t=top_up_ny.x;vec2 centroid_pos=vec2(0.0);\n#if defined(HAS_CENTROID) || defined(TERRAIN)\ncentroid_pos=a_centroid_pos;\n#endif\n#ifdef TERRAIN\nbool flat_roof=centroid_pos.x !=0.0 && t > 0.0;float ele=elevation(pos_nx.xy);float c_ele=flat_roof ? centroid_pos.y==0.0 ? elevationFromUint16(centroid_pos.x) : flatElevation(centroid_pos) : ele;float h=flat_roof ? max(c_ele+height,ele+base+2.0) : ele+(t > 0.0 ? height : base==0.0 ?-5.0 : base);vec3 pos=vec3(pos_nx.xy,h);\n#else\nvec3 pos=vec3(pos_nx.xy,t > 0.0 ? height : base);\n#endif\n#ifdef PROJECTION_GLOBE_VIEW\nfloat lift=float((t+base) > 0.0)*u_height_lift;vec3 globe_normal=normalize(mix(a_pos_normal_3/16384.0,u_up_dir,u_zoom_transition));vec3 globe_pos=a_pos_3+globe_normal*(u_tile_up_scale*(pos.z+lift));vec3 merc_pos=mercator_tile_position(u_inv_rot_matrix,pos.xy,u_tile_id,u_merc_center)+u_up_dir*u_tile_up_scale*pos.z;pos=mix_globe_mercator(globe_pos,merc_pos,u_zoom_transition);\n#endif\nfloat hidden=float(centroid_pos.x==0.0 && centroid_pos.y==1.0);gl_Position=mix(u_matrix*vec4(pos,1),AWAY,hidden);float colorvalue=color.r*0.2126+color.g*0.7152+color.b*0.0722;v_color=vec4(0.0,0.0,0.0,1.0);vec4 ambientlight=vec4(0.03,0.03,0.03,1.0);color+=ambientlight;float directional=clamp(dot(normal,u_lightpos),0.0,1.0);directional=mix((1.0-u_lightintensity),max((1.0-colorvalue+u_lightintensity),1.0),directional);if (normal.y !=0.0) {directional*=(\n(1.0-u_vertical_gradient)+(u_vertical_gradient*clamp((t+base)*pow(height/150.0,0.5),mix(0.7,0.98,1.0-u_lightintensity),1.0)));}v_color.rgb+=clamp(color.rgb*directional*u_lightcolor,mix(vec3(0.0),vec3(0.3),1.0-u_lightcolor),vec3(1.0));v_color*=u_opacity;\n#ifdef FOG\nv_fog_pos=fog_position(pos);\n#endif\n}";

	var fillExtrusionPatternFrag = "uniform vec2 u_texsize;uniform float u_fade;uniform sampler2D u_image;varying vec2 v_pos_a;varying vec2 v_pos_b;varying vec4 v_lighting;\n#pragma mapbox: define lowp float base\n#pragma mapbox: define lowp float height\n#pragma mapbox: define lowp vec4 pattern_from\n#pragma mapbox: define lowp vec4 pattern_to\n#pragma mapbox: define lowp float pixel_ratio_from\n#pragma mapbox: define lowp float pixel_ratio_to\nvoid main() {\n#pragma mapbox: initialize lowp float base\n#pragma mapbox: initialize lowp float height\n#pragma mapbox: initialize mediump vec4 pattern_from\n#pragma mapbox: initialize mediump vec4 pattern_to\n#pragma mapbox: initialize lowp float pixel_ratio_from\n#pragma mapbox: initialize lowp float pixel_ratio_to\nvec2 pattern_tl_a=pattern_from.xy;vec2 pattern_br_a=pattern_from.zw;vec2 pattern_tl_b=pattern_to.xy;vec2 pattern_br_b=pattern_to.zw;vec2 imagecoord=mod(v_pos_a,1.0);vec2 pos=mix(pattern_tl_a/u_texsize,pattern_br_a/u_texsize,imagecoord);vec4 color1=texture2D(u_image,pos);vec2 imagecoord_b=mod(v_pos_b,1.0);vec2 pos2=mix(pattern_tl_b/u_texsize,pattern_br_b/u_texsize,imagecoord_b);vec4 color2=texture2D(u_image,pos2);vec4 out_color=mix(color1,color2,u_fade);out_color=out_color*v_lighting;\n#ifdef FOG\nout_color=fog_dither(fog_apply_premultiplied(out_color,v_fog_pos));\n#endif\ngl_FragColor=out_color;\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var fillExtrusionPatternVert = "uniform mat4 u_matrix;uniform vec2 u_pixel_coord_upper;uniform vec2 u_pixel_coord_lower;uniform float u_height_factor;uniform vec3 u_scale;uniform float u_vertical_gradient;uniform lowp float u_opacity;uniform vec3 u_lightcolor;uniform lowp vec3 u_lightpos;uniform lowp float u_lightintensity;attribute vec4 a_pos_normal_ed;attribute vec2 a_centroid_pos;\n#ifdef PROJECTION_GLOBE_VIEW\nattribute vec3 a_pos_3;attribute vec3 a_pos_normal_3;uniform mat4 u_inv_rot_matrix;uniform vec2 u_merc_center;uniform vec3 u_tile_id;uniform float u_zoom_transition;uniform vec3 u_up_dir;uniform float u_height_lift;\n#endif\nvarying vec2 v_pos_a;varying vec2 v_pos_b;varying vec4 v_lighting;\n#pragma mapbox: define lowp float base\n#pragma mapbox: define lowp float height\n#pragma mapbox: define lowp vec4 pattern_from\n#pragma mapbox: define lowp vec4 pattern_to\n#pragma mapbox: define lowp float pixel_ratio_from\n#pragma mapbox: define lowp float pixel_ratio_to\nvoid main() {\n#pragma mapbox: initialize lowp float base\n#pragma mapbox: initialize lowp float height\n#pragma mapbox: initialize mediump vec4 pattern_from\n#pragma mapbox: initialize mediump vec4 pattern_to\n#pragma mapbox: initialize lowp float pixel_ratio_from\n#pragma mapbox: initialize lowp float pixel_ratio_to\nvec2 pattern_tl_a=pattern_from.xy;vec2 pattern_br_a=pattern_from.zw;vec2 pattern_tl_b=pattern_to.xy;vec2 pattern_br_b=pattern_to.zw;float tileRatio=u_scale.x;float fromScale=u_scale.y;float toScale=u_scale.z;vec3 pos_nx=floor(a_pos_normal_ed.xyz*0.5);mediump vec3 top_up_ny=a_pos_normal_ed.xyz-2.0*pos_nx;float x_normal=pos_nx.z/8192.0;vec3 normal=top_up_ny.y==1.0 ? vec3(0.0,0.0,1.0) : normalize(vec3(x_normal,(2.0*top_up_ny.z-1.0)*(1.0-abs(x_normal)),0.0));float edgedistance=a_pos_normal_ed.w;vec2 display_size_a=(pattern_br_a-pattern_tl_a)/pixel_ratio_from;vec2 display_size_b=(pattern_br_b-pattern_tl_b)/pixel_ratio_to;base=max(0.0,base);height=max(0.0,height);float t=top_up_ny.x;float z=t > 0.0 ? height : base;vec2 centroid_pos=vec2(0.0);\n#if defined(HAS_CENTROID) || defined(TERRAIN)\ncentroid_pos=a_centroid_pos;\n#endif\n#ifdef TERRAIN\nbool flat_roof=centroid_pos.x !=0.0 && t > 0.0;float ele=elevation(pos_nx.xy);float c_ele=flat_roof ? centroid_pos.y==0.0 ? elevationFromUint16(centroid_pos.x) : flatElevation(centroid_pos) : ele;float h=flat_roof ? max(c_ele+height,ele+base+2.0) : ele+(t > 0.0 ? height : base==0.0 ?-5.0 : base);vec3 p=vec3(pos_nx.xy,h);\n#else\nvec3 p=vec3(pos_nx.xy,z);\n#endif\n#ifdef PROJECTION_GLOBE_VIEW\nfloat lift=float((t+base) > 0.0)*u_height_lift;vec3 globe_normal=normalize(mix(a_pos_normal_3/16384.0,u_up_dir,u_zoom_transition));vec3 globe_pos=a_pos_3+globe_normal*(u_tile_up_scale*(p.z+lift));vec3 merc_pos=mercator_tile_position(u_inv_rot_matrix,p.xy,u_tile_id,u_merc_center)+u_up_dir*u_tile_up_scale*p.z;p=mix_globe_mercator(globe_pos,merc_pos,u_zoom_transition);\n#endif\nfloat hidden=float(centroid_pos.x==0.0 && centroid_pos.y==1.0);gl_Position=mix(u_matrix*vec4(p,1),AWAY,hidden);vec2 pos=normal.z==1.0\n? pos_nx.xy\n: vec2(edgedistance,z*u_height_factor);v_pos_a=get_pattern_pos(u_pixel_coord_upper,u_pixel_coord_lower,fromScale*display_size_a,tileRatio,pos);v_pos_b=get_pattern_pos(u_pixel_coord_upper,u_pixel_coord_lower,toScale*display_size_b,tileRatio,pos);v_lighting=vec4(0.0,0.0,0.0,1.0);float directional=clamp(dot(normal,u_lightpos),0.0,1.0);directional=mix((1.0-u_lightintensity),max((0.5+u_lightintensity),1.0),directional);if (normal.y !=0.0) {directional*=(\n(1.0-u_vertical_gradient)+(u_vertical_gradient*clamp((t+base)*pow(height/150.0,0.5),mix(0.7,0.98,1.0-u_lightintensity),1.0)));}v_lighting.rgb+=clamp(directional*u_lightcolor,mix(vec3(0.0),vec3(0.3),1.0-u_lightcolor),vec3(1.0));v_lighting*=u_opacity;\n#ifdef FOG\nv_fog_pos=fog_position(p);\n#endif\n}";

	var hillshadePrepareFrag = "#ifdef GL_ES\nprecision highp float;\n#endif\nuniform sampler2D u_image;varying vec2 v_pos;uniform vec2 u_dimension;uniform float u_zoom;uniform vec4 u_unpack;float getElevation(vec2 coord) {\n#ifdef TERRAIN_DEM_FLOAT_FORMAT\nreturn texture2D(u_image,coord).a/4.0;\n#else\nvec4 data=texture2D(u_image,coord)*255.0;data.a=-1.0;return dot(data,u_unpack)/4.0;\n#endif\n}void main() {vec2 epsilon=1.0/u_dimension;float a=getElevation(v_pos+vec2(-epsilon.x,-epsilon.y));float b=getElevation(v_pos+vec2(0,-epsilon.y));float c=getElevation(v_pos+vec2(epsilon.x,-epsilon.y));float d=getElevation(v_pos+vec2(-epsilon.x,0));float e=getElevation(v_pos);float f=getElevation(v_pos+vec2(epsilon.x,0));float g=getElevation(v_pos+vec2(-epsilon.x,epsilon.y));float h=getElevation(v_pos+vec2(0,epsilon.y));float i=getElevation(v_pos+vec2(epsilon.x,epsilon.y));float exaggerationFactor=u_zoom < 2.0 ? 0.4 : u_zoom < 4.5 ? 0.35 : 0.3;float exaggeration=u_zoom < 15.0 ? (u_zoom-15.0)*exaggerationFactor : 0.0;vec2 deriv=vec2(\n(c+f+f+i)-(a+d+d+g),(g+h+h+i)-(a+b+b+c)\n)/pow(2.0,exaggeration+(19.2562-u_zoom));gl_FragColor=clamp(vec4(\nderiv.x/2.0+0.5,deriv.y/2.0+0.5,1.0,1.0),0.0,1.0);\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var hillshadePrepareVert = "uniform mat4 u_matrix;uniform vec2 u_dimension;attribute vec2 a_pos;attribute vec2 a_texture_pos;varying vec2 v_pos;void main() {gl_Position=u_matrix*vec4(a_pos,0,1);highp vec2 epsilon=1.0/u_dimension;float scale=(u_dimension.x-2.0)/u_dimension.x;v_pos=(a_texture_pos/8192.0)*scale+epsilon;}";

	var hillshadeFrag = "uniform sampler2D u_image;varying vec2 v_pos;uniform vec2 u_latrange;uniform vec2 u_light;uniform vec4 u_shadow;uniform vec4 u_highlight;uniform vec4 u_accent;void main() {vec4 pixel=texture2D(u_image,v_pos);vec2 deriv=((pixel.rg*2.0)-1.0);float scaleFactor=cos(radians((u_latrange[0]-u_latrange[1])*(1.0-v_pos.y)+u_latrange[1]));float slope=atan(1.25*length(deriv)/scaleFactor);float aspect=deriv.x !=0.0 ? atan(deriv.y,-deriv.x) : PI/2.0*(deriv.y > 0.0 ? 1.0 :-1.0);float intensity=u_light.x;float azimuth=u_light.y+PI;float base=1.875-intensity*1.75;float maxValue=0.5*PI;float scaledSlope=intensity !=0.5 ? ((pow(base,slope)-1.0)/(pow(base,maxValue)-1.0))*maxValue : slope;float accent=cos(scaledSlope);vec4 accent_color=(1.0-accent)*u_accent*clamp(intensity*2.0,0.0,1.0);float shade=abs(mod((aspect+azimuth)/PI+0.5,2.0)-1.0);vec4 shade_color=mix(u_shadow,u_highlight,shade)*sin(scaledSlope)*clamp(intensity*2.0,0.0,1.0);gl_FragColor=accent_color*(1.0-shade_color.a)+shade_color;\n#ifdef FOG\ngl_FragColor=fog_dither(fog_apply_premultiplied(gl_FragColor,v_fog_pos));\n#endif\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var hillshadeVert = "uniform mat4 u_matrix;attribute vec2 a_pos;attribute vec2 a_texture_pos;varying vec2 v_pos;void main() {gl_Position=u_matrix*vec4(a_pos,0,1);v_pos=a_texture_pos/8192.0;\n#ifdef FOG\nv_fog_pos=fog_position(a_pos);\n#endif\n}";

	var lineFrag = "uniform lowp float u_device_pixel_ratio;uniform float u_alpha_discard_threshold;uniform highp vec2 u_trim_offset;varying vec2 v_width2;varying vec2 v_normal;varying float v_gamma_scale;varying highp vec4 v_uv;\n#ifdef RENDER_LINE_DASH\nuniform sampler2D u_dash_image;uniform float u_mix;uniform vec3 u_scale;varying vec2 v_tex_a;varying vec2 v_tex_b;\n#endif\n#ifdef RENDER_LINE_GRADIENT\nuniform sampler2D u_gradient_image;\n#endif\n#pragma mapbox: define highp vec4 color\n#pragma mapbox: define lowp float floorwidth\n#pragma mapbox: define lowp vec4 dash_from\n#pragma mapbox: define lowp vec4 dash_to\n#pragma mapbox: define lowp float blur\n#pragma mapbox: define lowp float opacity\nvoid main() {\n#pragma mapbox: initialize highp vec4 color\n#pragma mapbox: initialize lowp float floorwidth\n#pragma mapbox: initialize lowp vec4 dash_from\n#pragma mapbox: initialize lowp vec4 dash_to\n#pragma mapbox: initialize lowp float blur\n#pragma mapbox: initialize lowp float opacity\nfloat dist=length(v_normal)*v_width2.s;float blur2=(blur+1.0/u_device_pixel_ratio)*v_gamma_scale;float alpha=clamp(min(dist-(v_width2.t-blur2),v_width2.s-dist)/blur2,0.0,1.0);\n#ifdef RENDER_LINE_DASH\nfloat sdfdist_a=texture2D(u_dash_image,v_tex_a).a;float sdfdist_b=texture2D(u_dash_image,v_tex_b).a;float sdfdist=mix(sdfdist_a,sdfdist_b,u_mix);float sdfwidth=min(dash_from.z*u_scale.y,dash_to.z*u_scale.z);float sdfgamma=1.0/(2.0*u_device_pixel_ratio)/sdfwidth;alpha*=smoothstep(0.5-sdfgamma/floorwidth,0.5+sdfgamma/floorwidth,sdfdist);\n#endif\n#ifdef RENDER_LINE_GRADIENT\nhighp vec4 out_color=texture2D(u_gradient_image,v_uv.xy);\n#else\nvec4 out_color=color;\n#endif\n#ifdef RENDER_LINE_TRIM_OFFSET\nhighp float start=v_uv[2];highp float end=v_uv[3];highp float trim_start=u_trim_offset[0];highp float trim_end=u_trim_offset[1];highp float line_progress=(start+(v_uv.x)*(end-start));if (trim_end > trim_start) {if (line_progress <=trim_end && line_progress >=trim_start) {out_color=vec4(0,0,0,0);}}\n#endif\n#ifdef FOG\nout_color=fog_dither(fog_apply_premultiplied(out_color,v_fog_pos));\n#endif\n#ifdef RENDER_LINE_ALPHA_DISCARD\nif (alpha < u_alpha_discard_threshold) {discard;}\n#endif\ngl_FragColor=out_color*(alpha*opacity);\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var lineVert = "\n#define EXTRUDE_SCALE 0.015873016\nattribute vec2 a_pos_normal;attribute vec4 a_data;\n#if defined(RENDER_LINE_GRADIENT) || defined(RENDER_LINE_TRIM_OFFSET)\nattribute highp vec4 a_packed;\n#endif\n#ifdef RENDER_LINE_DASH\nattribute float a_linesofar;\n#endif\nuniform mat4 u_matrix;uniform mat2 u_pixels_to_tile_units;uniform vec2 u_units_to_pixels;uniform lowp float u_device_pixel_ratio;varying vec2 v_normal;varying vec2 v_width2;varying float v_gamma_scale;varying highp vec4 v_uv;\n#ifdef RENDER_LINE_DASH\nuniform vec2 u_texsize;uniform mediump vec3 u_scale;varying vec2 v_tex_a;varying vec2 v_tex_b;\n#endif\n#ifdef RENDER_LINE_GRADIENT\nuniform float u_image_height;\n#endif\n#pragma mapbox: define highp vec4 color\n#pragma mapbox: define lowp float floorwidth\n#pragma mapbox: define lowp vec4 dash_from\n#pragma mapbox: define lowp vec4 dash_to\n#pragma mapbox: define lowp float blur\n#pragma mapbox: define lowp float opacity\n#pragma mapbox: define mediump float gapwidth\n#pragma mapbox: define lowp float offset\n#pragma mapbox: define mediump float width\nvoid main() {\n#pragma mapbox: initialize highp vec4 color\n#pragma mapbox: initialize lowp float floorwidth\n#pragma mapbox: initialize lowp vec4 dash_from\n#pragma mapbox: initialize lowp vec4 dash_to\n#pragma mapbox: initialize lowp float blur\n#pragma mapbox: initialize lowp float opacity\n#pragma mapbox: initialize mediump float gapwidth\n#pragma mapbox: initialize lowp float offset\n#pragma mapbox: initialize mediump float width\nfloat ANTIALIASING=1.0/u_device_pixel_ratio/2.0;vec2 a_extrude=a_data.xy-128.0;float a_direction=mod(a_data.z,4.0)-1.0;vec2 pos=floor(a_pos_normal*0.5);mediump vec2 normal=a_pos_normal-2.0*pos;normal.y=normal.y*2.0-1.0;v_normal=normal;gapwidth=gapwidth/2.0;float halfwidth=width/2.0;offset=-1.0*offset;float inset=gapwidth+(gapwidth > 0.0 ? ANTIALIASING : 0.0);float outset=gapwidth+halfwidth*(gapwidth > 0.0 ? 2.0 : 1.0)+(halfwidth==0.0 ? 0.0 : ANTIALIASING);mediump vec2 dist=outset*a_extrude*EXTRUDE_SCALE;mediump float u=0.5*a_direction;mediump float t=1.0-abs(u);mediump vec2 offset2=offset*a_extrude*EXTRUDE_SCALE*normal.y*mat2(t,-u,u,t);vec4 projected_extrude=u_matrix*vec4(dist*u_pixels_to_tile_units,0.0,0.0);gl_Position=u_matrix*vec4(pos+offset2*u_pixels_to_tile_units,0.0,1.0)+projected_extrude;\n#ifndef RENDER_TO_TEXTURE\nfloat extrude_length_without_perspective=length(dist);float extrude_length_with_perspective=length(projected_extrude.xy/gl_Position.w*u_units_to_pixels);v_gamma_scale=extrude_length_without_perspective/extrude_length_with_perspective;\n#else\nv_gamma_scale=1.0;\n#endif\n#if defined(RENDER_LINE_GRADIENT) || defined(RENDER_LINE_TRIM_OFFSET)\nfloat a_uv_x=a_packed[0];float a_split_index=a_packed[1];highp float a_clip_start=a_packed[2];highp float a_clip_end=a_packed[3];\n#ifdef RENDER_LINE_GRADIENT\nhighp float texel_height=1.0/u_image_height;highp float half_texel_height=0.5*texel_height;v_uv=vec4(a_uv_x,a_split_index*texel_height-half_texel_height,a_clip_start,a_clip_end);\n#else\nv_uv=vec4(a_uv_x,0.0,a_clip_start,a_clip_end);\n#endif\n#endif\n#ifdef RENDER_LINE_DASH\nfloat tileZoomRatio=u_scale.x;float fromScale=u_scale.y;float toScale=u_scale.z;float scaleA=dash_from.z==0.0 ? 0.0 : tileZoomRatio/(dash_from.z*fromScale);float scaleB=dash_to.z==0.0 ? 0.0 : tileZoomRatio/(dash_to.z*toScale);float heightA=dash_from.y;float heightB=dash_to.y;v_tex_a=vec2(a_linesofar*scaleA/floorwidth,(-normal.y*heightA+dash_from.x+0.5)/u_texsize.y);v_tex_b=vec2(a_linesofar*scaleB/floorwidth,(-normal.y*heightB+dash_to.x+0.5)/u_texsize.y);\n#endif\nv_width2=vec2(outset,inset);\n#ifdef FOG\nv_fog_pos=fog_position(pos);\n#endif\n}";

	var linePatternFrag = "uniform lowp float u_device_pixel_ratio;uniform vec2 u_texsize;uniform float u_fade;uniform mediump vec3 u_scale;uniform sampler2D u_image;varying vec2 v_normal;varying vec2 v_width2;varying float v_linesofar;varying float v_gamma_scale;varying float v_width;\n#pragma mapbox: define lowp vec4 pattern_from\n#pragma mapbox: define lowp vec4 pattern_to\n#pragma mapbox: define lowp float pixel_ratio_from\n#pragma mapbox: define lowp float pixel_ratio_to\n#pragma mapbox: define lowp float blur\n#pragma mapbox: define lowp float opacity\nvoid main() {\n#pragma mapbox: initialize mediump vec4 pattern_from\n#pragma mapbox: initialize mediump vec4 pattern_to\n#pragma mapbox: initialize lowp float pixel_ratio_from\n#pragma mapbox: initialize lowp float pixel_ratio_to\n#pragma mapbox: initialize lowp float blur\n#pragma mapbox: initialize lowp float opacity\nvec2 pattern_tl_a=pattern_from.xy;vec2 pattern_br_a=pattern_from.zw;vec2 pattern_tl_b=pattern_to.xy;vec2 pattern_br_b=pattern_to.zw;float tileZoomRatio=u_scale.x;float fromScale=u_scale.y;float toScale=u_scale.z;vec2 display_size_a=(pattern_br_a-pattern_tl_a)/pixel_ratio_from;vec2 display_size_b=(pattern_br_b-pattern_tl_b)/pixel_ratio_to;vec2 pattern_size_a=vec2(display_size_a.x*fromScale/tileZoomRatio,display_size_a.y);vec2 pattern_size_b=vec2(display_size_b.x*toScale/tileZoomRatio,display_size_b.y);float aspect_a=display_size_a.y/v_width;float aspect_b=display_size_b.y/v_width;float dist=length(v_normal)*v_width2.s;float blur2=(blur+1.0/u_device_pixel_ratio)*v_gamma_scale;float alpha=clamp(min(dist-(v_width2.t-blur2),v_width2.s-dist)/blur2,0.0,1.0);float x_a=mod(v_linesofar/pattern_size_a.x*aspect_a,1.0);float x_b=mod(v_linesofar/pattern_size_b.x*aspect_b,1.0);float y=0.5*v_normal.y+0.5;vec2 texel_size=1.0/u_texsize;vec2 pos_a=mix(pattern_tl_a*texel_size-texel_size,pattern_br_a*texel_size+texel_size,vec2(x_a,y));vec2 pos_b=mix(pattern_tl_b*texel_size-texel_size,pattern_br_b*texel_size+texel_size,vec2(x_b,y));vec4 color=mix(texture2D(u_image,pos_a),texture2D(u_image,pos_b),u_fade);\n#ifdef FOG\ncolor=fog_dither(fog_apply_premultiplied(color,v_fog_pos));\n#endif\ngl_FragColor=color*(alpha*opacity);\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var linePatternVert = "\n#define scale 0.015873016\nattribute vec2 a_pos_normal;attribute vec4 a_data;attribute float a_linesofar;uniform mat4 u_matrix;uniform vec2 u_units_to_pixels;uniform mat2 u_pixels_to_tile_units;uniform lowp float u_device_pixel_ratio;varying vec2 v_normal;varying vec2 v_width2;varying float v_linesofar;varying float v_gamma_scale;varying float v_width;\n#pragma mapbox: define lowp float blur\n#pragma mapbox: define lowp float opacity\n#pragma mapbox: define lowp float offset\n#pragma mapbox: define mediump float gapwidth\n#pragma mapbox: define mediump float width\n#pragma mapbox: define lowp float floorwidth\n#pragma mapbox: define lowp vec4 pattern_from\n#pragma mapbox: define lowp vec4 pattern_to\n#pragma mapbox: define lowp float pixel_ratio_from\n#pragma mapbox: define lowp float pixel_ratio_to\nvoid main() {\n#pragma mapbox: initialize lowp float blur\n#pragma mapbox: initialize lowp float opacity\n#pragma mapbox: initialize lowp float offset\n#pragma mapbox: initialize mediump float gapwidth\n#pragma mapbox: initialize mediump float width\n#pragma mapbox: initialize lowp float floorwidth\n#pragma mapbox: initialize mediump vec4 pattern_from\n#pragma mapbox: initialize mediump vec4 pattern_to\n#pragma mapbox: initialize lowp float pixel_ratio_from\n#pragma mapbox: initialize lowp float pixel_ratio_to\nfloat ANTIALIASING=1.0/u_device_pixel_ratio/2.0;vec2 a_extrude=a_data.xy-128.0;float a_direction=mod(a_data.z,4.0)-1.0;vec2 pos=floor(a_pos_normal*0.5);mediump vec2 normal=a_pos_normal-2.0*pos;normal.y=normal.y*2.0-1.0;v_normal=normal;gapwidth=gapwidth/2.0;float halfwidth=width/2.0;offset=-1.0*offset;float inset=gapwidth+(gapwidth > 0.0 ? ANTIALIASING : 0.0);float outset=gapwidth+halfwidth*(gapwidth > 0.0 ? 2.0 : 1.0)+(halfwidth==0.0 ? 0.0 : ANTIALIASING);mediump vec2 dist=outset*a_extrude*scale;mediump float u=0.5*a_direction;mediump float t=1.0-abs(u);mediump vec2 offset2=offset*a_extrude*scale*normal.y*mat2(t,-u,u,t);vec4 projected_extrude=u_matrix*vec4(dist*u_pixels_to_tile_units,0.0,0.0);gl_Position=u_matrix*vec4(pos+offset2*u_pixels_to_tile_units,0.0,1.0)+projected_extrude;\n#ifndef RENDER_TO_TEXTURE\nfloat extrude_length_without_perspective=length(dist);float extrude_length_with_perspective=length(projected_extrude.xy/gl_Position.w*u_units_to_pixels);v_gamma_scale=extrude_length_without_perspective/extrude_length_with_perspective;\n#else\nv_gamma_scale=1.0;\n#endif\nv_linesofar=a_linesofar;v_width2=vec2(outset,inset);v_width=floorwidth;\n#ifdef FOG\nv_fog_pos=fog_position(pos);\n#endif\n}";

	var rasterFrag = "uniform float u_fade_t;uniform float u_opacity;uniform sampler2D u_image0;uniform sampler2D u_image1;varying vec2 v_pos0;varying vec2 v_pos1;uniform float u_brightness_low;uniform float u_brightness_high;uniform float u_saturation_factor;uniform float u_contrast_factor;uniform vec3 u_spin_weights;void main() {vec4 color0=texture2D(u_image0,v_pos0);vec4 color1=texture2D(u_image1,v_pos1);if (color0.a > 0.0) {color0.rgb=color0.rgb/color0.a;}if (color1.a > 0.0) {color1.rgb=color1.rgb/color1.a;}vec4 color=mix(color0,color1,u_fade_t);color.a*=u_opacity;vec3 rgb=color.rgb;rgb=vec3(\ndot(rgb,u_spin_weights.xyz),dot(rgb,u_spin_weights.zxy),dot(rgb,u_spin_weights.yzx));float average=(color.r+color.g+color.b)/3.0;rgb+=(average-rgb)*u_saturation_factor;rgb=(rgb-0.5)*u_contrast_factor+0.5;vec3 u_high_vec=vec3(u_brightness_low,u_brightness_low,u_brightness_low);vec3 u_low_vec=vec3(u_brightness_high,u_brightness_high,u_brightness_high);vec3 out_color=mix(u_high_vec,u_low_vec,rgb);\n#ifdef FOG\nout_color=fog_dither(fog_apply(out_color,v_fog_pos));\n#endif\ngl_FragColor=vec4(out_color*color.a,color.a);\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var rasterVert = "uniform mat4 u_matrix;uniform vec2 u_tl_parent;uniform float u_scale_parent;uniform vec2 u_perspective_transform;attribute vec2 a_pos;attribute vec2 a_texture_pos;varying vec2 v_pos0;varying vec2 v_pos1;void main() {float w=1.0+dot(a_texture_pos,u_perspective_transform);gl_Position=u_matrix*vec4(a_pos*w,0,w);v_pos0=a_texture_pos/8192.0;v_pos1=(v_pos0*u_scale_parent)+u_tl_parent;\n#ifdef FOG\nv_fog_pos=fog_position(a_pos);\n#endif\n}";

	var symbolIconFrag = "uniform sampler2D u_texture;varying vec2 v_tex;varying float v_fade_opacity;\n#pragma mapbox: define lowp float opacity\nvoid main() {\n#pragma mapbox: initialize lowp float opacity\nlowp float alpha=opacity*v_fade_opacity;gl_FragColor=texture2D(u_texture,v_tex)*alpha;\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var symbolIconVert = "attribute vec4 a_pos_offset;attribute vec4 a_tex_size;attribute vec4 a_pixeloffset;attribute vec4 a_projected_pos;attribute float a_fade_opacity;\n#ifdef PROJECTION_GLOBE_VIEW\nattribute vec3 a_globe_anchor;attribute vec3 a_globe_normal;\n#endif\nuniform bool u_is_size_zoom_constant;uniform bool u_is_size_feature_constant;uniform highp float u_size_t;uniform highp float u_size;uniform highp float u_camera_to_center_distance;uniform bool u_rotate_symbol;uniform highp float u_aspect_ratio;uniform float u_fade_change;uniform mat4 u_matrix;uniform mat4 u_label_plane_matrix;uniform mat4 u_coord_matrix;uniform bool u_is_text;uniform bool u_pitch_with_map;uniform vec2 u_texsize;uniform vec3 u_up_vector;\n#ifdef PROJECTION_GLOBE_VIEW\nuniform vec3 u_tile_id;uniform mat4 u_inv_rot_matrix;uniform vec2 u_merc_center;uniform vec3 u_camera_forward;uniform float u_zoom_transition;uniform vec3 u_ecef_origin;uniform mat4 u_tile_matrix;\n#endif\nvarying vec2 v_tex;varying float v_fade_opacity;\n#pragma mapbox: define lowp float opacity\nvoid main() {\n#pragma mapbox: initialize lowp float opacity\nvec2 a_pos=a_pos_offset.xy;vec2 a_offset=a_pos_offset.zw;vec2 a_tex=a_tex_size.xy;vec2 a_size=a_tex_size.zw;float a_size_min=floor(a_size[0]*0.5);vec2 a_pxoffset=a_pixeloffset.xy;vec2 a_min_font_scale=a_pixeloffset.zw/256.0;highp float segment_angle=-a_projected_pos[3];float size;if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {size=mix(a_size_min,a_size[1],u_size_t)/128.0;} else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {size=a_size_min/128.0;} else {size=u_size;}vec2 tile_anchor=a_pos;vec3 h=elevationVector(tile_anchor)*elevation(tile_anchor);\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 mercator_pos=mercator_tile_position(u_inv_rot_matrix,tile_anchor,u_tile_id,u_merc_center);vec3 world_pos=mix_globe_mercator(a_globe_anchor+h,mercator_pos,u_zoom_transition);vec4 ecef_point=u_tile_matrix*vec4(world_pos,1.0);vec3 origin_to_point=ecef_point.xyz-u_ecef_origin;float globe_occlusion_fade=dot(origin_to_point,u_camera_forward) >=0.0 ? 0.0 : 1.0;\n#else\nvec3 world_pos=vec3(tile_anchor,0)+h;float globe_occlusion_fade=1.0;\n#endif\nvec4 projected_point=u_matrix*vec4(world_pos,1);highp float camera_to_anchor_distance=projected_point.w;highp float distance_ratio=u_pitch_with_map ?\ncamera_to_anchor_distance/u_camera_to_center_distance :\nu_camera_to_center_distance/camera_to_anchor_distance;highp float perspective_ratio=clamp(\n0.5+0.5*distance_ratio,0.0,1.5);size*=perspective_ratio;float font_scale=u_is_text ? size/24.0 : size;highp float symbol_rotation=0.0;if (u_rotate_symbol) {\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 displacement=vec3(a_globe_normal.z,0,-a_globe_normal.x);vec4 offsetProjected_point=u_matrix*vec4(a_globe_anchor+displacement,1);\n#else\nvec4 offsetProjected_point=u_matrix*vec4(tile_anchor+vec2(1,0),0,1);\n#endif\nvec2 a=projected_point.xy/projected_point.w;vec2 b=offsetProjected_point.xy/offsetProjected_point.w;symbol_rotation=atan((b.y-a.y)/u_aspect_ratio,b.x-a.x);}\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 proj_pos=mix_globe_mercator(a_projected_pos.xyz+h,mercator_pos,u_zoom_transition);vec4 projected_pos=u_label_plane_matrix*vec4(proj_pos,1.0);\n#else\nvec4 projected_pos=u_label_plane_matrix*vec4(a_projected_pos.xy,h.z,1.0);\n#endif\nhighp float angle_sin=sin(segment_angle+symbol_rotation);highp float angle_cos=cos(segment_angle+symbol_rotation);mat2 rotation_matrix=mat2(angle_cos,-1.0*angle_sin,angle_sin,angle_cos);float z=0.0;vec2 offset=rotation_matrix*(a_offset/32.0*max(a_min_font_scale,font_scale)+a_pxoffset/16.0);\n#ifdef PITCH_WITH_MAP_TERRAIN\nvec4 tile_pos=u_label_plane_matrix_inv*vec4(a_projected_pos.xy+offset,0.0,1.0);z=elevation(tile_pos.xy);\n#endif\nfloat occlusion_fade=occlusionFade(projected_point)*globe_occlusion_fade;\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 xAxis=u_pitch_with_map ? normalize(cross(a_globe_normal,u_up_vector)) : vec3(1,0,0);vec3 yAxis=u_pitch_with_map ? normalize(cross(a_globe_normal,xAxis)) : vec3(0,1,0);gl_Position=mix(u_coord_matrix*vec4(projected_pos.xyz/projected_pos.w+xAxis*offset.x+yAxis*offset.y,1.0),AWAY,float(projected_point.w <=0.0 || occlusion_fade==0.0));\n#else\ngl_Position=mix(u_coord_matrix*vec4(projected_pos.xy/projected_pos.w+offset,z,1.0),AWAY,float(projected_point.w <=0.0 || occlusion_fade==0.0));\n#endif\nfloat projection_transition_fade=1.0;\n#if defined(PROJECTED_POS_ON_VIEWPORT) && defined(PROJECTION_GLOBE_VIEW)\nprojection_transition_fade=1.0-step(EPSILON,u_zoom_transition);\n#endif\nv_tex=a_tex/u_texsize;vec2 fade_opacity=unpack_opacity(a_fade_opacity);float fade_change=fade_opacity[1] > 0.5 ? u_fade_change :-u_fade_change;v_fade_opacity=max(0.0,min(occlusion_fade,fade_opacity[0]+fade_change))*projection_transition_fade;}";

	var symbolSDFFrag = "#define SDF_PX 8.0\nuniform bool u_is_halo;uniform sampler2D u_texture;uniform highp float u_gamma_scale;uniform lowp float u_device_pixel_ratio;uniform bool u_is_text;varying vec2 v_data0;varying vec3 v_data1;\n#pragma mapbox: define highp vec4 fill_color\n#pragma mapbox: define highp vec4 halo_color\n#pragma mapbox: define lowp float opacity\n#pragma mapbox: define lowp float halo_width\n#pragma mapbox: define lowp float halo_blur\nvoid main() {\n#pragma mapbox: initialize highp vec4 fill_color\n#pragma mapbox: initialize highp vec4 halo_color\n#pragma mapbox: initialize lowp float opacity\n#pragma mapbox: initialize lowp float halo_width\n#pragma mapbox: initialize lowp float halo_blur\nfloat EDGE_GAMMA=0.105/u_device_pixel_ratio;vec2 tex=v_data0.xy;float gamma_scale=v_data1.x;float size=v_data1.y;float fade_opacity=v_data1[2];float fontScale=u_is_text ? size/24.0 : size;lowp vec4 color=fill_color;highp float gamma=EDGE_GAMMA/(fontScale*u_gamma_scale);lowp float buff=(256.0-64.0)/256.0;if (u_is_halo) {color=halo_color;gamma=(halo_blur*1.19/SDF_PX+EDGE_GAMMA)/(fontScale*u_gamma_scale);buff=(6.0-halo_width/fontScale)/SDF_PX;}lowp float dist=texture2D(u_texture,tex).a;highp float gamma_scaled=gamma*gamma_scale;highp float alpha=smoothstep(buff-gamma_scaled,buff+gamma_scaled,dist);gl_FragColor=color*(alpha*opacity*fade_opacity);\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var symbolSDFVert = "attribute vec4 a_pos_offset;attribute vec4 a_tex_size;attribute vec4 a_pixeloffset;attribute vec4 a_projected_pos;attribute float a_fade_opacity;\n#ifdef PROJECTION_GLOBE_VIEW\nattribute vec3 a_globe_anchor;attribute vec3 a_globe_normal;\n#endif\nuniform bool u_is_size_zoom_constant;uniform bool u_is_size_feature_constant;uniform highp float u_size_t;uniform highp float u_size;uniform mat4 u_matrix;uniform mat4 u_label_plane_matrix;uniform mat4 u_coord_matrix;uniform bool u_is_text;uniform bool u_pitch_with_map;uniform bool u_rotate_symbol;uniform highp float u_aspect_ratio;uniform highp float u_camera_to_center_distance;uniform float u_fade_change;uniform vec2 u_texsize;uniform vec3 u_up_vector;\n#ifdef PROJECTION_GLOBE_VIEW\nuniform vec3 u_tile_id;uniform mat4 u_inv_rot_matrix;uniform vec2 u_merc_center;uniform vec3 u_camera_forward;uniform float u_zoom_transition;uniform vec3 u_ecef_origin;uniform mat4 u_tile_matrix;\n#endif\nvarying vec2 v_data0;varying vec3 v_data1;\n#pragma mapbox: define highp vec4 fill_color\n#pragma mapbox: define highp vec4 halo_color\n#pragma mapbox: define lowp float opacity\n#pragma mapbox: define lowp float halo_width\n#pragma mapbox: define lowp float halo_blur\nvoid main() {\n#pragma mapbox: initialize highp vec4 fill_color\n#pragma mapbox: initialize highp vec4 halo_color\n#pragma mapbox: initialize lowp float opacity\n#pragma mapbox: initialize lowp float halo_width\n#pragma mapbox: initialize lowp float halo_blur\nvec2 a_pos=a_pos_offset.xy;vec2 a_offset=a_pos_offset.zw;vec2 a_tex=a_tex_size.xy;vec2 a_size=a_tex_size.zw;float a_size_min=floor(a_size[0]*0.5);vec2 a_pxoffset=a_pixeloffset.xy;highp float segment_angle=-a_projected_pos[3];float size;if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {size=mix(a_size_min,a_size[1],u_size_t)/128.0;} else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {size=a_size_min/128.0;} else {size=u_size;}vec2 tile_anchor=a_pos;vec3 h=elevationVector(tile_anchor)*elevation(tile_anchor);\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 mercator_pos=mercator_tile_position(u_inv_rot_matrix,tile_anchor,u_tile_id,u_merc_center);vec3 world_pos=mix_globe_mercator(a_globe_anchor+h,mercator_pos,u_zoom_transition);vec4 ecef_point=u_tile_matrix*vec4(world_pos,1.0);vec3 origin_to_point=ecef_point.xyz-u_ecef_origin;float globe_occlusion_fade=dot(origin_to_point,u_camera_forward) >=0.0 ? 0.0 : 1.0;\n#else\nvec3 world_pos=vec3(tile_anchor,0)+h;float globe_occlusion_fade=1.0;\n#endif\nvec4 projected_point=u_matrix*vec4(world_pos,1);highp float camera_to_anchor_distance=projected_point.w;highp float distance_ratio=u_pitch_with_map ?\ncamera_to_anchor_distance/u_camera_to_center_distance :\nu_camera_to_center_distance/camera_to_anchor_distance;highp float perspective_ratio=clamp(\n0.5+0.5*distance_ratio,0.0,1.5);size*=perspective_ratio;float fontScale=u_is_text ? size/24.0 : size;highp float symbol_rotation=0.0;if (u_rotate_symbol) {\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 displacement=vec3(a_globe_normal.z,0,-a_globe_normal.x);vec4 offsetprojected_point=u_matrix*vec4(a_globe_anchor+displacement,1);\n#else\nvec4 offsetprojected_point=u_matrix*vec4(tile_anchor+vec2(1,0),0,1);\n#endif\nvec2 a=projected_point.xy/projected_point.w;vec2 b=offsetprojected_point.xy/offsetprojected_point.w;symbol_rotation=atan((b.y-a.y)/u_aspect_ratio,b.x-a.x);}\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 proj_pos=mix_globe_mercator(a_projected_pos.xyz+h,mercator_pos,u_zoom_transition);vec4 projected_pos=u_label_plane_matrix*vec4(proj_pos,1.0);\n#else\nvec4 projected_pos=u_label_plane_matrix*vec4(a_projected_pos.xy,h.z,1.0);\n#endif\nhighp float angle_sin=sin(segment_angle+symbol_rotation);highp float angle_cos=cos(segment_angle+symbol_rotation);mat2 rotation_matrix=mat2(angle_cos,-1.0*angle_sin,angle_sin,angle_cos);float z=0.0;vec2 offset=rotation_matrix*(a_offset/32.0*fontScale+a_pxoffset);\n#ifdef PITCH_WITH_MAP_TERRAIN\nvec4 tile_pos=u_label_plane_matrix_inv*vec4(a_projected_pos.xy+offset,0.0,1.0);z=elevation(tile_pos.xy);\n#endif\nfloat occlusion_fade=occlusionFade(projected_point)*globe_occlusion_fade;\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 xAxis=u_pitch_with_map ? normalize(cross(a_globe_normal,u_up_vector)) : vec3(1,0,0);vec3 yAxis=u_pitch_with_map ? normalize(cross(a_globe_normal,xAxis)) : vec3(0,1,0);gl_Position=mix(u_coord_matrix*vec4(projected_pos.xyz/projected_pos.w+xAxis*offset.x+yAxis*offset.y,1.0),AWAY,float(projected_point.w <=0.0 || occlusion_fade==0.0));\n#else\ngl_Position=mix(u_coord_matrix*vec4(projected_pos.xy/projected_pos.w+offset,z,1.0),AWAY,float(projected_point.w <=0.0 || occlusion_fade==0.0));\n#endif\nfloat gamma_scale=gl_Position.w;float projection_transition_fade=1.0;\n#if defined(PROJECTED_POS_ON_VIEWPORT) && defined(PROJECTION_GLOBE_VIEW)\nprojection_transition_fade=1.0-step(EPSILON,u_zoom_transition);\n#endif\nvec2 fade_opacity=unpack_opacity(a_fade_opacity);float fade_change=fade_opacity[1] > 0.5 ? u_fade_change :-u_fade_change;float interpolated_fade_opacity=max(0.0,min(occlusion_fade,fade_opacity[0]+fade_change));v_data0=a_tex/u_texsize;v_data1=vec3(gamma_scale,size,interpolated_fade_opacity*projection_transition_fade);}";

	var symbolTextAndIconFrag = "#define SDF_PX 8.0\n#define SDF 1.0\n#define ICON 0.0\nuniform bool u_is_halo;uniform sampler2D u_texture;uniform sampler2D u_texture_icon;uniform highp float u_gamma_scale;uniform lowp float u_device_pixel_ratio;varying vec4 v_data0;varying vec4 v_data1;\n#pragma mapbox: define highp vec4 fill_color\n#pragma mapbox: define highp vec4 halo_color\n#pragma mapbox: define lowp float opacity\n#pragma mapbox: define lowp float halo_width\n#pragma mapbox: define lowp float halo_blur\nvoid main() {\n#pragma mapbox: initialize highp vec4 fill_color\n#pragma mapbox: initialize highp vec4 halo_color\n#pragma mapbox: initialize lowp float opacity\n#pragma mapbox: initialize lowp float halo_width\n#pragma mapbox: initialize lowp float halo_blur\nfloat fade_opacity=v_data1[2];if (v_data1.w==ICON) {vec2 tex_icon=v_data0.zw;lowp float alpha=opacity*fade_opacity;gl_FragColor=texture2D(u_texture_icon,tex_icon)*alpha;\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\nreturn;}vec2 tex=v_data0.xy;float EDGE_GAMMA=0.105/u_device_pixel_ratio;float gamma_scale=v_data1.x;float size=v_data1.y;float fontScale=size/24.0;lowp vec4 color=fill_color;highp float gamma=EDGE_GAMMA/(fontScale*u_gamma_scale);lowp float buff=(256.0-64.0)/256.0;if (u_is_halo) {color=halo_color;gamma=(halo_blur*1.19/SDF_PX+EDGE_GAMMA)/(fontScale*u_gamma_scale);buff=(6.0-halo_width/fontScale)/SDF_PX;}lowp float dist=texture2D(u_texture,tex).a;highp float gamma_scaled=gamma*gamma_scale;highp float alpha=smoothstep(buff-gamma_scaled,buff+gamma_scaled,dist);gl_FragColor=color*(alpha*opacity*fade_opacity);\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var symbolTextAndIconVert = "attribute vec4 a_pos_offset;attribute vec4 a_tex_size;attribute vec4 a_projected_pos;attribute float a_fade_opacity;\n#ifdef PROJECTION_GLOBE_VIEW\nattribute vec3 a_globe_anchor;attribute vec3 a_globe_normal;\n#endif\nuniform bool u_is_size_zoom_constant;uniform bool u_is_size_feature_constant;uniform highp float u_size_t;uniform highp float u_size;uniform mat4 u_matrix;uniform mat4 u_label_plane_matrix;uniform mat4 u_coord_matrix;uniform bool u_is_text;uniform bool u_pitch_with_map;uniform bool u_rotate_symbol;uniform highp float u_aspect_ratio;uniform highp float u_camera_to_center_distance;uniform float u_fade_change;uniform vec2 u_texsize;uniform vec3 u_up_vector;uniform vec2 u_texsize_icon;\n#ifdef PROJECTION_GLOBE_VIEW\nuniform vec3 u_tile_id;uniform mat4 u_inv_rot_matrix;uniform vec2 u_merc_center;uniform vec3 u_camera_forward;uniform float u_zoom_transition;uniform vec3 u_ecef_origin;uniform mat4 u_tile_matrix;\n#endif\nvarying vec4 v_data0;varying vec4 v_data1;\n#pragma mapbox: define highp vec4 fill_color\n#pragma mapbox: define highp vec4 halo_color\n#pragma mapbox: define lowp float opacity\n#pragma mapbox: define lowp float halo_width\n#pragma mapbox: define lowp float halo_blur\nvoid main() {\n#pragma mapbox: initialize highp vec4 fill_color\n#pragma mapbox: initialize highp vec4 halo_color\n#pragma mapbox: initialize lowp float opacity\n#pragma mapbox: initialize lowp float halo_width\n#pragma mapbox: initialize lowp float halo_blur\nvec2 a_pos=a_pos_offset.xy;vec2 a_offset=a_pos_offset.zw;vec2 a_tex=a_tex_size.xy;vec2 a_size=a_tex_size.zw;float a_size_min=floor(a_size[0]*0.5);float is_sdf=a_size[0]-2.0*a_size_min;highp float segment_angle=-a_projected_pos[3];float size;if (!u_is_size_zoom_constant && !u_is_size_feature_constant) {size=mix(a_size_min,a_size[1],u_size_t)/128.0;} else if (u_is_size_zoom_constant && !u_is_size_feature_constant) {size=a_size_min/128.0;} else {size=u_size;}vec2 tile_anchor=a_pos;vec3 h=elevationVector(tile_anchor)*elevation(tile_anchor);\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 mercator_pos=mercator_tile_position(u_inv_rot_matrix,tile_anchor,u_tile_id,u_merc_center);vec3 world_pos=mix_globe_mercator(a_globe_anchor+h,mercator_pos,u_zoom_transition);vec4 ecef_point=u_tile_matrix*vec4(world_pos,1.0);vec3 origin_to_point=ecef_point.xyz-u_ecef_origin;float globe_occlusion_fade=dot(origin_to_point,u_camera_forward) >=0.0 ? 0.0 : 1.0;\n#else\nvec3 world_pos=vec3(tile_anchor,0)+h;float globe_occlusion_fade=1.0;\n#endif\nvec4 projected_point=u_matrix*vec4(world_pos,1);highp float camera_to_anchor_distance=projected_point.w;highp float distance_ratio=u_pitch_with_map ?\ncamera_to_anchor_distance/u_camera_to_center_distance :\nu_camera_to_center_distance/camera_to_anchor_distance;highp float perspective_ratio=clamp(\n0.5+0.5*distance_ratio,0.0,1.5);size*=perspective_ratio;float font_scale=size/24.0;highp float symbol_rotation=0.0;if (u_rotate_symbol) {vec4 offset_projected_point=u_matrix*vec4(a_pos+vec2(1,0),0,1);vec2 a=projected_point.xy/projected_point.w;vec2 b=offset_projected_point.xy/offset_projected_point.w;symbol_rotation=atan((b.y-a.y)/u_aspect_ratio,b.x-a.x);}\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 proj_pos=mix_globe_mercator(a_projected_pos.xyz+h,mercator_pos,u_zoom_transition);vec4 projected_pos=u_label_plane_matrix*vec4(proj_pos,1.0);\n#else\nvec4 projected_pos=u_label_plane_matrix*vec4(a_projected_pos.xy,h.z,1.0);\n#endif\nhighp float angle_sin=sin(segment_angle+symbol_rotation);highp float angle_cos=cos(segment_angle+symbol_rotation);mat2 rotation_matrix=mat2(angle_cos,-1.0*angle_sin,angle_sin,angle_cos);float z=0.0;vec2 offset=rotation_matrix*(a_offset/32.0*font_scale);\n#ifdef PITCH_WITH_MAP_TERRAIN\nvec4 tile_pos=u_label_plane_matrix_inv*vec4(a_projected_pos.xy+offset,0.0,1.0);z=elevation(tile_pos.xy);\n#endif\nfloat occlusion_fade=occlusionFade(projected_point)*globe_occlusion_fade;\n#ifdef PROJECTION_GLOBE_VIEW\nvec3 xAxis=u_pitch_with_map ? normalize(cross(a_globe_normal,u_up_vector)) : vec3(1,0,0);vec3 yAxis=u_pitch_with_map ? normalize(cross(a_globe_normal,xAxis)) : vec3(0,1,0);gl_Position=mix(u_coord_matrix*vec4(projected_pos.xyz/projected_pos.w+xAxis*offset.x+yAxis*offset.y,1.0),AWAY,float(projected_point.w <=0.0 || occlusion_fade==0.0));\n#else\ngl_Position=mix(u_coord_matrix*vec4(projected_pos.xy/projected_pos.w+offset,z,1.0),AWAY,float(projected_point.w <=0.0 || occlusion_fade==0.0));\n#endif\nfloat gamma_scale=gl_Position.w;vec2 fade_opacity=unpack_opacity(a_fade_opacity);float fade_change=fade_opacity[1] > 0.5 ? u_fade_change :-u_fade_change;float interpolated_fade_opacity=max(0.0,min(occlusion_fade,fade_opacity[0]+fade_change));float projection_transition_fade=1.0;\n#if defined(PROJECTED_POS_ON_VIEWPORT) && defined(PROJECTION_GLOBE_VIEW)\nprojection_transition_fade=1.0-step(EPSILON,u_zoom_transition);\n#endif\nv_data0.xy=a_tex/u_texsize;v_data0.zw=a_tex/u_texsize_icon;v_data1=vec4(gamma_scale,size,interpolated_fade_opacity*projection_transition_fade,is_sdf);}";

	var skyboxFrag = "\nvarying lowp vec3 v_uv;uniform lowp samplerCube u_cubemap;uniform lowp float u_opacity;uniform highp float u_temporal_offset;uniform highp vec3 u_sun_direction;float sun_disk(highp vec3 ray_direction,highp vec3 sun_direction) {highp float cos_angle=dot(normalize(ray_direction),sun_direction);const highp float cos_sun_angular_diameter=0.99996192306;const highp float smoothstep_delta=1e-5;return smoothstep(\ncos_sun_angular_diameter-smoothstep_delta,cos_sun_angular_diameter+smoothstep_delta,cos_angle);}float map(float value,float start,float end,float new_start,float new_end) {return ((value-start)*(new_end-new_start))/(end-start)+new_start;}void main() {vec3 uv=v_uv;const float y_bias=0.015;uv.y+=y_bias;uv.y=pow(abs(uv.y),1.0/5.0);uv.y=map(uv.y,0.0,1.0,-1.0,1.0);vec3 sky_color=textureCube(u_cubemap,uv).rgb;\n#ifdef FOG\nsky_color=fog_apply_sky_gradient(v_uv.xzy,sky_color);\n#endif\nsky_color.rgb=dither(sky_color.rgb,gl_FragCoord.xy+u_temporal_offset);sky_color+=0.1*sun_disk(v_uv,u_sun_direction);gl_FragColor=vec4(sky_color*u_opacity,u_opacity);\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var skyboxGradientFrag = "varying highp vec3 v_uv;uniform lowp sampler2D u_color_ramp;uniform highp vec3 u_center_direction;uniform lowp float u_radius;uniform lowp float u_opacity;uniform highp float u_temporal_offset;void main() {float progress=acos(dot(normalize(v_uv),u_center_direction))/u_radius;vec4 color=texture2D(u_color_ramp,vec2(progress,0.5));\n#ifdef FOG\ncolor.rgb=fog_apply_sky_gradient(v_uv.xzy,color.rgb/color.a)*color.a;\n#endif\ncolor*=u_opacity;color.rgb=dither(color.rgb,gl_FragCoord.xy+u_temporal_offset);gl_FragColor=color;\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var skyboxVert = "attribute highp vec3 a_pos_3f;uniform lowp mat4 u_matrix;varying highp vec3 v_uv;void main() {const mat3 half_neg_pi_around_x=mat3(1.0,0.0, 0.0,0.0,0.0,-1.0,0.0,1.0, 0.0);v_uv=half_neg_pi_around_x*a_pos_3f;vec4 pos=u_matrix*vec4(a_pos_3f,1.0);gl_Position=pos.xyww;}";

	var terrainRasterFrag = "uniform sampler2D u_image0;varying vec2 v_pos0;\n#ifdef FOG\nvarying float v_fog_opacity;\n#endif\nvoid main() {vec4 color=texture2D(u_image0,v_pos0);\n#ifdef FOG\ncolor=fog_dither(fog_apply_from_vert(color,v_fog_opacity));\n#endif\ngl_FragColor=color;\n#ifdef TERRAIN_WIREFRAME\ngl_FragColor=vec4(1.0,0.0,0.0,0.8);\n#endif\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var terrainRasterVert = "uniform mat4 u_matrix;uniform float u_skirt_height;attribute vec2 a_pos;attribute vec2 a_texture_pos;varying vec2 v_pos0;\n#ifdef FOG\nvarying float v_fog_opacity;\n#endif\nconst float skirtOffset=24575.0;const float wireframeOffset=0.00015;void main() {v_pos0=a_texture_pos/8192.0;float skirt=float(a_pos.x >=skirtOffset);float elevation=elevation(a_texture_pos)-skirt*u_skirt_height;\n#ifdef TERRAIN_WIREFRAME\nelevation+=u_skirt_height*u_skirt_height*wireframeOffset;\n#endif\nvec2 decodedPos=a_pos-vec2(skirt*skirtOffset,0.0);gl_Position=u_matrix*vec4(decodedPos,elevation,1.0);\n#ifdef FOG\nv_fog_opacity=fog(fog_position(vec3(decodedPos,elevation)));\n#endif\n}";

	var terrainDepthFrag = "#ifdef GL_ES\nprecision highp float;\n#endif\nvarying float v_depth;void main() {gl_FragColor=pack_depth(v_depth);}";

	var terrainDepthVert = "uniform mat4 u_matrix;attribute vec2 a_pos;attribute vec2 a_texture_pos;varying float v_depth;void main() {float elevation=elevation(a_texture_pos);gl_Position=u_matrix*vec4(a_pos,elevation,1.0);v_depth=gl_Position.z/gl_Position.w;}";

	var preludeTerrainVert = "\n#define ELEVATION_SCALE 7.0\n#define ELEVATION_OFFSET 450.0\n#ifdef PROJECTION_GLOBE_VIEW\nuniform vec3 u_tile_tl_up;uniform vec3 u_tile_tr_up;uniform vec3 u_tile_br_up;uniform vec3 u_tile_bl_up;uniform float u_tile_up_scale;vec3 elevationVector(vec2 pos) {vec2 uv=pos/EXTENT;vec3 up=normalize(mix(\nmix(u_tile_tl_up,u_tile_tr_up,uv.xxx),mix(u_tile_bl_up,u_tile_br_up,uv.xxx),uv.yyy));return up*u_tile_up_scale;}\n#else\nvec3 elevationVector(vec2 pos) { return vec3(0,0,1); }\n#endif\n#ifdef TERRAIN\n#ifdef TERRAIN_DEM_FLOAT_FORMAT\nuniform highp sampler2D u_dem;uniform highp sampler2D u_dem_prev;\n#else\nuniform sampler2D u_dem;uniform sampler2D u_dem_prev;\n#endif\nuniform vec4 u_dem_unpack;uniform vec2 u_dem_tl;uniform vec2 u_dem_tl_prev;uniform float u_dem_scale;uniform float u_dem_scale_prev;uniform float u_dem_size;uniform float u_dem_lerp;uniform float u_exaggeration;uniform float u_meter_to_dem;uniform mat4 u_label_plane_matrix_inv;uniform sampler2D u_depth;uniform vec2 u_depth_size_inv;vec4 tileUvToDemSample(vec2 uv,float dem_size,float dem_scale,vec2 dem_tl) {vec2 pos=dem_size*(uv*dem_scale+dem_tl)+1.0;vec2 f=fract(pos);return vec4((pos-f+0.5)/(dem_size+2.0),f);}float decodeElevation(vec4 v) {return dot(vec4(v.xyz*255.0,-1.0),u_dem_unpack);}float currentElevation(vec2 apos) {\n#ifdef TERRAIN_DEM_FLOAT_FORMAT\nvec2 pos=(u_dem_size*(apos/8192.0*u_dem_scale+u_dem_tl)+1.5)/(u_dem_size+2.0);return u_exaggeration*texture2D(u_dem,pos).a;\n#else\nfloat dd=1.0/(u_dem_size+2.0);vec4 r=tileUvToDemSample(apos/8192.0,u_dem_size,u_dem_scale,u_dem_tl);vec2 pos=r.xy;vec2 f=r.zw;float tl=decodeElevation(texture2D(u_dem,pos));\n#ifdef TERRAIN_DEM_NEAREST_FILTER\nreturn u_exaggeration*tl;\n#endif\nfloat tr=decodeElevation(texture2D(u_dem,pos+vec2(dd,0.0)));float bl=decodeElevation(texture2D(u_dem,pos+vec2(0.0,dd)));float br=decodeElevation(texture2D(u_dem,pos+vec2(dd,dd)));return u_exaggeration*mix(mix(tl,tr,f.x),mix(bl,br,f.x),f.y);\n#endif\n}float prevElevation(vec2 apos) {\n#ifdef TERRAIN_DEM_FLOAT_FORMAT\nvec2 pos=(u_dem_size*(apos/8192.0*u_dem_scale_prev+u_dem_tl_prev)+1.5)/(u_dem_size+2.0);return u_exaggeration*texture2D(u_dem_prev,pos).a;\n#else\nfloat dd=1.0/(u_dem_size+2.0);vec4 r=tileUvToDemSample(apos/8192.0,u_dem_size,u_dem_scale_prev,u_dem_tl_prev);vec2 pos=r.xy;vec2 f=r.zw;float tl=decodeElevation(texture2D(u_dem_prev,pos));float tr=decodeElevation(texture2D(u_dem_prev,pos+vec2(dd,0.0)));float bl=decodeElevation(texture2D(u_dem_prev,pos+vec2(0.0,dd)));float br=decodeElevation(texture2D(u_dem_prev,pos+vec2(dd,dd)));return u_exaggeration*mix(mix(tl,tr,f.x),mix(bl,br,f.x),f.y);\n#endif\n}\n#ifdef TERRAIN_VERTEX_MORPHING\nfloat elevation(vec2 apos) {float nextElevation=currentElevation(apos);float prevElevation=prevElevation(apos);return mix(prevElevation,nextElevation,u_dem_lerp);}\n#else\nfloat elevation(vec2 apos) {return currentElevation(apos);}\n#endif\nfloat unpack_depth(vec4 rgba_depth)\n{const vec4 bit_shift=vec4(1.0/(256.0*256.0*256.0),1.0/(256.0*256.0),1.0/256.0,1.0);return dot(rgba_depth,bit_shift)*2.0-1.0;}bool isOccluded(vec4 frag) {vec3 coord=frag.xyz/frag.w;float depth=unpack_depth(texture2D(u_depth,(coord.xy+1.0)*0.5));return coord.z > depth+0.0005;}float occlusionFade(vec4 frag) {vec3 coord=frag.xyz/frag.w;vec3 df=vec3(5.0*u_depth_size_inv,0.0);vec2 uv=0.5*coord.xy+0.5;vec4 depth=vec4(\nunpack_depth(texture2D(u_depth,uv-df.xz)),unpack_depth(texture2D(u_depth,uv+df.xz)),unpack_depth(texture2D(u_depth,uv-df.zy)),unpack_depth(texture2D(u_depth,uv+df.zy))\n);return dot(vec4(0.25),vec4(1.0)-clamp(300.0*(vec4(coord.z-0.001)-depth),0.0,1.0));}vec4 fourSample(vec2 pos,vec2 off) {\n#ifdef TERRAIN_DEM_FLOAT_FORMAT\nfloat tl=texture2D(u_dem,pos).a;float tr=texture2D(u_dem,pos+vec2(off.x,0.0)).a;float bl=texture2D(u_dem,pos+vec2(0.0,off.y)).a;float br=texture2D(u_dem,pos+off).a;\n#else\nvec4 demtl=vec4(texture2D(u_dem,pos).xyz*255.0,-1.0);float tl=dot(demtl,u_dem_unpack);vec4 demtr=vec4(texture2D(u_dem,pos+vec2(off.x,0.0)).xyz*255.0,-1.0);float tr=dot(demtr,u_dem_unpack);vec4 dembl=vec4(texture2D(u_dem,pos+vec2(0.0,off.y)).xyz*255.0,-1.0);float bl=dot(dembl,u_dem_unpack);vec4 dembr=vec4(texture2D(u_dem,pos+off).xyz*255.0,-1.0);float br=dot(dembr,u_dem_unpack);\n#endif\nreturn vec4(tl,tr,bl,br);}float flatElevation(vec2 pack) {vec2 apos=floor(pack/8.0);vec2 span=10.0*(pack-apos*8.0);vec2 uvTex=(apos-vec2(1.0,1.0))/8190.0;float size=u_dem_size+2.0;float dd=1.0/size;vec2 pos=u_dem_size*(uvTex*u_dem_scale+u_dem_tl)+1.0;vec2 f=fract(pos);pos=(pos-f+0.5)*dd;vec4 h=fourSample(pos,vec2(dd));float z=mix(mix(h.x,h.y,f.x),mix(h.z,h.w,f.x),f.y);vec2 w=floor(0.5*(span*u_meter_to_dem-1.0));vec2 d=dd*w;vec4 bounds=vec4(d,vec2(1.0)-d);h=fourSample(pos-d,2.0*d+vec2(dd));vec4 diff=abs(h.xzxy-h.ywzw);vec2 slope=min(vec2(0.25),u_meter_to_dem*0.5*(diff.xz+diff.yw)/(2.0*w+vec2(1.0)));vec2 fix=slope*span;float base=z+max(fix.x,fix.y);return u_exaggeration*base;}float elevationFromUint16(float word) {return u_exaggeration*(word/ELEVATION_SCALE-ELEVATION_OFFSET);}\n#else\nfloat elevation(vec2 pos) { return 0.0; }bool isOccluded(vec4 frag) { return false; }float occlusionFade(vec4 frag) { return 1.0; }\n#endif";

	var preludeFogVert = "#ifdef FOG\nuniform mediump vec4 u_fog_color;uniform mediump vec2 u_fog_range;uniform mediump float u_fog_horizon_blend;uniform mediump mat4 u_fog_matrix;varying vec3 v_fog_pos;float fog_range(float depth) {return (depth-u_fog_range[0])/(u_fog_range[1]-u_fog_range[0]);}float fog_horizon_blending(vec3 camera_dir) {float t=max(0.0,camera_dir.z/u_fog_horizon_blend);return u_fog_color.a*exp(-3.0*t*t);}float fog_opacity(float t) {const float decay=6.0;float falloff=1.0-min(1.0,exp(-decay*t));falloff*=falloff*falloff;return u_fog_color.a*min(1.0,1.00747*falloff);}vec3 fog_position(vec3 pos) {return (u_fog_matrix*vec4(pos,1.0)).xyz;}vec3 fog_position(vec2 pos) {return fog_position(vec3(pos,0.0));}float fog(vec3 pos) {float depth=length(pos);float opacity=fog_opacity(fog_range(depth));return opacity*fog_horizon_blending(pos/depth);}\n#endif";

	var preludeFogFrag = "#ifdef FOG\nuniform mediump vec4 u_fog_color;uniform mediump vec2 u_fog_range;uniform mediump float u_fog_horizon_blend;uniform mediump float u_fog_temporal_offset;varying vec3 v_fog_pos;uniform highp vec3 u_frustum_tl;uniform highp vec3 u_frustum_tr;uniform highp vec3 u_frustum_br;uniform highp vec3 u_frustum_bl;uniform highp vec3 u_globe_pos;uniform highp float u_globe_radius;uniform highp vec2 u_viewport;uniform float u_globe_transition;uniform int u_is_globe;float fog_range(float depth) {return (depth-u_fog_range[0])/(u_fog_range[1]-u_fog_range[0]);}float fog_horizon_blending(vec3 camera_dir) {float t=max(0.0,camera_dir.z/u_fog_horizon_blend);return u_fog_color.a*exp(-3.0*t*t);}float fog_opacity(float t) {const float decay=6.0;float falloff=1.0-min(1.0,exp(-decay*t));falloff*=falloff*falloff;return u_fog_color.a*min(1.0,1.00747*falloff);}float globe_glow_progress() {highp vec2 uv=gl_FragCoord.xy/u_viewport;highp vec3 ray_dir=mix(\nmix(u_frustum_tl,u_frustum_tr,uv.x),mix(u_frustum_bl,u_frustum_br,uv.x),1.0-uv.y);highp vec3 dir=normalize(ray_dir);highp vec3 closest_point=dot(u_globe_pos,dir)*dir;highp float sdf=length(closest_point-u_globe_pos)/u_globe_radius;return sdf+PI*0.5;}float fog_opacity(vec3 pos) {float depth=length(pos);return fog_opacity(fog_range(depth));}vec3 fog_apply(vec3 color,vec3 pos) {float depth=length(pos);float opacity;if (u_is_globe==1) {float glow_progress=globe_glow_progress();float t=mix(glow_progress,depth,u_globe_transition);opacity=fog_opacity(fog_range(t));} else {opacity=fog_opacity(fog_range(depth));opacity*=fog_horizon_blending(pos/depth);}return mix(color,u_fog_color.rgb,opacity);}vec4 fog_apply_from_vert(vec4 color,float fog_opac) {float alpha=EPSILON+color.a;color.rgb=mix(color.rgb/alpha,u_fog_color.rgb,fog_opac)*alpha;return color;}vec3 fog_apply_sky_gradient(vec3 camera_ray,vec3 sky_color) {float horizon_blend=fog_horizon_blending(normalize(camera_ray));return mix(sky_color,u_fog_color.rgb,horizon_blend);}vec4 fog_apply_premultiplied(vec4 color,vec3 pos) {float alpha=EPSILON+color.a;color.rgb=fog_apply(color.rgb/alpha,pos)*alpha;return color;}vec3 fog_dither(vec3 color) {vec2 dither_seed=gl_FragCoord.xy+u_fog_temporal_offset;return dither(color,dither_seed);}vec4 fog_dither(vec4 color) {return vec4(fog_dither(color.rgb),color.a);}\n#endif";

	var skyboxCaptureFrag = "\nvarying highp vec3 v_position;uniform highp float u_sun_intensity;uniform highp float u_luminance;uniform lowp vec3 u_sun_direction;uniform highp vec4 u_color_tint_r;uniform highp vec4 u_color_tint_m;\n#ifdef GL_ES\nprecision highp float;\n#endif\n#define BETA_R                  vec3(5.5e-6,13.0e-6,22.4e-6)\n#define BETA_M                  vec3(21e-6,21e-6,21e-6)\n#define MIE_G                   0.76\n#define DENSITY_HEIGHT_SCALE_R  8000.0\n#define DENSITY_HEIGHT_SCALE_M  1200.0\n#define PLANET_RADIUS           6360e3\n#define ATMOSPHERE_RADIUS       6420e3\n#define SAMPLE_STEPS            10\n#define DENSITY_STEPS           4\nfloat ray_sphere_exit(vec3 orig,vec3 dir,float radius) {float a=dot(dir,dir);float b=2.0*dot(dir,orig);float c=dot(orig,orig)-radius*radius;float d=sqrt(b*b-4.0*a*c);return (-b+d)/(2.0*a);}vec3 extinction(vec2 density) {return exp(-vec3(BETA_R*u_color_tint_r.a*density.x+BETA_M*u_color_tint_m.a*density.y));}vec2 local_density(vec3 point) {float height=max(length(point)-PLANET_RADIUS,0.0);float exp_r=exp(-height/DENSITY_HEIGHT_SCALE_R);float exp_m=exp(-height/DENSITY_HEIGHT_SCALE_M);return vec2(exp_r,exp_m);}float phase_ray(float cos_angle) {return (3.0/(16.0*PI))*(1.0+cos_angle*cos_angle);}float phase_mie(float cos_angle) {return (3.0/(8.0*PI))*((1.0-MIE_G*MIE_G)*(1.0+cos_angle*cos_angle))/((2.0+MIE_G*MIE_G)*pow(1.0+MIE_G*MIE_G-2.0*MIE_G*cos_angle,1.5));}vec2 density_to_atmosphere(vec3 point,vec3 light_dir) {float ray_len=ray_sphere_exit(point,light_dir,ATMOSPHERE_RADIUS);float step_len=ray_len/float(DENSITY_STEPS);vec2 density_point_to_atmosphere=vec2(0.0);for (int i=0; i < DENSITY_STEPS;++i) {vec3 point_on_ray=point+light_dir*((float(i)+0.5)*step_len);density_point_to_atmosphere+=local_density(point_on_ray)*step_len;;}return density_point_to_atmosphere;}vec3 atmosphere(vec3 ray_dir,vec3 sun_direction,float sun_intensity) {vec2 density_orig_to_point=vec2(0.0);vec3 scatter_r=vec3(0.0);vec3 scatter_m=vec3(0.0);vec3 origin=vec3(0.0,PLANET_RADIUS,0.0);float ray_len=ray_sphere_exit(origin,ray_dir,ATMOSPHERE_RADIUS);float step_len=ray_len/float(SAMPLE_STEPS);for (int i=0; i < SAMPLE_STEPS;++i) {vec3 point_on_ray=origin+ray_dir*((float(i)+0.5)*step_len);vec2 density=local_density(point_on_ray)*step_len;density_orig_to_point+=density;vec2 density_point_to_atmosphere=density_to_atmosphere(point_on_ray,sun_direction);vec2 density_orig_to_atmosphere=density_orig_to_point+density_point_to_atmosphere;vec3 extinction=extinction(density_orig_to_atmosphere);scatter_r+=density.x*extinction;scatter_m+=density.y*extinction;}float cos_angle=dot(ray_dir,sun_direction);float phase_r=phase_ray(cos_angle);float phase_m=phase_mie(cos_angle);vec3 beta_r=BETA_R*u_color_tint_r.rgb*u_color_tint_r.a;vec3 beta_m=BETA_M*u_color_tint_m.rgb*u_color_tint_m.a;return (scatter_r*phase_r*beta_r+scatter_m*phase_m*beta_m)*sun_intensity;}const float A=0.15;const float B=0.50;const float C=0.10;const float D=0.20;const float E=0.02;const float F=0.30;vec3 uncharted2_tonemap(vec3 x) {return ((x*(A*x+C*B)+D*E)/(x*(A*x+B)+D*F))-E/F;}void main() {vec3 ray_direction=v_position;ray_direction.y=pow(ray_direction.y,5.0);const float y_bias=0.015;ray_direction.y+=y_bias;vec3 color=atmosphere(normalize(ray_direction),u_sun_direction,u_sun_intensity);float white_scale=1.0748724675633854;color=uncharted2_tonemap((log2(2.0/pow(u_luminance,4.0)))*color)*white_scale;gl_FragColor=vec4(color,1.0);}";

	var skyboxCaptureVert = "attribute highp vec3 a_pos_3f;uniform mat3 u_matrix_3f;varying highp vec3 v_position;float map(float value,float start,float end,float new_start,float new_end) {return ((value-start)*(new_end-new_start))/(end-start)+new_start;}void main() {vec4 pos=vec4(u_matrix_3f*a_pos_3f,1.0);v_position=pos.xyz;v_position.y*=-1.0;v_position.y=map(v_position.y,-1.0,1.0,0.0,1.0);gl_Position=vec4(a_pos_3f.xy,0.0,1.0);}";

	var globeFrag = "uniform sampler2D u_image0;varying vec2 v_pos0;\n#ifndef FOG\nuniform highp vec3 u_frustum_tl;uniform highp vec3 u_frustum_tr;uniform highp vec3 u_frustum_br;uniform highp vec3 u_frustum_bl;uniform highp vec3 u_globe_pos;uniform highp float u_globe_radius;uniform vec2 u_viewport;\n#endif\nvoid main() {\n#ifdef CUSTOM_ANTIALIASING\nvec2 uv=gl_FragCoord.xy/u_viewport;highp vec3 ray_dir=mix(\nmix(u_frustum_tl,u_frustum_tr,uv.x),mix(u_frustum_bl,u_frustum_br,uv.x),1.0-uv.y);vec3 dir=normalize(ray_dir);vec3 closest_point=dot(u_globe_pos,dir)*dir;float norm_dist_from_center=1.0-length(closest_point-u_globe_pos)/u_globe_radius;const float antialias_pixel=2.0;float antialias_factor=antialias_pixel*fwidth(norm_dist_from_center);float antialias=smoothstep(0.0,antialias_factor,norm_dist_from_center);vec4 raster=texture2D(u_image0,v_pos0);vec4 color=vec4(raster.rgb*antialias,raster.a*antialias);\n#else\nvec4 color=texture2D(u_image0,v_pos0);\n#endif\n#ifdef FOG\ncolor=fog_dither(fog_apply_premultiplied(color,v_fog_pos));\n#endif\ngl_FragColor=color;\n#ifdef TERRAIN_WIREFRAME\ngl_FragColor=vec4(1.0,0.0,0.0,0.8);\n#endif\n#ifdef OVERDRAW_INSPECTOR\ngl_FragColor=vec4(1.0);\n#endif\n}";

	var globeVert = "uniform mat4 u_proj_matrix;uniform mat4 u_normalize_matrix;uniform mat4 u_globe_matrix;uniform mat4 u_merc_matrix;uniform float u_zoom_transition;uniform vec2 u_merc_center;uniform mat3 u_grid_matrix;\n#ifdef GLOBE_POLES\nattribute vec3 a_globe_pos;attribute vec2 a_merc_pos;attribute vec2 a_uv;\n#else\nattribute vec2 a_pos;\n#endif\nvarying vec2 v_pos0;const float wireframeOffset=1e3;float mercatorXfromLng(float lng) {return (180.0+lng)/360.0;}float mercatorYfromLat(float lat) {return (180.0-(RAD_TO_DEG*log(tan(QUARTER_PI+lat/2.0*DEG_TO_RAD))))/360.0;}vec3 latLngToECEF(vec2 latLng) {latLng=DEG_TO_RAD*latLng;float cosLat=cos(latLng[0]);float sinLat=sin(latLng[0]);float cosLng=cos(latLng[1]);float sinLng=sin(latLng[1]);float sx=cosLat*sinLng*GLOBE_RADIUS;float sy=-sinLat*GLOBE_RADIUS;float sz=cosLat*cosLng*GLOBE_RADIUS;return vec3(sx,sy,sz);}void main() {\n#ifdef GLOBE_POLES\nvec3 globe_pos=a_globe_pos;vec2 merc_pos=a_merc_pos;vec2 uv=a_uv;\n#else\nfloat tiles=u_grid_matrix[0][2];float idy=u_grid_matrix[1][2];float S=u_grid_matrix[2][2];vec3 latLng=u_grid_matrix*vec3(a_pos,1.0);float mercatorY=mercatorYfromLat(latLng[0]);float uvY=mercatorY*tiles-idy;float mercatorX=mercatorXfromLng(latLng[1]);float uvX=a_pos[0]*S;vec3 globe_pos=latLngToECEF(latLng.xy);vec2 merc_pos=vec2(mercatorX,mercatorY);vec2 uv=vec2(uvX,uvY);\n#endif\nv_pos0=uv;uv=uv*EXTENT;vec4 up_vector=vec4(elevationVector(uv),1.0);float height=elevation(uv);\n#ifdef TERRAIN_WIREFRAME\nheight+=wireframeOffset;\n#endif\nglobe_pos+=up_vector.xyz*height;vec4 globe=u_globe_matrix*vec4(globe_pos,1.0);vec4 mercator=vec4(0.0);if (u_zoom_transition > 0.0) {mercator=vec4(merc_pos,height,1.0);mercator.xy-=u_merc_center;mercator.x=wrap(mercator.x,-0.5,0.5);mercator=u_merc_matrix*mercator;}vec3 position=mix(globe.xyz,mercator.xyz,u_zoom_transition);gl_Position=u_proj_matrix*vec4(position,1.0);\n#ifdef FOG\nv_fog_pos=fog_position((u_normalize_matrix*vec4(globe_pos,1.0)).xyz);\n#endif\n}";

	var atmosphereFrag = "uniform float u_transition;uniform highp float u_fadeout_range;uniform highp float u_temporal_offset;uniform vec3 u_start_color;uniform vec4 u_color;uniform vec4 u_space_color;uniform vec4 u_high_color;uniform float u_star_intensity;uniform float u_star_size;uniform float u_star_density;uniform float u_horizon_angle;uniform mat4 u_rotation_matrix;varying highp vec3 v_ray_dir;varying highp vec3 v_horizon_dir;highp float random(highp vec3 p) {p=fract(p*vec3(23.2342,97.1231,91.2342));p+=dot(p.zxy,p.yxz+123.1234);return fract(p.x*p.y);}float stars(vec3 p,float scale,vec2 offset) {vec2 uv_scale=(u_viewport/u_star_size)*scale;vec3 position=vec3(p.xy*uv_scale+offset*u_viewport,p.z);vec3 q=fract(position)-0.5;vec3 id=floor(position);float random_visibility=step(random(id),u_star_density);float circle=smoothstep(0.5+u_star_intensity,0.5,length(q));return circle*random_visibility;}void main() {highp vec3 dir=normalize(v_ray_dir);\n#ifdef PROJECTION_GLOBE_VIEW\nfloat globe_pos_dot_dir=dot(u_globe_pos,dir);highp vec3 closest_point_forward=abs(globe_pos_dot_dir)*dir;float norm_dist_from_center=length(closest_point_forward-u_globe_pos)/u_globe_radius;if (norm_dist_from_center < 0.98) {discard;return;}\n#endif\nhighp vec3 horizon_dir=normalize(v_horizon_dir);float horizon_angle_mercator=dir.y < horizon_dir.y ?\n0.0 : max(acos(dot(dir,horizon_dir)),0.0);\n#ifdef PROJECTION_GLOBE_VIEW\nhighp vec3 closest_point=globe_pos_dot_dir*dir;float closest_point_to_center=length(closest_point-u_globe_pos);float theta=asin(clamp(closest_point_to_center/length(u_globe_pos),-1.0,1.0));float horizon_angle=globe_pos_dot_dir < 0.0 ?\nPI-theta-u_horizon_angle : theta-u_horizon_angle;float angle_t=pow(u_transition,10.0);horizon_angle=mix(horizon_angle,horizon_angle_mercator,angle_t);\n#else\nfloat horizon_angle=horizon_angle_mercator;\n#endif\nhorizon_angle/=PI;float t=exp(-horizon_angle/u_fadeout_range);float alpha_0=u_color.a;float alpha_1=u_high_color.a;float alpha_2=u_space_color.a;vec3 color_stop_0=u_color.rgb;vec3 color_stop_1=u_high_color.rgb;vec3 color_stop_2=u_space_color.rgb;vec3 c0=mix(color_stop_2,color_stop_1,alpha_1);vec3 c1=mix(c0,color_stop_0,alpha_0);vec3 c2=mix(c0,c1,t);vec3 c =mix(color_stop_2,c2,t);float a0=mix(alpha_2,1.0,alpha_1);float a1=mix(a0,1.0,alpha_0);float a2=mix(a0,a1,t);float a =mix(alpha_2,a2,t);vec2 uv=gl_FragCoord.xy/u_viewport-0.5;float aspect_ratio=u_viewport.x/u_viewport.y;vec4 uv_dir=vec4(normalize(vec3(uv.x*aspect_ratio,uv.y,1.0)),1.0);uv_dir=u_rotation_matrix*uv_dir;vec3 n=abs(uv_dir.xyz);vec2 uv_remap=(n.x > n.y && n.x > n.z) ? uv_dir.yz/uv_dir.x:\n(n.y > n.x && n.y > n.z) ? uv_dir.zx/uv_dir.y:\nuv_dir.xy/uv_dir.z;uv_remap.x/=aspect_ratio;vec3 D=vec3(uv_remap,1.0);highp float star_field=0.0;if (u_star_intensity > 0.0) {star_field+=stars(D,1.2,vec2(0.0,0.0));star_field+=stars(D,1.0,vec2(1.0,0.0));star_field+=stars(D,0.8,vec2(0.0,1.0));star_field+=stars(D,0.6,vec2(1.0,1.0));star_field*=(1.0-pow(t,0.25+(1.0-u_high_color.a)*0.75));c+=star_field*alpha_2;}c=dither(c,gl_FragCoord.xy+u_temporal_offset);gl_FragColor=vec4(c,a);}";

	var atmosphereVert = "attribute vec3 a_pos;attribute vec2 a_uv;uniform vec3 u_frustum_tl;uniform vec3 u_frustum_tr;uniform vec3 u_frustum_br;uniform vec3 u_frustum_bl;uniform float u_horizon;varying highp vec3 v_ray_dir;varying highp vec3 v_horizon_dir;void main() {v_ray_dir=mix(\nmix(u_frustum_tl,u_frustum_tr,a_uv.x),mix(u_frustum_bl,u_frustum_br,a_uv.x),a_uv.y);v_horizon_dir=mix(\nmix(u_frustum_tl,u_frustum_bl,u_horizon),mix(u_frustum_tr,u_frustum_br,u_horizon),a_uv.x);gl_Position=vec4(a_pos,1.0);}";

	let preludeTerrain = {};
	let preludeFog = {};
	preludeTerrain = compile('', preludeTerrainVert, true);
	preludeFog = compile(preludeFogFrag, preludeFogVert, true);
	const prelude = compile(preludeFrag, preludeVert);
	const preludeCommonSource = preludeCommon;
	const preludeVertPrecisionQualifiers = `
	#ifdef GL_ES
	precision highp float;
	#else

	#if !defined(lowp)
	#define lowp
	#endif

	#if !defined(mediump)
	#define mediump
	#endif

	#if !defined(highp)
	#define highp
	#endif

	#endif`;
	const preludeFragPrecisionQualifiers = `
	#ifdef GL_ES
	precision mediump float;
	#else

	#if !defined(lowp)
	#define lowp
	#endif

	#if !defined(mediump)
	#define mediump
	#endif

	#if !defined(highp)
	#define highp
	#endif

	#endif`;
	const standardDerivativesExt = '#extension GL_OES_standard_derivatives : enable\n';
	var shaders = {
	    background: compile(backgroundFrag, backgroundVert),
	    backgroundPattern: compile(backgroundPatternFrag, backgroundPatternVert),
	    circle: compile(circleFrag, circleVert),
	    clippingMask: compile(clippingMaskFrag, clippingMaskVert),
	    heatmap: compile(heatmapFrag, heatmapVert),
	    heatmapTexture: compile(heatmapTextureFrag, heatmapTextureVert),
	    collisionBox: compile(collisionBoxFrag, collisionBoxVert),
	    collisionCircle: compile(collisionCircleFrag, collisionCircleVert),
	    debug: compile(debugFrag, debugVert),
	    fill: compile(fillFrag, fillVert),
	    fillOutline: compile(fillOutlineFrag, fillOutlineVert),
	    fillOutlinePattern: compile(fillOutlinePatternFrag, fillOutlinePatternVert),
	    fillPattern: compile(fillPatternFrag, fillPatternVert),
	    fillExtrusion: compile(fillExtrusionFrag, fillExtrusionVert),
	    fillExtrusionPattern: compile(fillExtrusionPatternFrag, fillExtrusionPatternVert),
	    hillshadePrepare: compile(hillshadePrepareFrag, hillshadePrepareVert),
	    hillshade: compile(hillshadeFrag, hillshadeVert),
	    line: compile(lineFrag, lineVert),
	    linePattern: compile(linePatternFrag, linePatternVert),
	    raster: compile(rasterFrag, rasterVert),
	    symbolIcon: compile(symbolIconFrag, symbolIconVert),
	    symbolSDF: compile(symbolSDFFrag, symbolSDFVert),
	    symbolTextAndIcon: compile(symbolTextAndIconFrag, symbolTextAndIconVert),
	    terrainRaster: compile(terrainRasterFrag, terrainRasterVert),
	    terrainDepth: compile(terrainDepthFrag, terrainDepthVert),
	    skybox: compile(skyboxFrag, skyboxVert),
	    skyboxGradient: compile(skyboxGradientFrag, skyboxVert),
	    skyboxCapture: compile(skyboxCaptureFrag, skyboxCaptureVert),
	    globeRaster: compile(globeFrag, globeVert),
	    globeAtmosphere: compile(atmosphereFrag, atmosphereVert)
	};
	function compile(fragmentSource, vertexSource, isGlobalPrelude) {
	    const pragmaRegex = /#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g;
	    const uniformRegex = /uniform (highp |mediump |lowp )?([\w]+) ([\w]+)([\s]*)([\w]*)/g;
	    const attributeRegex = /attribute (highp |mediump |lowp )?([\w]+) ([\w]+)/g;
	    const staticAttributes = vertexSource.match(attributeRegex);
	    const fragmentUniforms = fragmentSource.match(uniformRegex);
	    const vertexUniforms = vertexSource.match(uniformRegex);
	    const commonUniforms = preludeCommon.match(uniformRegex);
	    let staticUniforms = vertexUniforms ? vertexUniforms.concat(fragmentUniforms) : fragmentUniforms;
	    if (!isGlobalPrelude) {
	        if (preludeTerrain.staticUniforms) {
	            staticUniforms = preludeTerrain.staticUniforms.concat(staticUniforms);
	        }
	        if (preludeFog.staticUniforms) {
	            staticUniforms = preludeFog.staticUniforms.concat(staticUniforms);
	        }
	    }
	    if (staticUniforms) {
	        staticUniforms = staticUniforms.concat(commonUniforms);
	    }
	    const fragmentPragmas = {};
	    fragmentSource = fragmentSource.replace(pragmaRegex, (match, operation, precision, type, name) => {
	        fragmentPragmas[name] = true;
	        if (operation === 'define') {
	            return `
	#ifndef HAS_UNIFORM_u_${ name }
	varying ${ precision } ${ type } ${ name };
	#else
	uniform ${ precision } ${ type } u_${ name };
	#endif
	`;
	        } else {
	            return `
	#ifdef HAS_UNIFORM_u_${ name }
	    ${ precision } ${ type } ${ name } = u_${ name };
	#endif
	`;
	        }
	    });
	    vertexSource = vertexSource.replace(pragmaRegex, (match, operation, precision, type, name) => {
	        const attrType = type === 'float' ? 'vec2' : 'vec4';
	        const unpackType = name.match(/color/) ? 'color' : attrType;
	        if (fragmentPragmas[name]) {
	            if (operation === 'define') {
	                return `
	#ifndef HAS_UNIFORM_u_${ name }
	uniform lowp float u_${ name }_t;
	attribute ${ precision } ${ attrType } a_${ name };
	varying ${ precision } ${ type } ${ name };
	#else
	uniform ${ precision } ${ type } u_${ name };
	#endif
	`;
	            } else {
	                if (unpackType === 'vec4') {
	                    return `
	#ifndef HAS_UNIFORM_u_${ name }
	    ${ name } = a_${ name };
	#else
	    ${ precision } ${ type } ${ name } = u_${ name };
	#endif
	`;
	                } else {
	                    return `
	#ifndef HAS_UNIFORM_u_${ name }
	    ${ name } = unpack_mix_${ unpackType }(a_${ name }, u_${ name }_t);
	#else
	    ${ precision } ${ type } ${ name } = u_${ name };
	#endif
	`;
	                }
	            }
	        } else {
	            if (operation === 'define') {
	                return `
	#ifndef HAS_UNIFORM_u_${ name }
	uniform lowp float u_${ name }_t;
	attribute ${ precision } ${ attrType } a_${ name };
	#else
	uniform ${ precision } ${ type } u_${ name };
	#endif
	`;
	            } else {
	                if (unpackType === 'vec4') {
	                    return `
	#ifndef HAS_UNIFORM_u_${ name }
	    ${ precision } ${ type } ${ name } = a_${ name };
	#else
	    ${ precision } ${ type } ${ name } = u_${ name };
	#endif
	`;
	                } else {
	                    return `
	#ifndef HAS_UNIFORM_u_${ name }
	    ${ precision } ${ type } ${ name } = unpack_mix_${ unpackType }(a_${ name }, u_${ name }_t);
	#else
	    ${ precision } ${ type } ${ name } = u_${ name };
	#endif
	`;
	                }
	            }
	        }
	    });
	    return {
	        fragmentSource,
	        vertexSource,
	        staticAttributes,
	        staticUniforms
	    };
	}

	class VertexArrayObject {
	    constructor() {
	        this.boundProgram = null;
	        this.boundLayoutVertexBuffer = null;
	        this.boundPaintVertexBuffers = [];
	        this.boundIndexBuffer = null;
	        this.boundVertexOffset = null;
	        this.boundDynamicVertexBuffer = null;
	        this.vao = null;
	    }
	    bind(context, program, layoutVertexBuffer, paintVertexBuffers, indexBuffer, vertexOffset, dynamicVertexBuffer, dynamicVertexBuffer2, dynamicVertexBuffer3) {
	        this.context = context;
	        let paintBuffersDiffer = this.boundPaintVertexBuffers.length !== paintVertexBuffers.length;
	        for (let i = 0; !paintBuffersDiffer && i < paintVertexBuffers.length; i++) {
	            if (this.boundPaintVertexBuffers[i] !== paintVertexBuffers[i]) {
	                paintBuffersDiffer = true;
	            }
	        }
	        const isFreshBindRequired = !this.vao || this.boundProgram !== program || this.boundLayoutVertexBuffer !== layoutVertexBuffer || paintBuffersDiffer || this.boundIndexBuffer !== indexBuffer || this.boundVertexOffset !== vertexOffset || this.boundDynamicVertexBuffer !== dynamicVertexBuffer || this.boundDynamicVertexBuffer2 !== dynamicVertexBuffer2 || this.boundDynamicVertexBuffer3 !== dynamicVertexBuffer3;
	        if (!context.extVertexArrayObject || isFreshBindRequired) {
	            this.freshBind(program, layoutVertexBuffer, paintVertexBuffers, indexBuffer, vertexOffset, dynamicVertexBuffer, dynamicVertexBuffer2, dynamicVertexBuffer3);
	        } else {
	            context.bindVertexArrayOES.set(this.vao);
	            if (dynamicVertexBuffer) {
	                dynamicVertexBuffer.bind();
	            }
	            if (indexBuffer && indexBuffer.dynamicDraw) {
	                indexBuffer.bind();
	            }
	            if (dynamicVertexBuffer2) {
	                dynamicVertexBuffer2.bind();
	            }
	            if (dynamicVertexBuffer3) {
	                dynamicVertexBuffer3.bind();
	            }
	        }
	    }
	    freshBind(program, layoutVertexBuffer, paintVertexBuffers, indexBuffer, vertexOffset, dynamicVertexBuffer, dynamicVertexBuffer2, dynamicVertexBuffer3) {
	        let numPrevAttributes;
	        const numNextAttributes = program.numAttributes;
	        const context = this.context;
	        const gl = context.gl;
	        if (context.extVertexArrayObject) {
	            if (this.vao)
	                this.destroy();
	            this.vao = context.extVertexArrayObject.createVertexArrayOES();
	            context.bindVertexArrayOES.set(this.vao);
	            numPrevAttributes = 0;
	            this.boundProgram = program;
	            this.boundLayoutVertexBuffer = layoutVertexBuffer;
	            this.boundPaintVertexBuffers = paintVertexBuffers;
	            this.boundIndexBuffer = indexBuffer;
	            this.boundVertexOffset = vertexOffset;
	            this.boundDynamicVertexBuffer = dynamicVertexBuffer;
	            this.boundDynamicVertexBuffer2 = dynamicVertexBuffer2;
	            this.boundDynamicVertexBuffer3 = dynamicVertexBuffer3;
	        } else {
	            numPrevAttributes = context.currentNumAttributes || 0;
	            for (let i = numNextAttributes; i < numPrevAttributes; i++) {
	                gl.disableVertexAttribArray(i);
	            }
	        }
	        layoutVertexBuffer.enableAttributes(gl, program);
	        for (const vertexBuffer of paintVertexBuffers) {
	            vertexBuffer.enableAttributes(gl, program);
	        }
	        if (dynamicVertexBuffer) {
	            dynamicVertexBuffer.enableAttributes(gl, program);
	        }
	        if (dynamicVertexBuffer2) {
	            dynamicVertexBuffer2.enableAttributes(gl, program);
	        }
	        if (dynamicVertexBuffer3) {
	            dynamicVertexBuffer3.enableAttributes(gl, program);
	        }
	        layoutVertexBuffer.bind();
	        layoutVertexBuffer.setVertexAttribPointers(gl, program, vertexOffset);
	        for (const vertexBuffer of paintVertexBuffers) {
	            vertexBuffer.bind();
	            vertexBuffer.setVertexAttribPointers(gl, program, vertexOffset);
	        }
	        if (dynamicVertexBuffer) {
	            dynamicVertexBuffer.bind();
	            dynamicVertexBuffer.setVertexAttribPointers(gl, program, vertexOffset);
	        }
	        if (indexBuffer) {
	            indexBuffer.bind();
	        }
	        if (dynamicVertexBuffer2) {
	            dynamicVertexBuffer2.bind();
	            dynamicVertexBuffer2.setVertexAttribPointers(gl, program, vertexOffset);
	        }
	        if (dynamicVertexBuffer3) {
	            dynamicVertexBuffer3.bind();
	            dynamicVertexBuffer3.setVertexAttribPointers(gl, program, vertexOffset);
	        }
	        context.currentNumAttributes = numNextAttributes;
	    }
	    destroy() {
	        if (this.vao) {
	            this.context.extVertexArrayObject.deleteVertexArrayOES(this.vao);
	            this.vao = null;
	        }
	    }
	}

	const hillshadeUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_image': new ref_properties.Uniform1i(context, locations.u_image),
	    'u_latrange': new ref_properties.Uniform2f(context, locations.u_latrange),
	    'u_light': new ref_properties.Uniform2f(context, locations.u_light),
	    'u_shadow': new ref_properties.UniformColor(context, locations.u_shadow),
	    'u_highlight': new ref_properties.UniformColor(context, locations.u_highlight),
	    'u_accent': new ref_properties.UniformColor(context, locations.u_accent)
	});
	const hillshadePrepareUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_image': new ref_properties.Uniform1i(context, locations.u_image),
	    'u_dimension': new ref_properties.Uniform2f(context, locations.u_dimension),
	    'u_zoom': new ref_properties.Uniform1f(context, locations.u_zoom),
	    'u_unpack': new ref_properties.Uniform4f(context, locations.u_unpack)
	});
	const hillshadeUniformValues = (painter, tile, layer, matrix) => {
	    const shadow = layer.paint.get('hillshade-shadow-color');
	    const highlight = layer.paint.get('hillshade-highlight-color');
	    const accent = layer.paint.get('hillshade-accent-color');
	    let azimuthal = layer.paint.get('hillshade-illumination-direction') * (Math.PI / 180);
	    if (layer.paint.get('hillshade-illumination-anchor') === 'viewport') {
	        azimuthal -= painter.transform.angle;
	    }
	    const align = !painter.options.moving;
	    return {
	        'u_matrix': matrix ? matrix : painter.transform.calculateProjMatrix(tile.tileID.toUnwrapped(), align),
	        'u_image': 0,
	        'u_latrange': getTileLatRange(painter, tile.tileID),
	        'u_light': [
	            layer.paint.get('hillshade-exaggeration'),
	            azimuthal
	        ],
	        'u_shadow': shadow,
	        'u_highlight': highlight,
	        'u_accent': accent
	    };
	};
	const hillshadeUniformPrepareValues = (tileID, dem) => {
	    const stride = dem.stride;
	    const matrix = ref_properties.create();
	    ref_properties.ortho(matrix, 0, ref_properties.EXTENT, -ref_properties.EXTENT, 0, 0, 1);
	    ref_properties.translate(matrix, matrix, [
	        0,
	        -ref_properties.EXTENT,
	        0
	    ]);
	    return {
	        'u_matrix': matrix,
	        'u_image': 1,
	        'u_dimension': [
	            stride,
	            stride
	        ],
	        'u_zoom': tileID.overscaledZ,
	        'u_unpack': dem.unpackVector
	    };
	};
	function getTileLatRange(painter, tileID) {
	    const tilesAtZoom = Math.pow(2, tileID.canonical.z);
	    const y = tileID.canonical.y;
	    return [
	        new ref_properties.MercatorCoordinate(0, y / tilesAtZoom).toLngLat().lat,
	        new ref_properties.MercatorCoordinate(0, (y + 1) / tilesAtZoom).toLngLat().lat
	    ];
	}

	function drawHillshade(painter, sourceCache, layer, tileIDs) {
	    if (painter.renderPass !== 'offscreen' && painter.renderPass !== 'translucent')
	        return;
	    const context = painter.context;
	    const depthMode = painter.depthModeForSublayer(0, ref_properties.DepthMode.ReadOnly);
	    const colorMode = painter.colorModeForRenderPass();
	    const renderingToTexture = painter.terrain && painter.terrain.renderingToTexture;
	    const [stencilModes, coords] = painter.renderPass === 'translucent' && !renderingToTexture ? painter.stencilConfigForOverlap(tileIDs) : [
	        {},
	        tileIDs
	    ];
	    for (const coord of coords) {
	        const tile = sourceCache.getTile(coord);
	        if (tile.needsHillshadePrepare && painter.renderPass === 'offscreen') {
	            prepareHillshade(painter, tile, layer, depthMode, ref_properties.StencilMode.disabled, colorMode);
	        } else if (painter.renderPass === 'translucent') {
	            const stencilMode = renderingToTexture && painter.terrain ? painter.terrain.stencilModeForRTTOverlap(coord) : stencilModes[coord.overscaledZ];
	            renderHillshade(painter, coord, tile, layer, depthMode, stencilMode, colorMode);
	        }
	    }
	    context.viewport.set([
	        0,
	        0,
	        painter.width,
	        painter.height
	    ]);
	    painter.resetStencilClippingMasks();
	}
	function renderHillshade(painter, coord, tile, layer, depthMode, stencilMode, colorMode) {
	    const context = painter.context;
	    const gl = context.gl;
	    const fbo = tile.fbo;
	    if (!fbo)
	        return;
	    painter.prepareDrawTile();
	    const program = painter.useProgram('hillshade');
	    context.activeTexture.set(gl.TEXTURE0);
	    gl.bindTexture(gl.TEXTURE_2D, fbo.colorAttachment.get());
	    const uniformValues = hillshadeUniformValues(painter, tile, layer, painter.terrain ? coord.projMatrix : null);
	    painter.prepareDrawProgram(context, program, coord.toUnwrapped());
	    const {tileBoundsBuffer, tileBoundsIndexBuffer, tileBoundsSegments} = painter.getTileBoundsBuffers(tile);
	    program.draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode, ref_properties.CullFaceMode.disabled, uniformValues, layer.id, tileBoundsBuffer, tileBoundsIndexBuffer, tileBoundsSegments);
	}
	function prepareDEMTexture(painter, tile, dem) {
	    if (!tile.needsDEMTextureUpload)
	        return;
	    const context = painter.context;
	    const gl = context.gl;
	    context.pixelStoreUnpackPremultiplyAlpha.set(false);
	    const textureStride = dem.stride;
	    tile.demTexture = tile.demTexture || painter.getTileTexture(textureStride);
	    const pixelData = dem.getPixels();
	    if (tile.demTexture) {
	        tile.demTexture.update(pixelData, { premultiply: false });
	    } else {
	        tile.demTexture = new ref_properties.Texture(context, pixelData, gl.RGBA, { premultiply: false });
	    }
	    tile.needsDEMTextureUpload = false;
	}
	function prepareHillshade(painter, tile, layer, depthMode, stencilMode, colorMode) {
	    const context = painter.context;
	    const gl = context.gl;
	    if (!tile.dem)
	        return;
	    const dem = tile.dem;
	    context.activeTexture.set(gl.TEXTURE1);
	    prepareDEMTexture(painter, tile, dem);
	    if (!tile.demTexture)
	        return;
	    tile.demTexture.bind(gl.NEAREST, gl.CLAMP_TO_EDGE);
	    const tileSize = dem.dim;
	    context.activeTexture.set(gl.TEXTURE0);
	    let fbo = tile.fbo;
	    if (!fbo) {
	        const renderTexture = new ref_properties.Texture(context, {
	            width: tileSize,
	            height: tileSize,
	            data: null
	        }, gl.RGBA);
	        renderTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	        fbo = tile.fbo = context.createFramebuffer(tileSize, tileSize, true);
	        fbo.colorAttachment.set(renderTexture.texture);
	    }
	    context.bindFramebuffer.set(fbo.framebuffer);
	    context.viewport.set([
	        0,
	        0,
	        tileSize,
	        tileSize
	    ]);
	    const {tileBoundsBuffer, tileBoundsIndexBuffer, tileBoundsSegments} = painter.getMercatorTileBoundsBuffers();
	    painter.useProgram('hillshadePrepare').draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode, ref_properties.CullFaceMode.disabled, hillshadeUniformPrepareValues(tile.tileID, dem), layer.id, tileBoundsBuffer, tileBoundsIndexBuffer, tileBoundsSegments);
	    tile.needsHillshadePrepare = false;
	}

	const terrainRasterUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_image0': new ref_properties.Uniform1i(context, locations.u_image0),
	    'u_skirt_height': new ref_properties.Uniform1f(context, locations.u_skirt_height)
	});
	const terrainRasterUniformValues = (matrix, skirtHeight) => ({
	    'u_matrix': matrix,
	    'u_image0': 0,
	    'u_skirt_height': skirtHeight
	});

	const globeRasterUniforms = (context, locations) => ({
	    'u_proj_matrix': new ref_properties.UniformMatrix4f(context, locations.u_proj_matrix),
	    'u_globe_matrix': new ref_properties.UniformMatrix4f(context, locations.u_globe_matrix),
	    'u_normalize_matrix': new ref_properties.UniformMatrix4f(context, locations.u_normalize_matrix),
	    'u_merc_matrix': new ref_properties.UniformMatrix4f(context, locations.u_merc_matrix),
	    'u_zoom_transition': new ref_properties.Uniform1f(context, locations.u_zoom_transition),
	    'u_merc_center': new ref_properties.Uniform2f(context, locations.u_merc_center),
	    'u_image0': new ref_properties.Uniform1i(context, locations.u_image0),
	    'u_grid_matrix': new ref_properties.UniformMatrix3f(context, locations.u_grid_matrix),
	    'u_frustum_tl': new ref_properties.Uniform3f(context, locations.u_frustum_tl),
	    'u_frustum_tr': new ref_properties.Uniform3f(context, locations.u_frustum_tr),
	    'u_frustum_br': new ref_properties.Uniform3f(context, locations.u_frustum_br),
	    'u_frustum_bl': new ref_properties.Uniform3f(context, locations.u_frustum_bl),
	    'u_globe_pos': new ref_properties.Uniform3f(context, locations.u_globe_pos),
	    'u_globe_radius': new ref_properties.Uniform1f(context, locations.u_globe_radius),
	    'u_viewport': new ref_properties.Uniform2f(context, locations.u_viewport)
	});
	const atmosphereUniforms = (context, locations) => ({
	    'u_frustum_tl': new ref_properties.Uniform3f(context, locations.u_frustum_tl),
	    'u_frustum_tr': new ref_properties.Uniform3f(context, locations.u_frustum_tr),
	    'u_frustum_br': new ref_properties.Uniform3f(context, locations.u_frustum_br),
	    'u_frustum_bl': new ref_properties.Uniform3f(context, locations.u_frustum_bl),
	    'u_horizon': new ref_properties.Uniform1f(context, locations.u_horizon),
	    'u_transition': new ref_properties.Uniform1f(context, locations.u_transition),
	    'u_fadeout_range': new ref_properties.Uniform1f(context, locations.u_fadeout_range),
	    'u_color': new ref_properties.Uniform4f(context, locations.u_color),
	    'u_high_color': new ref_properties.Uniform4f(context, locations.u_high_color),
	    'u_space_color': new ref_properties.Uniform4f(context, locations.u_space_color),
	    'u_star_intensity': new ref_properties.Uniform1f(context, locations.u_star_intensity),
	    'u_star_density': new ref_properties.Uniform1f(context, locations.u_star_density),
	    'u_star_size': new ref_properties.Uniform1f(context, locations.u_star_size),
	    'u_temporal_offset': new ref_properties.Uniform1f(context, locations.u_temporal_offset),
	    'u_horizon_angle': new ref_properties.Uniform1f(context, locations.u_horizon_angle),
	    'u_rotation_matrix': new ref_properties.UniformMatrix4f(context, locations.u_rotation_matrix)
	});
	const globeRasterUniformValues = (projMatrix, globeMatrix, globeMercatorMatrix, normalizeMatrix, zoomTransition, mercCenter, frustumDirTl, frustumDirTr, frustumDirBr, frustumDirBl, globePosition, globeRadius, viewport, gridMatrix) => ({
	    'u_proj_matrix': Float32Array.from(projMatrix),
	    'u_globe_matrix': globeMatrix,
	    'u_normalize_matrix': Float32Array.from(normalizeMatrix),
	    'u_merc_matrix': globeMercatorMatrix,
	    'u_zoom_transition': zoomTransition,
	    'u_merc_center': mercCenter,
	    'u_image0': 0,
	    'u_frustum_tl': frustumDirTl,
	    'u_frustum_tr': frustumDirTr,
	    'u_frustum_br': frustumDirBr,
	    'u_frustum_bl': frustumDirBl,
	    'u_globe_pos': globePosition,
	    'u_globe_radius': globeRadius,
	    'u_viewport': viewport,
	    'u_grid_matrix': gridMatrix ? Float32Array.from(gridMatrix) : new Float32Array(9)
	});
	const atmosphereUniformValues = (frustumDirTl, frustumDirTr, frustumDirBr, frustumDirBl, horizon, transitionT, fadeoutRange, color, highColor, spaceColor, starIntensity, temporalOffset, horizonAngle, rotationMatrix) => ({
	    'u_frustum_tl': frustumDirTl,
	    'u_frustum_tr': frustumDirTr,
	    'u_frustum_br': frustumDirBr,
	    'u_frustum_bl': frustumDirBl,
	    'u_horizon': horizon,
	    'u_transition': transitionT,
	    'u_fadeout_range': fadeoutRange,
	    'u_color': color,
	    'u_high_color': highColor,
	    'u_space_color': spaceColor,
	    'u_star_intensity': starIntensity,
	    'u_star_size': 5 * ref_properties.exported.devicePixelRatio,
	    'u_star_density': 0,
	    'u_temporal_offset': temporalOffset,
	    'u_horizon_angle': horizonAngle,
	    'u_rotation_matrix': rotationMatrix
	});

	class VertexMorphing {
	    constructor() {
	        this.operations = {};
	    }
	    newMorphing(key, from, to, now, duration) {
	        if (key in this.operations) {
	            const op = this.operations[key];
	            if (op.to.tileID.key !== to.tileID.key)
	                op.queued = to;
	        } else {
	            this.operations[key] = {
	                startTime: now,
	                phase: 0,
	                duration,
	                from,
	                to,
	                queued: null
	            };
	        }
	    }
	    getMorphValuesForProxy(key) {
	        if (!(key in this.operations))
	            return null;
	        const op = this.operations[key];
	        const from = op.from;
	        const to = op.to;
	        return {
	            from,
	            to,
	            phase: op.phase
	        };
	    }
	    update(now) {
	        for (const key in this.operations) {
	            const op = this.operations[key];
	            op.phase = (now - op.startTime) / op.duration;
	            while (op.phase >= 1 || !this._validOp(op)) {
	                if (!this._nextOp(op, now)) {
	                    delete this.operations[key];
	                    break;
	                }
	            }
	        }
	    }
	    _nextOp(op, now) {
	        if (!op.queued)
	            return false;
	        op.from = op.to;
	        op.to = op.queued;
	        op.queued = null;
	        op.phase = 0;
	        op.startTime = now;
	        return true;
	    }
	    _validOp(op) {
	        return op.from.hasData() && op.to.hasData();
	    }
	}
	function demTileChanged(prev, next) {
	    if (prev == null || next == null)
	        return false;
	    if (!prev.hasData() || !next.hasData())
	        return false;
	    if (prev.demTexture == null || next.demTexture == null)
	        return false;
	    return prev.tileID.key !== next.tileID.key;
	}
	const vertexMorphing = new VertexMorphing();
	const SHADER_DEFAULT = 0;
	const SHADER_MORPHING = 1;
	const SHADER_TERRAIN_WIREFRAME = 2;
	const defaultDuration = 250;
	const shaderDefines = {
	    '0': null,
	    '1': 'TERRAIN_VERTEX_MORPHING',
	    '2': 'TERRAIN_WIREFRAME'
	};
	function drawTerrainForGlobe(painter, terrain, sourceCache, tileIDs, now) {
	    const context = painter.context;
	    const gl = context.gl;
	    let program, programMode;
	    const showWireframe = painter.options.showTerrainWireframe ? SHADER_TERRAIN_WIREFRAME : SHADER_DEFAULT;
	    const tr = painter.transform;
	    const useCustomAntialiasing = ref_properties.globeUseCustomAntiAliasing(painter, context, tr);
	    const setShaderMode = (mode, isWireframe) => {
	        if (programMode === mode)
	            return;
	        const defines = [
	            shaderDefines[mode],
	            'PROJECTION_GLOBE_VIEW'
	        ];
	        if (useCustomAntialiasing)
	            defines.push('CUSTOM_ANTIALIASING');
	        if (isWireframe)
	            defines.push(shaderDefines[showWireframe]);
	        program = painter.useProgram('globeRaster', null, defines);
	        programMode = mode;
	    };
	    const colorMode = painter.colorModeForRenderPass();
	    const depthMode = new ref_properties.DepthMode(gl.LEQUAL, ref_properties.DepthMode.ReadWrite, painter.depthRangeFor3D);
	    vertexMorphing.update(now);
	    const globeMercatorMatrix = ref_properties.calculateGlobeMercatorMatrix(tr);
	    const mercatorCenter = [
	        ref_properties.mercatorXfromLng(tr.center.lng),
	        ref_properties.mercatorYfromLat(tr.center.lat)
	    ];
	    const batches = showWireframe ? [
	        false,
	        true
	    ] : [false];
	    const sharedBuffers = painter.globeSharedBuffers;
	    const viewport = [
	        tr.width * ref_properties.exported.devicePixelRatio,
	        tr.height * ref_properties.exported.devicePixelRatio
	    ];
	    batches.forEach(isWireframe => {
	        programMode = -1;
	        const primitive = isWireframe ? gl.LINES : gl.TRIANGLES;
	        for (const coord of tileIDs) {
	            const tile = sourceCache.getTile(coord);
	            const stencilMode = ref_properties.StencilMode.disabled;
	            const prevDemTile = terrain.prevTerrainTileForTile[coord.key];
	            const nextDemTile = terrain.terrainTileForTile[coord.key];
	            if (demTileChanged(prevDemTile, nextDemTile)) {
	                vertexMorphing.newMorphing(coord.key, prevDemTile, nextDemTile, now, defaultDuration);
	            }
	            context.activeTexture.set(gl.TEXTURE0);
	            tile.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	            const morph = vertexMorphing.getMorphValuesForProxy(coord.key);
	            const shaderMode = morph ? SHADER_MORPHING : SHADER_DEFAULT;
	            const elevationOptions = { useDenormalizedUpVectorScale: true };
	            if (morph) {
	                ref_properties.extend$1(elevationOptions, {
	                    morphing: {
	                        srcDemTile: morph.from,
	                        dstDemTile: morph.to,
	                        phase: ref_properties.easeCubicInOut(morph.phase)
	                    }
	                });
	            }
	            const globeMatrix = Float32Array.from(tr.globeMatrix);
	            const tileCornersLatLng = ref_properties.globeTileLatLngCorners(coord.canonical);
	            const tileCenterLatitude = (tileCornersLatLng[0][0] + tileCornersLatLng[1][0]) / 2;
	            const latitudinalLod = ref_properties.getLatitudinalLod(tileCenterLatitude);
	            const gridMatrix = ref_properties.getGridMatrix(coord.canonical, tileCornersLatLng, latitudinalLod);
	            const normalizeMatrix = ref_properties.globeNormalizeECEF(ref_properties.globeTileBounds(coord.canonical));
	            const uniformValues = globeRasterUniformValues(tr.projMatrix, globeMatrix, globeMercatorMatrix, normalizeMatrix, ref_properties.globeToMercatorTransition(tr.zoom), mercatorCenter, tr.frustumCorners.TL, tr.frustumCorners.TR, tr.frustumCorners.BR, tr.frustumCorners.BL, tr.globeCenterInViewSpace, tr.globeRadius, viewport, gridMatrix);
	            setShaderMode(shaderMode, isWireframe);
	            terrain.setupElevationDraw(tile, program, elevationOptions);
	            painter.prepareDrawProgram(context, program, coord.toUnwrapped());
	            if (sharedBuffers) {
	                const [buffer, indexBuffer, segments] = isWireframe ? sharedBuffers.getWirefameBuffers(painter.context, latitudinalLod) : sharedBuffers.getGridBuffers(latitudinalLod);
	                program.draw(context, primitive, depthMode, stencilMode, colorMode, ref_properties.CullFaceMode.backCCW, uniformValues, 'globe_raster', buffer, indexBuffer, segments);
	            }
	        }
	    });
	    if (sharedBuffers) {
	        const defines = [
	            'GLOBE_POLES',
	            'PROJECTION_GLOBE_VIEW'
	        ];
	        if (useCustomAntialiasing)
	            defines.push('CUSTOM_ANTIALIASING');
	        program = painter.useProgram('globeRaster', null, defines);
	        for (const coord of tileIDs) {
	            const {x, y, z} = coord.canonical;
	            const topCap = y === 0;
	            const bottomCap = y === (1 << z) - 1;
	            const [northPoleBuffer, southPoleBuffer, indexBuffer, segment] = sharedBuffers.getPoleBuffers(z);
	            if (segment && (topCap || bottomCap)) {
	                const tile = sourceCache.getTile(coord);
	                context.activeTexture.set(gl.TEXTURE0);
	                tile.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	                let poleMatrix = ref_properties.globePoleMatrixForTile(z, x, tr);
	                const normalizeMatrix = ref_properties.globeNormalizeECEF(ref_properties.globeTileBounds(coord.canonical));
	                const drawPole = (program, vertexBuffer) => program.draw(context, gl.TRIANGLES, depthMode, ref_properties.StencilMode.disabled, colorMode, ref_properties.CullFaceMode.disabled, globeRasterUniformValues(tr.projMatrix, poleMatrix, poleMatrix, normalizeMatrix, 0, mercatorCenter, tr.frustumCorners.TL, tr.frustumCorners.TR, tr.frustumCorners.BR, tr.frustumCorners.BL, tr.globeCenterInViewSpace, tr.globeRadius, viewport), 'globe_pole_raster', vertexBuffer, indexBuffer, segment);
	                terrain.setupElevationDraw(tile, program, {});
	                painter.prepareDrawProgram(context, program, coord.toUnwrapped());
	                if (topCap) {
	                    drawPole(program, northPoleBuffer);
	                }
	                if (bottomCap) {
	                    poleMatrix = ref_properties.scale(ref_properties.create(), poleMatrix, [
	                        1,
	                        -1,
	                        1
	                    ]);
	                    drawPole(program, southPoleBuffer);
	                }
	            }
	        }
	    }
	}
	function drawTerrainRaster(painter, terrain, sourceCache, tileIDs, now) {
	    if (painter.transform.projection.name === 'globe') {
	        drawTerrainForGlobe(painter, terrain, sourceCache, tileIDs, now);
	    } else {
	        const context = painter.context;
	        const gl = context.gl;
	        let program, programMode;
	        const showWireframe = painter.options.showTerrainWireframe ? SHADER_TERRAIN_WIREFRAME : SHADER_DEFAULT;
	        const setShaderMode = (mode, isWireframe) => {
	            if (programMode === mode)
	                return;
	            const modes = [shaderDefines[mode]];
	            if (isWireframe)
	                modes.push(shaderDefines[showWireframe]);
	            program = painter.useProgram('terrainRaster', null, modes);
	            programMode = mode;
	        };
	        const colorMode = painter.colorModeForRenderPass();
	        const depthMode = new ref_properties.DepthMode(gl.LEQUAL, ref_properties.DepthMode.ReadWrite, painter.depthRangeFor3D);
	        vertexMorphing.update(now);
	        const tr = painter.transform;
	        const skirt = skirtHeight(tr.zoom) * terrain.exaggeration();
	        const batches = showWireframe ? [
	            false,
	            true
	        ] : [false];
	        batches.forEach(isWireframe => {
	            programMode = -1;
	            const primitive = isWireframe ? gl.LINES : gl.TRIANGLES;
	            const [buffer, segments] = isWireframe ? terrain.getWirefameBuffer() : [
	                terrain.gridIndexBuffer,
	                terrain.gridSegments
	            ];
	            for (const coord of tileIDs) {
	                const tile = sourceCache.getTile(coord);
	                const stencilMode = ref_properties.StencilMode.disabled;
	                const prevDemTile = terrain.prevTerrainTileForTile[coord.key];
	                const nextDemTile = terrain.terrainTileForTile[coord.key];
	                if (demTileChanged(prevDemTile, nextDemTile)) {
	                    vertexMorphing.newMorphing(coord.key, prevDemTile, nextDemTile, now, defaultDuration);
	                }
	                context.activeTexture.set(gl.TEXTURE0);
	                tile.texture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE, gl.LINEAR_MIPMAP_NEAREST);
	                const morph = vertexMorphing.getMorphValuesForProxy(coord.key);
	                const shaderMode = morph ? SHADER_MORPHING : SHADER_DEFAULT;
	                let elevationOptions;
	                if (morph) {
	                    elevationOptions = {
	                        morphing: {
	                            srcDemTile: morph.from,
	                            dstDemTile: morph.to,
	                            phase: ref_properties.easeCubicInOut(morph.phase)
	                        }
	                    };
	                }
	                const uniformValues = terrainRasterUniformValues(coord.projMatrix, isEdgeTile(coord.canonical, tr.renderWorldCopies) ? skirt / 10 : skirt);
	                setShaderMode(shaderMode, isWireframe);
	                terrain.setupElevationDraw(tile, program, elevationOptions);
	                painter.prepareDrawProgram(context, program, coord.toUnwrapped());
	                program.draw(context, primitive, depthMode, stencilMode, colorMode, ref_properties.CullFaceMode.backCCW, uniformValues, 'terrain_raster', terrain.gridBuffer, buffer, segments);
	            }
	        });
	    }
	}
	function drawTerrainDepth(painter, terrain, sourceCache, tileIDs) {
	    if (painter.transform.projection.name === 'globe') {
	        return;
	    }
	    const context = painter.context;
	    const gl = context.gl;
	    context.clear({ depth: 1 });
	    const program = painter.useProgram('terrainDepth');
	    const depthMode = new ref_properties.DepthMode(gl.LESS, ref_properties.DepthMode.ReadWrite, painter.depthRangeFor3D);
	    for (const coord of tileIDs) {
	        const tile = sourceCache.getTile(coord);
	        const uniformValues = terrainRasterUniformValues(coord.projMatrix, 0);
	        terrain.setupElevationDraw(tile, program);
	        program.draw(context, gl.TRIANGLES, depthMode, ref_properties.StencilMode.disabled, ref_properties.ColorMode.unblended, ref_properties.CullFaceMode.backCCW, uniformValues, 'terrain_depth', terrain.gridBuffer, terrain.gridIndexBuffer, terrain.gridNoSkirtSegments);
	    }
	}
	function skirtHeight(zoom) {
	    return 6 * Math.pow(1.5, 22 - zoom);
	}
	function isEdgeTile(cid, renderWorldCopies) {
	    const numTiles = 1 << cid.z;
	    return !renderWorldCopies && (cid.x === 0 || cid.x === numTiles - 1) || cid.y === 0 || cid.y === numTiles - 1;
	}

	const clippingMaskUniforms = (context, locations) => ({ 'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix) });
	const clippingMaskUniformValues = matrix => ({ 'u_matrix': matrix });

	function rasterFade(tile, parentTile, sourceCache, transform, fadeDuration) {
	    if (fadeDuration > 0) {
	        const now = ref_properties.exported.now();
	        const sinceTile = (now - tile.timeAdded) / fadeDuration;
	        const sinceParent = parentTile ? (now - parentTile.timeAdded) / fadeDuration : -1;
	        const source = sourceCache.getSource();
	        const idealZ = transform.coveringZoomLevel({
	            tileSize: source.tileSize,
	            roundZoom: source.roundZoom
	        });
	        const fadeIn = !parentTile || Math.abs(parentTile.tileID.overscaledZ - idealZ) > Math.abs(tile.tileID.overscaledZ - idealZ);
	        const childOpacity = fadeIn && tile.refreshedUponExpiration ? 1 : ref_properties.clamp(fadeIn ? sinceTile : 1 - sinceParent, 0, 1);
	        if (tile.refreshedUponExpiration && sinceTile >= 1)
	            tile.refreshedUponExpiration = false;
	        if (parentTile) {
	            return {
	                opacity: 1,
	                mix: 1 - childOpacity
	            };
	        } else {
	            return {
	                opacity: childOpacity,
	                mix: 0
	            };
	        }
	    } else {
	        return {
	            opacity: 1,
	            mix: 0
	        };
	    }
	}

	const GRID_DIM = 128;
	const FBO_POOL_SIZE = 5;
	const RENDER_CACHE_MAX_SIZE = 50;
	class MockSourceCache extends ref_properties.SourceCache {
	    constructor(map) {
	        const sourceSpec = {
	            type: 'raster-dem',
	            maxzoom: map.transform.maxZoom
	        };
	        const sourceDispatcher = new Dispatcher(getGlobalWorkerPool(), null);
	        const source = create('mock-dem', sourceSpec, sourceDispatcher, map.style);
	        super('mock-dem', source, false);
	        source.setEventedParent(this);
	        this._sourceLoaded = true;
	    }
	    _loadTile(tile, callback) {
	        tile.state = 'loaded';
	        callback(null);
	    }
	}
	class ProxySourceCache extends ref_properties.SourceCache {
	    constructor(map) {
	        const source = create('proxy', {
	            type: 'geojson',
	            maxzoom: map.transform.maxZoom
	        }, new Dispatcher(getGlobalWorkerPool(), null), map.style);
	        super('proxy', source, false);
	        source.setEventedParent(this);
	        this.map = this.getSource().map = map;
	        this.used = this._sourceLoaded = true;
	        this.renderCache = [];
	        this.renderCachePool = [];
	        this.proxyCachedFBO = {};
	    }
	    update(transform, tileSize, updateForTerrain) {
	        if (transform.freezeTileCoverage) {
	            return;
	        }
	        this.transform = transform;
	        const idealTileIDs = transform.coveringTiles({
	            tileSize: this._source.tileSize,
	            minzoom: this._source.minzoom,
	            maxzoom: this._source.maxzoom,
	            roundZoom: this._source.roundZoom,
	            reparseOverscaled: this._source.reparseOverscaled
	        });
	        const incoming = idealTileIDs.reduce((acc, tileID) => {
	            acc[tileID.key] = '';
	            if (!this._tiles[tileID.key]) {
	                const tile = new ref_properties.Tile(tileID, this._source.tileSize * tileID.overscaleFactor(), transform.tileZoom);
	                tile.state = 'loaded';
	                this._tiles[tileID.key] = tile;
	            }
	            return acc;
	        }, {});
	        for (const id in this._tiles) {
	            if (!(id in incoming)) {
	                this.freeFBO(id);
	                this._tiles[id].unloadVectorData();
	                delete this._tiles[id];
	            }
	        }
	    }
	    freeFBO(id) {
	        const fbos = this.proxyCachedFBO[id];
	        if (fbos !== undefined) {
	            const fboIds = Object.values(fbos);
	            this.renderCachePool.push(...fboIds);
	            delete this.proxyCachedFBO[id];
	        }
	    }
	    deallocRenderCache() {
	        this.renderCache.forEach(fbo => fbo.fb.destroy());
	        this.renderCache = [];
	        this.renderCachePool = [];
	        this.proxyCachedFBO = {};
	    }
	}
	class ProxiedTileID extends ref_properties.OverscaledTileID {
	    constructor(tileID, proxyTileKey, projMatrix) {
	        super(tileID.overscaledZ, tileID.wrap, tileID.canonical.z, tileID.canonical.x, tileID.canonical.y);
	        this.proxyTileKey = proxyTileKey;
	        this.projMatrix = projMatrix;
	    }
	}
	class Terrain extends ref_properties.Elevation {
	    constructor(painter, style) {
	        super();
	        this.painter = painter;
	        this.terrainTileForTile = {};
	        this.prevTerrainTileForTile = {};
	        const [triangleGridArray, triangleGridIndices, skirtIndicesOffset] = createGrid(GRID_DIM + 1);
	        const context = painter.context;
	        this.gridBuffer = context.createVertexBuffer(triangleGridArray, ref_properties.boundsAttributes.members);
	        this.gridIndexBuffer = context.createIndexBuffer(triangleGridIndices);
	        this.gridSegments = ref_properties.SegmentVector.simpleSegment(0, 0, triangleGridArray.length, triangleGridIndices.length);
	        this.gridNoSkirtSegments = ref_properties.SegmentVector.simpleSegment(0, 0, triangleGridArray.length, skirtIndicesOffset);
	        this.proxyCoords = [];
	        this.proxiedCoords = {};
	        this._visibleDemTiles = [];
	        this._drapedRenderBatches = [];
	        this._sourceTilesOverlap = {};
	        this.proxySourceCache = new ProxySourceCache(style.map);
	        this.orthoMatrix = ref_properties.create();
	        ref_properties.ortho(this.orthoMatrix, 0, ref_properties.EXTENT, 0, ref_properties.EXTENT, 0, 1);
	        const gl = context.gl;
	        this._overlapStencilMode = new ref_properties.StencilMode({
	            func: gl.GEQUAL,
	            mask: 255
	        }, 0, 255, gl.KEEP, gl.KEEP, gl.REPLACE);
	        this._previousZoom = painter.transform.zoom;
	        this.pool = [];
	        this._findCoveringTileCache = {};
	        this._tilesDirty = {};
	        this.style = style;
	        this._useVertexMorphing = true;
	        this._exaggeration = 1;
	        this._mockSourceCache = new MockSourceCache(style.map);
	    }
	    set style(style) {
	        style.on('data', this._onStyleDataEvent.bind(this));
	        style.on('neworder', this._checkRenderCacheEfficiency.bind(this));
	        this._style = style;
	        this._checkRenderCacheEfficiency();
	    }
	    update(style, transform, cameraChanging) {
	        if (style && style.terrain) {
	            if (this._style !== style) {
	                this.style = style;
	            }
	            this.enabled = true;
	            const terrainProps = style.terrain.properties;
	            const isDrapeModeDeferred = style.terrain.drapeRenderMode === DrapeRenderMode.deferred;
	            this.sourceCache = isDrapeModeDeferred ? this._mockSourceCache : style._getSourceCache(terrainProps.get('source'));
	            this._exaggeration = terrainProps.get('exaggeration');
	            const updateSourceCache = () => {
	                if (this.sourceCache.used) {
	                    ref_properties.warnOnce(`Raster DEM source '${ this.sourceCache.id }' is used both for terrain and as layer source.\n` + 'This leads to lower resolution of hillshade. For full hillshade resolution but higher memory consumption, define another raster DEM source.');
	                }
	                const scaledDemTileSize = this.getScaledDemTileSize();
	                this.sourceCache.update(transform, scaledDemTileSize, true);
	                this.resetTileLookupCache(this.sourceCache.id);
	            };
	            if (!this.sourceCache.usedForTerrain) {
	                this.resetTileLookupCache(this.sourceCache.id);
	                this.sourceCache.usedForTerrain = true;
	                updateSourceCache();
	                this._initializing = true;
	            }
	            updateSourceCache();
	            transform.updateElevation(!cameraChanging);
	            this.resetTileLookupCache(this.proxySourceCache.id);
	            this.proxySourceCache.update(transform);
	            this._emptyDEMTextureDirty = true;
	        } else {
	            this._disable();
	        }
	    }
	    resetTileLookupCache(sourceCacheID) {
	        this._findCoveringTileCache[sourceCacheID] = {};
	    }
	    getScaledDemTileSize() {
	        const demScale = this.sourceCache.getSource().tileSize / GRID_DIM;
	        const proxyTileSize = this.proxySourceCache.getSource().tileSize;
	        return demScale * proxyTileSize;
	    }
	    _checkRenderCacheEfficiency() {
	        const renderCacheInfo = this.renderCacheEfficiency(this._style);
	        if (this._style.map._optimizeForTerrain) ; else if (renderCacheInfo.efficiency !== 100) {
	            ref_properties.warnOnce(`Terrain render cache efficiency is not optimal (${ renderCacheInfo.efficiency }%) and performance
	                may be affected negatively, consider placing all background, fill and line layers before layer
	                with id '${ renderCacheInfo.firstUndrapedLayer }' or create a map using optimizeForTerrain: true option.`);
	        }
	    }
	    _onStyleDataEvent(event) {
	        if (event.coord && event.dataType === 'source') {
	            this._clearRenderCacheForTile(event.sourceCacheId, event.coord);
	        } else if (event.dataType === 'style') {
	            this._invalidateRenderCache = true;
	        }
	    }
	    _disable() {
	        if (!this.enabled)
	            return;
	        this.enabled = false;
	        this._sharedDepthStencil = undefined;
	        this.proxySourceCache.deallocRenderCache();
	        if (this._style) {
	            for (const id in this._style._sourceCaches) {
	                this._style._sourceCaches[id].usedForTerrain = false;
	            }
	        }
	    }
	    destroy() {
	        this._disable();
	        if (this._emptyDEMTexture)
	            this._emptyDEMTexture.destroy();
	        if (this._emptyDepthBufferTexture)
	            this._emptyDepthBufferTexture.destroy();
	        this.pool.forEach(fbo => fbo.fb.destroy());
	        this.pool = [];
	        if (this._depthFBO) {
	            this._depthFBO.destroy();
	            this._depthFBO = undefined;
	            this._depthTexture = undefined;
	        }
	    }
	    _source() {
	        return this.enabled ? this.sourceCache : null;
	    }
	    exaggeration() {
	        return this._exaggeration;
	    }
	    get visibleDemTiles() {
	        return this._visibleDemTiles;
	    }
	    get drapeBufferSize() {
	        const extent = this.proxySourceCache.getSource().tileSize * 2;
	        return [
	            extent,
	            extent
	        ];
	    }
	    set useVertexMorphing(enable) {
	        this._useVertexMorphing = enable;
	    }
	    updateTileBinding(sourcesCoords) {
	        if (!this.enabled)
	            return;
	        this.prevTerrainTileForTile = this.terrainTileForTile;
	        const psc = this.proxySourceCache;
	        const tr = this.painter.transform;
	        if (this._initializing) {
	            this._initializing = tr._centerAltitude === 0 && this.getAtPointOrZero(ref_properties.MercatorCoordinate.fromLngLat(tr.center), -1) === -1;
	            this._emptyDEMTextureDirty = !this._initializing;
	        }
	        const coords = this.proxyCoords = psc.getIds().map(id => {
	            const tileID = psc.getTileByID(id).tileID;
	            tileID.projMatrix = tr.calculateProjMatrix(tileID.toUnwrapped());
	            return tileID;
	        });
	        sortByDistanceToCamera(coords, this.painter);
	        this._previousZoom = tr.zoom;
	        const previousProxyToSource = this.proxyToSource || {};
	        this.proxyToSource = {};
	        coords.forEach(tileID => {
	            this.proxyToSource[tileID.key] = {};
	        });
	        this.terrainTileForTile = {};
	        const sourceCaches = this._style._sourceCaches;
	        for (const id in sourceCaches) {
	            const sourceCache = sourceCaches[id];
	            if (!sourceCache.used)
	                continue;
	            if (sourceCache !== this.sourceCache)
	                this.resetTileLookupCache(sourceCache.id);
	            this._setupProxiedCoordsForOrtho(sourceCache, sourcesCoords[id], previousProxyToSource);
	            if (sourceCache.usedForTerrain)
	                continue;
	            const coordinates = sourcesCoords[id];
	            if (sourceCache.getSource().reparseOverscaled) {
	                this._assignTerrainTiles(coordinates);
	            }
	        }
	        this.proxiedCoords[psc.id] = coords.map(tileID => new ProxiedTileID(tileID, tileID.key, this.orthoMatrix));
	        this._assignTerrainTiles(coords);
	        this._prepareDEMTextures();
	        this._setupDrapedRenderBatches();
	        this._initFBOPool();
	        this._setupRenderCache(previousProxyToSource);
	        this.renderingToTexture = false;
	        this._updateTimestamp = ref_properties.exported.now();
	        const visibleKeys = {};
	        this._visibleDemTiles = [];
	        for (const id of this.proxyCoords) {
	            const demTile = this.terrainTileForTile[id.key];
	            if (!demTile)
	                continue;
	            const key = demTile.tileID.key;
	            if (key in visibleKeys)
	                continue;
	            this._visibleDemTiles.push(demTile);
	            visibleKeys[key] = key;
	        }
	    }
	    _assignTerrainTiles(coords) {
	        if (this._initializing)
	            return;
	        coords.forEach(tileID => {
	            if (this.terrainTileForTile[tileID.key])
	                return;
	            const demTile = this._findTileCoveringTileID(tileID, this.sourceCache);
	            if (demTile)
	                this.terrainTileForTile[tileID.key] = demTile;
	        });
	    }
	    _prepareDEMTextures() {
	        const context = this.painter.context;
	        const gl = context.gl;
	        for (const key in this.terrainTileForTile) {
	            const tile = this.terrainTileForTile[key];
	            const dem = tile.dem;
	            if (dem && (!tile.demTexture || tile.needsDEMTextureUpload)) {
	                context.activeTexture.set(gl.TEXTURE1);
	                prepareDEMTexture(this.painter, tile, dem);
	            }
	        }
	    }
	    _prepareDemTileUniforms(proxyTile, demTile, uniforms, uniformSuffix) {
	        if (!demTile || demTile.demTexture == null)
	            return false;
	        const proxyId = proxyTile.tileID.canonical;
	        const demId = demTile.tileID.canonical;
	        const demScaleBy = Math.pow(2, demId.z - proxyId.z);
	        const suffix = uniformSuffix || '';
	        uniforms[`u_dem_tl${ suffix }`] = [
	            proxyId.x * demScaleBy % 1,
	            proxyId.y * demScaleBy % 1
	        ];
	        uniforms[`u_dem_scale${ suffix }`] = demScaleBy;
	        return true;
	    }
	    get emptyDEMTexture() {
	        return !this._emptyDEMTextureDirty && this._emptyDEMTexture ? this._emptyDEMTexture : this._updateEmptyDEMTexture();
	    }
	    get emptyDepthBufferTexture() {
	        const context = this.painter.context;
	        const gl = context.gl;
	        if (!this._emptyDepthBufferTexture) {
	            const image = new ref_properties.RGBAImage({
	                width: 1,
	                height: 1
	            }, Uint8Array.of(255, 255, 255, 255));
	            this._emptyDepthBufferTexture = new ref_properties.Texture(context, image, gl.RGBA, { premultiply: false });
	        }
	        return this._emptyDepthBufferTexture;
	    }
	    _getLoadedAreaMinimum() {
	        let nonzero = 0;
	        const min = this._visibleDemTiles.reduce((acc, tile) => {
	            if (!tile.dem)
	                return acc;
	            const m = tile.dem.tree.minimums[0];
	            acc += m;
	            if (m > 0)
	                nonzero++;
	            return acc;
	        }, 0);
	        return nonzero ? min / nonzero : 0;
	    }
	    _updateEmptyDEMTexture() {
	        const context = this.painter.context;
	        const gl = context.gl;
	        context.activeTexture.set(gl.TEXTURE2);
	        const min = this._getLoadedAreaMinimum();
	        const image = new ref_properties.RGBAImage({
	            width: 1,
	            height: 1
	        }, new Uint8Array(ref_properties.DEMData.pack(min, this.sourceCache.getSource().encoding)));
	        this._emptyDEMTextureDirty = false;
	        let texture = this._emptyDEMTexture;
	        if (!texture) {
	            texture = this._emptyDEMTexture = new ref_properties.Texture(context, image, gl.RGBA, { premultiply: false });
	        } else {
	            texture.update(image, { premultiply: false });
	        }
	        return texture;
	    }
	    setupElevationDraw(tile, program, options) {
	        const context = this.painter.context;
	        const gl = context.gl;
	        const uniforms = defaultTerrainUniforms(this.sourceCache.getSource().encoding);
	        uniforms['u_dem_size'] = this.sourceCache.getSource().tileSize;
	        uniforms['u_exaggeration'] = this.exaggeration();
	        const tr = this.painter.transform;
	        const projection = tr.projection;
	        const id = tile.tileID.canonical;
	        uniforms['u_tile_tl_up'] = projection.upVector(id, 0, 0);
	        uniforms['u_tile_tr_up'] = projection.upVector(id, ref_properties.EXTENT, 0);
	        uniforms['u_tile_br_up'] = projection.upVector(id, ref_properties.EXTENT, ref_properties.EXTENT);
	        uniforms['u_tile_bl_up'] = projection.upVector(id, 0, ref_properties.EXTENT);
	        if (options && options.useDenormalizedUpVectorScale) {
	            uniforms['u_tile_up_scale'] = ref_properties.GLOBE_METERS_TO_ECEF;
	        } else {
	            uniforms['u_tile_up_scale'] = projection.upVectorScale(id, tr.center.lat, tr.worldSize).metersToTile;
	        }
	        let demTile = null;
	        let prevDemTile = null;
	        let morphingPhase = 1;
	        if (options && options.morphing && this._useVertexMorphing) {
	            const srcTile = options.morphing.srcDemTile;
	            const dstTile = options.morphing.dstDemTile;
	            morphingPhase = options.morphing.phase;
	            if (srcTile && dstTile) {
	                if (this._prepareDemTileUniforms(tile, srcTile, uniforms, '_prev'))
	                    prevDemTile = srcTile;
	                if (this._prepareDemTileUniforms(tile, dstTile, uniforms))
	                    demTile = dstTile;
	            }
	        }
	        if (prevDemTile && demTile) {
	            context.activeTexture.set(gl.TEXTURE2);
	            demTile.demTexture.bind(gl.NEAREST, gl.CLAMP_TO_EDGE, gl.NEAREST);
	            context.activeTexture.set(gl.TEXTURE4);
	            prevDemTile.demTexture.bind(gl.NEAREST, gl.CLAMP_TO_EDGE, gl.NEAREST);
	            uniforms['u_dem_lerp'] = morphingPhase;
	        } else {
	            demTile = this.terrainTileForTile[tile.tileID.key];
	            context.activeTexture.set(gl.TEXTURE2);
	            const demTexture = this._prepareDemTileUniforms(tile, demTile, uniforms) ? demTile.demTexture : this.emptyDEMTexture;
	            demTexture.bind(gl.NEAREST, gl.CLAMP_TO_EDGE);
	        }
	        context.activeTexture.set(gl.TEXTURE3);
	        if (options && options.useDepthForOcclusion) {
	            if (this._depthTexture)
	                this._depthTexture.bind(gl.NEAREST, gl.CLAMP_TO_EDGE);
	            if (this._depthFBO)
	                uniforms['u_depth_size_inv'] = [
	                    1 / this._depthFBO.width,
	                    1 / this._depthFBO.height
	                ];
	        } else {
	            this.emptyDepthBufferTexture.bind(gl.NEAREST, gl.CLAMP_TO_EDGE);
	            uniforms['u_depth_size_inv'] = [
	                1,
	                1
	            ];
	        }
	        if (options && options.useMeterToDem && demTile) {
	            const meterToDEM = (1 << demTile.tileID.canonical.z) * ref_properties.mercatorZfromAltitude(1, this.painter.transform.center.lat) * this.sourceCache.getSource().tileSize;
	            uniforms['u_meter_to_dem'] = meterToDEM;
	        }
	        if (options && options.labelPlaneMatrixInv) {
	            uniforms['u_label_plane_matrix_inv'] = options.labelPlaneMatrixInv;
	        }
	        program.setTerrainUniformValues(context, uniforms);
	    }
	    renderToBackBuffer(accumulatedDrapes) {
	        const painter = this.painter;
	        const context = this.painter.context;
	        if (accumulatedDrapes.length === 0) {
	            return;
	        }
	        context.bindFramebuffer.set(null);
	        context.viewport.set([
	            0,
	            0,
	            painter.width,
	            painter.height
	        ]);
	        painter.gpuTimingDeferredRenderStart();
	        this.renderingToTexture = false;
	        drawTerrainRaster(painter, this, this.proxySourceCache, accumulatedDrapes, this._updateTimestamp);
	        this.renderingToTexture = true;
	        painter.gpuTimingDeferredRenderEnd();
	        accumulatedDrapes.splice(0, accumulatedDrapes.length);
	    }
	    renderBatch(startLayerIndex) {
	        if (this._drapedRenderBatches.length === 0) {
	            return startLayerIndex + 1;
	        }
	        this.renderingToTexture = true;
	        const painter = this.painter;
	        const context = this.painter.context;
	        const psc = this.proxySourceCache;
	        const proxies = this.proxiedCoords[psc.id];
	        const drapedLayerBatch = this._drapedRenderBatches.shift();
	        const accumulatedDrapes = [];
	        const layerIds = painter.style.order;
	        let poolIndex = 0;
	        for (const proxy of proxies) {
	            const tile = psc.getTileByID(proxy.proxyTileKey);
	            const renderCacheIndex = psc.proxyCachedFBO[proxy.key] ? psc.proxyCachedFBO[proxy.key][startLayerIndex] : undefined;
	            const fbo = renderCacheIndex !== undefined ? psc.renderCache[renderCacheIndex] : this.pool[poolIndex++];
	            const useRenderCache = renderCacheIndex !== undefined;
	            tile.texture = fbo.tex;
	            if (useRenderCache && !fbo.dirty) {
	                accumulatedDrapes.push(tile.tileID);
	                continue;
	            }
	            context.bindFramebuffer.set(fbo.fb.framebuffer);
	            this.renderedToTile = false;
	            if (fbo.dirty) {
	                context.clear({
	                    color: ref_properties.Color.transparent,
	                    stencil: 0
	                });
	                fbo.dirty = false;
	            }
	            let currentStencilSource;
	            for (let j = drapedLayerBatch.start; j <= drapedLayerBatch.end; ++j) {
	                const layer = painter.style._layers[layerIds[j]];
	                const hidden = layer.isHidden(painter.transform.zoom);
	                if (hidden)
	                    continue;
	                const sourceCache = painter.style._getLayerSourceCache(layer);
	                const proxiedCoords = sourceCache ? this.proxyToSource[proxy.key][sourceCache.id] : [proxy];
	                if (!proxiedCoords)
	                    continue;
	                const coords = proxiedCoords;
	                context.viewport.set([
	                    0,
	                    0,
	                    fbo.fb.width,
	                    fbo.fb.height
	                ]);
	                if (currentStencilSource !== (sourceCache ? sourceCache.id : null)) {
	                    this._setupStencil(fbo, proxiedCoords, layer, sourceCache);
	                    currentStencilSource = sourceCache ? sourceCache.id : null;
	                }
	                painter.renderLayer(painter, sourceCache, layer, coords);
	            }
	            if (this.renderedToTile) {
	                fbo.dirty = true;
	                accumulatedDrapes.push(tile.tileID);
	            } else if (!useRenderCache) {
	                --poolIndex;
	            }
	            if (poolIndex === FBO_POOL_SIZE) {
	                poolIndex = 0;
	                this.renderToBackBuffer(accumulatedDrapes);
	            }
	        }
	        this.renderToBackBuffer(accumulatedDrapes);
	        this.renderingToTexture = false;
	        context.bindFramebuffer.set(null);
	        context.viewport.set([
	            0,
	            0,
	            painter.width,
	            painter.height
	        ]);
	        return drapedLayerBatch.end + 1;
	    }
	    postRender() {
	    }
	    renderCacheEfficiency(style) {
	        const layerCount = style.order.length;
	        if (layerCount === 0) {
	            return { efficiency: 100 };
	        }
	        let uncacheableLayerCount = 0;
	        let drapedLayerCount = 0;
	        let reachedUndrapedLayer = false;
	        let firstUndrapedLayer;
	        for (let i = 0; i < layerCount; ++i) {
	            const layer = style._layers[style.order[i]];
	            if (!this._style.isLayerDraped(layer)) {
	                if (!reachedUndrapedLayer) {
	                    reachedUndrapedLayer = true;
	                    firstUndrapedLayer = layer.id;
	                }
	            } else {
	                if (reachedUndrapedLayer) {
	                    ++uncacheableLayerCount;
	                }
	                ++drapedLayerCount;
	            }
	        }
	        if (drapedLayerCount === 0) {
	            return { efficiency: 100 };
	        }
	        return {
	            efficiency: (1 - uncacheableLayerCount / drapedLayerCount) * 100,
	            firstUndrapedLayer
	        };
	    }
	    getMinElevationBelowMSL() {
	        let min = 0;
	        const maxDEMError = 30;
	        this._visibleDemTiles.filter(tile => tile.dem).forEach(tile => {
	            const minMaxTree = tile.dem.tree;
	            min = Math.min(min, minMaxTree.minimums[0]);
	        });
	        return min === 0 ? min : (min - maxDEMError) * this._exaggeration;
	    }
	    raycast(pos, dir, exaggeration) {
	        if (!this._visibleDemTiles)
	            return null;
	        const preparedTiles = this._visibleDemTiles.filter(tile => tile.dem).map(tile => {
	            const id = tile.tileID;
	            const tiles = Math.pow(2, id.overscaledZ);
	            const {x, y} = id.canonical;
	            const minx = x / tiles;
	            const maxx = (x + 1) / tiles;
	            const miny = y / tiles;
	            const maxy = (y + 1) / tiles;
	            const tree = tile.dem.tree;
	            return {
	                minx,
	                miny,
	                maxx,
	                maxy,
	                t: tree.raycastRoot(minx, miny, maxx, maxy, pos, dir, exaggeration),
	                tile
	            };
	        });
	        preparedTiles.sort((a, b) => {
	            const at = a.t !== null ? a.t : Number.MAX_VALUE;
	            const bt = b.t !== null ? b.t : Number.MAX_VALUE;
	            return at - bt;
	        });
	        for (const obj of preparedTiles) {
	            if (obj.t == null)
	                return null;
	            const tree = obj.tile.dem.tree;
	            const t = tree.raycast(obj.minx, obj.miny, obj.maxx, obj.maxy, pos, dir, exaggeration);
	            if (t != null)
	                return t;
	        }
	        return null;
	    }
	    _createFBO() {
	        const painter = this.painter;
	        const context = painter.context;
	        const gl = context.gl;
	        const bufferSize = this.drapeBufferSize;
	        context.activeTexture.set(gl.TEXTURE0);
	        const tex = new ref_properties.Texture(context, {
	            width: bufferSize[0],
	            height: bufferSize[1],
	            data: null
	        }, gl.RGBA);
	        tex.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	        const fb = context.createFramebuffer(bufferSize[0], bufferSize[1], false);
	        fb.colorAttachment.set(tex.texture);
	        fb.depthAttachment = new DepthStencilAttachment(context, fb.framebuffer);
	        if (this._sharedDepthStencil === undefined) {
	            this._sharedDepthStencil = context.createRenderbuffer(context.gl.DEPTH_STENCIL, bufferSize[0], bufferSize[1]);
	            this._stencilRef = 0;
	            fb.depthAttachment.set(this._sharedDepthStencil);
	            context.clear({ stencil: 0 });
	        } else {
	            fb.depthAttachment.set(this._sharedDepthStencil);
	        }
	        if (context.extTextureFilterAnisotropic && !context.extTextureFilterAnisotropicForceOff) {
	            gl.texParameterf(gl.TEXTURE_2D, context.extTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, context.extTextureFilterAnisotropicMax);
	        }
	        return {
	            fb,
	            tex,
	            dirty: false
	        };
	    }
	    _initFBOPool() {
	        while (this.pool.length < Math.min(FBO_POOL_SIZE, this.proxyCoords.length)) {
	            this.pool.push(this._createFBO());
	        }
	    }
	    _shouldDisableRenderCache() {
	        if (this._style.light && this._style.light.hasTransition()) {
	            return true;
	        }
	        for (const id in this._style._sourceCaches) {
	            if (this._style._sourceCaches[id].hasTransition()) {
	                return true;
	            }
	        }
	        const fadingOrTransitioning = id => {
	            const layer = this._style._layers[id];
	            const isHidden = layer.isHidden(this.painter.transform.zoom);
	            const crossFade = layer.getCrossfadeParameters();
	            const isFading = !!crossFade && crossFade.t !== 1;
	            const isTransitioning = layer.hasTransition();
	            return layer.type !== 'custom' && !isHidden && (isFading || isTransitioning);
	        };
	        return this._style.order.some(fadingOrTransitioning);
	    }
	    _clearRasterFadeFromRenderCache() {
	        let hasRasterSource = false;
	        for (const id in this._style._sourceCaches) {
	            if (this._style._sourceCaches[id]._source instanceof RasterTileSource) {
	                hasRasterSource = true;
	                break;
	            }
	        }
	        if (!hasRasterSource) {
	            return;
	        }
	        for (let i = 0; i < this._style.order.length; ++i) {
	            const layer = this._style._layers[this._style.order[i]];
	            const isHidden = layer.isHidden(this.painter.transform.zoom);
	            const sourceCache = this._style._getLayerSourceCache(layer);
	            if (layer.type !== 'raster' || isHidden || !sourceCache) {
	                continue;
	            }
	            const rasterLayer = layer;
	            const fadeDuration = rasterLayer.paint.get('raster-fade-duration');
	            for (const proxy of this.proxyCoords) {
	                const proxiedCoords = this.proxyToSource[proxy.key][sourceCache.id];
	                const coords = proxiedCoords;
	                if (!coords) {
	                    continue;
	                }
	                for (const coord of coords) {
	                    const tile = sourceCache.getTile(coord);
	                    const parent = sourceCache.findLoadedParent(coord, 0);
	                    const fade = rasterFade(tile, parent, sourceCache, this.painter.transform, fadeDuration);
	                    const isFading = fade.opacity !== 1 || fade.mix !== 0;
	                    if (isFading) {
	                        this._clearRenderCacheForTile(sourceCache.id, coord);
	                    }
	                }
	            }
	        }
	    }
	    _setupDrapedRenderBatches() {
	        const layerIds = this._style.order;
	        const layerCount = layerIds.length;
	        if (layerCount === 0) {
	            return;
	        }
	        const batches = [];
	        let currentLayer = 0;
	        let layer = this._style._layers[layerIds[currentLayer]];
	        while (!this._style.isLayerDraped(layer) && layer.isHidden(this.painter.transform.zoom) && ++currentLayer < layerCount) {
	            layer = this._style._layers[layerIds[currentLayer]];
	        }
	        let batchStart;
	        for (; currentLayer < layerCount; ++currentLayer) {
	            const layer = this._style._layers[layerIds[currentLayer]];
	            if (layer.isHidden(this.painter.transform.zoom)) {
	                continue;
	            }
	            if (!this._style.isLayerDraped(layer)) {
	                if (batchStart !== undefined) {
	                    batches.push({
	                        start: batchStart,
	                        end: currentLayer - 1
	                    });
	                    batchStart = undefined;
	                }
	                continue;
	            }
	            if (batchStart === undefined) {
	                batchStart = currentLayer;
	            }
	        }
	        if (batchStart !== undefined) {
	            batches.push({
	                start: batchStart,
	                end: currentLayer - 1
	            });
	        }
	        if (this._style.map._optimizeForTerrain) ;
	        this._drapedRenderBatches = batches;
	    }
	    _setupRenderCache(previousProxyToSource) {
	        const psc = this.proxySourceCache;
	        if (this._shouldDisableRenderCache() || this._invalidateRenderCache) {
	            this._invalidateRenderCache = false;
	            if (psc.renderCache.length > psc.renderCachePool.length) {
	                const used = Object.values(psc.proxyCachedFBO);
	                psc.proxyCachedFBO = {};
	                for (let i = 0; i < used.length; ++i) {
	                    const fbos = Object.values(used[i]);
	                    psc.renderCachePool.push(...fbos);
	                }
	            }
	            return;
	        }
	        this._clearRasterFadeFromRenderCache();
	        const coords = this.proxyCoords;
	        const dirty = this._tilesDirty;
	        for (let i = coords.length - 1; i >= 0; i--) {
	            const proxy = coords[i];
	            psc.getTileByID(proxy.key);
	            if (psc.proxyCachedFBO[proxy.key] !== undefined) {
	                const prev = previousProxyToSource[proxy.key];
	                const current = this.proxyToSource[proxy.key];
	                let equal = 0;
	                for (const source in current) {
	                    const tiles = current[source];
	                    const prevTiles = prev[source];
	                    if (!prevTiles || prevTiles.length !== tiles.length || tiles.some((t, index) => t !== prevTiles[index] || dirty[source] && dirty[source].hasOwnProperty(t.key))) {
	                        equal = -1;
	                        break;
	                    }
	                    ++equal;
	                }
	                for (const proxyFBO in psc.proxyCachedFBO[proxy.key]) {
	                    psc.renderCache[psc.proxyCachedFBO[proxy.key][proxyFBO]].dirty = equal < 0 || equal !== Object.values(prev).length;
	                }
	            }
	        }
	        const sortedRenderBatches = [...this._drapedRenderBatches];
	        sortedRenderBatches.sort((batchA, batchB) => {
	            const batchASize = batchA.end - batchA.start;
	            const batchBSize = batchB.end - batchB.start;
	            return batchBSize - batchASize;
	        });
	        for (const batch of sortedRenderBatches) {
	            for (const id of coords) {
	                if (psc.proxyCachedFBO[id.key]) {
	                    continue;
	                }
	                let index = psc.renderCachePool.pop();
	                if (index === undefined && psc.renderCache.length < RENDER_CACHE_MAX_SIZE) {
	                    index = psc.renderCache.length;
	                    psc.renderCache.push(this._createFBO());
	                }
	                if (index !== undefined) {
	                    psc.proxyCachedFBO[id.key] = {};
	                    psc.proxyCachedFBO[id.key][batch.start] = index;
	                    psc.renderCache[index].dirty = true;
	                }
	            }
	        }
	        this._tilesDirty = {};
	    }
	    _setupStencil(fbo, proxiedCoords, layer, sourceCache) {
	        if (!sourceCache || !this._sourceTilesOverlap[sourceCache.id]) {
	            if (this._overlapStencilType)
	                this._overlapStencilType = false;
	            return;
	        }
	        const context = this.painter.context;
	        const gl = context.gl;
	        if (proxiedCoords.length <= 1) {
	            this._overlapStencilType = false;
	            return;
	        }
	        let stencilRange;
	        if (layer.isTileClipped()) {
	            stencilRange = proxiedCoords.length;
	            this._overlapStencilMode.test = {
	                func: gl.EQUAL,
	                mask: 255
	            };
	            this._overlapStencilType = 'Clip';
	        } else if (proxiedCoords[0].overscaledZ > proxiedCoords[proxiedCoords.length - 1].overscaledZ) {
	            stencilRange = 1;
	            this._overlapStencilMode.test = {
	                func: gl.GREATER,
	                mask: 255
	            };
	            this._overlapStencilType = 'Mask';
	        } else {
	            this._overlapStencilType = false;
	            return;
	        }
	        if (this._stencilRef + stencilRange > 255) {
	            context.clear({ stencil: 0 });
	            this._stencilRef = 0;
	        }
	        this._stencilRef += stencilRange;
	        this._overlapStencilMode.ref = this._stencilRef;
	        if (layer.isTileClipped()) {
	            this._renderTileClippingMasks(proxiedCoords, this._overlapStencilMode.ref);
	        }
	    }
	    clipOrMaskOverlapStencilType() {
	        return this._overlapStencilType === 'Clip' || this._overlapStencilType === 'Mask';
	    }
	    stencilModeForRTTOverlap(id) {
	        if (!this.renderingToTexture || !this._overlapStencilType) {
	            return ref_properties.StencilMode.disabled;
	        }
	        if (this._overlapStencilType === 'Clip') {
	            this._overlapStencilMode.ref = this.painter._tileClippingMaskIDs[id.key];
	        }
	        return this._overlapStencilMode;
	    }
	    _renderTileClippingMasks(proxiedCoords, ref) {
	        const painter = this.painter;
	        const context = this.painter.context;
	        const gl = context.gl;
	        painter._tileClippingMaskIDs = {};
	        context.setColorMode(ref_properties.ColorMode.disabled);
	        context.setDepthMode(ref_properties.DepthMode.disabled);
	        const program = painter.useProgram('clippingMask');
	        for (const tileID of proxiedCoords) {
	            const id = painter._tileClippingMaskIDs[tileID.key] = --ref;
	            program.draw(context, gl.TRIANGLES, ref_properties.DepthMode.disabled, new ref_properties.StencilMode({
	                func: gl.ALWAYS,
	                mask: 0
	            }, id, 255, gl.KEEP, gl.KEEP, gl.REPLACE), ref_properties.ColorMode.disabled, ref_properties.CullFaceMode.disabled, clippingMaskUniformValues(tileID.projMatrix), '$clipping', painter.tileExtentBuffer, painter.quadTriangleIndexBuffer, painter.tileExtentSegments);
	        }
	    }
	    pointCoordinate(screenPoint) {
	        const transform = this.painter.transform;
	        if (screenPoint.x < 0 || screenPoint.x > transform.width || screenPoint.y < 0 || screenPoint.y > transform.height) {
	            return null;
	        }
	        const far = [
	            screenPoint.x,
	            screenPoint.y,
	            1,
	            1
	        ];
	        ref_properties.transformMat4$1(far, far, transform.pixelMatrixInverse);
	        ref_properties.scale$1(far, far, 1 / far[3]);
	        far[0] /= transform.worldSize;
	        far[1] /= transform.worldSize;
	        const camera = transform._camera.position;
	        const mercatorZScale = ref_properties.mercatorZfromAltitude(1, transform.center.lat);
	        const p = [
	            camera[0],
	            camera[1],
	            camera[2] / mercatorZScale,
	            0
	        ];
	        const dir = ref_properties.subtract([], far.slice(0, 3), p);
	        ref_properties.normalize(dir, dir);
	        const exaggeration = this._exaggeration;
	        const distanceAlongRay = this.raycast(p, dir, exaggeration);
	        if (distanceAlongRay === null || !distanceAlongRay)
	            return null;
	        ref_properties.scaleAndAdd(p, p, dir, distanceAlongRay);
	        p[3] = p[2];
	        p[2] *= mercatorZScale;
	        return p;
	    }
	    drawDepth() {
	        const painter = this.painter;
	        const context = painter.context;
	        const psc = this.proxySourceCache;
	        const width = Math.ceil(painter.width), height = Math.ceil(painter.height);
	        if (this._depthFBO && (this._depthFBO.width !== width || this._depthFBO.height !== height)) {
	            this._depthFBO.destroy();
	            this._depthFBO = undefined;
	            this._depthTexture = undefined;
	        }
	        if (!this._depthFBO) {
	            const gl = context.gl;
	            const fbo = context.createFramebuffer(width, height, true);
	            context.activeTexture.set(gl.TEXTURE0);
	            const texture = new ref_properties.Texture(context, {
	                width,
	                height,
	                data: null
	            }, gl.RGBA);
	            texture.bind(gl.NEAREST, gl.CLAMP_TO_EDGE);
	            fbo.colorAttachment.set(texture.texture);
	            const renderbuffer = context.createRenderbuffer(context.gl.DEPTH_COMPONENT16, width, height);
	            fbo.depthAttachment.set(renderbuffer);
	            this._depthFBO = fbo;
	            this._depthTexture = texture;
	        }
	        context.bindFramebuffer.set(this._depthFBO.framebuffer);
	        context.viewport.set([
	            0,
	            0,
	            width,
	            height
	        ]);
	        drawTerrainDepth(painter, this, psc, this.proxyCoords);
	    }
	    _setupProxiedCoordsForOrtho(sourceCache, sourceCoords, previousProxyToSource) {
	        if (sourceCache.getSource() instanceof ImageSource) {
	            return this._setupProxiedCoordsForImageSource(sourceCache, sourceCoords, previousProxyToSource);
	        }
	        this._findCoveringTileCache[sourceCache.id] = this._findCoveringTileCache[sourceCache.id] || {};
	        const coords = this.proxiedCoords[sourceCache.id] = [];
	        const proxys = this.proxyCoords;
	        for (let i = 0; i < proxys.length; i++) {
	            const proxyTileID = proxys[i];
	            const proxied = this._findTileCoveringTileID(proxyTileID, sourceCache);
	            if (proxied) {
	                const id = this._createProxiedId(proxyTileID, proxied, previousProxyToSource[proxyTileID.key] && previousProxyToSource[proxyTileID.key][sourceCache.id]);
	                coords.push(id);
	                this.proxyToSource[proxyTileID.key][sourceCache.id] = [id];
	            }
	        }
	        let hasOverlap = false;
	        for (let i = 0; i < sourceCoords.length; i++) {
	            const tile = sourceCache.getTile(sourceCoords[i]);
	            if (!tile || !tile.hasData())
	                continue;
	            const proxy = this._findTileCoveringTileID(tile.tileID, this.proxySourceCache);
	            if (proxy && proxy.tileID.canonical.z !== tile.tileID.canonical.z) {
	                const array = this.proxyToSource[proxy.tileID.key][sourceCache.id];
	                const id = this._createProxiedId(proxy.tileID, tile, previousProxyToSource[proxy.tileID.key] && previousProxyToSource[proxy.tileID.key][sourceCache.id]);
	                if (!array) {
	                    this.proxyToSource[proxy.tileID.key][sourceCache.id] = [id];
	                } else {
	                    array.splice(array.length - 1, 0, id);
	                }
	                coords.push(id);
	                hasOverlap = true;
	            }
	        }
	        this._sourceTilesOverlap[sourceCache.id] = hasOverlap;
	    }
	    _setupProxiedCoordsForImageSource(sourceCache, sourceCoords, previousProxyToSource) {
	        if (!sourceCache.getSource().loaded())
	            return;
	        const coords = this.proxiedCoords[sourceCache.id] = [];
	        const proxys = this.proxyCoords;
	        const imageSource = sourceCache.getSource();
	        const anchor = new ref_properties.pointGeometry(imageSource.tileID.x, imageSource.tileID.y)._div(1 << imageSource.tileID.z);
	        const aabb = imageSource.coordinates.map(ref_properties.MercatorCoordinate.fromLngLat).reduce((acc, coord) => {
	            acc.min.x = Math.min(acc.min.x, coord.x - anchor.x);
	            acc.min.y = Math.min(acc.min.y, coord.y - anchor.y);
	            acc.max.x = Math.max(acc.max.x, coord.x - anchor.x);
	            acc.max.y = Math.max(acc.max.y, coord.y - anchor.y);
	            return acc;
	        }, {
	            min: new ref_properties.pointGeometry(Number.MAX_VALUE, Number.MAX_VALUE),
	            max: new ref_properties.pointGeometry(-Number.MAX_VALUE, -Number.MAX_VALUE)
	        });
	        const tileOutsideImage = (tileID, imageTileID) => {
	            const x = tileID.wrap + tileID.canonical.x / (1 << tileID.canonical.z);
	            const y = tileID.canonical.y / (1 << tileID.canonical.z);
	            const d = ref_properties.EXTENT / (1 << tileID.canonical.z);
	            const ix = imageTileID.wrap + imageTileID.canonical.x / (1 << imageTileID.canonical.z);
	            const iy = imageTileID.canonical.y / (1 << imageTileID.canonical.z);
	            return x + d < ix + aabb.min.x || x > ix + aabb.max.x || y + d < iy + aabb.min.y || y > iy + aabb.max.y;
	        };
	        for (let i = 0; i < proxys.length; i++) {
	            const proxyTileID = proxys[i];
	            for (let j = 0; j < sourceCoords.length; j++) {
	                const tile = sourceCache.getTile(sourceCoords[j]);
	                if (!tile || !tile.hasData())
	                    continue;
	                if (tileOutsideImage(proxyTileID, tile.tileID))
	                    continue;
	                const id = this._createProxiedId(proxyTileID, tile, previousProxyToSource[proxyTileID.key] && previousProxyToSource[proxyTileID.key][sourceCache.id]);
	                const array = this.proxyToSource[proxyTileID.key][sourceCache.id];
	                if (!array) {
	                    this.proxyToSource[proxyTileID.key][sourceCache.id] = [id];
	                } else {
	                    array.push(id);
	                }
	                coords.push(id);
	            }
	        }
	    }
	    _createProxiedId(proxyTileID, tile, recycle) {
	        let matrix = this.orthoMatrix;
	        if (recycle) {
	            const recycled = recycle.find(proxied => proxied.key === tile.tileID.key);
	            if (recycled)
	                return recycled;
	        }
	        if (tile.tileID.key !== proxyTileID.key) {
	            const scale = proxyTileID.canonical.z - tile.tileID.canonical.z;
	            matrix = ref_properties.create();
	            let size, xOffset, yOffset;
	            const wrap = tile.tileID.wrap - proxyTileID.wrap << proxyTileID.overscaledZ;
	            if (scale > 0) {
	                size = ref_properties.EXTENT >> scale;
	                xOffset = size * ((tile.tileID.canonical.x << scale) - proxyTileID.canonical.x + wrap);
	                yOffset = size * ((tile.tileID.canonical.y << scale) - proxyTileID.canonical.y);
	            } else {
	                size = ref_properties.EXTENT << -scale;
	                xOffset = ref_properties.EXTENT * (tile.tileID.canonical.x - (proxyTileID.canonical.x + wrap << -scale));
	                yOffset = ref_properties.EXTENT * (tile.tileID.canonical.y - (proxyTileID.canonical.y << -scale));
	            }
	            ref_properties.ortho(matrix, 0, size, 0, size, 0, 1);
	            ref_properties.translate(matrix, matrix, [
	                xOffset,
	                yOffset,
	                0
	            ]);
	        }
	        return new ProxiedTileID(tile.tileID, proxyTileID.key, matrix);
	    }
	    _findTileCoveringTileID(tileID, sourceCache) {
	        let tile = sourceCache.getTile(tileID);
	        if (tile && tile.hasData())
	            return tile;
	        const lookup = this._findCoveringTileCache[sourceCache.id];
	        const key = lookup[tileID.key];
	        tile = key ? sourceCache.getTileByID(key) : null;
	        if (tile && tile.hasData() || key === null)
	            return tile;
	        let sourceTileID = tile ? tile.tileID : tileID;
	        let z = sourceTileID.overscaledZ;
	        const minzoom = sourceCache.getSource().minzoom;
	        const path = [];
	        if (!key) {
	            const maxzoom = sourceCache.getSource().maxzoom;
	            if (tileID.canonical.z >= maxzoom) {
	                const downscale = tileID.canonical.z - maxzoom;
	                if (sourceCache.getSource().reparseOverscaled) {
	                    z = Math.max(tileID.canonical.z + 2, sourceCache.transform.tileZoom);
	                    sourceTileID = new ref_properties.OverscaledTileID(z, tileID.wrap, maxzoom, tileID.canonical.x >> downscale, tileID.canonical.y >> downscale);
	                } else if (downscale !== 0) {
	                    z = maxzoom;
	                    sourceTileID = new ref_properties.OverscaledTileID(z, tileID.wrap, maxzoom, tileID.canonical.x >> downscale, tileID.canonical.y >> downscale);
	                }
	            }
	            if (sourceTileID.key !== tileID.key) {
	                path.push(sourceTileID.key);
	                tile = sourceCache.getTile(sourceTileID);
	            }
	        }
	        const pathToLookup = key => {
	            path.forEach(id => {
	                lookup[id] = key;
	            });
	            path.length = 0;
	        };
	        for (z = z - 1; z >= minzoom && !(tile && tile.hasData()); z--) {
	            if (tile) {
	                pathToLookup(tile.tileID.key);
	            }
	            const id = sourceTileID.calculateScaledKey(z);
	            tile = sourceCache.getTileByID(id);
	            if (tile && tile.hasData())
	                break;
	            const key = lookup[id];
	            if (key === null) {
	                break;
	            } else if (key !== undefined) {
	                tile = sourceCache.getTileByID(key);
	                continue;
	            }
	            path.push(id);
	        }
	        pathToLookup(tile ? tile.tileID.key : null);
	        return tile && tile.hasData() ? tile : null;
	    }
	    findDEMTileFor(tileID) {
	        return this.enabled ? this._findTileCoveringTileID(tileID, this.sourceCache) : null;
	    }
	    prepareDrawTile() {
	        this.renderedToTile = true;
	    }
	    _clearRenderCacheForTile(source, coord) {
	        let sourceTiles = this._tilesDirty[source];
	        if (!sourceTiles)
	            sourceTiles = this._tilesDirty[source] = {};
	        sourceTiles[coord.key] = true;
	    }
	    getWirefameBuffer() {
	        if (!this.wireframeSegments) {
	            const wireframeGridIndices = createWireframeGrid(GRID_DIM + 1);
	            this.wireframeIndexBuffer = this.painter.context.createIndexBuffer(wireframeGridIndices);
	            this.wireframeSegments = ref_properties.SegmentVector.simpleSegment(0, 0, this.gridBuffer.length, wireframeGridIndices.length);
	        }
	        return [
	            this.wireframeIndexBuffer,
	            this.wireframeSegments
	        ];
	    }
	}
	function sortByDistanceToCamera(tileIDs, painter) {
	    const cameraCoordinate = painter.transform.pointCoordinate(painter.transform.getCameraPoint());
	    const cameraPoint = new ref_properties.pointGeometry(cameraCoordinate.x, cameraCoordinate.y);
	    tileIDs.sort((a, b) => {
	        if (b.overscaledZ - a.overscaledZ)
	            return b.overscaledZ - a.overscaledZ;
	        const aPoint = new ref_properties.pointGeometry(a.canonical.x + (1 << a.canonical.z) * a.wrap, a.canonical.y);
	        const bPoint = new ref_properties.pointGeometry(b.canonical.x + (1 << b.canonical.z) * b.wrap, b.canonical.y);
	        const cameraScaled = cameraPoint.mult(1 << a.canonical.z);
	        cameraScaled.x -= 0.5;
	        cameraScaled.y -= 0.5;
	        return cameraScaled.distSqr(aPoint) - cameraScaled.distSqr(bPoint);
	    });
	}
	function createGrid(count) {
	    const boundsArray = new ref_properties.StructArrayLayout4i8();
	    const indexArray = new ref_properties.StructArrayLayout3ui6();
	    const size = count + 2;
	    boundsArray.reserve(size * size);
	    indexArray.reserve((size - 1) * (size - 1) * 2);
	    const step = ref_properties.EXTENT / (count - 1);
	    const gridBound = ref_properties.EXTENT + step / 2;
	    const bound = gridBound + step;
	    const skirtOffset = 24575;
	    for (let y = -step; y < bound; y += step) {
	        for (let x = -step; x < bound; x += step) {
	            const offset = x < 0 || x > gridBound || y < 0 || y > gridBound ? skirtOffset : 0;
	            const xi = ref_properties.clamp(Math.round(x), 0, ref_properties.EXTENT);
	            const yi = ref_properties.clamp(Math.round(y), 0, ref_properties.EXTENT);
	            boundsArray.emplaceBack(xi + offset, yi, xi, yi);
	        }
	    }
	    const skirtIndicesOffset = (size - 3) * (size - 3) * 2;
	    const quad = (i, j) => {
	        const index = j * size + i;
	        indexArray.emplaceBack(index + 1, index, index + size);
	        indexArray.emplaceBack(index + size, index + size + 1, index + 1);
	    };
	    for (let j = 1; j < size - 2; j++) {
	        for (let i = 1; i < size - 2; i++) {
	            quad(i, j);
	        }
	    }
	    [
	        0,
	        size - 2
	    ].forEach(j => {
	        for (let i = 0; i < size - 1; i++) {
	            quad(i, j);
	            quad(j, i);
	        }
	    });
	    return [
	        boundsArray,
	        indexArray,
	        skirtIndicesOffset
	    ];
	}
	function createWireframeGrid(count) {
	    let index = 0;
	    const indexArray = new ref_properties.StructArrayLayout2ui4();
	    const size = count + 2;
	    for (let j = 1; j < count; j++) {
	        for (let i = 1; i < count; i++) {
	            index = j * size + i;
	            indexArray.emplaceBack(index, index + 1);
	            indexArray.emplaceBack(index, index + size);
	            indexArray.emplaceBack(index + 1, index + size);
	            if (j === count - 1)
	                indexArray.emplaceBack(index + size, index + size + 1);
	        }
	        indexArray.emplaceBack(index + 1, index + 1 + size);
	    }
	    return indexArray;
	}
	const terrainUniforms = (context, locations) => ({
	    'u_dem': new ref_properties.Uniform1i(context, locations.u_dem),
	    'u_dem_prev': new ref_properties.Uniform1i(context, locations.u_dem_prev),
	    'u_dem_unpack': new ref_properties.Uniform4f(context, locations.u_dem_unpack),
	    'u_dem_tl': new ref_properties.Uniform2f(context, locations.u_dem_tl),
	    'u_dem_scale': new ref_properties.Uniform1f(context, locations.u_dem_scale),
	    'u_dem_tl_prev': new ref_properties.Uniform2f(context, locations.u_dem_tl_prev),
	    'u_dem_scale_prev': new ref_properties.Uniform1f(context, locations.u_dem_scale_prev),
	    'u_dem_size': new ref_properties.Uniform1f(context, locations.u_dem_size),
	    'u_dem_lerp': new ref_properties.Uniform1f(context, locations.u_dem_lerp),
	    'u_exaggeration': new ref_properties.Uniform1f(context, locations.u_exaggeration),
	    'u_depth': new ref_properties.Uniform1i(context, locations.u_depth),
	    'u_depth_size_inv': new ref_properties.Uniform2f(context, locations.u_depth_size_inv),
	    'u_meter_to_dem': new ref_properties.Uniform1f(context, locations.u_meter_to_dem),
	    'u_label_plane_matrix_inv': new ref_properties.UniformMatrix4f(context, locations.u_label_plane_matrix_inv),
	    'u_tile_tl_up': new ref_properties.Uniform3f(context, locations.u_tile_tl_up),
	    'u_tile_tr_up': new ref_properties.Uniform3f(context, locations.u_tile_tr_up),
	    'u_tile_br_up': new ref_properties.Uniform3f(context, locations.u_tile_br_up),
	    'u_tile_bl_up': new ref_properties.Uniform3f(context, locations.u_tile_bl_up),
	    'u_tile_up_scale': new ref_properties.Uniform1f(context, locations.u_tile_up_scale)
	});
	function defaultTerrainUniforms(encoding) {
	    return {
	        'u_dem': 2,
	        'u_dem_prev': 4,
	        'u_dem_unpack': ref_properties.DEMData.getUnpackVector(encoding),
	        'u_dem_tl': [
	            0,
	            0
	        ],
	        'u_dem_tl_prev': [
	            0,
	            0
	        ],
	        'u_dem_scale': 0,
	        'u_dem_scale_prev': 0,
	        'u_dem_size': 0,
	        'u_dem_lerp': 1,
	        'u_depth': 3,
	        'u_depth_size_inv': [
	            0,
	            0
	        ],
	        'u_exaggeration': 0,
	        'u_tile_tl_up': [
	            0,
	            0,
	            1
	        ],
	        'u_tile_tr_up': [
	            0,
	            0,
	            1
	        ],
	        'u_tile_br_up': [
	            0,
	            0,
	            1
	        ],
	        'u_tile_bl_up': [
	            0,
	            0,
	            1
	        ],
	        'u_tile_up_scale': 1
	    };
	}

	const fogUniforms = (context, locations) => ({
	    'u_fog_matrix': new ref_properties.UniformMatrix4f(context, locations.u_fog_matrix),
	    'u_fog_range': new ref_properties.Uniform2f(context, locations.u_fog_range),
	    'u_fog_color': new ref_properties.Uniform4f(context, locations.u_fog_color),
	    'u_fog_horizon_blend': new ref_properties.Uniform1f(context, locations.u_fog_horizon_blend),
	    'u_fog_temporal_offset': new ref_properties.Uniform1f(context, locations.u_fog_temporal_offset),
	    'u_frustum_tl': new ref_properties.Uniform3f(context, locations.u_frustum_tl),
	    'u_frustum_tr': new ref_properties.Uniform3f(context, locations.u_frustum_tr),
	    'u_frustum_br': new ref_properties.Uniform3f(context, locations.u_frustum_br),
	    'u_frustum_bl': new ref_properties.Uniform3f(context, locations.u_frustum_bl),
	    'u_globe_pos': new ref_properties.Uniform3f(context, locations.u_globe_pos),
	    'u_globe_radius': new ref_properties.Uniform1f(context, locations.u_globe_radius),
	    'u_globe_transition': new ref_properties.Uniform1f(context, locations.u_globe_transition),
	    'u_is_globe': new ref_properties.Uniform1i(context, locations.u_is_globe),
	    'u_viewport': new ref_properties.Uniform2f(context, locations.u_viewport)
	});
	const fogUniformValues = (painter, fog, tileID, fogOpacity, frustumDirTl, frustumDirTr, frustumDirBr, frustumDirBl, globePosition, globeRadius, viewport) => {
	    const tr = painter.transform;
	    const fogColor = fog.properties.get('color').toArray01();
	    fogColor[3] = fogOpacity;
	    const temporalOffset = painter.frameCounter / 1000 % 1;
	    return {
	        'u_fog_matrix': tileID ? tr.calculateFogTileMatrix(tileID) : painter.identityMat,
	        'u_fog_range': fog.getFovAdjustedRange(tr._fov),
	        'u_fog_color': fogColor,
	        'u_fog_horizon_blend': fog.properties.get('horizon-blend'),
	        'u_fog_temporal_offset': temporalOffset,
	        'u_frustum_tl': frustumDirTl,
	        'u_frustum_tr': frustumDirTr,
	        'u_frustum_br': frustumDirBr,
	        'u_frustum_bl': frustumDirBl,
	        'u_globe_pos': globePosition,
	        'u_globe_radius': globeRadius,
	        'u_viewport': viewport,
	        'u_globe_transition': ref_properties.globeToMercatorTransition(tr.zoom),
	        'u_is_globe': +(tr.projection.name === 'globe')
	    };
	};

	function getTokenizedAttributesAndUniforms(array) {
	    const result = [];
	    for (let i = 0; i < array.length; i++) {
	        if (array[i] === null)
	            continue;
	        const token = array[i].split(' ');
	        result.push(token.pop());
	    }
	    return result;
	}
	class Program {
	    static cacheKey(name, defines, programConfiguration) {
	        let key = `${ name }${ programConfiguration ? programConfiguration.cacheKey : '' }`;
	        for (const define of defines) {
	            key += `/${ define }`;
	        }
	        return key;
	    }
	    constructor(context, name, source, configuration, fixedUniforms, fixedDefines) {
	        const gl = context.gl;
	        this.program = gl.createProgram();
	        const staticAttrInfo = getTokenizedAttributesAndUniforms(source.staticAttributes);
	        const dynamicAttrInfo = configuration ? configuration.getBinderAttributes() : [];
	        const allAttrInfo = staticAttrInfo.concat(dynamicAttrInfo);
	        const staticUniformsInfo = source.staticUniforms ? getTokenizedAttributesAndUniforms(source.staticUniforms) : [];
	        const dynamicUniformsInfo = configuration ? configuration.getBinderUniforms() : [];
	        const uniformList = staticUniformsInfo.concat(dynamicUniformsInfo);
	        const allUniformsInfo = [];
	        for (const uniform of uniformList) {
	            if (allUniformsInfo.indexOf(uniform) < 0)
	                allUniformsInfo.push(uniform);
	        }
	        let defines = configuration ? configuration.defines() : [];
	        defines = defines.concat(fixedDefines.map(define => `#define ${ define }`));
	        const fragmentSource = defines.concat(context.extStandardDerivatives ? standardDerivativesExt.concat(preludeFragPrecisionQualifiers) : preludeFragPrecisionQualifiers, preludeFragPrecisionQualifiers, preludeCommonSource, prelude.fragmentSource, preludeFog.fragmentSource, source.fragmentSource).join('\n');
	        const vertexSource = defines.concat(preludeVertPrecisionQualifiers, preludeCommonSource, prelude.vertexSource, preludeFog.vertexSource, preludeTerrain.vertexSource, source.vertexSource).join('\n');
	        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
	        if (gl.isContextLost()) {
	            this.failedToCreate = true;
	            return;
	        }
	        gl.shaderSource(fragmentShader, fragmentSource);
	        gl.compileShader(fragmentShader);
	        gl.attachShader(this.program, fragmentShader);
	        const vertexShader = gl.createShader(gl.VERTEX_SHADER);
	        if (gl.isContextLost()) {
	            this.failedToCreate = true;
	            return;
	        }
	        gl.shaderSource(vertexShader, vertexSource);
	        gl.compileShader(vertexShader);
	        gl.attachShader(this.program, vertexShader);
	        this.attributes = {};
	        const uniformLocations = {};
	        this.numAttributes = allAttrInfo.length;
	        for (let i = 0; i < this.numAttributes; i++) {
	            if (allAttrInfo[i]) {
	                gl.bindAttribLocation(this.program, i, allAttrInfo[i]);
	                this.attributes[allAttrInfo[i]] = i;
	            }
	        }
	        gl.linkProgram(this.program);
	        gl.deleteShader(vertexShader);
	        gl.deleteShader(fragmentShader);
	        for (let it = 0; it < allUniformsInfo.length; it++) {
	            const uniform = allUniformsInfo[it];
	            if (uniform && !uniformLocations[uniform]) {
	                const uniformLocation = gl.getUniformLocation(this.program, uniform);
	                if (uniformLocation) {
	                    uniformLocations[uniform] = uniformLocation;
	                }
	            }
	        }
	        this.fixedUniforms = fixedUniforms(context, uniformLocations);
	        this.binderUniforms = configuration ? configuration.getUniforms(context, uniformLocations) : [];
	        if (fixedDefines.indexOf('TERRAIN') !== -1) {
	            this.terrainUniforms = terrainUniforms(context, uniformLocations);
	        }
	        if (fixedDefines.indexOf('FOG') !== -1) {
	            this.fogUniforms = fogUniforms(context, uniformLocations);
	        }
	    }
	    setTerrainUniformValues(context, terrainUniformValues) {
	        if (!this.terrainUniforms)
	            return;
	        const uniforms = this.terrainUniforms;
	        if (this.failedToCreate)
	            return;
	        context.program.set(this.program);
	        for (const name in terrainUniformValues) {
	            uniforms[name].set(terrainUniformValues[name]);
	        }
	    }
	    setFogUniformValues(context, fogUniformsValues) {
	        if (!this.fogUniforms)
	            return;
	        const uniforms = this.fogUniforms;
	        if (this.failedToCreate)
	            return;
	        context.program.set(this.program);
	        for (const name in fogUniformsValues) {
	            if (uniforms[name].location) {
	                uniforms[name].set(fogUniformsValues[name]);
	            }
	        }
	    }
	    draw(context, drawMode, depthMode, stencilMode, colorMode, cullFaceMode, uniformValues, layerID, layoutVertexBuffer, indexBuffer, segments, currentProperties, zoom, configuration, dynamicLayoutBuffer, dynamicLayoutBuffer2, dynamicLayoutBuffer3) {
	        const gl = context.gl;
	        if (this.failedToCreate)
	            return;
	        context.program.set(this.program);
	        context.setDepthMode(depthMode);
	        context.setStencilMode(stencilMode);
	        context.setColorMode(colorMode);
	        context.setCullFace(cullFaceMode);
	        for (const name of Object.keys(this.fixedUniforms)) {
	            this.fixedUniforms[name].set(uniformValues[name]);
	        }
	        if (configuration) {
	            configuration.setUniforms(context, this.binderUniforms, currentProperties, { zoom: zoom });
	        }
	        const primitiveSize = {
	            [gl.LINES]: 2,
	            [gl.TRIANGLES]: 3,
	            [gl.LINE_STRIP]: 1
	        }[drawMode];
	        for (const segment of segments.get()) {
	            const vaos = segment.vaos || (segment.vaos = {});
	            const vao = vaos[layerID] || (vaos[layerID] = new VertexArrayObject());
	            vao.bind(context, this, layoutVertexBuffer, configuration ? configuration.getPaintVertexBuffers() : [], indexBuffer, segment.vertexOffset, dynamicLayoutBuffer, dynamicLayoutBuffer2, dynamicLayoutBuffer3);
	            gl.drawElements(drawMode, segment.primitiveLength * primitiveSize, gl.UNSIGNED_SHORT, segment.primitiveOffset * primitiveSize * 2);
	        }
	    }
	}

	function patternUniformValues(crossfade, painter, tile) {
	    const tileRatio = 1 / pixelsToTileUnits(tile, 1, painter.transform.tileZoom);
	    const numTiles = Math.pow(2, tile.tileID.overscaledZ);
	    const tileSizeAtNearestZoom = tile.tileSize * Math.pow(2, painter.transform.tileZoom) / numTiles;
	    const pixelX = tileSizeAtNearestZoom * (tile.tileID.canonical.x + tile.tileID.wrap * numTiles);
	    const pixelY = tileSizeAtNearestZoom * tile.tileID.canonical.y;
	    return {
	        'u_image': 0,
	        'u_texsize': tile.imageAtlasTexture.size,
	        'u_scale': [
	            tileRatio,
	            crossfade.fromScale,
	            crossfade.toScale
	        ],
	        'u_fade': crossfade.t,
	        'u_pixel_coord_upper': [
	            pixelX >> 16,
	            pixelY >> 16
	        ],
	        'u_pixel_coord_lower': [
	            pixelX & 65535,
	            pixelY & 65535
	        ]
	    };
	}
	function bgPatternUniformValues(image, crossfade, painter, tile) {
	    const imagePosA = painter.imageManager.getPattern(image.from.toString());
	    const imagePosB = painter.imageManager.getPattern(image.to.toString());
	    const {width, height} = painter.imageManager.getPixelSize();
	    const numTiles = Math.pow(2, tile.tileID.overscaledZ);
	    const tileSizeAtNearestZoom = tile.tileSize * Math.pow(2, painter.transform.tileZoom) / numTiles;
	    const pixelX = tileSizeAtNearestZoom * (tile.tileID.canonical.x + tile.tileID.wrap * numTiles);
	    const pixelY = tileSizeAtNearestZoom * tile.tileID.canonical.y;
	    return {
	        'u_image': 0,
	        'u_pattern_tl_a': imagePosA.tl,
	        'u_pattern_br_a': imagePosA.br,
	        'u_pattern_tl_b': imagePosB.tl,
	        'u_pattern_br_b': imagePosB.br,
	        'u_texsize': [
	            width,
	            height
	        ],
	        'u_mix': crossfade.t,
	        'u_pattern_size_a': imagePosA.displaySize,
	        'u_pattern_size_b': imagePosB.displaySize,
	        'u_scale_a': crossfade.fromScale,
	        'u_scale_b': crossfade.toScale,
	        'u_tile_units_to_pixels': 1 / pixelsToTileUnits(tile, 1, painter.transform.tileZoom),
	        'u_pixel_coord_upper': [
	            pixelX >> 16,
	            pixelY >> 16
	        ],
	        'u_pixel_coord_lower': [
	            pixelX & 65535,
	            pixelY & 65535
	        ]
	    };
	}

	const fillExtrusionUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_lightpos': new ref_properties.Uniform3f(context, locations.u_lightpos),
	    'u_lightintensity': new ref_properties.Uniform1f(context, locations.u_lightintensity),
	    'u_lightcolor': new ref_properties.Uniform3f(context, locations.u_lightcolor),
	    'u_vertical_gradient': new ref_properties.Uniform1f(context, locations.u_vertical_gradient),
	    'u_opacity': new ref_properties.Uniform1f(context, locations.u_opacity),
	    'u_tile_id': new ref_properties.Uniform3f(context, locations.u_tile_id),
	    'u_zoom_transition': new ref_properties.Uniform1f(context, locations.u_zoom_transition),
	    'u_inv_rot_matrix': new ref_properties.UniformMatrix4f(context, locations.u_inv_rot_matrix),
	    'u_merc_center': new ref_properties.Uniform2f(context, locations.u_merc_center),
	    'u_up_dir': new ref_properties.Uniform3f(context, locations.u_up_dir),
	    'u_height_lift': new ref_properties.Uniform1f(context, locations.u_height_lift)
	});
	const fillExtrusionPatternUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_lightpos': new ref_properties.Uniform3f(context, locations.u_lightpos),
	    'u_lightintensity': new ref_properties.Uniform1f(context, locations.u_lightintensity),
	    'u_lightcolor': new ref_properties.Uniform3f(context, locations.u_lightcolor),
	    'u_vertical_gradient': new ref_properties.Uniform1f(context, locations.u_vertical_gradient),
	    'u_height_factor': new ref_properties.Uniform1f(context, locations.u_height_factor),
	    'u_tile_id': new ref_properties.Uniform3f(context, locations.u_tile_id),
	    'u_zoom_transition': new ref_properties.Uniform1f(context, locations.u_zoom_transition),
	    'u_inv_rot_matrix': new ref_properties.UniformMatrix4f(context, locations.u_inv_rot_matrix),
	    'u_merc_center': new ref_properties.Uniform2f(context, locations.u_merc_center),
	    'u_up_dir': new ref_properties.Uniform3f(context, locations.u_up_dir),
	    'u_height_lift': new ref_properties.Uniform1f(context, locations.u_height_lift),
	    'u_image': new ref_properties.Uniform1i(context, locations.u_image),
	    'u_texsize': new ref_properties.Uniform2f(context, locations.u_texsize),
	    'u_pixel_coord_upper': new ref_properties.Uniform2f(context, locations.u_pixel_coord_upper),
	    'u_pixel_coord_lower': new ref_properties.Uniform2f(context, locations.u_pixel_coord_lower),
	    'u_scale': new ref_properties.Uniform3f(context, locations.u_scale),
	    'u_fade': new ref_properties.Uniform1f(context, locations.u_fade),
	    'u_opacity': new ref_properties.Uniform1f(context, locations.u_opacity)
	});
	const identityMatrix$3 = ref_properties.create();
	const fillExtrusionUniformValues = (matrix, painter, shouldUseVerticalGradient, opacity, coord, heightLift, zoomTransition, mercatorCenter, invMatrix) => {
	    const light = painter.style.light;
	    const _lp = light.properties.get('position');
	    const lightPos = [
	        _lp.x,
	        _lp.y,
	        _lp.z
	    ];
	    const lightMat = ref_properties.create$1();
	    const anchor = light.properties.get('anchor');
	    if (anchor === 'viewport') {
	        ref_properties.fromRotation(lightMat, -painter.transform.angle);
	        ref_properties.transformMat3(lightPos, lightPos, lightMat);
	    }
	    const lightColor = light.properties.get('color');
	    const tr = painter.transform;
	    const uniformValues = {
	        'u_matrix': matrix,
	        'u_lightpos': lightPos,
	        'u_lightintensity': light.properties.get('intensity'),
	        'u_lightcolor': [
	            lightColor.r,
	            lightColor.g,
	            lightColor.b
	        ],
	        'u_vertical_gradient': +shouldUseVerticalGradient,
	        'u_opacity': opacity,
	        'u_tile_id': [
	            0,
	            0,
	            0
	        ],
	        'u_zoom_transition': 0,
	        'u_inv_rot_matrix': identityMatrix$3,
	        'u_merc_center': [
	            0,
	            0
	        ],
	        'u_up_dir': [
	            0,
	            0,
	            0
	        ],
	        'u_height_lift': 0
	    };
	    if (tr.projection.name === 'globe') {
	        uniformValues['u_tile_id'] = [
	            coord.canonical.x,
	            coord.canonical.y,
	            1 << coord.canonical.z
	        ];
	        uniformValues['u_zoom_transition'] = zoomTransition;
	        uniformValues['u_inv_rot_matrix'] = invMatrix;
	        uniformValues['u_merc_center'] = mercatorCenter;
	        uniformValues['u_up_dir'] = tr.projection.upVector(new ref_properties.CanonicalTileID(0, 0, 0), mercatorCenter[0] * ref_properties.EXTENT, mercatorCenter[1] * ref_properties.EXTENT);
	        uniformValues['u_height_lift'] = heightLift;
	    }
	    return uniformValues;
	};
	const fillExtrusionPatternUniformValues = (matrix, painter, shouldUseVerticalGradient, opacity, coord, crossfade, tile, heightLift, zoomTransition, mercatorCenter, invMatrix) => {
	    const uniformValues = fillExtrusionUniformValues(matrix, painter, shouldUseVerticalGradient, opacity, coord, heightLift, zoomTransition, mercatorCenter, invMatrix);
	    const heightFactorUniform = { 'u_height_factor': -Math.pow(2, coord.overscaledZ) / tile.tileSize / 8 };
	    return ref_properties.extend(uniformValues, patternUniformValues(crossfade, painter, tile), heightFactorUniform);
	};

	const fillUniforms = (context, locations) => ({ 'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix) });
	const fillPatternUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_image': new ref_properties.Uniform1i(context, locations.u_image),
	    'u_texsize': new ref_properties.Uniform2f(context, locations.u_texsize),
	    'u_pixel_coord_upper': new ref_properties.Uniform2f(context, locations.u_pixel_coord_upper),
	    'u_pixel_coord_lower': new ref_properties.Uniform2f(context, locations.u_pixel_coord_lower),
	    'u_scale': new ref_properties.Uniform3f(context, locations.u_scale),
	    'u_fade': new ref_properties.Uniform1f(context, locations.u_fade)
	});
	const fillOutlineUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_world': new ref_properties.Uniform2f(context, locations.u_world)
	});
	const fillOutlinePatternUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_world': new ref_properties.Uniform2f(context, locations.u_world),
	    'u_image': new ref_properties.Uniform1i(context, locations.u_image),
	    'u_texsize': new ref_properties.Uniform2f(context, locations.u_texsize),
	    'u_pixel_coord_upper': new ref_properties.Uniform2f(context, locations.u_pixel_coord_upper),
	    'u_pixel_coord_lower': new ref_properties.Uniform2f(context, locations.u_pixel_coord_lower),
	    'u_scale': new ref_properties.Uniform3f(context, locations.u_scale),
	    'u_fade': new ref_properties.Uniform1f(context, locations.u_fade)
	});
	const fillUniformValues = matrix => ({ 'u_matrix': matrix });
	const fillPatternUniformValues = (matrix, painter, crossfade, tile) => ref_properties.extend(fillUniformValues(matrix), patternUniformValues(crossfade, painter, tile));
	const fillOutlineUniformValues = (matrix, drawingBufferSize) => ({
	    'u_matrix': matrix,
	    'u_world': drawingBufferSize
	});
	const fillOutlinePatternUniformValues = (matrix, painter, crossfade, tile, drawingBufferSize) => ref_properties.extend(fillPatternUniformValues(matrix, painter, crossfade, tile), { 'u_world': drawingBufferSize });

	const circleUniforms = (context, locations) => ({
	    'u_camera_to_center_distance': new ref_properties.Uniform1f(context, locations.u_camera_to_center_distance),
	    'u_extrude_scale': new ref_properties.UniformMatrix2f(context, locations.u_extrude_scale),
	    'u_device_pixel_ratio': new ref_properties.Uniform1f(context, locations.u_device_pixel_ratio),
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_inv_rot_matrix': new ref_properties.UniformMatrix4f(context, locations.u_inv_rot_matrix),
	    'u_merc_center': new ref_properties.Uniform2f(context, locations.u_merc_center),
	    'u_tile_id': new ref_properties.Uniform3f(context, locations.u_tile_id),
	    'u_zoom_transition': new ref_properties.Uniform1f(context, locations.u_zoom_transition),
	    'u_up_dir': new ref_properties.Uniform3f(context, locations.u_up_dir)
	});
	const identityMatrix$2 = ref_properties.create();
	const circleUniformValues = (painter, coord, tile, invMatrix, mercatorCenter, layer) => {
	    const transform = painter.transform;
	    const isGlobe = transform.projection.name === 'globe';
	    let extrudeScale;
	    if (layer.paint.get('circle-pitch-alignment') === 'map') {
	        if (isGlobe) {
	            const s = ref_properties.globePixelsToTileUnits(transform.zoom, coord.canonical) * transform._projectionScaler;
	            extrudeScale = Float32Array.from([
	                s,
	                0,
	                0,
	                s
	            ]);
	        } else {
	            extrudeScale = transform.calculatePixelsToTileUnitsMatrix(tile);
	        }
	    } else {
	        extrudeScale = new Float32Array([
	            transform.pixelsToGLUnits[0],
	            0,
	            0,
	            transform.pixelsToGLUnits[1]
	        ]);
	    }
	    const values = {
	        'u_camera_to_center_distance': transform.cameraToCenterDistance,
	        'u_matrix': painter.translatePosMatrix(coord.projMatrix, tile, layer.paint.get('circle-translate'), layer.paint.get('circle-translate-anchor')),
	        'u_device_pixel_ratio': ref_properties.exported.devicePixelRatio,
	        'u_extrude_scale': extrudeScale,
	        'u_inv_rot_matrix': identityMatrix$2,
	        'u_merc_center': [
	            0,
	            0
	        ],
	        'u_tile_id': [
	            0,
	            0,
	            0
	        ],
	        'u_zoom_transition': 0,
	        'u_up_dir': [
	            0,
	            0,
	            0
	        ]
	    };
	    if (isGlobe) {
	        values['u_inv_rot_matrix'] = invMatrix;
	        values['u_merc_center'] = mercatorCenter;
	        values['u_tile_id'] = [
	            coord.canonical.x,
	            coord.canonical.y,
	            1 << coord.canonical.z
	        ];
	        values['u_zoom_transition'] = ref_properties.globeToMercatorTransition(transform.zoom);
	        const x = mercatorCenter[0] * ref_properties.EXTENT;
	        const y = mercatorCenter[1] * ref_properties.EXTENT;
	        values['u_up_dir'] = transform.projection.upVector(new ref_properties.CanonicalTileID(0, 0, 0), x, y);
	    }
	    return values;
	};
	const circleDefinesValues = layer => {
	    const values = [];
	    if (layer.paint.get('circle-pitch-alignment') === 'map')
	        values.push('PITCH_WITH_MAP');
	    if (layer.paint.get('circle-pitch-scale') === 'map')
	        values.push('SCALE_WITH_MAP');
	    return values;
	};

	const collisionUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_camera_to_center_distance': new ref_properties.Uniform1f(context, locations.u_camera_to_center_distance),
	    'u_extrude_scale': new ref_properties.Uniform2f(context, locations.u_extrude_scale)
	});
	const collisionCircleUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_inv_matrix': new ref_properties.UniformMatrix4f(context, locations.u_inv_matrix),
	    'u_camera_to_center_distance': new ref_properties.Uniform1f(context, locations.u_camera_to_center_distance),
	    'u_viewport_size': new ref_properties.Uniform2f(context, locations.u_viewport_size)
	});
	const collisionUniformValues = (matrix, transform, tile, projection) => {
	    const pixelRatio = ref_properties.EXTENT / tile.tileSize;
	    return {
	        'u_matrix': matrix,
	        'u_camera_to_center_distance': transform.getCameraToCenterDistance(projection),
	        'u_extrude_scale': [
	            transform.pixelsToGLUnits[0] / pixelRatio,
	            transform.pixelsToGLUnits[1] / pixelRatio
	        ]
	    };
	};
	const collisionCircleUniformValues = (matrix, invMatrix, transform, projection) => {
	    return {
	        'u_matrix': matrix,
	        'u_inv_matrix': invMatrix,
	        'u_camera_to_center_distance': transform.getCameraToCenterDistance(projection),
	        'u_viewport_size': [
	            transform.width,
	            transform.height
	        ]
	    };
	};

	const debugUniforms = (context, locations) => ({
	    'u_color': new ref_properties.UniformColor(context, locations.u_color),
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_overlay': new ref_properties.Uniform1i(context, locations.u_overlay),
	    'u_overlay_scale': new ref_properties.Uniform1f(context, locations.u_overlay_scale)
	});
	const debugUniformValues = (matrix, color, scaleRatio = 1) => ({
	    'u_matrix': matrix,
	    'u_color': color,
	    'u_overlay': 0,
	    'u_overlay_scale': scaleRatio
	});

	const heatmapUniforms = (context, locations) => ({
	    'u_extrude_scale': new ref_properties.Uniform1f(context, locations.u_extrude_scale),
	    'u_intensity': new ref_properties.Uniform1f(context, locations.u_intensity),
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_inv_rot_matrix': new ref_properties.UniformMatrix4f(context, locations.u_inv_rot_matrix),
	    'u_merc_center': new ref_properties.Uniform2f(context, locations.u_merc_center),
	    'u_tile_id': new ref_properties.Uniform3f(context, locations.u_tile_id),
	    'u_zoom_transition': new ref_properties.Uniform1f(context, locations.u_zoom_transition),
	    'u_up_dir': new ref_properties.Uniform3f(context, locations.u_up_dir)
	});
	const heatmapTextureUniforms = (context, locations) => ({
	    'u_image': new ref_properties.Uniform1i(context, locations.u_image),
	    'u_color_ramp': new ref_properties.Uniform1i(context, locations.u_color_ramp),
	    'u_opacity': new ref_properties.Uniform1f(context, locations.u_opacity)
	});
	const identityMatrix$1 = ref_properties.create();
	const heatmapUniformValues = (painter, coord, tile, invMatrix, mercatorCenter, zoom, intensity) => {
	    const transform = painter.transform;
	    const isGlobe = transform.projection.name === 'globe';
	    const extrudeScale = isGlobe ? ref_properties.globePixelsToTileUnits(transform.zoom, coord.canonical) * transform._projectionScaler : pixelsToTileUnits(tile, 1, zoom);
	    const values = {
	        'u_matrix': coord.projMatrix,
	        'u_extrude_scale': extrudeScale,
	        'u_intensity': intensity,
	        'u_inv_rot_matrix': identityMatrix$1,
	        'u_merc_center': [
	            0,
	            0
	        ],
	        'u_tile_id': [
	            0,
	            0,
	            0
	        ],
	        'u_zoom_transition': 0,
	        'u_up_dir': [
	            0,
	            0,
	            0
	        ]
	    };
	    if (isGlobe) {
	        values['u_inv_rot_matrix'] = invMatrix;
	        values['u_merc_center'] = mercatorCenter;
	        values['u_tile_id'] = [
	            coord.canonical.x,
	            coord.canonical.y,
	            1 << coord.canonical.z
	        ];
	        values['u_zoom_transition'] = ref_properties.globeToMercatorTransition(transform.zoom);
	        const x = mercatorCenter[0] * ref_properties.EXTENT;
	        const y = mercatorCenter[1] * ref_properties.EXTENT;
	        values['u_up_dir'] = transform.projection.upVector(new ref_properties.CanonicalTileID(0, 0, 0), x, y);
	    }
	    return values;
	};
	const heatmapTextureUniformValues = (painter, layer, textureUnit, colorRampUnit) => {
	    return {
	        'u_image': textureUnit,
	        'u_color_ramp': colorRampUnit,
	        'u_opacity': layer.paint.get('heatmap-opacity')
	    };
	};

	const lineUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_pixels_to_tile_units': new ref_properties.UniformMatrix2f(context, locations.u_pixels_to_tile_units),
	    'u_device_pixel_ratio': new ref_properties.Uniform1f(context, locations.u_device_pixel_ratio),
	    'u_units_to_pixels': new ref_properties.Uniform2f(context, locations.u_units_to_pixels),
	    'u_dash_image': new ref_properties.Uniform1i(context, locations.u_dash_image),
	    'u_gradient_image': new ref_properties.Uniform1i(context, locations.u_gradient_image),
	    'u_image_height': new ref_properties.Uniform1f(context, locations.u_image_height),
	    'u_texsize': new ref_properties.Uniform2f(context, locations.u_texsize),
	    'u_scale': new ref_properties.Uniform3f(context, locations.u_scale),
	    'u_mix': new ref_properties.Uniform1f(context, locations.u_mix),
	    'u_alpha_discard_threshold': new ref_properties.Uniform1f(context, locations.u_alpha_discard_threshold),
	    'u_trim_offset': new ref_properties.Uniform2f(context, locations.u_trim_offset)
	});
	const linePatternUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_texsize': new ref_properties.Uniform2f(context, locations.u_texsize),
	    'u_pixels_to_tile_units': new ref_properties.UniformMatrix2f(context, locations.u_pixels_to_tile_units),
	    'u_device_pixel_ratio': new ref_properties.Uniform1f(context, locations.u_device_pixel_ratio),
	    'u_image': new ref_properties.Uniform1i(context, locations.u_image),
	    'u_units_to_pixels': new ref_properties.Uniform2f(context, locations.u_units_to_pixels),
	    'u_scale': new ref_properties.Uniform3f(context, locations.u_scale),
	    'u_fade': new ref_properties.Uniform1f(context, locations.u_fade),
	    'u_alpha_discard_threshold': new ref_properties.Uniform1f(context, locations.u_alpha_discard_threshold)
	});
	const lineUniformValues = (painter, tile, layer, crossfade, matrix, imageHeight, pixelRatio, trimOffset) => {
	    const transform = painter.transform;
	    const pixelsToTileUnits = transform.calculatePixelsToTileUnitsMatrix(tile);
	    const values = {
	        'u_matrix': calculateMatrix(painter, tile, layer, matrix),
	        'u_pixels_to_tile_units': pixelsToTileUnits,
	        'u_device_pixel_ratio': pixelRatio,
	        'u_units_to_pixels': [
	            1 / transform.pixelsToGLUnits[0],
	            1 / transform.pixelsToGLUnits[1]
	        ],
	        'u_dash_image': 0,
	        'u_gradient_image': 1,
	        'u_image_height': imageHeight,
	        'u_texsize': [
	            0,
	            0
	        ],
	        'u_scale': [
	            0,
	            0,
	            0
	        ],
	        'u_mix': 0,
	        'u_alpha_discard_threshold': 0,
	        'u_trim_offset': trimOffset
	    };
	    if (hasDash(layer)) {
	        const tileZoomRatio = calculateTileRatio(tile, painter.transform);
	        values['u_texsize'] = tile.lineAtlasTexture.size;
	        values['u_scale'] = [
	            tileZoomRatio,
	            crossfade.fromScale,
	            crossfade.toScale
	        ];
	        values['u_mix'] = crossfade.t;
	    }
	    return values;
	};
	const linePatternUniformValues = (painter, tile, layer, crossfade, matrix, pixelRatio) => {
	    const transform = painter.transform;
	    const tileZoomRatio = calculateTileRatio(tile, transform);
	    return {
	        'u_matrix': calculateMatrix(painter, tile, layer, matrix),
	        'u_texsize': tile.imageAtlasTexture.size,
	        'u_pixels_to_tile_units': transform.calculatePixelsToTileUnitsMatrix(tile),
	        'u_device_pixel_ratio': pixelRatio,
	        'u_image': 0,
	        'u_scale': [
	            tileZoomRatio,
	            crossfade.fromScale,
	            crossfade.toScale
	        ],
	        'u_fade': crossfade.t,
	        'u_units_to_pixels': [
	            1 / transform.pixelsToGLUnits[0],
	            1 / transform.pixelsToGLUnits[1]
	        ],
	        'u_alpha_discard_threshold': 0
	    };
	};
	function calculateTileRatio(tile, transform) {
	    return 1 / pixelsToTileUnits(tile, 1, transform.tileZoom);
	}
	function calculateMatrix(painter, tile, layer, matrix) {
	    return painter.translatePosMatrix(matrix ? matrix : tile.tileID.projMatrix, tile, layer.paint.get('line-translate'), layer.paint.get('line-translate-anchor'));
	}
	const lineDefinesValues = layer => {
	    const values = [];
	    if (hasDash(layer))
	        values.push('RENDER_LINE_DASH');
	    if (layer.paint.get('line-gradient'))
	        values.push('RENDER_LINE_GRADIENT');
	    const trimOffset = layer.paint.get('line-trim-offset');
	    if (trimOffset[0] !== 0 || trimOffset[1] !== 0) {
	        values.push('RENDER_LINE_TRIM_OFFSET');
	    }
	    const hasPattern = layer.paint.get('line-pattern').constantOr(1);
	    const hasOpacity = layer.paint.get('line-opacity').constantOr(1) !== 1;
	    if (!hasPattern && hasOpacity) {
	        values.push('RENDER_LINE_ALPHA_DISCARD');
	    }
	    return values;
	};
	function hasDash(layer) {
	    const dashPropertyValue = layer.paint.get('line-dasharray').value;
	    return dashPropertyValue.value || dashPropertyValue.kind !== 'constant';
	}

	const rasterUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_tl_parent': new ref_properties.Uniform2f(context, locations.u_tl_parent),
	    'u_scale_parent': new ref_properties.Uniform1f(context, locations.u_scale_parent),
	    'u_fade_t': new ref_properties.Uniform1f(context, locations.u_fade_t),
	    'u_opacity': new ref_properties.Uniform1f(context, locations.u_opacity),
	    'u_image0': new ref_properties.Uniform1i(context, locations.u_image0),
	    'u_image1': new ref_properties.Uniform1i(context, locations.u_image1),
	    'u_brightness_low': new ref_properties.Uniform1f(context, locations.u_brightness_low),
	    'u_brightness_high': new ref_properties.Uniform1f(context, locations.u_brightness_high),
	    'u_saturation_factor': new ref_properties.Uniform1f(context, locations.u_saturation_factor),
	    'u_contrast_factor': new ref_properties.Uniform1f(context, locations.u_contrast_factor),
	    'u_spin_weights': new ref_properties.Uniform3f(context, locations.u_spin_weights),
	    'u_perspective_transform': new ref_properties.Uniform2f(context, locations.u_perspective_transform)
	});
	const rasterUniformValues = (matrix, parentTL, parentScaleBy, fade, layer, perspectiveTransform) => ({
	    'u_matrix': matrix,
	    'u_tl_parent': parentTL,
	    'u_scale_parent': parentScaleBy,
	    'u_fade_t': fade.mix,
	    'u_opacity': fade.opacity * layer.paint.get('raster-opacity'),
	    'u_image0': 0,
	    'u_image1': 1,
	    'u_brightness_low': layer.paint.get('raster-brightness-min'),
	    'u_brightness_high': layer.paint.get('raster-brightness-max'),
	    'u_saturation_factor': saturationFactor(layer.paint.get('raster-saturation')),
	    'u_contrast_factor': contrastFactor(layer.paint.get('raster-contrast')),
	    'u_spin_weights': spinWeights(layer.paint.get('raster-hue-rotate')),
	    'u_perspective_transform': perspectiveTransform
	});
	function spinWeights(angle) {
	    angle *= Math.PI / 180;
	    const s = Math.sin(angle);
	    const c = Math.cos(angle);
	    return [
	        (2 * c + 1) / 3,
	        (-Math.sqrt(3) * s - c + 1) / 3,
	        (Math.sqrt(3) * s - c + 1) / 3
	    ];
	}
	function contrastFactor(contrast) {
	    return contrast > 0 ? 1 / (1 - contrast) : 1 + contrast;
	}
	function saturationFactor(saturation) {
	    return saturation > 0 ? 1 - 1 / (1.001 - saturation) : -saturation;
	}

	const symbolIconUniforms = (context, locations) => ({
	    'u_is_size_zoom_constant': new ref_properties.Uniform1i(context, locations.u_is_size_zoom_constant),
	    'u_is_size_feature_constant': new ref_properties.Uniform1i(context, locations.u_is_size_feature_constant),
	    'u_size_t': new ref_properties.Uniform1f(context, locations.u_size_t),
	    'u_size': new ref_properties.Uniform1f(context, locations.u_size),
	    'u_camera_to_center_distance': new ref_properties.Uniform1f(context, locations.u_camera_to_center_distance),
	    'u_rotate_symbol': new ref_properties.Uniform1i(context, locations.u_rotate_symbol),
	    'u_aspect_ratio': new ref_properties.Uniform1f(context, locations.u_aspect_ratio),
	    'u_fade_change': new ref_properties.Uniform1f(context, locations.u_fade_change),
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_label_plane_matrix': new ref_properties.UniformMatrix4f(context, locations.u_label_plane_matrix),
	    'u_coord_matrix': new ref_properties.UniformMatrix4f(context, locations.u_coord_matrix),
	    'u_is_text': new ref_properties.Uniform1i(context, locations.u_is_text),
	    'u_pitch_with_map': new ref_properties.Uniform1i(context, locations.u_pitch_with_map),
	    'u_texsize': new ref_properties.Uniform2f(context, locations.u_texsize),
	    'u_tile_id': new ref_properties.Uniform3f(context, locations.u_tile_id),
	    'u_zoom_transition': new ref_properties.Uniform1f(context, locations.u_zoom_transition),
	    'u_inv_rot_matrix': new ref_properties.UniformMatrix4f(context, locations.u_inv_rot_matrix),
	    'u_merc_center': new ref_properties.Uniform2f(context, locations.u_merc_center),
	    'u_camera_forward': new ref_properties.Uniform3f(context, locations.u_camera_forward),
	    'u_tile_matrix': new ref_properties.UniformMatrix4f(context, locations.u_tile_matrix),
	    'u_up_vector': new ref_properties.Uniform3f(context, locations.u_up_vector),
	    'u_ecef_origin': new ref_properties.Uniform3f(context, locations.u_ecef_origin),
	    'u_texture': new ref_properties.Uniform1i(context, locations.u_texture)
	});
	const symbolSDFUniforms = (context, locations) => ({
	    'u_is_size_zoom_constant': new ref_properties.Uniform1i(context, locations.u_is_size_zoom_constant),
	    'u_is_size_feature_constant': new ref_properties.Uniform1i(context, locations.u_is_size_feature_constant),
	    'u_size_t': new ref_properties.Uniform1f(context, locations.u_size_t),
	    'u_size': new ref_properties.Uniform1f(context, locations.u_size),
	    'u_camera_to_center_distance': new ref_properties.Uniform1f(context, locations.u_camera_to_center_distance),
	    'u_rotate_symbol': new ref_properties.Uniform1i(context, locations.u_rotate_symbol),
	    'u_aspect_ratio': new ref_properties.Uniform1f(context, locations.u_aspect_ratio),
	    'u_fade_change': new ref_properties.Uniform1f(context, locations.u_fade_change),
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_label_plane_matrix': new ref_properties.UniformMatrix4f(context, locations.u_label_plane_matrix),
	    'u_coord_matrix': new ref_properties.UniformMatrix4f(context, locations.u_coord_matrix),
	    'u_is_text': new ref_properties.Uniform1i(context, locations.u_is_text),
	    'u_pitch_with_map': new ref_properties.Uniform1i(context, locations.u_pitch_with_map),
	    'u_texsize': new ref_properties.Uniform2f(context, locations.u_texsize),
	    'u_texture': new ref_properties.Uniform1i(context, locations.u_texture),
	    'u_gamma_scale': new ref_properties.Uniform1f(context, locations.u_gamma_scale),
	    'u_device_pixel_ratio': new ref_properties.Uniform1f(context, locations.u_device_pixel_ratio),
	    'u_tile_id': new ref_properties.Uniform3f(context, locations.u_tile_id),
	    'u_zoom_transition': new ref_properties.Uniform1f(context, locations.u_zoom_transition),
	    'u_inv_rot_matrix': new ref_properties.UniformMatrix4f(context, locations.u_inv_rot_matrix),
	    'u_merc_center': new ref_properties.Uniform2f(context, locations.u_merc_center),
	    'u_camera_forward': new ref_properties.Uniform3f(context, locations.u_camera_forward),
	    'u_tile_matrix': new ref_properties.UniformMatrix4f(context, locations.u_tile_matrix),
	    'u_up_vector': new ref_properties.Uniform3f(context, locations.u_up_vector),
	    'u_ecef_origin': new ref_properties.Uniform3f(context, locations.u_ecef_origin),
	    'u_is_halo': new ref_properties.Uniform1i(context, locations.u_is_halo)
	});
	const symbolTextAndIconUniforms = (context, locations) => ({
	    'u_is_size_zoom_constant': new ref_properties.Uniform1i(context, locations.u_is_size_zoom_constant),
	    'u_is_size_feature_constant': new ref_properties.Uniform1i(context, locations.u_is_size_feature_constant),
	    'u_size_t': new ref_properties.Uniform1f(context, locations.u_size_t),
	    'u_size': new ref_properties.Uniform1f(context, locations.u_size),
	    'u_camera_to_center_distance': new ref_properties.Uniform1f(context, locations.u_camera_to_center_distance),
	    'u_rotate_symbol': new ref_properties.Uniform1i(context, locations.u_rotate_symbol),
	    'u_aspect_ratio': new ref_properties.Uniform1f(context, locations.u_aspect_ratio),
	    'u_fade_change': new ref_properties.Uniform1f(context, locations.u_fade_change),
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_label_plane_matrix': new ref_properties.UniformMatrix4f(context, locations.u_label_plane_matrix),
	    'u_coord_matrix': new ref_properties.UniformMatrix4f(context, locations.u_coord_matrix),
	    'u_is_text': new ref_properties.Uniform1i(context, locations.u_is_text),
	    'u_pitch_with_map': new ref_properties.Uniform1i(context, locations.u_pitch_with_map),
	    'u_texsize': new ref_properties.Uniform2f(context, locations.u_texsize),
	    'u_texsize_icon': new ref_properties.Uniform2f(context, locations.u_texsize_icon),
	    'u_texture': new ref_properties.Uniform1i(context, locations.u_texture),
	    'u_texture_icon': new ref_properties.Uniform1i(context, locations.u_texture_icon),
	    'u_gamma_scale': new ref_properties.Uniform1f(context, locations.u_gamma_scale),
	    'u_device_pixel_ratio': new ref_properties.Uniform1f(context, locations.u_device_pixel_ratio),
	    'u_is_halo': new ref_properties.Uniform1i(context, locations.u_is_halo)
	});
	const identityMatrix = ref_properties.create();
	const symbolIconUniformValues = (functionType, size, rotateInShader, pitchWithMap, painter, matrix, labelPlaneMatrix, glCoordMatrix, isText, texSize, coord, zoomTransition, mercatorCenter, invMatrix, upVector, projection) => {
	    const transform = painter.transform;
	    const values = {
	        'u_is_size_zoom_constant': +(functionType === 'constant' || functionType === 'source'),
	        'u_is_size_feature_constant': +(functionType === 'constant' || functionType === 'camera'),
	        'u_size_t': size ? size.uSizeT : 0,
	        'u_size': size ? size.uSize : 0,
	        'u_camera_to_center_distance': transform.cameraToCenterDistance,
	        'u_rotate_symbol': +rotateInShader,
	        'u_aspect_ratio': transform.width / transform.height,
	        'u_fade_change': painter.options.fadeDuration ? painter.symbolFadeChange : 1,
	        'u_matrix': matrix,
	        'u_label_plane_matrix': labelPlaneMatrix,
	        'u_coord_matrix': glCoordMatrix,
	        'u_is_text': +isText,
	        'u_pitch_with_map': +pitchWithMap,
	        'u_texsize': texSize,
	        'u_texture': 0,
	        'u_tile_id': [
	            0,
	            0,
	            0
	        ],
	        'u_zoom_transition': 0,
	        'u_inv_rot_matrix': identityMatrix,
	        'u_merc_center': [
	            0,
	            0
	        ],
	        'u_camera_forward': [
	            0,
	            0,
	            0
	        ],
	        'u_ecef_origin': [
	            0,
	            0,
	            0
	        ],
	        'u_tile_matrix': identityMatrix,
	        'u_up_vector': [
	            0,
	            -1,
	            0
	        ]
	    };
	    if (projection.name === 'globe') {
	        values['u_tile_id'] = [
	            coord.canonical.x,
	            coord.canonical.y,
	            1 << coord.canonical.z
	        ];
	        values['u_zoom_transition'] = zoomTransition;
	        values['u_inv_rot_matrix'] = invMatrix;
	        values['u_merc_center'] = mercatorCenter;
	        values['u_camera_forward'] = transform._camera.forward();
	        values['u_ecef_origin'] = ref_properties.globeECEFOrigin(transform.globeMatrix, coord.toUnwrapped());
	        values['u_tile_matrix'] = Float32Array.from(transform.globeMatrix);
	        values['u_up_vector'] = upVector;
	    }
	    return values;
	};
	const symbolSDFUniformValues = (functionType, size, rotateInShader, pitchWithMap, painter, matrix, labelPlaneMatrix, glCoordMatrix, isText, texSize, isHalo, coord, zoomTransition, mercatorCenter, invMatrix, upVector, projection) => {
	    return ref_properties.extend(symbolIconUniformValues(functionType, size, rotateInShader, pitchWithMap, painter, matrix, labelPlaneMatrix, glCoordMatrix, isText, texSize, coord, zoomTransition, mercatorCenter, invMatrix, upVector, projection), {
	        'u_gamma_scale': pitchWithMap ? painter.transform.cameraToCenterDistance * Math.cos(painter.terrain ? 0 : painter.transform._pitch) : 1,
	        'u_device_pixel_ratio': ref_properties.exported.devicePixelRatio,
	        'u_is_halo': +isHalo
	    });
	};
	const symbolTextAndIconUniformValues = (functionType, size, rotateInShader, pitchWithMap, painter, matrix, labelPlaneMatrix, glCoordMatrix, texSizeSDF, texSizeIcon, coord, zoomTransition, mercatorCenter, invMatrix, upVector, projection) => {
	    return ref_properties.extend(symbolSDFUniformValues(functionType, size, rotateInShader, pitchWithMap, painter, matrix, labelPlaneMatrix, glCoordMatrix, true, texSizeSDF, true, coord, zoomTransition, mercatorCenter, invMatrix, upVector, projection), {
	        'u_texsize_icon': texSizeIcon,
	        'u_texture_icon': 1
	    });
	};

	const backgroundUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_opacity': new ref_properties.Uniform1f(context, locations.u_opacity),
	    'u_color': new ref_properties.UniformColor(context, locations.u_color)
	});
	const backgroundPatternUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_opacity': new ref_properties.Uniform1f(context, locations.u_opacity),
	    'u_image': new ref_properties.Uniform1i(context, locations.u_image),
	    'u_pattern_tl_a': new ref_properties.Uniform2f(context, locations.u_pattern_tl_a),
	    'u_pattern_br_a': new ref_properties.Uniform2f(context, locations.u_pattern_br_a),
	    'u_pattern_tl_b': new ref_properties.Uniform2f(context, locations.u_pattern_tl_b),
	    'u_pattern_br_b': new ref_properties.Uniform2f(context, locations.u_pattern_br_b),
	    'u_texsize': new ref_properties.Uniform2f(context, locations.u_texsize),
	    'u_mix': new ref_properties.Uniform1f(context, locations.u_mix),
	    'u_pattern_size_a': new ref_properties.Uniform2f(context, locations.u_pattern_size_a),
	    'u_pattern_size_b': new ref_properties.Uniform2f(context, locations.u_pattern_size_b),
	    'u_scale_a': new ref_properties.Uniform1f(context, locations.u_scale_a),
	    'u_scale_b': new ref_properties.Uniform1f(context, locations.u_scale_b),
	    'u_pixel_coord_upper': new ref_properties.Uniform2f(context, locations.u_pixel_coord_upper),
	    'u_pixel_coord_lower': new ref_properties.Uniform2f(context, locations.u_pixel_coord_lower),
	    'u_tile_units_to_pixels': new ref_properties.Uniform1f(context, locations.u_tile_units_to_pixels)
	});
	const backgroundUniformValues = (matrix, opacity, color) => ({
	    'u_matrix': matrix,
	    'u_opacity': opacity,
	    'u_color': color
	});
	const backgroundPatternUniformValues = (matrix, opacity, painter, image, tile, crossfade) => ref_properties.extend(bgPatternUniformValues(image, crossfade, painter, tile), {
	    'u_matrix': matrix,
	    'u_opacity': opacity
	});

	const skyboxUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_sun_direction': new ref_properties.Uniform3f(context, locations.u_sun_direction),
	    'u_cubemap': new ref_properties.Uniform1i(context, locations.u_cubemap),
	    'u_opacity': new ref_properties.Uniform1f(context, locations.u_opacity),
	    'u_temporal_offset': new ref_properties.Uniform1f(context, locations.u_temporal_offset)
	});
	const skyboxUniformValues = (matrix, sunDirection, cubemap, opacity, temporalOffset) => ({
	    'u_matrix': matrix,
	    'u_sun_direction': sunDirection,
	    'u_cubemap': cubemap,
	    'u_opacity': opacity,
	    'u_temporal_offset': temporalOffset
	});
	const skyboxGradientUniforms = (context, locations) => ({
	    'u_matrix': new ref_properties.UniformMatrix4f(context, locations.u_matrix),
	    'u_color_ramp': new ref_properties.Uniform1i(context, locations.u_color_ramp),
	    'u_center_direction': new ref_properties.Uniform3f(context, locations.u_center_direction),
	    'u_radius': new ref_properties.Uniform1f(context, locations.u_radius),
	    'u_opacity': new ref_properties.Uniform1f(context, locations.u_opacity),
	    'u_temporal_offset': new ref_properties.Uniform1f(context, locations.u_temporal_offset)
	});
	const skyboxGradientUniformValues = (matrix, centerDirection, radius, opacity, temporalOffset) => {
	    return {
	        'u_matrix': matrix,
	        'u_color_ramp': 0,
	        'u_center_direction': centerDirection,
	        'u_radius': ref_properties.degToRad(radius),
	        'u_opacity': opacity,
	        'u_temporal_offset': temporalOffset
	    };
	};

	const skyboxCaptureUniforms = (context, locations) => ({
	    'u_matrix_3f': new ref_properties.UniformMatrix3f(context, locations.u_matrix_3f),
	    'u_sun_direction': new ref_properties.Uniform3f(context, locations.u_sun_direction),
	    'u_sun_intensity': new ref_properties.Uniform1f(context, locations.u_sun_intensity),
	    'u_color_tint_r': new ref_properties.Uniform4f(context, locations.u_color_tint_r),
	    'u_color_tint_m': new ref_properties.Uniform4f(context, locations.u_color_tint_m),
	    'u_luminance': new ref_properties.Uniform1f(context, locations.u_luminance)
	});
	const skyboxCaptureUniformValues = (matrix, sunDirection, sunIntensity, atmosphereColor, atmosphereHaloColor) => ({
	    'u_matrix_3f': matrix,
	    'u_sun_direction': sunDirection,
	    'u_sun_intensity': sunIntensity,
	    'u_color_tint_r': [
	        atmosphereColor.r,
	        atmosphereColor.g,
	        atmosphereColor.b,
	        atmosphereColor.a
	    ],
	    'u_color_tint_m': [
	        atmosphereHaloColor.r,
	        atmosphereHaloColor.g,
	        atmosphereHaloColor.b,
	        atmosphereHaloColor.a
	    ],
	    'u_luminance': 0.00005
	});

	const programUniforms = {
	    fillExtrusion: fillExtrusionUniforms,
	    fillExtrusionPattern: fillExtrusionPatternUniforms,
	    fill: fillUniforms,
	    fillPattern: fillPatternUniforms,
	    fillOutline: fillOutlineUniforms,
	    fillOutlinePattern: fillOutlinePatternUniforms,
	    circle: circleUniforms,
	    collisionBox: collisionUniforms,
	    collisionCircle: collisionCircleUniforms,
	    debug: debugUniforms,
	    clippingMask: clippingMaskUniforms,
	    heatmap: heatmapUniforms,
	    heatmapTexture: heatmapTextureUniforms,
	    hillshade: hillshadeUniforms,
	    hillshadePrepare: hillshadePrepareUniforms,
	    line: lineUniforms,
	    linePattern: linePatternUniforms,
	    raster: rasterUniforms,
	    symbolIcon: symbolIconUniforms,
	    symbolSDF: symbolSDFUniforms,
	    symbolTextAndIcon: symbolTextAndIconUniforms,
	    background: backgroundUniforms,
	    backgroundPattern: backgroundPatternUniforms,
	    terrainRaster: terrainRasterUniforms,
	    terrainDepth: terrainRasterUniforms,
	    skybox: skyboxUniforms,
	    skyboxGradient: skyboxGradientUniforms,
	    skyboxCapture: skyboxCaptureUniforms,
	    globeRaster: globeRasterUniforms,
	    globeAtmosphere: atmosphereUniforms
	};

	let quadTriangles;
	function drawCollisionDebug(painter, sourceCache, layer, coords, translate, translateAnchor, isText) {
	    const context = painter.context;
	    const gl = context.gl;
	    const tr = painter.transform;
	    const program = painter.useProgram('collisionBox');
	    const tileBatches = [];
	    let circleCount = 0;
	    let circleOffset = 0;
	    for (let i = 0; i < coords.length; i++) {
	        const coord = coords[i];
	        const tile = sourceCache.getTile(coord);
	        const bucket = tile.getBucket(layer);
	        if (!bucket)
	            continue;
	        const tileMatrix = getCollisionDebugTileProjectionMatrix(coord, bucket, tr);
	        let posMatrix = tileMatrix;
	        if (translate[0] !== 0 || translate[1] !== 0) {
	            posMatrix = painter.translatePosMatrix(tileMatrix, tile, translate, translateAnchor);
	        }
	        const buffers = isText ? bucket.textCollisionBox : bucket.iconCollisionBox;
	        const circleArray = bucket.collisionCircleArray;
	        if (circleArray.length > 0) {
	            const invTransform = ref_properties.create();
	            const transform = posMatrix;
	            ref_properties.mul(invTransform, bucket.placementInvProjMatrix, tr.glCoordMatrix);
	            ref_properties.mul(invTransform, invTransform, bucket.placementViewportMatrix);
	            tileBatches.push({
	                circleArray,
	                circleOffset,
	                transform,
	                invTransform,
	                projection: bucket.getProjection()
	            });
	            circleCount += circleArray.length / 4;
	            circleOffset = circleCount;
	        }
	        if (!buffers)
	            continue;
	        if (painter.terrain)
	            painter.terrain.setupElevationDraw(tile, program);
	        program.draw(context, gl.LINES, ref_properties.DepthMode.disabled, ref_properties.StencilMode.disabled, painter.colorModeForRenderPass(), ref_properties.CullFaceMode.disabled, collisionUniformValues(posMatrix, tr, tile, bucket.getProjection()), layer.id, buffers.layoutVertexBuffer, buffers.indexBuffer, buffers.segments, null, tr.zoom, null, buffers.collisionVertexBuffer, buffers.collisionVertexBufferExt);
	    }
	    if (!isText || !tileBatches.length) {
	        return;
	    }
	    const circleProgram = painter.useProgram('collisionCircle');
	    const vertexData = new ref_properties.StructArrayLayout2f1f2i16();
	    vertexData.resize(circleCount * 4);
	    vertexData._trim();
	    let vertexOffset = 0;
	    for (const batch of tileBatches) {
	        for (let i = 0; i < batch.circleArray.length / 4; i++) {
	            const circleIdx = i * 4;
	            const x = batch.circleArray[circleIdx + 0];
	            const y = batch.circleArray[circleIdx + 1];
	            const radius = batch.circleArray[circleIdx + 2];
	            const collision = batch.circleArray[circleIdx + 3];
	            vertexData.emplace(vertexOffset++, x, y, radius, collision, 0);
	            vertexData.emplace(vertexOffset++, x, y, radius, collision, 1);
	            vertexData.emplace(vertexOffset++, x, y, radius, collision, 2);
	            vertexData.emplace(vertexOffset++, x, y, radius, collision, 3);
	        }
	    }
	    if (!quadTriangles || quadTriangles.length < circleCount * 2) {
	        quadTriangles = createQuadTriangles(circleCount);
	    }
	    const indexBuffer = context.createIndexBuffer(quadTriangles, true);
	    const vertexBuffer = context.createVertexBuffer(vertexData, ref_properties.collisionCircleLayout.members, true);
	    for (const batch of tileBatches) {
	        const uniforms = collisionCircleUniformValues(batch.transform, batch.invTransform, tr, batch.projection);
	        circleProgram.draw(context, gl.TRIANGLES, ref_properties.DepthMode.disabled, ref_properties.StencilMode.disabled, painter.colorModeForRenderPass(), ref_properties.CullFaceMode.disabled, uniforms, layer.id, vertexBuffer, indexBuffer, ref_properties.SegmentVector.simpleSegment(0, batch.circleOffset * 2, batch.circleArray.length, batch.circleArray.length / 2), null, tr.zoom);
	    }
	    vertexBuffer.destroy();
	    indexBuffer.destroy();
	}
	function createQuadTriangles(quadCount) {
	    const triCount = quadCount * 2;
	    const array = new ref_properties.StructArrayLayout3ui6();
	    array.resize(triCount);
	    array._trim();
	    for (let i = 0; i < triCount; i++) {
	        const idx = i * 6;
	        array.uint16[idx + 0] = i * 4 + 0;
	        array.uint16[idx + 1] = i * 4 + 1;
	        array.uint16[idx + 2] = i * 4 + 2;
	        array.uint16[idx + 3] = i * 4 + 2;
	        array.uint16[idx + 4] = i * 4 + 3;
	        array.uint16[idx + 5] = i * 4 + 0;
	    }
	    return array;
	}

	const identityMat4 = ref_properties.create();
	function drawSymbols(painter, sourceCache, layer, coords, variableOffsets) {
	    if (painter.renderPass !== 'translucent')
	        return;
	    const stencilMode = ref_properties.StencilMode.disabled;
	    const colorMode = painter.colorModeForRenderPass();
	    const variablePlacement = layer.layout.get('text-variable-anchor');
	    if (variablePlacement) {
	        updateVariableAnchors(coords, painter, layer, sourceCache, layer.layout.get('text-rotation-alignment'), layer.layout.get('text-pitch-alignment'), variableOffsets);
	    }
	    if (layer.paint.get('icon-opacity').constantOr(1) !== 0) {
	        drawLayerSymbols(painter, sourceCache, layer, coords, false, layer.paint.get('icon-translate'), layer.paint.get('icon-translate-anchor'), layer.layout.get('icon-rotation-alignment'), layer.layout.get('icon-pitch-alignment'), layer.layout.get('icon-keep-upright'), stencilMode, colorMode);
	    }
	    if (layer.paint.get('text-opacity').constantOr(1) !== 0) {
	        drawLayerSymbols(painter, sourceCache, layer, coords, true, layer.paint.get('text-translate'), layer.paint.get('text-translate-anchor'), layer.layout.get('text-rotation-alignment'), layer.layout.get('text-pitch-alignment'), layer.layout.get('text-keep-upright'), stencilMode, colorMode);
	    }
	    if (sourceCache.map.showCollisionBoxes) {
	        drawCollisionDebug(painter, sourceCache, layer, coords, layer.paint.get('text-translate'), layer.paint.get('text-translate-anchor'), true);
	        drawCollisionDebug(painter, sourceCache, layer, coords, layer.paint.get('icon-translate'), layer.paint.get('icon-translate-anchor'), false);
	    }
	}
	function computeGlobeCameraUp(transform) {
	    const viewMatrix = transform._camera.getWorldToCamera(transform.worldSize, 1);
	    const viewToEcef = ref_properties.multiply([], viewMatrix, transform.globeMatrix);
	    ref_properties.invert(viewToEcef, viewToEcef);
	    const cameraUpVector = [
	        0,
	        0,
	        0
	    ];
	    const up = [
	        0,
	        1,
	        0,
	        0
	    ];
	    ref_properties.transformMat4$1(up, up, viewToEcef);
	    cameraUpVector[0] = up[0];
	    cameraUpVector[1] = up[1];
	    cameraUpVector[2] = up[2];
	    ref_properties.normalize(cameraUpVector, cameraUpVector);
	    return cameraUpVector;
	}
	function calculateVariableRenderShift(anchor, width, height, textOffset, textScale, renderTextSize) {
	    const {horizontalAlign, verticalAlign} = ref_properties.getAnchorAlignment(anchor);
	    const shiftX = -(horizontalAlign - 0.5) * width;
	    const shiftY = -(verticalAlign - 0.5) * height;
	    const variableOffset = ref_properties.evaluateVariableOffset(anchor, textOffset);
	    return new ref_properties.pointGeometry((shiftX / textScale + variableOffset[0]) * renderTextSize, (shiftY / textScale + variableOffset[1]) * renderTextSize);
	}
	function updateVariableAnchors(coords, painter, layer, sourceCache, rotationAlignment, pitchAlignment, variableOffsets) {
	    const tr = painter.transform;
	    const rotateWithMap = rotationAlignment === 'map';
	    const pitchWithMap = pitchAlignment === 'map';
	    for (const coord of coords) {
	        const tile = sourceCache.getTile(coord);
	        const bucket = tile.getBucket(layer);
	        if (!bucket || !bucket.text || !bucket.text.segments.get().length) {
	            continue;
	        }
	        const sizeData = bucket.textSizeData;
	        const size = ref_properties.evaluateSizeForZoom(sizeData, tr.zoom);
	        const tileMatrix = getSymbolTileProjectionMatrix(coord, bucket.getProjection(), tr);
	        const pixelsToTileUnits = tr.calculatePixelsToTileUnitsMatrix(tile);
	        const labelPlaneMatrix = getLabelPlaneMatrixForRendering(tileMatrix, tile.tileID.canonical, pitchWithMap, rotateWithMap, tr, bucket.getProjection(), pixelsToTileUnits);
	        const updateTextFitIcon = layer.layout.get('icon-text-fit') !== 'none' && bucket.hasIconData();
	        if (size) {
	            const tileScale = Math.pow(2, tr.zoom - tile.tileID.overscaledZ);
	            updateVariableAnchorsForBucket(bucket, rotateWithMap, pitchWithMap, variableOffsets, ref_properties.symbolSize, tr, labelPlaneMatrix, coord, tileScale, size, updateTextFitIcon);
	        }
	    }
	}
	function updateVariableAnchorsForBucket(bucket, rotateWithMap, pitchWithMap, variableOffsets, symbolSize, transform, labelPlaneMatrix, coord, tileScale, size, updateTextFitIcon) {
	    const placedSymbols = bucket.text.placedSymbolArray;
	    const dynamicTextLayoutVertexArray = bucket.text.dynamicLayoutVertexArray;
	    const dynamicIconLayoutVertexArray = bucket.icon.dynamicLayoutVertexArray;
	    const placedTextShifts = {};
	    const tileMatrix = getSymbolTileProjectionMatrix(coord, bucket.getProjection(), transform);
	    const elevation = transform.elevation;
	    const upVectorScale = bucket.getProjection().upVectorScale(coord.canonical, transform.center.lat, transform.worldSize);
	    dynamicTextLayoutVertexArray.clear();
	    for (let s = 0; s < placedSymbols.length; s++) {
	        const symbol = placedSymbols.get(s);
	        const skipOrientation = bucket.allowVerticalPlacement && !symbol.placedOrientation;
	        const variableOffset = !symbol.hidden && symbol.crossTileID && !skipOrientation ? variableOffsets[symbol.crossTileID] : null;
	        if (!variableOffset) {
	            hideGlyphs(symbol.numGlyphs, dynamicTextLayoutVertexArray);
	        } else {
	            const tileAnchor = new ref_properties.pointGeometry(symbol.tileAnchorX, symbol.tileAnchorY);
	            const upDir = bucket.getProjection().upVector(coord.canonical, tileAnchor.x, tileAnchor.y);
	            const anchorElevation = elevation ? elevation.getAtTileOffset(coord, tileAnchor.x, tileAnchor.y) : 0;
	            const reprojectedAnchor = [
	                symbol.projectedAnchorX + anchorElevation * upDir[0] * upVectorScale.metersToTile,
	                symbol.projectedAnchorY + anchorElevation * upDir[1] * upVectorScale.metersToTile,
	                symbol.projectedAnchorZ + anchorElevation * upDir[2] * upVectorScale.metersToTile
	            ];
	            const projectedAnchor = projectVector(reprojectedAnchor, pitchWithMap ? tileMatrix : labelPlaneMatrix);
	            const perspectiveRatio = getPerspectiveRatio(transform.getCameraToCenterDistance(bucket.getProjection()), projectedAnchor.signedDistanceFromCamera);
	            let renderTextSize = symbolSize.evaluateSizeForFeature(bucket.textSizeData, size, symbol) * perspectiveRatio / ref_properties.ONE_EM;
	            if (pitchWithMap) {
	                renderTextSize *= bucket.tilePixelRatio / tileScale;
	            }
	            const {width, height, anchor, textOffset, textScale} = variableOffset;
	            const shift = calculateVariableRenderShift(anchor, width, height, textOffset, textScale, renderTextSize);
	            let shiftedAnchor;
	            if (pitchWithMap) {
	                const shiftedTileAnchor = tileAnchor.add(shift);
	                const {x, y, z} = bucket.getProjection().projectTilePoint(shiftedTileAnchor.x, shiftedTileAnchor.y, coord.canonical);
	                const reprojectedShiftedAnchor = [
	                    x + anchorElevation * upDir[0] * upVectorScale.metersToTile,
	                    y + anchorElevation * upDir[1] * upVectorScale.metersToTile,
	                    z + anchorElevation * upDir[2] * upVectorScale.metersToTile
	                ];
	                shiftedAnchor = projectVector(reprojectedShiftedAnchor, labelPlaneMatrix).point;
	            } else {
	                const rotatedShift = rotateWithMap ? shift.rotate(-transform.angle) : shift;
	                shiftedAnchor = [
	                    projectedAnchor.point[0] + rotatedShift.x,
	                    projectedAnchor.point[1] + rotatedShift.y,
	                    0
	                ];
	            }
	            const angle = bucket.allowVerticalPlacement && symbol.placedOrientation === ref_properties.WritingMode.vertical ? Math.PI / 2 : 0;
	            for (let g = 0; g < symbol.numGlyphs; g++) {
	                ref_properties.addDynamicAttributes(dynamicTextLayoutVertexArray, shiftedAnchor[0], shiftedAnchor[1], shiftedAnchor[2], angle);
	            }
	            if (updateTextFitIcon && symbol.associatedIconIndex >= 0) {
	                placedTextShifts[symbol.associatedIconIndex] = {
	                    shiftedAnchor,
	                    angle
	                };
	            }
	        }
	    }
	    if (updateTextFitIcon) {
	        dynamicIconLayoutVertexArray.clear();
	        const placedIcons = bucket.icon.placedSymbolArray;
	        for (let i = 0; i < placedIcons.length; i++) {
	            const placedIcon = placedIcons.get(i);
	            if (placedIcon.hidden) {
	                hideGlyphs(placedIcon.numGlyphs, dynamicIconLayoutVertexArray);
	            } else {
	                const shift = placedTextShifts[i];
	                if (!shift) {
	                    hideGlyphs(placedIcon.numGlyphs, dynamicIconLayoutVertexArray);
	                } else {
	                    for (let g = 0; g < placedIcon.numGlyphs; g++) {
	                        ref_properties.addDynamicAttributes(dynamicIconLayoutVertexArray, shift.shiftedAnchor[0], shift.shiftedAnchor[1], shift.shiftedAnchor[2], shift.angle);
	                    }
	                }
	            }
	        }
	        bucket.icon.dynamicLayoutVertexBuffer.updateData(dynamicIconLayoutVertexArray);
	    }
	    bucket.text.dynamicLayoutVertexBuffer.updateData(dynamicTextLayoutVertexArray);
	}
	function getSymbolProgramName(isSDF, isText, bucket) {
	    if (bucket.iconsInText && isText) {
	        return 'symbolTextAndIcon';
	    } else if (isSDF) {
	        return 'symbolSDF';
	    } else {
	        return 'symbolIcon';
	    }
	}
	function drawLayerSymbols(painter, sourceCache, layer, coords, isText, translate, translateAnchor, rotationAlignment, pitchAlignment, keepUpright, stencilMode, colorMode) {
	    const context = painter.context;
	    const gl = context.gl;
	    const tr = painter.transform;
	    const rotateWithMap = rotationAlignment === 'map';
	    const pitchWithMap = pitchAlignment === 'map';
	    const alongLine = rotateWithMap && layer.layout.get('symbol-placement') !== 'point';
	    const rotateInShader = rotateWithMap && !pitchWithMap && !alongLine;
	    const hasSortKey = layer.layout.get('symbol-sort-key').constantOr(1) !== undefined;
	    let sortFeaturesByKey = false;
	    const depthMode = painter.depthModeForSublayer(0, ref_properties.DepthMode.ReadOnly);
	    const mercatorCenter = [
	        ref_properties.mercatorXfromLng(tr.center.lng),
	        ref_properties.mercatorYfromLat(tr.center.lat)
	    ];
	    const variablePlacement = layer.layout.get('text-variable-anchor');
	    const isGlobeProjection = tr.projection.name === 'globe';
	    const tileRenderState = [];
	    const mercatorCameraUp = [
	        0,
	        -1,
	        0
	    ];
	    let globeCameraUp = mercatorCameraUp;
	    if ((isGlobeProjection || tr.mercatorFromTransition) && !rotateWithMap) {
	        globeCameraUp = computeGlobeCameraUp(tr);
	    }
	    for (const coord of coords) {
	        const tile = sourceCache.getTile(coord);
	        const bucket = tile.getBucket(layer);
	        if (!bucket)
	            continue;
	        if (bucket.projection.name === 'mercator' && isGlobeProjection) {
	            continue;
	        }
	        const buffers = isText ? bucket.text : bucket.icon;
	        if (!buffers || bucket.fullyClipped || !buffers.segments.get().length)
	            continue;
	        const programConfiguration = buffers.programConfigurations.get(layer.id);
	        const isSDF = isText || bucket.sdfIcons;
	        const sizeData = isText ? bucket.textSizeData : bucket.iconSizeData;
	        const transformed = pitchWithMap || tr.pitch !== 0;
	        const size = ref_properties.evaluateSizeForZoom(sizeData, tr.zoom);
	        let texSize;
	        let texSizeIcon = [
	            0,
	            0
	        ];
	        let atlasTexture;
	        let atlasInterpolation;
	        let atlasTextureIcon = null;
	        let atlasInterpolationIcon;
	        if (isText) {
	            atlasTexture = tile.glyphAtlasTexture;
	            atlasInterpolation = gl.LINEAR;
	            texSize = tile.glyphAtlasTexture.size;
	            if (bucket.iconsInText) {
	                texSizeIcon = tile.imageAtlasTexture.size;
	                atlasTextureIcon = tile.imageAtlasTexture;
	                const zoomDependentSize = sizeData.kind === 'composite' || sizeData.kind === 'camera';
	                atlasInterpolationIcon = transformed || painter.options.rotating || painter.options.zooming || zoomDependentSize ? gl.LINEAR : gl.NEAREST;
	            }
	        } else {
	            const iconScaled = layer.layout.get('icon-size').constantOr(0) !== 1 || bucket.iconsNeedLinear;
	            atlasTexture = tile.imageAtlasTexture;
	            atlasInterpolation = isSDF || painter.options.rotating || painter.options.zooming || iconScaled || transformed ? gl.LINEAR : gl.NEAREST;
	            texSize = tile.imageAtlasTexture.size;
	        }
	        const bucketIsGlobeProjection = bucket.projection.name === 'globe';
	        const cameraUpVector = bucketIsGlobeProjection ? globeCameraUp : mercatorCameraUp;
	        const globeToMercator = bucketIsGlobeProjection ? ref_properties.globeToMercatorTransition(tr.zoom) : 0;
	        const tileMatrix = getSymbolTileProjectionMatrix(coord, bucket.getProjection(), tr);
	        const s = tr.calculatePixelsToTileUnitsMatrix(tile);
	        const labelPlaneMatrixRendering = getLabelPlaneMatrixForRendering(tileMatrix, tile.tileID.canonical, pitchWithMap, rotateWithMap, tr, bucket.getProjection(), s);
	        const labelPlaneMatrixInv = painter.terrain && pitchWithMap && alongLine ? ref_properties.invert(ref_properties.create(), labelPlaneMatrixRendering) : identityMat4;
	        const glCoordMatrix = getGlCoordMatrix(tileMatrix, tile.tileID.canonical, pitchWithMap, rotateWithMap, tr, bucket.getProjection(), s);
	        const hasVariableAnchors = variablePlacement && bucket.hasTextData();
	        const updateTextFitIcon = layer.layout.get('icon-text-fit') !== 'none' && hasVariableAnchors && bucket.hasIconData();
	        if (alongLine) {
	            const elevation = tr.elevation;
	            const getElevation = elevation ? elevation.getAtTileOffsetFunc(coord, tr.center.lat, tr.worldSize, bucket.getProjection()) : _ => [
	                0,
	                0,
	                0
	            ];
	            const labelPlaneMatrixPlacement = getLabelPlaneMatrixForPlacement(tileMatrix, tile.tileID.canonical, pitchWithMap, rotateWithMap, tr, bucket.getProjection(), s);
	            updateLineLabels(bucket, tileMatrix, painter, isText, labelPlaneMatrixPlacement, glCoordMatrix, pitchWithMap, keepUpright, getElevation, coord);
	        }
	        const projectedPosOnLabelSpace = alongLine || isText && variablePlacement || updateTextFitIcon;
	        const matrix = painter.translatePosMatrix(tileMatrix, tile, translate, translateAnchor);
	        const uLabelPlaneMatrix = projectedPosOnLabelSpace ? identityMat4 : labelPlaneMatrixRendering;
	        const uglCoordMatrix = painter.translatePosMatrix(glCoordMatrix, tile, translate, translateAnchor, true);
	        const invMatrix = bucket.getProjection().createInversionMatrix(tr, coord.canonical);
	        const baseDefines = [];
	        if (painter.terrain && pitchWithMap) {
	            baseDefines.push('PITCH_WITH_MAP_TERRAIN');
	        }
	        if (bucketIsGlobeProjection) {
	            baseDefines.push('PROJECTION_GLOBE_VIEW');
	        }
	        if (projectedPosOnLabelSpace) {
	            baseDefines.push('PROJECTED_POS_ON_VIEWPORT');
	        }
	        const hasHalo = isSDF && layer.paint.get(isText ? 'text-halo-width' : 'icon-halo-width').constantOr(1) !== 0;
	        let uniformValues;
	        if (isSDF) {
	            if (!bucket.iconsInText) {
	                uniformValues = symbolSDFUniformValues(sizeData.kind, size, rotateInShader, pitchWithMap, painter, matrix, uLabelPlaneMatrix, uglCoordMatrix, isText, texSize, true, coord, globeToMercator, mercatorCenter, invMatrix, cameraUpVector, bucket.getProjection());
	            } else {
	                uniformValues = symbolTextAndIconUniformValues(sizeData.kind, size, rotateInShader, pitchWithMap, painter, matrix, uLabelPlaneMatrix, uglCoordMatrix, texSize, texSizeIcon, coord, globeToMercator, mercatorCenter, invMatrix, cameraUpVector, bucket.getProjection());
	            }
	        } else {
	            uniformValues = symbolIconUniformValues(sizeData.kind, size, rotateInShader, pitchWithMap, painter, matrix, uLabelPlaneMatrix, uglCoordMatrix, isText, texSize, coord, globeToMercator, mercatorCenter, invMatrix, cameraUpVector, bucket.getProjection());
	        }
	        const program = painter.useProgram(getSymbolProgramName(isSDF, isText, bucket), programConfiguration, baseDefines);
	        const state = {
	            program,
	            buffers,
	            uniformValues,
	            atlasTexture,
	            atlasTextureIcon,
	            atlasInterpolation,
	            atlasInterpolationIcon,
	            isSDF,
	            hasHalo,
	            tile,
	            labelPlaneMatrixInv
	        };
	        if (hasSortKey && bucket.canOverlap) {
	            sortFeaturesByKey = true;
	            const oldSegments = buffers.segments.get();
	            for (const segment of oldSegments) {
	                tileRenderState.push({
	                    segments: new ref_properties.SegmentVector([segment]),
	                    sortKey: segment.sortKey,
	                    state
	                });
	            }
	        } else {
	            tileRenderState.push({
	                segments: buffers.segments,
	                sortKey: 0,
	                state
	            });
	        }
	    }
	    if (sortFeaturesByKey) {
	        tileRenderState.sort((a, b) => a.sortKey - b.sortKey);
	    }
	    for (const segmentState of tileRenderState) {
	        const state = segmentState.state;
	        if (painter.terrain) {
	            const options = {
	                useDepthForOcclusion: !isGlobeProjection,
	                labelPlaneMatrixInv: state.labelPlaneMatrixInv
	            };
	            painter.terrain.setupElevationDraw(state.tile, state.program, options);
	        }
	        context.activeTexture.set(gl.TEXTURE0);
	        state.atlasTexture.bind(state.atlasInterpolation, gl.CLAMP_TO_EDGE);
	        if (state.atlasTextureIcon) {
	            context.activeTexture.set(gl.TEXTURE1);
	            if (state.atlasTextureIcon) {
	                state.atlasTextureIcon.bind(state.atlasInterpolationIcon, gl.CLAMP_TO_EDGE);
	            }
	        }
	        if (state.isSDF) {
	            const uniformValues = state.uniformValues;
	            if (state.hasHalo) {
	                uniformValues['u_is_halo'] = 1;
	                drawSymbolElements(state.buffers, segmentState.segments, layer, painter, state.program, depthMode, stencilMode, colorMode, uniformValues);
	            }
	            uniformValues['u_is_halo'] = 0;
	        }
	        drawSymbolElements(state.buffers, segmentState.segments, layer, painter, state.program, depthMode, stencilMode, colorMode, state.uniformValues);
	    }
	}
	function drawSymbolElements(buffers, segments, layer, painter, program, depthMode, stencilMode, colorMode, uniformValues) {
	    const context = painter.context;
	    const gl = context.gl;
	    program.draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode, ref_properties.CullFaceMode.disabled, uniformValues, layer.id, buffers.layoutVertexBuffer, buffers.indexBuffer, segments, layer.paint, painter.transform.zoom, buffers.programConfigurations.get(layer.id), buffers.dynamicLayoutVertexBuffer, buffers.opacityVertexBuffer, buffers.globeExtVertexBuffer);
	}

	function drawCircles(painter, sourceCache, layer, coords) {
	    if (painter.renderPass !== 'translucent')
	        return;
	    const opacity = layer.paint.get('circle-opacity');
	    const strokeWidth = layer.paint.get('circle-stroke-width');
	    const strokeOpacity = layer.paint.get('circle-stroke-opacity');
	    const sortFeaturesByKey = layer.layout.get('circle-sort-key').constantOr(1) !== undefined;
	    if (opacity.constantOr(1) === 0 && (strokeWidth.constantOr(1) === 0 || strokeOpacity.constantOr(1) === 0)) {
	        return;
	    }
	    const context = painter.context;
	    const gl = context.gl;
	    const tr = painter.transform;
	    const depthMode = painter.depthModeForSublayer(0, ref_properties.DepthMode.ReadOnly);
	    const stencilMode = ref_properties.StencilMode.disabled;
	    const colorMode = painter.colorModeForRenderPass();
	    const isGlobeProjection = tr.projection.name === 'globe';
	    const mercatorCenter = [
	        ref_properties.mercatorXfromLng(tr.center.lng),
	        ref_properties.mercatorYfromLat(tr.center.lat)
	    ];
	    const segmentsRenderStates = [];
	    for (let i = 0; i < coords.length; i++) {
	        const coord = coords[i];
	        const tile = sourceCache.getTile(coord);
	        const bucket = tile.getBucket(layer);
	        if (!bucket || bucket.projection.name !== tr.projection.name)
	            continue;
	        const programConfiguration = bucket.programConfigurations.get(layer.id);
	        const definesValues = circleDefinesValues(layer);
	        if (isGlobeProjection) {
	            definesValues.push('PROJECTION_GLOBE_VIEW');
	        }
	        const program = painter.useProgram('circle', programConfiguration, definesValues);
	        const layoutVertexBuffer = bucket.layoutVertexBuffer;
	        const globeExtVertexBuffer = bucket.globeExtVertexBuffer;
	        const indexBuffer = bucket.indexBuffer;
	        const invMatrix = tr.projection.createInversionMatrix(tr, coord.canonical);
	        const uniformValues = circleUniformValues(painter, coord, tile, invMatrix, mercatorCenter, layer);
	        const state = {
	            programConfiguration,
	            program,
	            layoutVertexBuffer,
	            globeExtVertexBuffer,
	            indexBuffer,
	            uniformValues,
	            tile
	        };
	        if (sortFeaturesByKey) {
	            const oldSegments = bucket.segments.get();
	            for (const segment of oldSegments) {
	                segmentsRenderStates.push({
	                    segments: new ref_properties.SegmentVector([segment]),
	                    sortKey: segment.sortKey,
	                    state
	                });
	            }
	        } else {
	            segmentsRenderStates.push({
	                segments: bucket.segments,
	                sortKey: 0,
	                state
	            });
	        }
	    }
	    if (sortFeaturesByKey) {
	        segmentsRenderStates.sort((a, b) => a.sortKey - b.sortKey);
	    }
	    const terrainOptions = { useDepthForOcclusion: !isGlobeProjection };
	    for (const segmentsState of segmentsRenderStates) {
	        const {programConfiguration, program, layoutVertexBuffer, globeExtVertexBuffer, indexBuffer, uniformValues, tile} = segmentsState.state;
	        const segments = segmentsState.segments;
	        if (painter.terrain)
	            painter.terrain.setupElevationDraw(tile, program, terrainOptions);
	        painter.prepareDrawProgram(context, program, tile.tileID.toUnwrapped());
	        program.draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode, ref_properties.CullFaceMode.disabled, uniformValues, layer.id, layoutVertexBuffer, indexBuffer, segments, layer.paint, tr.zoom, programConfiguration, isGlobeProjection ? globeExtVertexBuffer : null);
	    }
	}

	function drawHeatmap(painter, sourceCache, layer, coords) {
	    if (layer.paint.get('heatmap-opacity') === 0) {
	        return;
	    }
	    if (painter.renderPass === 'offscreen') {
	        const context = painter.context;
	        const gl = context.gl;
	        const stencilMode = ref_properties.StencilMode.disabled;
	        const colorMode = new ref_properties.ColorMode([
	            gl.ONE,
	            gl.ONE
	        ], ref_properties.Color.transparent, [
	            true,
	            true,
	            true,
	            true
	        ]);
	        const resolutionScaling = painter.transform.projection.name === 'globe' ? 0.5 : 0.25;
	        bindFramebuffer(context, painter, layer, resolutionScaling);
	        context.clear({ color: ref_properties.Color.transparent });
	        const tr = painter.transform;
	        const isGlobeProjection = tr.projection.name === 'globe';
	        const definesValues = isGlobeProjection ? ['PROJECTION_GLOBE_VIEW'] : null;
	        const cullMode = isGlobeProjection ? ref_properties.CullFaceMode.frontCCW : ref_properties.CullFaceMode.disabled;
	        const mercatorCenter = [
	            ref_properties.mercatorXfromLng(tr.center.lng),
	            ref_properties.mercatorYfromLat(tr.center.lat)
	        ];
	        for (let i = 0; i < coords.length; i++) {
	            const coord = coords[i];
	            if (sourceCache.hasRenderableParent(coord))
	                continue;
	            const tile = sourceCache.getTile(coord);
	            const bucket = tile.getBucket(layer);
	            if (!bucket || bucket.projection.name !== tr.projection.name)
	                continue;
	            const programConfiguration = bucket.programConfigurations.get(layer.id);
	            const program = painter.useProgram('heatmap', programConfiguration, definesValues);
	            const {zoom} = painter.transform;
	            if (painter.terrain)
	                painter.terrain.setupElevationDraw(tile, program);
	            painter.prepareDrawProgram(context, program, coord.toUnwrapped());
	            const invMatrix = tr.projection.createInversionMatrix(tr, coord.canonical);
	            program.draw(context, gl.TRIANGLES, ref_properties.DepthMode.disabled, stencilMode, colorMode, cullMode, heatmapUniformValues(painter, coord, tile, invMatrix, mercatorCenter, zoom, layer.paint.get('heatmap-intensity')), layer.id, bucket.layoutVertexBuffer, bucket.indexBuffer, bucket.segments, layer.paint, painter.transform.zoom, programConfiguration, isGlobeProjection ? bucket.globeExtVertexBuffer : null);
	        }
	        context.viewport.set([
	            0,
	            0,
	            painter.width,
	            painter.height
	        ]);
	    } else if (painter.renderPass === 'translucent') {
	        painter.context.setColorMode(painter.colorModeForRenderPass());
	        renderTextureToMap(painter, layer);
	    }
	}
	function bindFramebuffer(context, painter, layer, scaling) {
	    const gl = context.gl;
	    const width = painter.width * scaling;
	    const height = painter.height * scaling;
	    context.activeTexture.set(gl.TEXTURE1);
	    context.viewport.set([
	        0,
	        0,
	        width,
	        height
	    ]);
	    let fbo = layer.heatmapFbo;
	    if (!fbo || fbo && (fbo.width !== width || fbo.height !== height)) {
	        if (fbo) {
	            fbo.destroy();
	        }
	        const texture = gl.createTexture();
	        gl.bindTexture(gl.TEXTURE_2D, texture);
	        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
	        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
	        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
	        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
	        fbo = layer.heatmapFbo = context.createFramebuffer(width, height, false);
	        bindTextureToFramebuffer(context, painter, texture, fbo, width, height);
	    } else {
	        gl.bindTexture(gl.TEXTURE_2D, fbo.colorAttachment.get());
	        context.bindFramebuffer.set(fbo.framebuffer);
	    }
	}
	function bindTextureToFramebuffer(context, painter, texture, fbo, width, height) {
	    const gl = context.gl;
	    const internalFormat = context.extRenderToTextureHalfFloat ? context.extTextureHalfFloat.HALF_FLOAT_OES : gl.UNSIGNED_BYTE;
	    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, internalFormat, null);
	    fbo.colorAttachment.set(texture);
	}
	function renderTextureToMap(painter, layer) {
	    const context = painter.context;
	    const gl = context.gl;
	    const fbo = layer.heatmapFbo;
	    if (!fbo)
	        return;
	    context.activeTexture.set(gl.TEXTURE0);
	    gl.bindTexture(gl.TEXTURE_2D, fbo.colorAttachment.get());
	    context.activeTexture.set(gl.TEXTURE1);
	    let colorRampTexture = layer.colorRampTexture;
	    if (!colorRampTexture) {
	        colorRampTexture = layer.colorRampTexture = new ref_properties.Texture(context, layer.colorRamp, gl.RGBA);
	    }
	    colorRampTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	    painter.useProgram('heatmapTexture').draw(context, gl.TRIANGLES, ref_properties.DepthMode.disabled, ref_properties.StencilMode.disabled, painter.colorModeForRenderPass(), ref_properties.CullFaceMode.disabled, heatmapTextureUniformValues(painter, layer, 0, 1), layer.id, painter.viewportBuffer, painter.quadTriangleIndexBuffer, painter.viewportSegments, layer.paint, painter.transform.zoom);
	}

	function drawLine(painter, sourceCache, layer, coords) {
	    if (painter.renderPass !== 'translucent')
	        return;
	    const opacity = layer.paint.get('line-opacity');
	    const width = layer.paint.get('line-width');
	    if (opacity.constantOr(1) === 0 || width.constantOr(1) === 0)
	        return;
	    const depthMode = painter.depthModeForSublayer(0, ref_properties.DepthMode.ReadOnly);
	    const colorMode = painter.colorModeForRenderPass();
	    const pixelRatio = painter.terrain && painter.terrain.renderingToTexture ? 1 : ref_properties.exported.devicePixelRatio;
	    const dasharrayProperty = layer.paint.get('line-dasharray');
	    const dasharray = dasharrayProperty.constantOr(1);
	    const capProperty = layer.layout.get('line-cap');
	    const patternProperty = layer.paint.get('line-pattern');
	    const image = patternProperty.constantOr(1);
	    const gradient = layer.paint.get('line-gradient');
	    const crossfade = layer.getCrossfadeParameters();
	    const programId = image ? 'linePattern' : 'line';
	    const context = painter.context;
	    const gl = context.gl;
	    const definesValues = lineDefinesValues(layer);
	    let useStencilMaskRenderPass = definesValues.includes('RENDER_LINE_ALPHA_DISCARD');
	    if (painter.terrain && painter.terrain.clipOrMaskOverlapStencilType()) {
	        useStencilMaskRenderPass = false;
	    }
	    for (const coord of coords) {
	        const tile = sourceCache.getTile(coord);
	        if (image && !tile.patternsLoaded())
	            continue;
	        const bucket = tile.getBucket(layer);
	        if (!bucket)
	            continue;
	        painter.prepareDrawTile();
	        const programConfiguration = bucket.programConfigurations.get(layer.id);
	        const program = painter.useProgram(programId, programConfiguration, definesValues);
	        const constantPattern = patternProperty.constantOr(null);
	        if (constantPattern && tile.imageAtlas) {
	            const atlas = tile.imageAtlas;
	            const posTo = atlas.patternPositions[constantPattern.to.toString()];
	            const posFrom = atlas.patternPositions[constantPattern.from.toString()];
	            if (posTo && posFrom)
	                programConfiguration.setConstantPatternPositions(posTo, posFrom);
	        }
	        const constantDash = dasharrayProperty.constantOr(null);
	        const constantCap = capProperty.constantOr(null);
	        if (!image && constantDash && constantCap && tile.lineAtlas) {
	            const atlas = tile.lineAtlas;
	            const posTo = atlas.getDash(constantDash.to, constantCap);
	            const posFrom = atlas.getDash(constantDash.from, constantCap);
	            if (posTo && posFrom)
	                programConfiguration.setConstantPatternPositions(posTo, posFrom);
	        }
	        let [trimStart, trimEnd] = layer.paint.get('line-trim-offset');
	        if (constantCap === 'round' || constantCap === 'square') {
	            const fakeOffsetShift = 1;
	            if (trimStart !== trimEnd) {
	                if (trimStart === 0) {
	                    trimStart -= fakeOffsetShift;
	                }
	                if (trimEnd === 1) {
	                    trimEnd += fakeOffsetShift;
	                }
	            }
	        }
	        const matrix = painter.terrain ? coord.projMatrix : null;
	        const uniformValues = image ? linePatternUniformValues(painter, tile, layer, crossfade, matrix, pixelRatio) : lineUniformValues(painter, tile, layer, crossfade, matrix, bucket.lineClipsArray.length, pixelRatio, [
	            trimStart,
	            trimEnd
	        ]);
	        if (gradient) {
	            const layerGradient = bucket.gradients[layer.id];
	            let gradientTexture = layerGradient.texture;
	            if (layer.gradientVersion !== layerGradient.version) {
	                let textureResolution = 256;
	                if (layer.stepInterpolant) {
	                    const sourceMaxZoom = sourceCache.getSource().maxzoom;
	                    const potentialOverzoom = coord.canonical.z === sourceMaxZoom ? Math.ceil(1 << painter.transform.maxZoom - coord.canonical.z) : 1;
	                    const lineLength = bucket.maxLineLength / ref_properties.EXTENT;
	                    const maxTilePixelSize = 1024;
	                    const maxTextureCoverage = lineLength * maxTilePixelSize * potentialOverzoom;
	                    textureResolution = ref_properties.clamp(ref_properties.nextPowerOfTwo(maxTextureCoverage), 256, context.maxTextureSize);
	                }
	                layerGradient.gradient = ref_properties.renderColorRamp({
	                    expression: layer.gradientExpression(),
	                    evaluationKey: 'lineProgress',
	                    resolution: textureResolution,
	                    image: layerGradient.gradient || undefined,
	                    clips: bucket.lineClipsArray
	                });
	                if (layerGradient.texture) {
	                    layerGradient.texture.update(layerGradient.gradient);
	                } else {
	                    layerGradient.texture = new ref_properties.Texture(context, layerGradient.gradient, gl.RGBA);
	                }
	                layerGradient.version = layer.gradientVersion;
	                gradientTexture = layerGradient.texture;
	            }
	            context.activeTexture.set(gl.TEXTURE1);
	            gradientTexture.bind(layer.stepInterpolant ? gl.NEAREST : gl.LINEAR, gl.CLAMP_TO_EDGE);
	        }
	        if (dasharray) {
	            context.activeTexture.set(gl.TEXTURE0);
	            tile.lineAtlasTexture.bind(gl.LINEAR, gl.REPEAT);
	            programConfiguration.updatePaintBuffers(crossfade);
	        }
	        if (image) {
	            context.activeTexture.set(gl.TEXTURE0);
	            tile.imageAtlasTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	            programConfiguration.updatePaintBuffers(crossfade);
	        }
	        painter.prepareDrawProgram(context, program, coord.toUnwrapped());
	        const renderLine = stencilMode => {
	            program.draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode, ref_properties.CullFaceMode.disabled, uniformValues, layer.id, bucket.layoutVertexBuffer, bucket.indexBuffer, bucket.segments, layer.paint, painter.transform.zoom, programConfiguration, bucket.layoutVertexBuffer2);
	        };
	        if (useStencilMaskRenderPass) {
	            const stencilId = painter.stencilModeForClipping(coord).ref;
	            if (stencilId === 0 && painter.terrain) {
	                context.clear({ stencil: 0 });
	            }
	            const stencilFunc = {
	                func: gl.EQUAL,
	                mask: 255
	            };
	            uniformValues['u_alpha_discard_threshold'] = 0.8;
	            renderLine(new ref_properties.StencilMode(stencilFunc, stencilId, 255, gl.KEEP, gl.KEEP, gl.INVERT));
	            uniformValues['u_alpha_discard_threshold'] = 0;
	            renderLine(new ref_properties.StencilMode(stencilFunc, stencilId, 255, gl.KEEP, gl.KEEP, gl.KEEP));
	        } else {
	            renderLine(painter.stencilModeForClipping(coord));
	        }
	    }
	    if (useStencilMaskRenderPass) {
	        painter.resetStencilClippingMasks();
	        if (painter.terrain) {
	            context.clear({ stencil: 0 });
	        }
	    }
	}

	function drawFill(painter, sourceCache, layer, coords) {
	    const color = layer.paint.get('fill-color');
	    const opacity = layer.paint.get('fill-opacity');
	    if (opacity.constantOr(1) === 0) {
	        return;
	    }
	    const colorMode = painter.colorModeForRenderPass();
	    const pattern = layer.paint.get('fill-pattern');
	    const pass = painter.opaquePassEnabledForLayer() && (!pattern.constantOr(1) && color.constantOr(ref_properties.Color.transparent).a === 1 && opacity.constantOr(0) === 1) ? 'opaque' : 'translucent';
	    if (painter.renderPass === pass) {
	        const depthMode = painter.depthModeForSublayer(1, painter.renderPass === 'opaque' ? ref_properties.DepthMode.ReadWrite : ref_properties.DepthMode.ReadOnly);
	        drawFillTiles(painter, sourceCache, layer, coords, depthMode, colorMode, false);
	    }
	    if (painter.renderPass === 'translucent' && layer.paint.get('fill-antialias')) {
	        const depthMode = painter.depthModeForSublayer(layer.getPaintProperty('fill-outline-color') ? 2 : 0, ref_properties.DepthMode.ReadOnly);
	        drawFillTiles(painter, sourceCache, layer, coords, depthMode, colorMode, true);
	    }
	}
	function drawFillTiles(painter, sourceCache, layer, coords, depthMode, colorMode, isOutline) {
	    const gl = painter.context.gl;
	    const patternProperty = layer.paint.get('fill-pattern');
	    const image = patternProperty && patternProperty.constantOr(1);
	    const crossfade = layer.getCrossfadeParameters();
	    let drawMode, programName, uniformValues, indexBuffer, segments;
	    if (!isOutline) {
	        programName = image ? 'fillPattern' : 'fill';
	        drawMode = gl.TRIANGLES;
	    } else {
	        programName = image && !layer.getPaintProperty('fill-outline-color') ? 'fillOutlinePattern' : 'fillOutline';
	        drawMode = gl.LINES;
	    }
	    for (const coord of coords) {
	        const tile = sourceCache.getTile(coord);
	        if (image && !tile.patternsLoaded())
	            continue;
	        const bucket = tile.getBucket(layer);
	        if (!bucket)
	            continue;
	        painter.prepareDrawTile();
	        const programConfiguration = bucket.programConfigurations.get(layer.id);
	        const program = painter.useProgram(programName, programConfiguration);
	        if (image) {
	            painter.context.activeTexture.set(gl.TEXTURE0);
	            tile.imageAtlasTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	            programConfiguration.updatePaintBuffers(crossfade);
	        }
	        const constantPattern = patternProperty.constantOr(null);
	        if (constantPattern && tile.imageAtlas) {
	            const atlas = tile.imageAtlas;
	            const posTo = atlas.patternPositions[constantPattern.to.toString()];
	            const posFrom = atlas.patternPositions[constantPattern.from.toString()];
	            if (posTo && posFrom)
	                programConfiguration.setConstantPatternPositions(posTo, posFrom);
	        }
	        const tileMatrix = painter.translatePosMatrix(coord.projMatrix, tile, layer.paint.get('fill-translate'), layer.paint.get('fill-translate-anchor'));
	        if (!isOutline) {
	            indexBuffer = bucket.indexBuffer;
	            segments = bucket.segments;
	            uniformValues = image ? fillPatternUniformValues(tileMatrix, painter, crossfade, tile) : fillUniformValues(tileMatrix);
	        } else {
	            indexBuffer = bucket.indexBuffer2;
	            segments = bucket.segments2;
	            const drawingBufferSize = painter.terrain && painter.terrain.renderingToTexture ? painter.terrain.drapeBufferSize : [
	                gl.drawingBufferWidth,
	                gl.drawingBufferHeight
	            ];
	            uniformValues = programName === 'fillOutlinePattern' && image ? fillOutlinePatternUniformValues(tileMatrix, painter, crossfade, tile, drawingBufferSize) : fillOutlineUniformValues(tileMatrix, drawingBufferSize);
	        }
	        painter.prepareDrawProgram(painter.context, program, coord.toUnwrapped());
	        program.draw(painter.context, drawMode, depthMode, painter.stencilModeForClipping(coord), colorMode, ref_properties.CullFaceMode.disabled, uniformValues, layer.id, bucket.layoutVertexBuffer, indexBuffer, segments, layer.paint, painter.transform.zoom, programConfiguration);
	    }
	}

	function draw$1(painter, source, layer, coords) {
	    const opacity = layer.paint.get('fill-extrusion-opacity');
	    if (opacity === 0) {
	        return;
	    }
	    if (painter.renderPass === 'translucent') {
	        const depthMode = new ref_properties.DepthMode(painter.context.gl.LEQUAL, ref_properties.DepthMode.ReadWrite, painter.depthRangeFor3D);
	        if (opacity === 1 && !layer.paint.get('fill-extrusion-pattern').constantOr(1)) {
	            const colorMode = painter.colorModeForRenderPass();
	            drawExtrusionTiles(painter, source, layer, coords, depthMode, ref_properties.StencilMode.disabled, colorMode);
	        } else {
	            drawExtrusionTiles(painter, source, layer, coords, depthMode, ref_properties.StencilMode.disabled, ref_properties.ColorMode.disabled);
	            drawExtrusionTiles(painter, source, layer, coords, depthMode, painter.stencilModeFor3D(), painter.colorModeForRenderPass());
	            painter.resetStencilClippingMasks();
	        }
	    }
	}
	function drawExtrusionTiles(painter, source, layer, coords, depthMode, stencilMode, colorMode) {
	    const context = painter.context;
	    const gl = context.gl;
	    const tr = painter.transform;
	    const patternProperty = layer.paint.get('fill-extrusion-pattern');
	    const image = patternProperty.constantOr(1);
	    const crossfade = layer.getCrossfadeParameters();
	    const opacity = layer.paint.get('fill-extrusion-opacity');
	    const heightLift = tr.projection.name === 'globe' ? ref_properties.fillExtrusionHeightLift() : 0;
	    const isGlobeProjection = tr.projection.name === 'globe';
	    const globeToMercator = isGlobeProjection ? ref_properties.globeToMercatorTransition(tr.zoom) : 0;
	    const mercatorCenter = [
	        ref_properties.mercatorXfromLng(tr.center.lng),
	        ref_properties.mercatorYfromLat(tr.center.lat)
	    ];
	    const baseDefines = [];
	    if (isGlobeProjection) {
	        baseDefines.push('PROJECTION_GLOBE_VIEW');
	    }
	    for (const coord of coords) {
	        const tile = source.getTile(coord);
	        const bucket = tile.getBucket(layer);
	        if (!bucket || bucket.projection.name !== tr.projection.name)
	            continue;
	        const programConfiguration = bucket.programConfigurations.get(layer.id);
	        const program = painter.useProgram(image ? 'fillExtrusionPattern' : 'fillExtrusion', programConfiguration, baseDefines);
	        if (painter.terrain) {
	            const terrain = painter.terrain;
	            if (painter.style.terrainSetForDrapingOnly()) {
	                terrain.setupElevationDraw(tile, program, { useMeterToDem: true });
	            } else {
	                if (!bucket.enableTerrain)
	                    continue;
	                terrain.setupElevationDraw(tile, program, { useMeterToDem: true });
	                flatRoofsUpdate(context, source, coord, bucket, layer, terrain);
	                if (!bucket.centroidVertexBuffer) {
	                    const attrIndex = program.attributes['a_centroid_pos'];
	                    if (attrIndex !== undefined)
	                        gl.vertexAttrib2f(attrIndex, 0, 0);
	                }
	            }
	        }
	        if (image) {
	            painter.context.activeTexture.set(gl.TEXTURE0);
	            tile.imageAtlasTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	            programConfiguration.updatePaintBuffers(crossfade);
	        }
	        const constantPattern = patternProperty.constantOr(null);
	        if (constantPattern && tile.imageAtlas) {
	            const atlas = tile.imageAtlas;
	            const posTo = atlas.patternPositions[constantPattern.to.toString()];
	            const posFrom = atlas.patternPositions[constantPattern.from.toString()];
	            if (posTo && posFrom)
	                programConfiguration.setConstantPatternPositions(posTo, posFrom);
	        }
	        const matrix = painter.translatePosMatrix(coord.projMatrix, tile, layer.paint.get('fill-extrusion-translate'), layer.paint.get('fill-extrusion-translate-anchor'));
	        const invMatrix = tr.projection.createInversionMatrix(tr, coord.canonical);
	        const shouldUseVerticalGradient = layer.paint.get('fill-extrusion-vertical-gradient');
	        const uniformValues = image ? fillExtrusionPatternUniformValues(matrix, painter, shouldUseVerticalGradient, opacity, coord, crossfade, tile, heightLift, globeToMercator, mercatorCenter, invMatrix) : fillExtrusionUniformValues(matrix, painter, shouldUseVerticalGradient, opacity, coord, heightLift, globeToMercator, mercatorCenter, invMatrix);
	        painter.prepareDrawProgram(context, program, coord.toUnwrapped());
	        program.draw(context, context.gl.TRIANGLES, depthMode, stencilMode, colorMode, ref_properties.CullFaceMode.backCCW, uniformValues, layer.id, bucket.layoutVertexBuffer, bucket.indexBuffer, bucket.segments, layer.paint, painter.transform.zoom, programConfiguration, painter.terrain ? bucket.centroidVertexBuffer : null, isGlobeProjection ? bucket.layoutVertexExtBuffer : null);
	    }
	}
	function flatRoofsUpdate(context, source, coord, bucket, layer, terrain) {
	    const neighborCoord = [
	        coord => {
	            let x = coord.canonical.x - 1;
	            let w = coord.wrap;
	            if (x < 0) {
	                x = (1 << coord.canonical.z) - 1;
	                w--;
	            }
	            return new ref_properties.OverscaledTileID(coord.overscaledZ, w, coord.canonical.z, x, coord.canonical.y);
	        },
	        coord => {
	            let x = coord.canonical.x + 1;
	            let w = coord.wrap;
	            if (x === 1 << coord.canonical.z) {
	                x = 0;
	                w++;
	            }
	            return new ref_properties.OverscaledTileID(coord.overscaledZ, w, coord.canonical.z, x, coord.canonical.y);
	        },
	        coord => new ref_properties.OverscaledTileID(coord.overscaledZ, coord.wrap, coord.canonical.z, coord.canonical.x, (coord.canonical.y === 0 ? 1 << coord.canonical.z : coord.canonical.y) - 1),
	        coord => new ref_properties.OverscaledTileID(coord.overscaledZ, coord.wrap, coord.canonical.z, coord.canonical.x, coord.canonical.y === (1 << coord.canonical.z) - 1 ? 0 : coord.canonical.y + 1)
	    ];
	    const getLoadedBucket = nid => {
	        const minzoom = source.getSource().minzoom;
	        const getBucket = key => {
	            const n = source.getTileByID(key);
	            if (n && n.hasData()) {
	                return n.getBucket(layer);
	            }
	        };
	        const zoomLevels = [
	            0,
	            -1,
	            1
	        ];
	        for (const i of zoomLevels) {
	            const z = nid.overscaledZ + i;
	            if (z < minzoom)
	                continue;
	            const key = nid.calculateScaledKey(nid.overscaledZ + i);
	            const b = getBucket(key);
	            if (b) {
	                return b;
	            }
	        }
	    };
	    const projectedToBorder = [
	        0,
	        0,
	        0
	    ];
	    const xjoin = (a, b) => {
	        projectedToBorder[0] = Math.min(a.min.y, b.min.y);
	        projectedToBorder[1] = Math.max(a.max.y, b.max.y);
	        projectedToBorder[2] = ref_properties.EXTENT - b.min.x > a.max.x ? b.min.x - ref_properties.EXTENT : a.max.x;
	        return projectedToBorder;
	    };
	    const yjoin = (a, b) => {
	        projectedToBorder[0] = Math.min(a.min.x, b.min.x);
	        projectedToBorder[1] = Math.max(a.max.x, b.max.x);
	        projectedToBorder[2] = ref_properties.EXTENT - b.min.y > a.max.y ? b.min.y - ref_properties.EXTENT : a.max.y;
	        return projectedToBorder;
	    };
	    const projectCombinedSpanToBorder = [
	        (a, b) => xjoin(a, b),
	        (a, b) => xjoin(b, a),
	        (a, b) => yjoin(a, b),
	        (a, b) => yjoin(b, a)
	    ];
	    const centroid = new ref_properties.pointGeometry(0, 0);
	    const error = 3;
	    let demTile, neighborDEMTile, neighborTileID;
	    const flatBase = (min, max, edge, verticalEdge, maxOffsetFromBorder) => {
	        const points = [
	            [
	                verticalEdge ? edge : min,
	                verticalEdge ? min : edge,
	                0
	            ],
	            [
	                verticalEdge ? edge : max,
	                verticalEdge ? max : edge,
	                0
	            ]
	        ];
	        const coord3 = maxOffsetFromBorder < 0 ? ref_properties.EXTENT + maxOffsetFromBorder : maxOffsetFromBorder;
	        const thirdPoint = [
	            verticalEdge ? coord3 : (min + max) / 2,
	            verticalEdge ? (min + max) / 2 : coord3,
	            0
	        ];
	        if (edge === 0 && maxOffsetFromBorder < 0 || edge !== 0 && maxOffsetFromBorder > 0) {
	            terrain.getForTilePoints(neighborTileID, [thirdPoint], true, neighborDEMTile);
	        } else {
	            points.push(thirdPoint);
	        }
	        terrain.getForTilePoints(coord, points, true, demTile);
	        return Math.max(points[0][2], points[1][2], thirdPoint[2]) / terrain.exaggeration();
	    };
	    for (let i = 0; i < 4; i++) {
	        const j = (i < 2 ? 1 : 5) - i;
	        const a = bucket.borders[i];
	        if (a.length === 0)
	            continue;
	        const nid = neighborTileID = neighborCoord[i](coord);
	        const nBucket = getLoadedBucket(nid);
	        if (!nBucket || !(nBucket instanceof ref_properties.FillExtrusionBucket) || !nBucket.enableTerrain)
	            continue;
	        if (bucket.borderDoneWithNeighborZ[i] === nBucket.canonical.z && nBucket.borderDoneWithNeighborZ[j] === bucket.canonical.z) {
	            continue;
	        }
	        neighborDEMTile = terrain.findDEMTileFor(nid);
	        if (!neighborDEMTile || !neighborDEMTile.dem)
	            continue;
	        if (!demTile) {
	            const dem = terrain.findDEMTileFor(coord);
	            if (!(dem && dem.dem))
	                return;
	            demTile = dem;
	        }
	        const b = nBucket.borders[j];
	        let ib = 0;
	        const updateNeighbor = nBucket.borderDoneWithNeighborZ[j] !== bucket.canonical.z;
	        if (bucket.canonical.z !== nBucket.canonical.z) {
	            for (const index of a) {
	                bucket.encodeCentroid(undefined, bucket.featuresOnBorder[index], false);
	            }
	            if (updateNeighbor) {
	                for (const index of b) {
	                    nBucket.encodeCentroid(undefined, nBucket.featuresOnBorder[index], false);
	                }
	                nBucket.borderDoneWithNeighborZ[j] = bucket.canonical.z;
	                nBucket.needsCentroidUpdate = true;
	            }
	            bucket.borderDoneWithNeighborZ[i] = nBucket.canonical.z;
	            bucket.needsCentroidUpdate = true;
	            continue;
	        }
	        for (let ia = 0; ia < a.length; ia++) {
	            const parta = bucket.featuresOnBorder[a[ia]];
	            const partABorderRange = parta.borders[i];
	            let partb;
	            while (ib < b.length) {
	                partb = nBucket.featuresOnBorder[b[ib]];
	                const partBBorderRange = partb.borders[j];
	                if (partBBorderRange[1] > partABorderRange[0] + error)
	                    break;
	                if (updateNeighbor)
	                    nBucket.encodeCentroid(undefined, partb, false);
	                ib++;
	            }
	            if (partb && ib < b.length) {
	                const saveIb = ib;
	                let count = 0;
	                while (true) {
	                    const partBBorderRange = partb.borders[j];
	                    if (partBBorderRange[0] > partABorderRange[1] - error)
	                        break;
	                    count++;
	                    if (++ib === b.length)
	                        break;
	                    partb = nBucket.featuresOnBorder[b[ib]];
	                }
	                partb = nBucket.featuresOnBorder[b[saveIb]];
	                if (parta.intersectsCount() > 1 || partb.intersectsCount() > 1 || count !== 1) {
	                    if (count !== 1) {
	                        ib = saveIb;
	                    }
	                    bucket.encodeCentroid(undefined, parta, false);
	                    if (updateNeighbor)
	                        nBucket.encodeCentroid(undefined, partb, false);
	                    continue;
	                }
	                const span = projectCombinedSpanToBorder[i](parta, partb);
	                const edge = i % 2 ? ref_properties.EXTENT - 1 : 0;
	                centroid.x = flatBase(span[0], Math.min(ref_properties.EXTENT - 1, span[1]), edge, i < 2, span[2]);
	                centroid.y = 0;
	                bucket.encodeCentroid(centroid, parta, false);
	                if (updateNeighbor)
	                    nBucket.encodeCentroid(centroid, partb, false);
	            } else {
	                bucket.encodeCentroid(undefined, parta, false);
	            }
	        }
	        bucket.borderDoneWithNeighborZ[i] = nBucket.canonical.z;
	        bucket.needsCentroidUpdate = true;
	        if (updateNeighbor) {
	            nBucket.borderDoneWithNeighborZ[j] = bucket.canonical.z;
	            nBucket.needsCentroidUpdate = true;
	        }
	    }
	    if (bucket.needsCentroidUpdate || !bucket.centroidVertexBuffer && bucket.centroidVertexArray.length !== 0) {
	        bucket.uploadCentroid(context);
	    }
	}

	function drawRaster(painter, sourceCache, layer, tileIDs, variableOffsets, isInitialLoad) {
	    if (painter.renderPass !== 'translucent')
	        return;
	    if (layer.paint.get('raster-opacity') === 0)
	        return;
	    if (!tileIDs.length)
	        return;
	    const context = painter.context;
	    const gl = context.gl;
	    const source = sourceCache.getSource();
	    const program = painter.useProgram('raster');
	    const colorMode = painter.colorModeForRenderPass();
	    const renderingToTexture = painter.terrain && painter.terrain.renderingToTexture;
	    const [stencilModes, coords] = source instanceof ImageSource || renderingToTexture ? [
	        {},
	        tileIDs
	    ] : painter.stencilConfigForOverlap(tileIDs);
	    const minTileZ = coords[coords.length - 1].overscaledZ;
	    const align = !painter.options.moving;
	    for (const coord of coords) {
	        const depthMode = renderingToTexture ? ref_properties.DepthMode.disabled : painter.depthModeForSublayer(coord.overscaledZ - minTileZ, layer.paint.get('raster-opacity') === 1 ? ref_properties.DepthMode.ReadWrite : ref_properties.DepthMode.ReadOnly, gl.LESS);
	        const unwrappedTileID = coord.toUnwrapped();
	        const tile = sourceCache.getTile(coord);
	        if (renderingToTexture && !(tile && tile.hasData()))
	            continue;
	        const projMatrix = renderingToTexture ? coord.projMatrix : painter.transform.calculateProjMatrix(unwrappedTileID, align);
	        const stencilMode = painter.terrain && renderingToTexture ? painter.terrain.stencilModeForRTTOverlap(coord) : stencilModes[coord.overscaledZ];
	        const rasterFadeDuration = isInitialLoad ? 0 : layer.paint.get('raster-fade-duration');
	        tile.registerFadeDuration(rasterFadeDuration);
	        const parentTile = sourceCache.findLoadedParent(coord, 0);
	        const fade = rasterFade(tile, parentTile, sourceCache, painter.transform, rasterFadeDuration);
	        if (painter.terrain)
	            painter.terrain.prepareDrawTile();
	        let parentScaleBy, parentTL;
	        const textureFilter = layer.paint.get('raster-resampling') === 'nearest' ? gl.NEAREST : gl.LINEAR;
	        context.activeTexture.set(gl.TEXTURE0);
	        tile.texture.bind(textureFilter, gl.CLAMP_TO_EDGE);
	        context.activeTexture.set(gl.TEXTURE1);
	        if (parentTile) {
	            parentTile.texture.bind(textureFilter, gl.CLAMP_TO_EDGE);
	            parentScaleBy = Math.pow(2, parentTile.tileID.overscaledZ - tile.tileID.overscaledZ);
	            parentTL = [
	                tile.tileID.canonical.x * parentScaleBy % 1,
	                tile.tileID.canonical.y * parentScaleBy % 1
	            ];
	        } else {
	            tile.texture.bind(textureFilter, gl.CLAMP_TO_EDGE);
	        }
	        const perspectiveTransform = source instanceof ImageSource ? source.perspectiveTransform : [
	            0,
	            0
	        ];
	        const uniformValues = rasterUniformValues(projMatrix, parentTL || [
	            0,
	            0
	        ], parentScaleBy || 1, fade, layer, perspectiveTransform);
	        painter.prepareDrawProgram(context, program, unwrappedTileID);
	        if (source instanceof ImageSource) {
	            if (source.boundsBuffer && source.boundsSegments)
	                program.draw(context, gl.TRIANGLES, depthMode, ref_properties.StencilMode.disabled, colorMode, ref_properties.CullFaceMode.disabled, uniformValues, layer.id, source.boundsBuffer, painter.quadTriangleIndexBuffer, source.boundsSegments);
	        } else {
	            const {tileBoundsBuffer, tileBoundsIndexBuffer, tileBoundsSegments} = painter.getTileBoundsBuffers(tile);
	            program.draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode, ref_properties.CullFaceMode.disabled, uniformValues, layer.id, tileBoundsBuffer, tileBoundsIndexBuffer, tileBoundsSegments);
	        }
	    }
	    painter.resetStencilClippingMasks();
	}

	function drawBackground(painter, sourceCache, layer, coords) {
	    const color = layer.paint.get('background-color');
	    const opacity = layer.paint.get('background-opacity');
	    if (opacity === 0)
	        return;
	    const context = painter.context;
	    const gl = context.gl;
	    const transform = painter.transform;
	    const tileSize = transform.tileSize;
	    const image = layer.paint.get('background-pattern');
	    if (painter.isPatternMissing(image))
	        return;
	    const pass = !image && color.a === 1 && opacity === 1 && painter.opaquePassEnabledForLayer() ? 'opaque' : 'translucent';
	    if (painter.renderPass !== pass)
	        return;
	    const stencilMode = ref_properties.StencilMode.disabled;
	    const depthMode = painter.depthModeForSublayer(0, pass === 'opaque' ? ref_properties.DepthMode.ReadWrite : ref_properties.DepthMode.ReadOnly);
	    const colorMode = painter.colorModeForRenderPass();
	    const program = painter.useProgram(image ? 'backgroundPattern' : 'background');
	    let tileIDs = coords;
	    let backgroundTiles;
	    if (!tileIDs) {
	        backgroundTiles = painter.getBackgroundTiles();
	        tileIDs = Object.values(backgroundTiles).map(tile => tile.tileID);
	    }
	    if (image) {
	        context.activeTexture.set(gl.TEXTURE0);
	        painter.imageManager.bind(painter.context);
	    }
	    const crossfade = layer.getCrossfadeParameters();
	    for (const tileID of tileIDs) {
	        const unwrappedTileID = tileID.toUnwrapped();
	        const matrix = coords ? tileID.projMatrix : painter.transform.calculateProjMatrix(unwrappedTileID);
	        painter.prepareDrawTile();
	        const tile = sourceCache ? sourceCache.getTile(tileID) : backgroundTiles ? backgroundTiles[tileID.key] : new ref_properties.Tile(tileID, tileSize, transform.zoom, painter);
	        const uniformValues = image ? backgroundPatternUniformValues(matrix, opacity, painter, image, {
	            tileID,
	            tileSize
	        }, crossfade) : backgroundUniformValues(matrix, opacity, color);
	        painter.prepareDrawProgram(context, program, unwrappedTileID);
	        const {tileBoundsBuffer, tileBoundsIndexBuffer, tileBoundsSegments} = painter.getTileBoundsBuffers(tile);
	        program.draw(context, gl.TRIANGLES, depthMode, stencilMode, colorMode, ref_properties.CullFaceMode.disabled, uniformValues, layer.id, tileBoundsBuffer, tileBoundsIndexBuffer, tileBoundsSegments);
	    }
	}

	const topColor = new ref_properties.Color(1, 0, 0, 1);
	const btmColor = new ref_properties.Color(0, 1, 0, 1);
	const leftColor = new ref_properties.Color(0, 0, 1, 1);
	const rightColor = new ref_properties.Color(1, 0, 1, 1);
	const centerColor = new ref_properties.Color(0, 1, 1, 1);
	function drawDebugPadding(painter) {
	    const padding = painter.transform.padding;
	    const lineWidth = 3;
	    drawHorizontalLine(painter, painter.transform.height - (padding.top || 0), lineWidth, topColor);
	    drawHorizontalLine(painter, padding.bottom || 0, lineWidth, btmColor);
	    drawVerticalLine(painter, padding.left || 0, lineWidth, leftColor);
	    drawVerticalLine(painter, painter.transform.width - (padding.right || 0), lineWidth, rightColor);
	    const center = painter.transform.centerPoint;
	    drawCrosshair(painter, center.x, painter.transform.height - center.y, centerColor);
	}
	function drawCrosshair(painter, x, y, color) {
	    const size = 20;
	    const lineWidth = 2;
	    drawDebugSSRect(painter, x - lineWidth / 2, y - size / 2, lineWidth, size, color);
	    drawDebugSSRect(painter, x - size / 2, y - lineWidth / 2, size, lineWidth, color);
	}
	function drawHorizontalLine(painter, y, lineWidth, color) {
	    drawDebugSSRect(painter, 0, y + lineWidth / 2, painter.transform.width, lineWidth, color);
	}
	function drawVerticalLine(painter, x, lineWidth, color) {
	    drawDebugSSRect(painter, x - lineWidth / 2, 0, lineWidth, painter.transform.height, color);
	}
	function drawDebugSSRect(painter, x, y, width, height, color) {
	    const context = painter.context;
	    const gl = context.gl;
	    gl.enable(gl.SCISSOR_TEST);
	    gl.scissor(x * ref_properties.exported.devicePixelRatio, y * ref_properties.exported.devicePixelRatio, width * ref_properties.exported.devicePixelRatio, height * ref_properties.exported.devicePixelRatio);
	    context.clear({ color });
	    gl.disable(gl.SCISSOR_TEST);
	}
	function drawDebug(painter, sourceCache, coords) {
	    for (let i = 0; i < coords.length; i++) {
	        drawDebugTile(painter, sourceCache, coords[i]);
	    }
	}
	function drawDebugTile(painter, sourceCache, coord) {
	    const context = painter.context;
	    const gl = context.gl;
	    const isGlobeProjection = painter.transform.projection.name === 'globe';
	    const definesValues = isGlobeProjection ? ['PROJECTION_GLOBE_VIEW'] : null;
	    const posMatrix = coord.projMatrix;
	    const program = painter.useProgram('debug', null, definesValues);
	    const tile = sourceCache.getTileByID(coord.key);
	    if (painter.terrain)
	        painter.terrain.setupElevationDraw(tile, program);
	    const depthMode = ref_properties.DepthMode.disabled;
	    const stencilMode = ref_properties.StencilMode.disabled;
	    const colorMode = painter.colorModeForRenderPass();
	    const id = '$debug';
	    context.activeTexture.set(gl.TEXTURE0);
	    painter.emptyTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	    if (isGlobeProjection) {
	        tile._makeGlobeTileDebugBuffers(painter.context, painter.transform.projection);
	    } else {
	        tile._makeDebugTileBoundsBuffers(painter.context, painter.transform.projection);
	    }
	    const debugBuffer = tile._tileDebugBuffer || painter.debugBuffer;
	    const debugIndexBuffer = tile._tileDebugIndexBuffer || painter.debugIndexBuffer;
	    const debugSegments = tile._tileDebugSegments || painter.debugSegments;
	    program.draw(context, gl.LINE_STRIP, depthMode, stencilMode, colorMode, ref_properties.CullFaceMode.disabled, debugUniformValues(posMatrix, ref_properties.Color.red), id, debugBuffer, debugIndexBuffer, debugSegments, null, null, null, tile._globeTileDebugBorderBuffer);
	    const tileRawData = tile.latestRawTileData;
	    const tileByteLength = tileRawData && tileRawData.byteLength || 0;
	    const tileSizeKb = Math.floor(tileByteLength / 1024);
	    const tileSize = sourceCache.getTile(coord).tileSize;
	    const scaleRatio = 512 / Math.min(tileSize, 512) * (coord.overscaledZ / painter.transform.zoom) * 0.5;
	    let tileIdText = coord.canonical.toString();
	    if (coord.overscaledZ !== coord.canonical.z) {
	        tileIdText += ` => ${ coord.overscaledZ }`;
	    }
	    const tileLabel = `${ tileIdText } ${ tileSizeKb }kb`;
	    drawTextToOverlay(painter, tileLabel);
	    const debugTextBuffer = tile._tileDebugTextBuffer || painter.debugBuffer;
	    const debugTextIndexBuffer = tile._tileDebugTextIndexBuffer || painter.quadTriangleIndexBuffer;
	    const debugTextSegments = tile._tileDebugTextSegments || painter.debugSegments;
	    program.draw(context, gl.TRIANGLES, depthMode, stencilMode, ref_properties.ColorMode.alphaBlended, ref_properties.CullFaceMode.disabled, debugUniformValues(posMatrix, ref_properties.Color.transparent, scaleRatio), id, debugTextBuffer, debugTextIndexBuffer, debugTextSegments, null, null, null, tile._globeTileDebugTextBuffer);
	}
	function drawTextToOverlay(painter, text) {
	    painter.initDebugOverlayCanvas();
	    const canvas = painter.debugOverlayCanvas;
	    const gl = painter.context.gl;
	    const ctx2d = painter.debugOverlayCanvas.getContext('2d');
	    ctx2d.clearRect(0, 0, canvas.width, canvas.height);
	    ctx2d.shadowColor = 'white';
	    ctx2d.shadowBlur = 2;
	    ctx2d.lineWidth = 1.5;
	    ctx2d.strokeStyle = 'white';
	    ctx2d.textBaseline = 'top';
	    ctx2d.font = `bold ${ 36 }px Open Sans, sans-serif`;
	    ctx2d.fillText(text, 5, 5);
	    ctx2d.strokeText(text, 5, 5);
	    painter.debugOverlayTexture.update(canvas);
	    painter.debugOverlayTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	}

	function drawCustom(painter, sourceCache, layer) {
	    const context = painter.context;
	    const implementation = layer.implementation;
	    if (painter.transform.projection.unsupportedLayers && painter.transform.projection.unsupportedLayers.includes('custom')) {
	        ref_properties.warnOnce('Custom layers are not yet supported with non-mercator projections. Use mercator to enable custom layers.');
	        return;
	    }
	    if (painter.renderPass === 'offscreen') {
	        const prerender = implementation.prerender;
	        if (prerender) {
	            painter.setCustomLayerDefaults();
	            context.setColorMode(painter.colorModeForRenderPass());
	            prerender.call(implementation, context.gl, painter.transform.customLayerMatrix());
	            context.setDirty();
	            painter.setBaseState();
	        }
	    } else if (painter.renderPass === 'translucent') {
	        painter.setCustomLayerDefaults();
	        context.setColorMode(painter.colorModeForRenderPass());
	        context.setStencilMode(ref_properties.StencilMode.disabled);
	        const depthMode = implementation.renderingMode === '3d' ? new ref_properties.DepthMode(painter.context.gl.LEQUAL, ref_properties.DepthMode.ReadWrite, painter.depthRangeFor3D) : painter.depthModeForSublayer(0, ref_properties.DepthMode.ReadOnly);
	        context.setDepthMode(depthMode);
	        implementation.render(context.gl, painter.transform.customLayerMatrix());
	        context.setDirty();
	        painter.setBaseState();
	        context.bindFramebuffer.set(null);
	    }
	}

	const skyboxAttributes = ref_properties.createLayout([{
	        name: 'a_pos_3f',
	        components: 3,
	        type: 'Float32'
	    }]);
	const {members, size, alignment} = skyboxAttributes;

	function addVertex(vertexArray, x, y, z) {
	    vertexArray.emplaceBack(x, y, z);
	}
	class SkyboxGeometry {
	    constructor(context) {
	        this.vertexArray = new ref_properties.StructArrayLayout3f12();
	        this.indices = new ref_properties.StructArrayLayout3ui6();
	        addVertex(this.vertexArray, -1, -1, 1);
	        addVertex(this.vertexArray, 1, -1, 1);
	        addVertex(this.vertexArray, -1, 1, 1);
	        addVertex(this.vertexArray, 1, 1, 1);
	        addVertex(this.vertexArray, -1, -1, -1);
	        addVertex(this.vertexArray, 1, -1, -1);
	        addVertex(this.vertexArray, -1, 1, -1);
	        addVertex(this.vertexArray, 1, 1, -1);
	        this.indices.emplaceBack(5, 1, 3);
	        this.indices.emplaceBack(3, 7, 5);
	        this.indices.emplaceBack(6, 2, 0);
	        this.indices.emplaceBack(0, 4, 6);
	        this.indices.emplaceBack(2, 6, 7);
	        this.indices.emplaceBack(7, 3, 2);
	        this.indices.emplaceBack(5, 4, 0);
	        this.indices.emplaceBack(0, 1, 5);
	        this.indices.emplaceBack(0, 2, 3);
	        this.indices.emplaceBack(3, 1, 0);
	        this.indices.emplaceBack(7, 6, 4);
	        this.indices.emplaceBack(4, 5, 7);
	        this.vertexBuffer = context.createVertexBuffer(this.vertexArray, members);
	        this.indexBuffer = context.createIndexBuffer(this.indices);
	        this.segment = ref_properties.SegmentVector.simpleSegment(0, 0, 36, 12);
	    }
	}

	const TRANSITION_OPACITY_ZOOM_START = 7;
	const TRANSITION_OPACITY_ZOOM_END = 8;
	function drawSky(painter, sourceCache, layer) {
	    const tr = painter.transform;
	    const globeOrMercator = tr.projection.name === 'mercator' || tr.projection.name === 'globe';
	    const transitionOpacity = globeOrMercator ? 1 : ref_properties.smoothstep(TRANSITION_OPACITY_ZOOM_START, TRANSITION_OPACITY_ZOOM_END, tr.zoom);
	    const opacity = layer.paint.get('sky-opacity') * transitionOpacity;
	    if (opacity === 0) {
	        return;
	    }
	    const context = painter.context;
	    const type = layer.paint.get('sky-type');
	    const depthMode = new ref_properties.DepthMode(context.gl.LEQUAL, ref_properties.DepthMode.ReadOnly, [
	        0,
	        1
	    ]);
	    const temporalOffset = painter.frameCounter / 1000 % 1;
	    if (type === 'atmosphere') {
	        if (painter.renderPass === 'offscreen') {
	            if (layer.needsSkyboxCapture(painter)) {
	                captureSkybox(painter, layer, 32, 32);
	                layer.markSkyboxValid(painter);
	            }
	        } else if (painter.renderPass === 'sky') {
	            drawSkyboxFromCapture(painter, layer, depthMode, opacity, temporalOffset);
	        }
	    } else if (type === 'gradient') {
	        if (painter.renderPass === 'sky') {
	            drawSkyboxGradient(painter, layer, depthMode, opacity, temporalOffset);
	        }
	    } else ;
	}
	function drawSkyboxGradient(painter, layer, depthMode, opacity, temporalOffset) {
	    const context = painter.context;
	    const gl = context.gl;
	    const transform = painter.transform;
	    const program = painter.useProgram('skyboxGradient');
	    if (!layer.skyboxGeometry) {
	        layer.skyboxGeometry = new SkyboxGeometry(context);
	    }
	    context.activeTexture.set(gl.TEXTURE0);
	    let colorRampTexture = layer.colorRampTexture;
	    if (!colorRampTexture) {
	        colorRampTexture = layer.colorRampTexture = new ref_properties.Texture(context, layer.colorRamp, gl.RGBA);
	    }
	    colorRampTexture.bind(gl.LINEAR, gl.CLAMP_TO_EDGE);
	    const uniformValues = skyboxGradientUniformValues(transform.skyboxMatrix, layer.getCenter(painter, false), layer.paint.get('sky-gradient-radius'), opacity, temporalOffset);
	    painter.prepareDrawProgram(context, program);
	    program.draw(context, gl.TRIANGLES, depthMode, ref_properties.StencilMode.disabled, painter.colorModeForRenderPass(), ref_properties.CullFaceMode.backCW, uniformValues, 'skyboxGradient', layer.skyboxGeometry.vertexBuffer, layer.skyboxGeometry.indexBuffer, layer.skyboxGeometry.segment);
	}
	function drawSkyboxFromCapture(painter, layer, depthMode, opacity, temporalOffset) {
	    const context = painter.context;
	    const gl = context.gl;
	    const transform = painter.transform;
	    const program = painter.useProgram('skybox');
	    context.activeTexture.set(gl.TEXTURE0);
	    gl.bindTexture(gl.TEXTURE_CUBE_MAP, layer.skyboxTexture);
	    const uniformValues = skyboxUniformValues(transform.skyboxMatrix, layer.getCenter(painter, false), 0, opacity, temporalOffset);
	    painter.prepareDrawProgram(context, program);
	    program.draw(context, gl.TRIANGLES, depthMode, ref_properties.StencilMode.disabled, painter.colorModeForRenderPass(), ref_properties.CullFaceMode.backCW, uniformValues, 'skybox', layer.skyboxGeometry.vertexBuffer, layer.skyboxGeometry.indexBuffer, layer.skyboxGeometry.segment);
	}
	function drawSkyboxFace(context, layer, program, faceRotate, sunDirection, i) {
	    const gl = context.gl;
	    const atmosphereColor = layer.paint.get('sky-atmosphere-color');
	    const atmosphereHaloColor = layer.paint.get('sky-atmosphere-halo-color');
	    const sunIntensity = layer.paint.get('sky-atmosphere-sun-intensity');
	    const uniformValues = skyboxCaptureUniformValues(ref_properties.fromMat4(ref_properties.create$1(), faceRotate), sunDirection, sunIntensity, atmosphereColor, atmosphereHaloColor);
	    const glFace = gl.TEXTURE_CUBE_MAP_POSITIVE_X + i;
	    gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, glFace, layer.skyboxTexture, 0);
	    program.draw(context, gl.TRIANGLES, ref_properties.DepthMode.disabled, ref_properties.StencilMode.disabled, ref_properties.ColorMode.unblended, ref_properties.CullFaceMode.frontCW, uniformValues, 'skyboxCapture', layer.skyboxGeometry.vertexBuffer, layer.skyboxGeometry.indexBuffer, layer.skyboxGeometry.segment);
	}
	function captureSkybox(painter, layer, width, height) {
	    const context = painter.context;
	    const gl = context.gl;
	    let fbo = layer.skyboxFbo;
	    if (!fbo) {
	        fbo = layer.skyboxFbo = context.createFramebuffer(width, height, false);
	        layer.skyboxGeometry = new SkyboxGeometry(context);
	        layer.skyboxTexture = context.gl.createTexture();
	        gl.bindTexture(gl.TEXTURE_CUBE_MAP, layer.skyboxTexture);
	        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
	        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
	        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
	        gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
	        for (let i = 0; i < 6; ++i) {
	            const glFace = gl.TEXTURE_CUBE_MAP_POSITIVE_X + i;
	            gl.texImage2D(glFace, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
	        }
	    }
	    context.bindFramebuffer.set(fbo.framebuffer);
	    context.viewport.set([
	        0,
	        0,
	        width,
	        height
	    ]);
	    const sunDirection = layer.getCenter(painter, true);
	    const program = painter.useProgram('skyboxCapture');
	    const faceRotate = new Float64Array(16);
	    ref_properties.identity(faceRotate);
	    ref_properties.rotateY(faceRotate, faceRotate, -Math.PI * 0.5);
	    drawSkyboxFace(context, layer, program, faceRotate, sunDirection, 0);
	    ref_properties.identity(faceRotate);
	    ref_properties.rotateY(faceRotate, faceRotate, Math.PI * 0.5);
	    drawSkyboxFace(context, layer, program, faceRotate, sunDirection, 1);
	    ref_properties.identity(faceRotate);
	    ref_properties.rotateX(faceRotate, faceRotate, -Math.PI * 0.5);
	    drawSkyboxFace(context, layer, program, faceRotate, sunDirection, 2);
	    ref_properties.identity(faceRotate);
	    ref_properties.rotateX(faceRotate, faceRotate, Math.PI * 0.5);
	    drawSkyboxFace(context, layer, program, faceRotate, sunDirection, 3);
	    ref_properties.identity(faceRotate);
	    drawSkyboxFace(context, layer, program, faceRotate, sunDirection, 4);
	    ref_properties.identity(faceRotate);
	    ref_properties.rotateY(faceRotate, faceRotate, Math.PI);
	    drawSkyboxFace(context, layer, program, faceRotate, sunDirection, 5);
	    context.viewport.set([
	        0,
	        0,
	        painter.width,
	        painter.height
	    ]);
	}

	function drawAtmosphere(painter, fog) {
	    const context = painter.context;
	    const gl = context.gl;
	    const tr = painter.transform;
	    const depthMode = new ref_properties.DepthMode(gl.LEQUAL, ref_properties.DepthMode.ReadOnly, [
	        0,
	        1
	    ]);
	    const defines = tr.projection.name === 'globe' ? [
	        'PROJECTION_GLOBE_VIEW',
	        'FOG'
	    ] : ['FOG'];
	    const program = painter.useProgram('globeAtmosphere', null, defines);
	    const transitionT = ref_properties.globeToMercatorTransition(tr.zoom);
	    const fogColor = fog.properties.get('color').toArray01();
	    const highColor = fog.properties.get('high-color').toArray01();
	    const spaceColor = fog.properties.get('space-color').toArray01PremultipliedAlpha();
	    const orientation = ref_properties.identity$1([]);
	    ref_properties.rotateY$1(orientation, orientation, -ref_properties.degToRad(tr._center.lng));
	    ref_properties.rotateX$1(orientation, orientation, ref_properties.degToRad(tr._center.lat));
	    ref_properties.rotateZ$1(orientation, orientation, tr.angle);
	    ref_properties.rotateX$1(orientation, orientation, -tr._pitch);
	    const rotationMatrix = ref_properties.fromQuat(new Float32Array(16), orientation);
	    const starIntensity = ref_properties.mapValue(fog.properties.get('star-intensity'), 0, 1, 0, 0.25);
	    const minHorizonBlend = 0.0005;
	    const horizonBlend = ref_properties.mapValue(fog.properties.get('horizon-blend'), 0, 1, minHorizonBlend, 0.25);
	    const globeRadius = ref_properties.globeUseCustomAntiAliasing(painter, context, tr) && horizonBlend === minHorizonBlend ? tr.worldSize / (2 * Math.PI * 1.025) - 1 : tr.globeRadius;
	    const temporalOffset = painter.frameCounter / 1000 % 1;
	    const globeCenterInViewSpace = tr.globeCenterInViewSpace;
	    const globeCenterDistance = ref_properties.length(globeCenterInViewSpace);
	    const distanceToHorizon = Math.sqrt(Math.pow(globeCenterDistance, 2) - Math.pow(globeRadius, 2));
	    const horizonAngle = Math.acos(distanceToHorizon / globeCenterDistance);
	    const uniforms = atmosphereUniformValues(tr.frustumCorners.TL, tr.frustumCorners.TR, tr.frustumCorners.BR, tr.frustumCorners.BL, tr.frustumCorners.horizon, transitionT, horizonBlend, fogColor, highColor, spaceColor, starIntensity, temporalOffset, horizonAngle, rotationMatrix);
	    painter.prepareDrawProgram(context, program);
	    const buffer = painter.atmosphereBuffer;
	    if (buffer) {
	        program.draw(context, gl.TRIANGLES, depthMode, ref_properties.StencilMode.disabled, ref_properties.ColorMode.alphaBlended, ref_properties.CullFaceMode.backCW, uniforms, 'skybox', buffer.vertexBuffer, buffer.indexBuffer, buffer.segments);
	    }
	}

	const atmosphereLayout = ref_properties.createLayout([
	    {
	        type: 'Float32',
	        name: 'a_pos',
	        components: 3
	    },
	    {
	        type: 'Float32',
	        name: 'a_uv',
	        components: 2
	    }
	]);

	class AtmosphereBuffer {
	    constructor(context) {
	        const vertices = new ref_properties.StructArrayLayout5f20();
	        vertices.emplaceBack(-1, 1, 1, 0, 0);
	        vertices.emplaceBack(1, 1, 1, 1, 0);
	        vertices.emplaceBack(1, -1, 1, 1, 1);
	        vertices.emplaceBack(-1, -1, 1, 0, 1);
	        const triangles = new ref_properties.StructArrayLayout3ui6();
	        triangles.emplaceBack(0, 1, 2);
	        triangles.emplaceBack(2, 3, 0);
	        this.vertexBuffer = context.createVertexBuffer(vertices, atmosphereLayout.members);
	        this.indexBuffer = context.createIndexBuffer(triangles);
	        this.segments = ref_properties.SegmentVector.simpleSegment(0, 0, 4, 2);
	    }
	    destroy() {
	        this.vertexBuffer.destroy();
	        this.indexBuffer.destroy();
	        this.segments.destroy();
	    }
	}

	const draw = {
	    symbol: drawSymbols,
	    circle: drawCircles,
	    heatmap: drawHeatmap,
	    line: drawLine,
	    fill: drawFill,
	    'fill-extrusion': draw$1,
	    hillshade: drawHillshade,
	    raster: drawRaster,
	    background: drawBackground,
	    sky: drawSky,
	    debug: drawDebug,
	    custom: drawCustom
	};
	class Painter {
	    constructor(gl, transform) {
	        this.context = new Context(gl);
	        this.transform = transform;
	        this._tileTextures = {};
	        this.frameCopies = [];
	        this.loadTimeStamps = [];
	        this.setup();
	        this.numSublayers = ref_properties.SourceCache.maxUnderzooming + ref_properties.SourceCache.maxOverzooming + 1;
	        this.depthEpsilon = 1 / Math.pow(2, 16);
	        this.crossTileSymbolIndex = new CrossTileSymbolIndex();
	        this.deferredRenderGpuTimeQueries = [];
	        this.gpuTimers = {};
	        this.frameCounter = 0;
	        this._backgroundTiles = {};
	    }
	    updateTerrain(style, cameraChanging) {
	        const enabled = !!style && !!style.terrain && this.transform.projection.supportsTerrain;
	        if (!enabled && (!this._terrain || !this._terrain.enabled))
	            return;
	        if (!this._terrain) {
	            this._terrain = new Terrain(this, style);
	        }
	        const terrain = this._terrain;
	        this.transform.elevation = enabled ? terrain : null;
	        terrain.update(style, this.transform, cameraChanging);
	    }
	    _updateFog(style) {
	        const isGlobe = this.transform.projection.name === 'globe';
	        const fog = style.fog;
	        if (!fog || isGlobe || fog.getOpacity(this.transform.pitch) < 1 || fog.properties.get('horizon-blend') < 0.03) {
	            this.transform.fogCullDistSq = null;
	            return;
	        }
	        const [start, end] = fog.getFovAdjustedRange(this.transform._fov);
	        if (start > end) {
	            this.transform.fogCullDistSq = null;
	            return;
	        }
	        const fogBoundFraction = 0.78;
	        const fogCullDist = start + (end - start) * fogBoundFraction;
	        this.transform.fogCullDistSq = fogCullDist * fogCullDist;
	    }
	    get terrain() {
	        return this.transform._terrainEnabled() && this._terrain && this._terrain.enabled ? this._terrain : null;
	    }
	    resize(width, height) {
	        this.width = width * ref_properties.exported.devicePixelRatio;
	        this.height = height * ref_properties.exported.devicePixelRatio;
	        this.context.viewport.set([
	            0,
	            0,
	            this.width,
	            this.height
	        ]);
	        if (this.style) {
	            for (const layerId of this.style.order) {
	                this.style._layers[layerId].resize();
	            }
	        }
	    }
	    setup() {
	        const context = this.context;
	        const tileExtentArray = new ref_properties.StructArrayLayout2i4();
	        tileExtentArray.emplaceBack(0, 0);
	        tileExtentArray.emplaceBack(ref_properties.EXTENT, 0);
	        tileExtentArray.emplaceBack(0, ref_properties.EXTENT);
	        tileExtentArray.emplaceBack(ref_properties.EXTENT, ref_properties.EXTENT);
	        this.tileExtentBuffer = context.createVertexBuffer(tileExtentArray, ref_properties.posAttributes.members);
	        this.tileExtentSegments = ref_properties.SegmentVector.simpleSegment(0, 0, 4, 2);
	        const debugArray = new ref_properties.StructArrayLayout2i4();
	        debugArray.emplaceBack(0, 0);
	        debugArray.emplaceBack(ref_properties.EXTENT, 0);
	        debugArray.emplaceBack(0, ref_properties.EXTENT);
	        debugArray.emplaceBack(ref_properties.EXTENT, ref_properties.EXTENT);
	        this.debugBuffer = context.createVertexBuffer(debugArray, ref_properties.posAttributes.members);
	        this.debugSegments = ref_properties.SegmentVector.simpleSegment(0, 0, 4, 5);
	        const viewportArray = new ref_properties.StructArrayLayout2i4();
	        viewportArray.emplaceBack(-1, -1);
	        viewportArray.emplaceBack(1, -1);
	        viewportArray.emplaceBack(-1, 1);
	        viewportArray.emplaceBack(1, 1);
	        this.viewportBuffer = context.createVertexBuffer(viewportArray, ref_properties.posAttributes.members);
	        this.viewportSegments = ref_properties.SegmentVector.simpleSegment(0, 0, 4, 2);
	        const tileBoundsArray = new ref_properties.StructArrayLayout4i8();
	        tileBoundsArray.emplaceBack(0, 0, 0, 0);
	        tileBoundsArray.emplaceBack(ref_properties.EXTENT, 0, ref_properties.EXTENT, 0);
	        tileBoundsArray.emplaceBack(0, ref_properties.EXTENT, 0, ref_properties.EXTENT);
	        tileBoundsArray.emplaceBack(ref_properties.EXTENT, ref_properties.EXTENT, ref_properties.EXTENT, ref_properties.EXTENT);
	        this.mercatorBoundsBuffer = context.createVertexBuffer(tileBoundsArray, ref_properties.boundsAttributes.members);
	        this.mercatorBoundsSegments = ref_properties.SegmentVector.simpleSegment(0, 0, 4, 2);
	        const quadTriangleIndices = new ref_properties.StructArrayLayout3ui6();
	        quadTriangleIndices.emplaceBack(0, 1, 2);
	        quadTriangleIndices.emplaceBack(2, 1, 3);
	        this.quadTriangleIndexBuffer = context.createIndexBuffer(quadTriangleIndices);
	        const tileLineStripIndices = new ref_properties.StructArrayLayout1ui2();
	        for (const i of [
	                0,
	                1,
	                3,
	                2,
	                0
	            ])
	            tileLineStripIndices.emplaceBack(i);
	        this.debugIndexBuffer = context.createIndexBuffer(tileLineStripIndices);
	        this.emptyTexture = new ref_properties.Texture(context, new ref_properties.RGBAImage({
	            width: 1,
	            height: 1
	        }, Uint8Array.of(0, 0, 0, 0)), context.gl.RGBA);
	        this.identityMat = ref_properties.create();
	        const gl = this.context.gl;
	        this.stencilClearMode = new ref_properties.StencilMode({
	            func: gl.ALWAYS,
	            mask: 0
	        }, 0, 255, gl.ZERO, gl.ZERO, gl.ZERO);
	        this.loadTimeStamps.push(ref_properties.window.performance.now());
	        this.atmosphereBuffer = new AtmosphereBuffer(this.context);
	    }
	    getMercatorTileBoundsBuffers() {
	        return {
	            tileBoundsBuffer: this.mercatorBoundsBuffer,
	            tileBoundsIndexBuffer: this.quadTriangleIndexBuffer,
	            tileBoundsSegments: this.mercatorBoundsSegments
	        };
	    }
	    getTileBoundsBuffers(tile) {
	        tile._makeTileBoundsBuffers(this.context, this.transform.projection);
	        if (tile._tileBoundsBuffer) {
	            const tileBoundsBuffer = tile._tileBoundsBuffer;
	            const tileBoundsIndexBuffer = tile._tileBoundsIndexBuffer;
	            const tileBoundsSegments = tile._tileBoundsSegments;
	            return {
	                tileBoundsBuffer,
	                tileBoundsIndexBuffer,
	                tileBoundsSegments
	            };
	        } else {
	            return this.getMercatorTileBoundsBuffers();
	        }
	    }
	    clearStencil() {
	        const context = this.context;
	        const gl = context.gl;
	        this.nextStencilID = 1;
	        this.currentStencilSource = undefined;
	        this._tileClippingMaskIDs = {};
	        this.useProgram('clippingMask').draw(context, gl.TRIANGLES, ref_properties.DepthMode.disabled, this.stencilClearMode, ref_properties.ColorMode.disabled, ref_properties.CullFaceMode.disabled, clippingMaskUniformValues(this.identityMat), '$clipping', this.viewportBuffer, this.quadTriangleIndexBuffer, this.viewportSegments);
	    }
	    resetStencilClippingMasks() {
	        if (!this.terrain) {
	            this.currentStencilSource = undefined;
	            this._tileClippingMaskIDs = {};
	        }
	    }
	    _renderTileClippingMasks(layer, sourceCache, tileIDs) {
	        if (!sourceCache || this.currentStencilSource === sourceCache.id || !layer.isTileClipped() || !tileIDs || tileIDs.length === 0) {
	            return;
	        }
	        if (this._tileClippingMaskIDs && !this.terrain) {
	            let dirtyStencilClippingMasks = false;
	            for (const coord of tileIDs) {
	                if (this._tileClippingMaskIDs[coord.key] === undefined) {
	                    dirtyStencilClippingMasks = true;
	                    break;
	                }
	            }
	            if (!dirtyStencilClippingMasks) {
	                return;
	            }
	        }
	        this.currentStencilSource = sourceCache.id;
	        const context = this.context;
	        const gl = context.gl;
	        if (this.nextStencilID + tileIDs.length > 256) {
	            this.clearStencil();
	        }
	        context.setColorMode(ref_properties.ColorMode.disabled);
	        context.setDepthMode(ref_properties.DepthMode.disabled);
	        const program = this.useProgram('clippingMask');
	        this._tileClippingMaskIDs = {};
	        for (const tileID of tileIDs) {
	            const tile = sourceCache.getTile(tileID);
	            const id = this._tileClippingMaskIDs[tileID.key] = this.nextStencilID++;
	            const {tileBoundsBuffer, tileBoundsIndexBuffer, tileBoundsSegments} = this.getTileBoundsBuffers(tile);
	            program.draw(context, gl.TRIANGLES, ref_properties.DepthMode.disabled, new ref_properties.StencilMode({
	                func: gl.ALWAYS,
	                mask: 0
	            }, id, 255, gl.KEEP, gl.KEEP, gl.REPLACE), ref_properties.ColorMode.disabled, ref_properties.CullFaceMode.disabled, clippingMaskUniformValues(tileID.projMatrix), '$clipping', tileBoundsBuffer, tileBoundsIndexBuffer, tileBoundsSegments);
	        }
	    }
	    stencilModeFor3D() {
	        this.currentStencilSource = undefined;
	        if (this.nextStencilID + 1 > 256) {
	            this.clearStencil();
	        }
	        const id = this.nextStencilID++;
	        const gl = this.context.gl;
	        return new ref_properties.StencilMode({
	            func: gl.NOTEQUAL,
	            mask: 255
	        }, id, 255, gl.KEEP, gl.KEEP, gl.REPLACE);
	    }
	    stencilModeForClipping(tileID) {
	        if (this.terrain)
	            return this.terrain.stencilModeForRTTOverlap(tileID);
	        const gl = this.context.gl;
	        return new ref_properties.StencilMode({
	            func: gl.EQUAL,
	            mask: 255
	        }, this._tileClippingMaskIDs[tileID.key], 0, gl.KEEP, gl.KEEP, gl.REPLACE);
	    }
	    stencilConfigForOverlap(tileIDs) {
	        const gl = this.context.gl;
	        const coords = tileIDs.sort((a, b) => b.overscaledZ - a.overscaledZ);
	        const minTileZ = coords[coords.length - 1].overscaledZ;
	        const stencilValues = coords[0].overscaledZ - minTileZ + 1;
	        if (stencilValues > 1) {
	            this.currentStencilSource = undefined;
	            if (this.nextStencilID + stencilValues > 256) {
	                this.clearStencil();
	            }
	            const zToStencilMode = {};
	            for (let i = 0; i < stencilValues; i++) {
	                zToStencilMode[i + minTileZ] = new ref_properties.StencilMode({
	                    func: gl.GEQUAL,
	                    mask: 255
	                }, i + this.nextStencilID, 255, gl.KEEP, gl.KEEP, gl.REPLACE);
	            }
	            this.nextStencilID += stencilValues;
	            return [
	                zToStencilMode,
	                coords
	            ];
	        }
	        return [
	            { [minTileZ]: ref_properties.StencilMode.disabled },
	            coords
	        ];
	    }
	    colorModeForRenderPass() {
	        const gl = this.context.gl;
	        if (this._showOverdrawInspector) {
	            const numOverdrawSteps = 8;
	            const a = 1 / numOverdrawSteps;
	            return new ref_properties.ColorMode([
	                gl.CONSTANT_COLOR,
	                gl.ONE
	            ], new ref_properties.Color(a, a, a, 0), [
	                true,
	                true,
	                true,
	                true
	            ]);
	        } else if (this.renderPass === 'opaque') {
	            return ref_properties.ColorMode.unblended;
	        } else {
	            return ref_properties.ColorMode.alphaBlended;
	        }
	    }
	    depthModeForSublayer(n, mask, func) {
	        if (!this.opaquePassEnabledForLayer())
	            return ref_properties.DepthMode.disabled;
	        const depth = 1 - ((1 + this.currentLayer) * this.numSublayers + n) * this.depthEpsilon;
	        return new ref_properties.DepthMode(func || this.context.gl.LEQUAL, mask, [
	            depth,
	            depth
	        ]);
	    }
	    opaquePassEnabledForLayer() {
	        return this.currentLayer < this.opaquePassCutoff;
	    }
	    render(style, options) {
	        this.style = style;
	        this.options = options;
	        this.lineAtlas = style.lineAtlas;
	        this.imageManager = style.imageManager;
	        this.glyphManager = style.glyphManager;
	        this.symbolFadeChange = style.placement.symbolFadeChange(ref_properties.exported.now());
	        this.imageManager.beginFrame();
	        const layerIds = this.style.order;
	        const sourceCaches = this.style._sourceCaches;
	        for (const id in sourceCaches) {
	            const sourceCache = sourceCaches[id];
	            if (sourceCache.used) {
	                sourceCache.prepare(this.context);
	            }
	        }
	        const coordsAscending = {};
	        const coordsDescending = {};
	        const coordsDescendingSymbol = {};
	        for (const id in sourceCaches) {
	            const sourceCache = sourceCaches[id];
	            coordsAscending[id] = sourceCache.getVisibleCoordinates();
	            coordsDescending[id] = coordsAscending[id].slice().reverse();
	            coordsDescendingSymbol[id] = sourceCache.getVisibleCoordinates(true).reverse();
	        }
	        this.opaquePassCutoff = Infinity;
	        for (let i = 0; i < layerIds.length; i++) {
	            const layerId = layerIds[i];
	            if (this.style._layers[layerId].is3D()) {
	                this.opaquePassCutoff = i;
	                break;
	            }
	        }
	        if (this.terrain) {
	            this.terrain.updateTileBinding(coordsDescendingSymbol);
	            this.opaquePassCutoff = 0;
	        }
	        if (this.transform.projection.name === 'globe' && !this.globeSharedBuffers) {
	            this.globeSharedBuffers = new ref_properties.GlobeSharedBuffers(this.context);
	        }
	        if (!ref_properties.isMapAuthenticated(this.context.gl))
	            return;
	        this.renderPass = 'offscreen';
	        for (const layerId of layerIds) {
	            const layer = this.style._layers[layerId];
	            const sourceCache = style._getLayerSourceCache(layer);
	            if (!layer.hasOffscreenPass() || layer.isHidden(this.transform.zoom))
	                continue;
	            const coords = sourceCache ? coordsDescending[sourceCache.id] : undefined;
	            if (!(layer.type === 'custom' || layer.isSky()) && !(coords && coords.length))
	                continue;
	            this.renderLayer(this, sourceCache, layer, coords);
	        }
	        this.depthRangeFor3D = [
	            0,
	            1 - (style.order.length + 2) * this.numSublayers * this.depthEpsilon
	        ];
	        if (this.terrain && (this.style.hasSymbolLayers() || this.style.hasCircleLayers())) {
	            this.terrain.drawDepth();
	        }
	        this.context.bindFramebuffer.set(null);
	        this.context.viewport.set([
	            0,
	            0,
	            this.width,
	            this.height
	        ]);
	        this.context.clear({
	            color: options.showOverdrawInspector ? ref_properties.Color.black : ref_properties.Color.transparent,
	            depth: 1
	        });
	        this.clearStencil();
	        this._showOverdrawInspector = options.showOverdrawInspector;
	        this.renderPass = 'opaque';
	        if (!this.terrain) {
	            for (this.currentLayer = layerIds.length - 1; this.currentLayer >= 0; this.currentLayer--) {
	                const layer = this.style._layers[layerIds[this.currentLayer]];
	                const sourceCache = style._getLayerSourceCache(layer);
	                if (layer.isSky())
	                    continue;
	                const coords = sourceCache ? coordsDescending[sourceCache.id] : undefined;
	                this._renderTileClippingMasks(layer, sourceCache, coords);
	                this.renderLayer(this, sourceCache, layer, coords);
	            }
	        }
	        if (this.style.fog && this.transform.projection.supportsFog) {
	            drawAtmosphere(this, this.style.fog);
	        }
	        this.renderPass = 'sky';
	        const isTransitioning = ref_properties.globeToMercatorTransition(this.transform.zoom) > 0;
	        if ((isTransitioning || this.transform.projection.name !== 'globe') && this.transform.isHorizonVisible()) {
	            for (this.currentLayer = 0; this.currentLayer < layerIds.length; this.currentLayer++) {
	                const layer = this.style._layers[layerIds[this.currentLayer]];
	                const sourceCache = style._getLayerSourceCache(layer);
	                if (!layer.isSky())
	                    continue;
	                const coords = sourceCache ? coordsDescending[sourceCache.id] : undefined;
	                this.renderLayer(this, sourceCache, layer, coords);
	            }
	        }
	        this.renderPass = 'translucent';
	        this.currentLayer = 0;
	        while (this.currentLayer < layerIds.length) {
	            const layer = this.style._layers[layerIds[this.currentLayer]];
	            const sourceCache = style._getLayerSourceCache(layer);
	            if (layer.isSky()) {
	                ++this.currentLayer;
	                continue;
	            }
	            if (this.terrain && this.style.isLayerDraped(layer)) {
	                if (layer.isHidden(this.transform.zoom)) {
	                    ++this.currentLayer;
	                    continue;
	                }
	                const terrain = this.terrain;
	                this.currentLayer;
	                this.currentLayer = terrain.renderBatch(this.currentLayer);
	                continue;
	            }
	            const coords = sourceCache ? (layer.type === 'symbol' ? coordsDescendingSymbol : coordsDescending)[sourceCache.id] : undefined;
	            this._renderTileClippingMasks(layer, sourceCache, sourceCache ? coordsAscending[sourceCache.id] : undefined);
	            this.renderLayer(this, sourceCache, layer, coords);
	            ++this.currentLayer;
	        }
	        if (this.terrain) {
	            this.terrain.postRender();
	        }
	        if (this.options.showTileBoundaries || this.options.showQueryGeometry) {
	            let selectedSource = null;
	            const layers = ref_properties.values(this.style._layers);
	            layers.forEach(layer => {
	                const sourceCache = style._getLayerSourceCache(layer);
	                if (sourceCache && !layer.isHidden(this.transform.zoom)) {
	                    if (!selectedSource || selectedSource.getSource().maxzoom < sourceCache.getSource().maxzoom) {
	                        selectedSource = sourceCache;
	                    }
	                }
	            });
	            if (selectedSource) {
	                if (this.options.showTileBoundaries) {
	                    draw.debug(this, selectedSource, selectedSource.getVisibleCoordinates());
	                }
	            }
	        }
	        if (this.options.showPadding) {
	            drawDebugPadding(this);
	        }
	        this.context.setDefault();
	        this.frameCounter = (this.frameCounter + 1) % Number.MAX_SAFE_INTEGER;
	        if (this.tileLoaded && this.options.speedIndexTiming) {
	            this.loadTimeStamps.push(ref_properties.window.performance.now());
	            this.saveCanvasCopy();
	        }
	    }
	    renderLayer(painter, sourceCache, layer, coords) {
	        if (layer.isHidden(this.transform.zoom))
	            return;
	        if (layer.type !== 'background' && layer.type !== 'sky' && layer.type !== 'custom' && !(coords && coords.length))
	            return;
	        this.id = layer.id;
	        this.gpuTimingStart(layer);
	        if (!painter.transform.projection.unsupportedLayers || !painter.transform.projection.unsupportedLayers.includes(layer.type)) {
	            draw[layer.type](painter, sourceCache, layer, coords, this.style.placement.variableOffsets, this.options.isInitialLoad);
	        }
	        this.gpuTimingEnd();
	    }
	    gpuTimingStart(layer) {
	        if (!this.options.gpuTiming)
	            return;
	        const ext = this.context.extTimerQuery;
	        let layerTimer = this.gpuTimers[layer.id];
	        if (!layerTimer) {
	            layerTimer = this.gpuTimers[layer.id] = {
	                calls: 0,
	                cpuTime: 0,
	                query: ext.createQueryEXT()
	            };
	        }
	        layerTimer.calls++;
	        ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, layerTimer.query);
	    }
	    gpuTimingDeferredRenderStart() {
	        if (this.options.gpuTimingDeferredRender) {
	            const ext = this.context.extTimerQuery;
	            const query = ext.createQueryEXT();
	            this.deferredRenderGpuTimeQueries.push(query);
	            ext.beginQueryEXT(ext.TIME_ELAPSED_EXT, query);
	        }
	    }
	    gpuTimingDeferredRenderEnd() {
	        if (!this.options.gpuTimingDeferredRender)
	            return;
	        const ext = this.context.extTimerQuery;
	        ext.endQueryEXT(ext.TIME_ELAPSED_EXT);
	    }
	    gpuTimingEnd() {
	        if (!this.options.gpuTiming)
	            return;
	        const ext = this.context.extTimerQuery;
	        ext.endQueryEXT(ext.TIME_ELAPSED_EXT);
	    }
	    collectGpuTimers() {
	        const currentLayerTimers = this.gpuTimers;
	        this.gpuTimers = {};
	        return currentLayerTimers;
	    }
	    collectDeferredRenderGpuQueries() {
	        const currentQueries = this.deferredRenderGpuTimeQueries;
	        this.deferredRenderGpuTimeQueries = [];
	        return currentQueries;
	    }
	    queryGpuTimers(gpuTimers) {
	        const layers = {};
	        for (const layerId in gpuTimers) {
	            const gpuTimer = gpuTimers[layerId];
	            const ext = this.context.extTimerQuery;
	            const gpuTime = ext.getQueryObjectEXT(gpuTimer.query, ext.QUERY_RESULT_EXT) / (1000 * 1000);
	            ext.deleteQueryEXT(gpuTimer.query);
	            layers[layerId] = gpuTime;
	        }
	        return layers;
	    }
	    queryGpuTimeDeferredRender(gpuQueries) {
	        if (!this.options.gpuTimingDeferredRender)
	            return 0;
	        const ext = this.context.extTimerQuery;
	        let gpuTime = 0;
	        for (const query of gpuQueries) {
	            gpuTime += ext.getQueryObjectEXT(query, ext.QUERY_RESULT_EXT) / (1000 * 1000);
	            ext.deleteQueryEXT(query);
	        }
	        return gpuTime;
	    }
	    translatePosMatrix(matrix, tile, translate, translateAnchor, inViewportPixelUnitsUnits) {
	        if (!translate[0] && !translate[1])
	            return matrix;
	        const angle = inViewportPixelUnitsUnits ? translateAnchor === 'map' ? this.transform.angle : 0 : translateAnchor === 'viewport' ? -this.transform.angle : 0;
	        if (angle) {
	            const sinA = Math.sin(angle);
	            const cosA = Math.cos(angle);
	            translate = [
	                translate[0] * cosA - translate[1] * sinA,
	                translate[0] * sinA + translate[1] * cosA
	            ];
	        }
	        const translation = [
	            inViewportPixelUnitsUnits ? translate[0] : pixelsToTileUnits(tile, translate[0], this.transform.zoom),
	            inViewportPixelUnitsUnits ? translate[1] : pixelsToTileUnits(tile, translate[1], this.transform.zoom),
	            0
	        ];
	        const translatedMatrix = new Float32Array(16);
	        ref_properties.translate(translatedMatrix, matrix, translation);
	        return translatedMatrix;
	    }
	    saveTileTexture(texture) {
	        const textures = this._tileTextures[texture.size[0]];
	        if (!textures) {
	            this._tileTextures[texture.size[0]] = [texture];
	        } else {
	            textures.push(texture);
	        }
	    }
	    getTileTexture(size) {
	        const textures = this._tileTextures[size];
	        return textures && textures.length > 0 ? textures.pop() : null;
	    }
	    isPatternMissing(image) {
	        if (!image)
	            return false;
	        if (!image.from || !image.to)
	            return true;
	        const imagePosA = this.imageManager.getPattern(image.from.toString());
	        const imagePosB = this.imageManager.getPattern(image.to.toString());
	        return !imagePosA || !imagePosB;
	    }
	    currentGlobalDefines() {
	        const terrain = this.terrain && !this.terrain.renderingToTexture;
	        const rtt = this.terrain && this.terrain.renderingToTexture;
	        const fog = this.style && this.style.fog;
	        const defines = [];
	        if (terrain)
	            defines.push('TERRAIN');
	        if (fog && !rtt && fog.getOpacity(this.transform.pitch) !== 0) {
	            defines.push('FOG');
	        }
	        if (rtt)
	            defines.push('RENDER_TO_TEXTURE');
	        if (this._showOverdrawInspector)
	            defines.push('OVERDRAW_INSPECTOR');
	        return defines;
	    }
	    useProgram(name, programConfiguration, fixedDefines) {
	        this.cache = this.cache || {};
	        const defines = fixedDefines || [];
	        const globalDefines = this.currentGlobalDefines();
	        const allDefines = globalDefines.concat(defines);
	        const key = Program.cacheKey(name, allDefines, programConfiguration);
	        if (!this.cache[key]) {
	            this.cache[key] = new Program(this.context, name, shaders[name], programConfiguration, programUniforms[name], allDefines);
	        }
	        return this.cache[key];
	    }
	    setCustomLayerDefaults() {
	        this.context.unbindVAO();
	        this.context.cullFace.setDefault();
	        this.context.frontFace.setDefault();
	        this.context.cullFaceSide.setDefault();
	        this.context.activeTexture.setDefault();
	        this.context.pixelStoreUnpack.setDefault();
	        this.context.pixelStoreUnpackPremultiplyAlpha.setDefault();
	        this.context.pixelStoreUnpackFlipY.setDefault();
	    }
	    setBaseState() {
	        const gl = this.context.gl;
	        this.context.cullFace.set(false);
	        this.context.viewport.set([
	            0,
	            0,
	            this.width,
	            this.height
	        ]);
	        this.context.blendEquation.set(gl.FUNC_ADD);
	    }
	    initDebugOverlayCanvas() {
	        if (this.debugOverlayCanvas == null) {
	            this.debugOverlayCanvas = ref_properties.window.document.createElement('canvas');
	            this.debugOverlayCanvas.width = 512;
	            this.debugOverlayCanvas.height = 512;
	            const gl = this.context.gl;
	            this.debugOverlayTexture = new ref_properties.Texture(this.context, this.debugOverlayCanvas, gl.RGBA);
	        }
	    }
	    destroy() {
	        if (this._terrain) {
	            this._terrain.destroy();
	        }
	        if (this.globeSharedBuffers) {
	            this.globeSharedBuffers.destroy();
	        }
	        this.emptyTexture.destroy();
	        if (this.debugOverlayTexture) {
	            this.debugOverlayTexture.destroy();
	        }
	        if (this.atmosphereBuffer) {
	            this.atmosphereBuffer.destroy();
	        }
	    }
	    prepareDrawTile() {
	        if (this.terrain) {
	            this.terrain.prepareDrawTile();
	        }
	    }
	    prepareDrawProgram(context, program, tileID) {
	        if (this.terrain && this.terrain.renderingToTexture) {
	            return;
	        }
	        const fog = this.style.fog;
	        if (fog) {
	            const fogOpacity = fog.getOpacity(this.transform.pitch);
	            const fogUniforms = fogUniformValues(this, fog, tileID, fogOpacity, this.transform.frustumCorners.TL, this.transform.frustumCorners.TR, this.transform.frustumCorners.BR, this.transform.frustumCorners.BL, this.transform.globeCenterInViewSpace, this.transform.globeRadius, [
	                this.transform.width * ref_properties.exported.devicePixelRatio,
	                this.transform.height * ref_properties.exported.devicePixelRatio
	            ]);
	            program.setFogUniformValues(context, fogUniforms);
	        }
	    }
	    setTileLoadedFlag(flag) {
	        this.tileLoaded = flag;
	    }
	    saveCanvasCopy() {
	        this.frameCopies.push(this.canvasCopy());
	        this.tileLoaded = false;
	    }
	    canvasCopy() {
	        const gl = this.context.gl;
	        const texture = gl.createTexture();
	        gl.bindTexture(gl.TEXTURE_2D, texture);
	        gl.copyTexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, 0);
	        return texture;
	    }
	    getCanvasCopiesAndTimestamps() {
	        return {
	            canvasCopies: this.frameCopies,
	            timeStamps: this.loadTimeStamps
	        };
	    }
	    averageElevationNeedsEasing() {
	        if (!this.transform._elevation)
	            return false;
	        const fog = this.style && this.style.fog;
	        if (!fog)
	            return false;
	        const fogOpacity = fog.getOpacity(this.transform.pitch);
	        if (fogOpacity === 0)
	            return false;
	        return true;
	    }
	    getBackgroundTiles() {
	        const oldTiles = this._backgroundTiles;
	        const newTiles = this._backgroundTiles = {};
	        const tileSize = 512;
	        const tileIDs = this.transform.coveringTiles({ tileSize });
	        for (const tileID of tileIDs) {
	            newTiles[tileID.key] = oldTiles[tileID.key] || new ref_properties.Tile(tileID, tileSize, this.transform.tileZoom, this);
	        }
	        return newTiles;
	    }
	    clearBackgroundTiles() {
	        this._backgroundTiles = {};
	    }
	}

	class EdgeInsets {
	    constructor(top = 0, bottom = 0, left = 0, right = 0) {
	        if (isNaN(top) || top < 0 || isNaN(bottom) || bottom < 0 || isNaN(left) || left < 0 || isNaN(right) || right < 0) {
	            throw new Error('Invalid value for edge-insets, top, bottom, left and right must all be numbers');
	        }
	        this.top = top;
	        this.bottom = bottom;
	        this.left = left;
	        this.right = right;
	    }
	    interpolate(start, target, t) {
	        if (target.top != null && start.top != null)
	            this.top = ref_properties.number(start.top, target.top, t);
	        if (target.bottom != null && start.bottom != null)
	            this.bottom = ref_properties.number(start.bottom, target.bottom, t);
	        if (target.left != null && start.left != null)
	            this.left = ref_properties.number(start.left, target.left, t);
	        if (target.right != null && start.right != null)
	            this.right = ref_properties.number(start.right, target.right, t);
	        return this;
	    }
	    getCenter(width, height) {
	        const x = ref_properties.clamp((this.left + width - this.right) / 2, 0, width);
	        const y = ref_properties.clamp((this.top + height - this.bottom) / 2, 0, height);
	        return new ref_properties.pointGeometry(x, y);
	    }
	    equals(other) {
	        return this.top === other.top && this.bottom === other.bottom && this.left === other.left && this.right === other.right;
	    }
	    clone() {
	        return new EdgeInsets(this.top, this.bottom, this.left, this.right);
	    }
	    toJSON() {
	        return {
	            top: this.top,
	            bottom: this.bottom,
	            left: this.left,
	            right: this.right
	        };
	    }
	}

	function updateTransformOrientation(matrix, orientation) {
	    const position = ref_properties.getColumn(matrix, 3);
	    ref_properties.fromQuat(matrix, orientation);
	    ref_properties.setColumn(matrix, 3, position);
	}
	function updateTransformPosition(matrix, position) {
	    ref_properties.setColumn(matrix, 3, [
	        position[0],
	        position[1],
	        position[2],
	        1
	    ]);
	}
	function orientationFromPitchBearing(pitch, bearing) {
	    const orientation = ref_properties.identity$1([]);
	    ref_properties.rotateZ$1(orientation, orientation, -bearing);
	    ref_properties.rotateX$1(orientation, orientation, -pitch);
	    return orientation;
	}
	function orientationFromFrame(forward, up) {
	    const xyForward = [
	        forward[0],
	        forward[1],
	        0
	    ];
	    const xyUp = [
	        up[0],
	        up[1],
	        0
	    ];
	    const epsilon = 1e-15;
	    if (ref_properties.length(xyForward) >= epsilon) {
	        const xyDir = ref_properties.normalize([], xyForward);
	        ref_properties.scale$2(xyUp, xyDir, ref_properties.dot(xyUp, xyDir));
	        up[0] = xyUp[0];
	        up[1] = xyUp[1];
	    }
	    const right = ref_properties.cross([], up, forward);
	    if (ref_properties.len(right) < epsilon) {
	        return null;
	    }
	    const bearing = Math.atan2(-right[1], right[0]);
	    const pitch = Math.atan2(Math.sqrt(forward[0] * forward[0] + forward[1] * forward[1]), -forward[2]);
	    return orientationFromPitchBearing(pitch, bearing);
	}
	class FreeCameraOptions {
	    constructor(position, orientation) {
	        this.position = position;
	        this.orientation = orientation;
	    }
	    get position() {
	        return this._position;
	    }
	    set position(position) {
	        if (!position) {
	            this._position = null;
	        } else {
	            const mercatorCoordinate = position instanceof ref_properties.MercatorCoordinate ? position : new ref_properties.MercatorCoordinate(position[0], position[1], position[2]);
	            if (this._renderWorldCopies) {
	                mercatorCoordinate.x = ref_properties.wrap(mercatorCoordinate.x, 0, 1);
	            }
	            this._position = mercatorCoordinate;
	        }
	    }
	    lookAtPoint(location, up) {
	        this.orientation = null;
	        if (!this.position) {
	            return;
	        }
	        const altitude = this._elevation ? this._elevation.getAtPointOrZero(ref_properties.MercatorCoordinate.fromLngLat(location)) : 0;
	        const pos = this.position;
	        const target = ref_properties.MercatorCoordinate.fromLngLat(location, altitude);
	        const forward = [
	            target.x - pos.x,
	            target.y - pos.y,
	            target.z - pos.z
	        ];
	        if (!up)
	            up = [
	                0,
	                0,
	                1
	            ];
	        up[2] = Math.abs(up[2]);
	        this.orientation = orientationFromFrame(forward, up);
	    }
	    setPitchBearing(pitch, bearing) {
	        this.orientation = orientationFromPitchBearing(ref_properties.degToRad(pitch), ref_properties.degToRad(-bearing));
	    }
	}
	class FreeCamera {
	    constructor(position, orientation) {
	        this._transform = ref_properties.identity([]);
	        this.orientation = orientation;
	        this.position = position;
	    }
	    get mercatorPosition() {
	        const pos = this.position;
	        return new ref_properties.MercatorCoordinate(pos[0], pos[1], pos[2]);
	    }
	    get position() {
	        const col = ref_properties.getColumn(this._transform, 3);
	        return [
	            col[0],
	            col[1],
	            col[2]
	        ];
	    }
	    set position(value) {
	        if (value) {
	            updateTransformPosition(this._transform, value);
	        }
	    }
	    get orientation() {
	        return this._orientation;
	    }
	    set orientation(value) {
	        this._orientation = value || ref_properties.identity$1([]);
	        if (value) {
	            updateTransformOrientation(this._transform, this._orientation);
	        }
	    }
	    getPitchBearing() {
	        const f = this.forward();
	        const r = this.right();
	        return {
	            bearing: Math.atan2(-r[1], r[0]),
	            pitch: Math.atan2(Math.sqrt(f[0] * f[0] + f[1] * f[1]), -f[2])
	        };
	    }
	    setPitchBearing(pitch, bearing) {
	        this._orientation = orientationFromPitchBearing(pitch, bearing);
	        updateTransformOrientation(this._transform, this._orientation);
	    }
	    forward() {
	        const col = ref_properties.getColumn(this._transform, 2);
	        return [
	            -col[0],
	            -col[1],
	            -col[2]
	        ];
	    }
	    up() {
	        const col = ref_properties.getColumn(this._transform, 1);
	        return [
	            -col[0],
	            -col[1],
	            -col[2]
	        ];
	    }
	    right() {
	        const col = ref_properties.getColumn(this._transform, 0);
	        return [
	            col[0],
	            col[1],
	            col[2]
	        ];
	    }
	    getCameraToWorld(worldSize, pixelsPerMeter) {
	        const cameraToWorld = new Float64Array(16);
	        ref_properties.invert(cameraToWorld, this.getWorldToCamera(worldSize, pixelsPerMeter));
	        return cameraToWorld;
	    }
	    getWorldToCameraPosition(worldSize, pixelsPerMeter, uniformScale) {
	        const invPosition = this.position;
	        ref_properties.scale$2(invPosition, invPosition, -worldSize);
	        const matrix = new Float64Array(16);
	        ref_properties.fromScaling(matrix, [
	            uniformScale,
	            uniformScale,
	            uniformScale
	        ]);
	        ref_properties.translate(matrix, matrix, invPosition);
	        matrix[10] *= pixelsPerMeter;
	        return matrix;
	    }
	    getWorldToCamera(worldSize, pixelsPerMeter) {
	        const matrix = new Float64Array(16);
	        const invOrientation = new Float64Array(4);
	        const invPosition = this.position;
	        ref_properties.conjugate(invOrientation, this._orientation);
	        ref_properties.scale$2(invPosition, invPosition, -worldSize);
	        ref_properties.fromQuat(matrix, invOrientation);
	        ref_properties.translate(matrix, matrix, invPosition);
	        matrix[1] *= -1;
	        matrix[5] *= -1;
	        matrix[9] *= -1;
	        matrix[13] *= -1;
	        matrix[8] *= pixelsPerMeter;
	        matrix[9] *= pixelsPerMeter;
	        matrix[10] *= pixelsPerMeter;
	        matrix[11] *= pixelsPerMeter;
	        return matrix;
	    }
	    getCameraToClipPerspective(fovy, aspectRatio, nearZ, farZ) {
	        const matrix = new Float64Array(16);
	        ref_properties.perspective(matrix, fovy, aspectRatio, nearZ, farZ);
	        return matrix;
	    }
	    getDistanceToElevation(elevationMeters) {
	        const z0 = elevationMeters === 0 ? 0 : ref_properties.mercatorZfromAltitude(elevationMeters, this.position[1]);
	        const f = this.forward();
	        return (z0 - this.position[2]) / f[2];
	    }
	    clone() {
	        return new FreeCamera([...this.position], [...this.orientation]);
	    }
	}

	function getProjectionAdjustments(transform, withoutRotation) {
	    const interpT = getProjectionInterpolationT(transform.projection, transform.zoom, transform.width, transform.height);
	    const matrix = getShearAdjustment(transform.projection, transform.zoom, transform.center, interpT, withoutRotation);
	    const scaleAdjustment = getScaleAdjustment(transform);
	    ref_properties.scale(matrix, matrix, [
	        scaleAdjustment,
	        scaleAdjustment,
	        1
	    ]);
	    return matrix;
	}
	function getScaleAdjustment(transform) {
	    const projection = transform.projection;
	    const interpT = getProjectionInterpolationT(transform.projection, transform.zoom, transform.width, transform.height);
	    const zoomAdjustment = getZoomAdjustment(projection, transform.center);
	    const zoomAdjustmentOrigin = getZoomAdjustment(projection, ref_properties.LngLat.convert(projection.center));
	    const scaleAdjustment = Math.pow(2, zoomAdjustment * interpT + (1 - interpT) * zoomAdjustmentOrigin);
	    return scaleAdjustment;
	}
	function getProjectionAdjustmentInverted(transform) {
	    const m = getProjectionAdjustments(transform, true);
	    return invert([], [
	        m[0],
	        m[1],
	        m[4],
	        m[5]
	    ]);
	}
	function getProjectionInterpolationT(projection, zoom, width, height, maxSize = Infinity) {
	    const range = projection.range;
	    if (!range)
	        return 0;
	    const size = Math.min(maxSize, Math.max(width, height));
	    const rangeAdjustment = Math.log(size / 1024) / Math.LN2;
	    const zoomA = range[0] + rangeAdjustment;
	    const zoomB = range[1] + rangeAdjustment;
	    const t = ref_properties.smoothstep(zoomA, zoomB, zoom);
	    return t;
	}
	const offset = 1 / 40000;
	function getZoomAdjustment(projection, loc) {
	    const lat = ref_properties.clamp(loc.lat, -ref_properties.MAX_MERCATOR_LATITUDE, ref_properties.MAX_MERCATOR_LATITUDE);
	    const loc1 = new ref_properties.LngLat(loc.lng - 180 * offset, lat);
	    const loc2 = new ref_properties.LngLat(loc.lng + 180 * offset, lat);
	    const p1 = projection.project(loc1.lng, lat);
	    const p2 = projection.project(loc2.lng, lat);
	    const m1 = ref_properties.MercatorCoordinate.fromLngLat(loc1);
	    const m2 = ref_properties.MercatorCoordinate.fromLngLat(loc2);
	    const pdx = p2.x - p1.x;
	    const pdy = p2.y - p1.y;
	    const mdx = m2.x - m1.x;
	    const mdy = m2.y - m1.y;
	    const scale = Math.sqrt((mdx * mdx + mdy * mdy) / (pdx * pdx + pdy * pdy));
	    return Math.log(scale) / Math.LN2;
	}
	function getShearAdjustment(projection, zoom, loc, interpT, withoutRotation) {
	    const locw = new ref_properties.LngLat(loc.lng - 180 * offset, loc.lat);
	    const loce = new ref_properties.LngLat(loc.lng + 180 * offset, loc.lat);
	    const pw = projection.project(locw.lng, locw.lat);
	    const pe = projection.project(loce.lng, loce.lat);
	    const pdx = pe.x - pw.x;
	    const pdy = pe.y - pw.y;
	    const angleAdjust = -Math.atan2(pdy, pdx);
	    const mc2 = ref_properties.MercatorCoordinate.fromLngLat(loc);
	    mc2.y = ref_properties.clamp(mc2.y, -1 + offset, 1 - offset);
	    const loc2 = mc2.toLngLat();
	    const p2 = projection.project(loc2.lng, loc2.lat);
	    const mc3 = ref_properties.MercatorCoordinate.fromLngLat(loc2);
	    mc3.x += offset;
	    const loc3 = mc3.toLngLat();
	    const p3 = projection.project(loc3.lng, loc3.lat);
	    const pdx3 = p3.x - p2.x;
	    const pdy3 = p3.y - p2.y;
	    const delta3 = rotate(pdx3, pdy3, angleAdjust);
	    const mc4 = ref_properties.MercatorCoordinate.fromLngLat(loc2);
	    mc4.y += offset;
	    const loc4 = mc4.toLngLat();
	    const p4 = projection.project(loc4.lng, loc4.lat);
	    const pdx4 = p4.x - p2.x;
	    const pdy4 = p4.y - p2.y;
	    const delta4 = rotate(pdx4, pdy4, angleAdjust);
	    const scale = Math.abs(delta3.x) / Math.abs(delta4.y);
	    const unrotate = ref_properties.identity([]);
	    ref_properties.rotateZ(unrotate, unrotate, -angleAdjust * (1 - (withoutRotation ? 0 : interpT)));
	    const shear = ref_properties.identity([]);
	    ref_properties.scale(shear, shear, [
	        1,
	        1 - (1 - scale) * interpT,
	        1
	    ]);
	    shear[4] = -delta4.x / delta4.y * interpT;
	    ref_properties.rotateZ(shear, shear, angleAdjust);
	    ref_properties.multiply(shear, unrotate, shear);
	    return shear;
	}
	function rotate(x, y, angle) {
	    const cos = Math.cos(angle);
	    const sin = Math.sin(angle);
	    return {
	        x: x * cos - y * sin,
	        y: x * sin + y * cos
	    };
	}

	const NUM_WORLD_COPIES = 3;
	const DEFAULT_MIN_ZOOM = 0;
	class Transform {
	    constructor(minZoom, maxZoom, minPitch, maxPitch, renderWorldCopies, projection, bounds) {
	        this.tileSize = 512;
	        this._renderWorldCopies = renderWorldCopies === undefined ? true : renderWorldCopies;
	        this._minZoom = minZoom || DEFAULT_MIN_ZOOM;
	        this._maxZoom = maxZoom || 22;
	        this._minPitch = minPitch === undefined || minPitch === null ? 0 : minPitch;
	        this._maxPitch = maxPitch === undefined || maxPitch === null ? 60 : maxPitch;
	        this.setProjection(projection);
	        this.setMaxBounds(bounds);
	        this.width = 0;
	        this.height = 0;
	        this._center = new ref_properties.LngLat(0, 0);
	        this.zoom = 0;
	        this.angle = 0;
	        this._fov = 0.6435011087932844;
	        this._pitch = 0;
	        this._nearZ = 0;
	        this._farZ = 0;
	        this._unmodified = true;
	        this._edgeInsets = new EdgeInsets();
	        this._projMatrixCache = {};
	        this._alignedProjMatrixCache = {};
	        this._fogTileMatrixCache = {};
	        this._distanceTileDataCache = {};
	        this._camera = new FreeCamera();
	        this._centerAltitude = 0;
	        this._averageElevation = 0;
	        this.cameraElevationReference = 'ground';
	        this._projectionScaler = 1;
	        this.globeRadius = 0;
	        this.globeCenterInViewSpace = [
	            0,
	            0,
	            0
	        ];
	        this._horizonShift = 0.1;
	    }
	    clone() {
	        const clone = new Transform(this._minZoom, this._maxZoom, this._minPitch, this.maxPitch, this._renderWorldCopies, this.getProjection());
	        clone._elevation = this._elevation;
	        clone._centerAltitude = this._centerAltitude;
	        clone._centerAltitudeValidForExaggeration = this._centerAltitudeValidForExaggeration;
	        clone.tileSize = this.tileSize;
	        clone.width = this.width;
	        clone.height = this.height;
	        clone.cameraElevationReference = this.cameraElevationReference;
	        clone._center = this._center;
	        clone._setZoom(this.zoom);
	        clone._seaLevelZoom = this._seaLevelZoom;
	        clone.angle = this.angle;
	        clone._fov = this._fov;
	        clone._pitch = this._pitch;
	        clone._nearZ = this._nearZ;
	        clone._farZ = this._farZ;
	        clone._averageElevation = this._averageElevation;
	        clone._unmodified = this._unmodified;
	        clone._edgeInsets = this._edgeInsets.clone();
	        clone._camera = this._camera.clone();
	        clone._calcMatrices();
	        clone.freezeTileCoverage = this.freezeTileCoverage;
	        clone.frustumCorners = this.frustumCorners;
	        return clone;
	    }
	    get elevation() {
	        return this._elevation;
	    }
	    set elevation(elevation) {
	        if (this._elevation === elevation)
	            return;
	        this._elevation = elevation;
	        this._updateCameraOnTerrain();
	        this._calcMatrices();
	    }
	    updateElevation(constrainCameraOverTerrain) {
	        const centerAltitudeChanged = this._elevation && this._elevation.exaggeration() !== this._centerAltitudeValidForExaggeration;
	        if (this._seaLevelZoom == null || centerAltitudeChanged) {
	            this._updateCameraOnTerrain();
	        }
	        if (constrainCameraOverTerrain || centerAltitudeChanged) {
	            this._constrainCameraAltitude();
	        }
	        this._calcMatrices();
	    }
	    getProjection() {
	        return ref_properties.pick(this.projection, [
	            'name',
	            'center',
	            'parallels'
	        ]);
	    }
	    setProjection(projection) {
	        this.projectionOptions = projection || { name: 'mercator' };
	        const oldProjection = this.projection ? this.getProjection() : undefined;
	        this.projection = ref_properties.getProjection(this.projectionOptions);
	        const newProjection = this.getProjection();
	        const projectionHasChanged = !deepEqual(oldProjection, newProjection);
	        if (projectionHasChanged) {
	            this._calcMatrices();
	        }
	        return projectionHasChanged;
	    }
	    get minZoom() {
	        return this._minZoom;
	    }
	    set minZoom(zoom) {
	        if (this._minZoom === zoom)
	            return;
	        this._minZoom = zoom;
	        this.zoom = Math.max(this.zoom, zoom);
	    }
	    get maxZoom() {
	        return this._maxZoom;
	    }
	    set maxZoom(zoom) {
	        if (this._maxZoom === zoom)
	            return;
	        this._maxZoom = zoom;
	        this.zoom = Math.min(this.zoom, zoom);
	    }
	    get minPitch() {
	        return this._minPitch;
	    }
	    set minPitch(pitch) {
	        if (this._minPitch === pitch)
	            return;
	        this._minPitch = pitch;
	        this.pitch = Math.max(this.pitch, pitch);
	    }
	    get maxPitch() {
	        return this._maxPitch;
	    }
	    set maxPitch(pitch) {
	        if (this._maxPitch === pitch)
	            return;
	        this._maxPitch = pitch;
	        this.pitch = Math.min(this.pitch, pitch);
	    }
	    get renderWorldCopies() {
	        return this._renderWorldCopies && this.projection.supportsWorldCopies === true;
	    }
	    set renderWorldCopies(renderWorldCopies) {
	        if (renderWorldCopies === undefined) {
	            renderWorldCopies = true;
	        } else if (renderWorldCopies === null) {
	            renderWorldCopies = false;
	        }
	        this._renderWorldCopies = renderWorldCopies;
	    }
	    get worldSize() {
	        return this.tileSize * this.scale;
	    }
	    get cameraWorldSize() {
	        const distance = Math.max(this._camera.getDistanceToElevation(this._averageElevation), Number.EPSILON);
	        return this._worldSizeFromZoom(this._zoomFromMercatorZ(distance));
	    }
	    get pixelsPerMeter() {
	        return this.projection.pixelsPerMeter(this.center.lat, this.worldSize);
	    }
	    get cameraPixelsPerMeter() {
	        return ref_properties.mercatorZfromAltitude(this.center.lat, this.cameraWorldSize);
	    }
	    get centerOffset() {
	        return this.centerPoint._sub(this.size._div(2));
	    }
	    get size() {
	        return new ref_properties.pointGeometry(this.width, this.height);
	    }
	    get bearing() {
	        return ref_properties.wrap(this.rotation, -180, 180);
	    }
	    set bearing(bearing) {
	        this.rotation = bearing;
	    }
	    get rotation() {
	        return -this.angle / Math.PI * 180;
	    }
	    set rotation(rotation) {
	        const b = -rotation * Math.PI / 180;
	        if (this.angle === b)
	            return;
	        this._unmodified = false;
	        this.angle = b;
	        this._calcMatrices();
	        this.rotationMatrix = create$1();
	        rotate$1(this.rotationMatrix, this.rotationMatrix, this.angle);
	    }
	    get pitch() {
	        return this._pitch / Math.PI * 180;
	    }
	    set pitch(pitch) {
	        const p = ref_properties.clamp(pitch, this.minPitch, this.maxPitch) / 180 * Math.PI;
	        if (this._pitch === p)
	            return;
	        this._unmodified = false;
	        this._pitch = p;
	        this._calcMatrices();
	    }
	    get fov() {
	        return this._fov / Math.PI * 180;
	    }
	    set fov(fov) {
	        fov = Math.max(0.01, Math.min(60, fov));
	        if (this._fov === fov)
	            return;
	        this._unmodified = false;
	        this._fov = fov / 180 * Math.PI;
	        this._calcMatrices();
	    }
	    get averageElevation() {
	        return this._averageElevation;
	    }
	    set averageElevation(averageElevation) {
	        this._averageElevation = averageElevation;
	        this._calcFogMatrices();
	        this._distanceTileDataCache = {};
	    }
	    get zoom() {
	        return this._zoom;
	    }
	    set zoom(zoom) {
	        const z = Math.min(Math.max(zoom, this.minZoom), this.maxZoom);
	        if (this._zoom === z)
	            return;
	        this._unmodified = false;
	        this._setZoom(z);
	        this._updateSeaLevelZoom();
	        this._constrain();
	        this._calcMatrices();
	    }
	    _setZoom(z) {
	        this._zoom = z;
	        this.scale = this.zoomScale(z);
	        this.tileZoom = Math.floor(z);
	        this.zoomFraction = z - this.tileZoom;
	    }
	    _updateCameraOnTerrain() {
	        if (!this._elevation || !this._elevation.isDataAvailableAtPoint(this.locationCoordinate(this.center))) {
	            this._centerAltitude = 0;
	            this._seaLevelZoom = null;
	            this._centerAltitudeValidForExaggeration = undefined;
	            return;
	        }
	        const elevation = this._elevation;
	        this._centerAltitude = elevation.getAtPointOrZero(this.locationCoordinate(this.center));
	        this._centerAltitudeValidForExaggeration = elevation.exaggeration();
	        this._updateSeaLevelZoom();
	    }
	    _updateSeaLevelZoom() {
	        if (this._centerAltitudeValidForExaggeration === undefined) {
	            return;
	        }
	        const height = this.cameraToCenterDistance;
	        const terrainElevation = this.pixelsPerMeter * this._centerAltitude;
	        const mercatorZ = (terrainElevation + height) / this.worldSize;
	        this._seaLevelZoom = this._zoomFromMercatorZ(mercatorZ);
	    }
	    sampleAverageElevation() {
	        if (!this._elevation)
	            return 0;
	        const elevation = this._elevation;
	        const elevationSamplePoints = [
	            [
	                0.5,
	                0.2
	            ],
	            [
	                0.3,
	                0.5
	            ],
	            [
	                0.5,
	                0.5
	            ],
	            [
	                0.7,
	                0.5
	            ],
	            [
	                0.5,
	                0.8
	            ]
	        ];
	        const horizon = this.horizonLineFromTop();
	        let elevationSum = 0;
	        let weightSum = 0;
	        for (let i = 0; i < elevationSamplePoints.length; i++) {
	            const pt = new ref_properties.pointGeometry(elevationSamplePoints[i][0] * this.width, horizon + elevationSamplePoints[i][1] * (this.height - horizon));
	            const hit = elevation.pointCoordinate(pt);
	            if (!hit)
	                continue;
	            const distanceToHit = Math.hypot(hit[0] - this._camera.position[0], hit[1] - this._camera.position[1]);
	            const weight = 1 / distanceToHit;
	            elevationSum += hit[3] * weight;
	            weightSum += weight;
	        }
	        if (weightSum === 0)
	            return NaN;
	        return elevationSum / weightSum;
	    }
	    get center() {
	        return this._center;
	    }
	    set center(center) {
	        if (center.lat === this._center.lat && center.lng === this._center.lng)
	            return;
	        this._unmodified = false;
	        this._center = center;
	        if (this._terrainEnabled()) {
	            if (this.cameraElevationReference === 'ground') {
	                this._updateCameraOnTerrain();
	            } else {
	                this._updateZoomFromElevation();
	            }
	        }
	        this._constrain();
	        this._calcMatrices();
	    }
	    _updateZoomFromElevation() {
	        if (this._seaLevelZoom == null || !this._elevation)
	            return;
	        const seaLevelZoom = this._seaLevelZoom;
	        const elevationAtCenter = this._elevation.getAtPointOrZero(this.locationCoordinate(this.center));
	        const mercatorElevation = this.pixelsPerMeter / this.worldSize * elevationAtCenter;
	        const altitude = this._mercatorZfromZoom(seaLevelZoom);
	        const minHeight = this._mercatorZfromZoom(this._maxZoom);
	        const height = Math.max(altitude - mercatorElevation, minHeight);
	        this._setZoom(this._zoomFromMercatorZ(height));
	    }
	    get padding() {
	        return this._edgeInsets.toJSON();
	    }
	    set padding(padding) {
	        if (this._edgeInsets.equals(padding))
	            return;
	        this._unmodified = false;
	        this._edgeInsets.interpolate(this._edgeInsets, padding, 1);
	        this._calcMatrices();
	    }
	    computeZoomRelativeTo(position) {
	        const centerOnTargetAltitude = this.rayIntersectionCoordinate(this.pointRayIntersection(this.centerPoint, position.toAltitude()));
	        let targetPosition;
	        if (position.z < this._camera.position[2]) {
	            targetPosition = [
	                centerOnTargetAltitude.x,
	                centerOnTargetAltitude.y,
	                centerOnTargetAltitude.z
	            ];
	        } else {
	            targetPosition = [
	                position.x,
	                position.y,
	                position.z
	            ];
	        }
	        const distToTarget = ref_properties.length(ref_properties.sub([], this._camera.position, targetPosition));
	        return ref_properties.clamp(this._zoomFromMercatorZ(distToTarget), this._minZoom, this._maxZoom);
	    }
	    setFreeCameraOptions(options) {
	        if (!this.height)
	            return;
	        if (!options.position && !options.orientation)
	            return;
	        this._updateCameraState();
	        let changed = false;
	        if (options.orientation && !ref_properties.exactEquals(options.orientation, this._camera.orientation)) {
	            changed = this._setCameraOrientation(options.orientation);
	        }
	        if (options.position) {
	            const newPosition = [
	                options.position.x,
	                options.position.y,
	                options.position.z
	            ];
	            if (!ref_properties.exactEquals$1(newPosition, this._camera.position)) {
	                this._setCameraPosition(newPosition);
	                changed = true;
	            }
	        }
	        if (changed) {
	            this._updateStateFromCamera();
	            this.recenterOnTerrain();
	        }
	    }
	    getFreeCameraOptions() {
	        this._updateCameraState();
	        const pos = this._camera.position;
	        const options = new FreeCameraOptions();
	        options.position = new ref_properties.MercatorCoordinate(pos[0], pos[1], pos[2]);
	        options.orientation = this._camera.orientation;
	        options._elevation = this.elevation;
	        options._renderWorldCopies = this.renderWorldCopies;
	        return options;
	    }
	    _setCameraOrientation(orientation) {
	        if (!ref_properties.length$1(orientation))
	            return false;
	        ref_properties.normalize$1(orientation, orientation);
	        const forward = ref_properties.transformQuat([], [
	            0,
	            0,
	            -1
	        ], orientation);
	        const up = ref_properties.transformQuat([], [
	            0,
	            -1,
	            0
	        ], orientation);
	        if (up[2] < 0)
	            return false;
	        const updatedOrientation = orientationFromFrame(forward, up);
	        if (!updatedOrientation)
	            return false;
	        this._camera.orientation = updatedOrientation;
	        return true;
	    }
	    _setCameraPosition(position) {
	        const minWorldSize = this.zoomScale(this.minZoom) * this.tileSize;
	        const maxWorldSize = this.zoomScale(this.maxZoom) * this.tileSize;
	        const distToCenter = this.cameraToCenterDistance;
	        position[2] = ref_properties.clamp(position[2], distToCenter / maxWorldSize, distToCenter / minWorldSize);
	        this._camera.position = position;
	    }
	    get centerPoint() {
	        return this._edgeInsets.getCenter(this.width, this.height);
	    }
	    get fovAboveCenter() {
	        return this._fov * (0.5 + this.centerOffset.y / this.height);
	    }
	    isPaddingEqual(padding) {
	        return this._edgeInsets.equals(padding);
	    }
	    interpolatePadding(start, target, t) {
	        this._unmodified = false;
	        this._edgeInsets.interpolate(start, target, t);
	        this._constrain();
	        this._calcMatrices();
	    }
	    coveringZoomLevel(options) {
	        const z = (options.roundZoom ? Math.round : Math.floor)(this.zoom + this.scaleZoom(this.tileSize / options.tileSize));
	        return Math.max(0, z);
	    }
	    getVisibleUnwrappedCoordinates(tileID) {
	        const result = [new ref_properties.UnwrappedTileID(0, tileID)];
	        if (this.renderWorldCopies) {
	            const utl = this.pointCoordinate(new ref_properties.pointGeometry(0, 0));
	            const utr = this.pointCoordinate(new ref_properties.pointGeometry(this.width, 0));
	            const ubl = this.pointCoordinate(new ref_properties.pointGeometry(this.width, this.height));
	            const ubr = this.pointCoordinate(new ref_properties.pointGeometry(0, this.height));
	            const w0 = Math.floor(Math.min(utl.x, utr.x, ubl.x, ubr.x));
	            const w1 = Math.floor(Math.max(utl.x, utr.x, ubl.x, ubr.x));
	            const extraWorldCopy = 1;
	            for (let w = w0 - extraWorldCopy; w <= w1 + extraWorldCopy; w++) {
	                if (w === 0)
	                    continue;
	                result.push(new ref_properties.UnwrappedTileID(w, tileID));
	            }
	        }
	        return result;
	    }
	    coveringTiles(options) {
	        let z = this.coveringZoomLevel(options);
	        const actualZ = z;
	        const useElevationData = this.elevation && !options.isTerrainDEM;
	        const isMercator = this.projection.name === 'mercator';
	        if (options.minzoom !== undefined && z < options.minzoom)
	            return [];
	        if (options.maxzoom !== undefined && z > options.maxzoom)
	            z = options.maxzoom;
	        const centerCoord = this.locationCoordinate(this.center);
	        const centerLatitude = this.center.lat;
	        const numTiles = 1 << z;
	        const centerPoint = [
	            numTiles * centerCoord.x,
	            numTiles * centerCoord.y,
	            0
	        ];
	        const isGlobe = this.projection.name === 'globe';
	        const zInMeters = !isGlobe;
	        const cameraFrustum = ref_properties.Frustum.fromInvProjectionMatrix(this.invProjMatrix, this.worldSize, z, zInMeters);
	        const cameraCoord = isGlobe ? this._camera.mercatorPosition : this.pointCoordinate(this.getCameraPoint());
	        const meterToTile = numTiles * ref_properties.mercatorZfromAltitude(1, this.center.lat);
	        const cameraAltitude = this._camera.position[2] / ref_properties.mercatorZfromAltitude(1, this.center.lat);
	        const cameraPoint = [
	            numTiles * cameraCoord.x,
	            numTiles * cameraCoord.y,
	            cameraAltitude * (zInMeters ? 1 : meterToTile)
	        ];
	        const zoomSplitDistance = this.cameraToCenterDistance / options.tileSize * (options.roundZoom ? 1 : 0.502);
	        const minZoom = this.pitch <= 60 && this._edgeInsets.top <= this._edgeInsets.bottom && !this._elevation && !this.projection.isReprojectedInTileSpace ? z : 0;
	        const maxRange = options.isTerrainDEM && this._elevation ? this._elevation.exaggeration() * 10000 : this._centerAltitude;
	        const minRange = options.isTerrainDEM ? -maxRange : this._elevation ? this._elevation.getMinElevationBelowMSL() : 0;
	        const scaleAdjustment = this.projection.isReprojectedInTileSpace ? getScaleAdjustment(this) : 1;
	        const relativeScaleAtMercatorCoord = mc => {
	            const offset = 1 / 40000;
	            const mcEast = new ref_properties.MercatorCoordinate(mc.x + offset, mc.y, mc.z);
	            const mcSouth = new ref_properties.MercatorCoordinate(mc.x, mc.y + offset, mc.z);
	            const ll = mc.toLngLat();
	            const llEast = mcEast.toLngLat();
	            const llSouth = mcSouth.toLngLat();
	            const p = this.locationCoordinate(ll);
	            const pEast = this.locationCoordinate(llEast);
	            const pSouth = this.locationCoordinate(llSouth);
	            const dx = Math.hypot(pEast.x - p.x, pEast.y - p.y);
	            const dy = Math.hypot(pSouth.x - p.x, pSouth.y - p.y);
	            return Math.sqrt(dx * dy) * scaleAdjustment / offset;
	        };
	        const newRootTile = wrap => {
	            const max = maxRange;
	            const min = minRange;
	            return {
	                aabb: ref_properties.tileAABB(this, numTiles, 0, 0, 0, wrap, min, max, this.projection),
	                zoom: 0,
	                x: 0,
	                y: 0,
	                minZ: min,
	                maxZ: max,
	                wrap,
	                fullyVisible: false
	            };
	        };
	        const stack = [];
	        let result = [];
	        const maxZoom = z;
	        const overscaledZ = options.reparseOverscaled ? actualZ : z;
	        const square = a => a * a;
	        const cameraHeightSqr = square((cameraAltitude - this._centerAltitude) * meterToTile);
	        const getAABBFromElevation = it => {
	            if (!this._elevation || !it.tileID || !isMercator)
	                return;
	            const minmax = this._elevation.getMinMaxForTile(it.tileID);
	            const aabb = it.aabb;
	            if (minmax) {
	                aabb.min[2] = minmax.min;
	                aabb.max[2] = minmax.max;
	                aabb.center[2] = (aabb.min[2] + aabb.max[2]) / 2;
	            } else {
	                it.shouldSplit = shouldSplit(it);
	                if (!it.shouldSplit) {
	                    aabb.min[2] = aabb.max[2] = aabb.center[2] = this._centerAltitude;
	                }
	            }
	        };
	        const distToSplitScale = (dzSqr, dSqr) => {
	            const acuteAngleThresholdSin = 0.707;
	            const stretchTile = 1.1;
	            if (dSqr * square(acuteAngleThresholdSin) < dzSqr)
	                return 1;
	            const r = Math.sqrt(dSqr / dzSqr);
	            const k = r - 1 / acuteAngleThresholdSin;
	            return r / (1 / acuteAngleThresholdSin + (Math.pow(stretchTile, k + 1) - 1) / (stretchTile - 1) - 1);
	        };
	        const shouldSplit = it => {
	            if (it.zoom < minZoom) {
	                return true;
	            } else if (it.zoom === maxZoom) {
	                return false;
	            }
	            if (it.shouldSplit != null) {
	                return it.shouldSplit;
	            }
	            const dx = it.aabb.distanceX(cameraPoint);
	            const dy = it.aabb.distanceY(cameraPoint);
	            let dzSqr = cameraHeightSqr;
	            let tileScaleAdjustment = 1;
	            if (isGlobe) {
	                dzSqr = square(it.aabb.distanceZ(cameraPoint));
	                const tilesAtZoom = Math.pow(2, it.zoom);
	                const minLat = ref_properties.latFromMercatorY((it.y + 1) / tilesAtZoom);
	                const maxLat = ref_properties.latFromMercatorY(it.y / tilesAtZoom);
	                const closestLat = Math.min(Math.max(centerLatitude, minLat), maxLat);
	                const relativeTileScale = ref_properties.circumferenceAtLatitude(closestLat) / ref_properties.circumferenceAtLatitude(centerLatitude);
	                if (closestLat === centerLatitude) {
	                    const maxDivergence = 0.3;
	                    tileScaleAdjustment = 1 / Math.max(1, this._mercatorScaleRatio - maxDivergence);
	                } else {
	                    tileScaleAdjustment = Math.min(1, relativeTileScale / this._mercatorScaleRatio);
	                }
	                if (this.zoom <= ref_properties.GLOBE_ZOOM_THRESHOLD_MIN && it.zoom === maxZoom - 1 && relativeTileScale >= 0.9) {
	                    return true;
	                }
	            } else {
	                if (useElevationData) {
	                    dzSqr = square(it.aabb.distanceZ(cameraPoint) * meterToTile);
	                }
	                if (this.projection.isReprojectedInTileSpace && actualZ <= 5) {
	                    const numTiles = Math.pow(2, it.zoom);
	                    const relativeScale = relativeScaleAtMercatorCoord(new ref_properties.MercatorCoordinate((it.x + 0.5) / numTiles, (it.y + 0.5) / numTiles));
	                    tileScaleAdjustment = relativeScale > 0.85 ? 1 : relativeScale;
	                }
	            }
	            const distanceSqr = dx * dx + dy * dy + dzSqr;
	            const distToSplit = (1 << maxZoom - it.zoom) * zoomSplitDistance * tileScaleAdjustment;
	            const distToSplitSqr = square(distToSplit * distToSplitScale(Math.max(dzSqr, cameraHeightSqr), distanceSqr));
	            return distanceSqr < distToSplitSqr;
	        };
	        if (this.renderWorldCopies) {
	            for (let i = 1; i <= NUM_WORLD_COPIES; i++) {
	                stack.push(newRootTile(-i));
	                stack.push(newRootTile(i));
	            }
	        }
	        stack.push(newRootTile(0));
	        while (stack.length > 0) {
	            const it = stack.pop();
	            const x = it.x;
	            const y = it.y;
	            let fullyVisible = it.fullyVisible;
	            if (!fullyVisible) {
	                const intersectResult = it.aabb.intersects(cameraFrustum);
	                if (intersectResult === 0)
	                    continue;
	                fullyVisible = intersectResult === 2;
	            }
	            if (it.zoom === maxZoom || !shouldSplit(it)) {
	                const tileZoom = it.zoom === maxZoom ? overscaledZ : it.zoom;
	                if (!!options.minzoom && options.minzoom > tileZoom) {
	                    continue;
	                }
	                const dx = centerPoint[0] - (0.5 + x + (it.wrap << it.zoom)) * (1 << z - it.zoom);
	                const dy = centerPoint[1] - 0.5 - y;
	                const id = it.tileID ? it.tileID : new ref_properties.OverscaledTileID(tileZoom, it.wrap, it.zoom, x, y);
	                result.push({
	                    tileID: id,
	                    distanceSq: dx * dx + dy * dy
	                });
	                continue;
	            }
	            for (let i = 0; i < 4; i++) {
	                const childX = (x << 1) + i % 2;
	                const childY = (y << 1) + (i >> 1);
	                const aabb = isMercator ? it.aabb.quadrant(i) : ref_properties.tileAABB(this, numTiles, it.zoom + 1, childX, childY, it.wrap, it.minZ, it.maxZ, this.projection);
	                const child = {
	                    aabb,
	                    zoom: it.zoom + 1,
	                    x: childX,
	                    y: childY,
	                    wrap: it.wrap,
	                    fullyVisible,
	                    tileID: undefined,
	                    shouldSplit: undefined,
	                    minZ: it.minZ,
	                    maxZ: it.maxZ
	                };
	                if (useElevationData && !isGlobe) {
	                    child.tileID = new ref_properties.OverscaledTileID(it.zoom + 1 === maxZoom ? overscaledZ : it.zoom + 1, it.wrap, it.zoom + 1, childX, childY);
	                    getAABBFromElevation(child);
	                }
	                stack.push(child);
	            }
	        }
	        if (this.fogCullDistSq) {
	            const fogCullDistSq = this.fogCullDistSq;
	            const horizonLineFromTop = this.horizonLineFromTop();
	            result = result.filter(entry => {
	                const min = [
	                    0,
	                    0,
	                    0,
	                    1
	                ];
	                const max = [
	                    ref_properties.EXTENT,
	                    ref_properties.EXTENT,
	                    0,
	                    1
	                ];
	                const fogTileMatrix = this.calculateFogTileMatrix(entry.tileID.toUnwrapped());
	                ref_properties.transformMat4$1(min, min, fogTileMatrix);
	                ref_properties.transformMat4$1(max, max, fogTileMatrix);
	                const sqDist = ref_properties.getAABBPointSquareDist(min, max);
	                if (sqDist === 0) {
	                    return true;
	                }
	                let overHorizonLine = false;
	                const elevation = this._elevation;
	                if (elevation && sqDist > fogCullDistSq && horizonLineFromTop !== 0) {
	                    const projMatrix = this.calculateProjMatrix(entry.tileID.toUnwrapped());
	                    let minmax;
	                    if (!options.isTerrainDEM) {
	                        minmax = elevation.getMinMaxForTile(entry.tileID);
	                    }
	                    if (!minmax) {
	                        minmax = {
	                            min: minRange,
	                            max: maxRange
	                        };
	                    }
	                    const cornerFar = ref_properties.furthestTileCorner(this.rotation);
	                    const farX = cornerFar[0] * ref_properties.EXTENT;
	                    const farY = cornerFar[1] * ref_properties.EXTENT;
	                    const worldFar = [
	                        farX,
	                        farY,
	                        minmax.max
	                    ];
	                    ref_properties.transformMat4(worldFar, worldFar, projMatrix);
	                    const screenCoordY = (1 - worldFar[1]) * this.height * 0.5;
	                    overHorizonLine = screenCoordY < horizonLineFromTop;
	                }
	                return sqDist < fogCullDistSq || overHorizonLine;
	            });
	        }
	        const cover = result.sort((a, b) => a.distanceSq - b.distanceSq).map(a => a.tileID);
	        return cover;
	    }
	    resize(width, height) {
	        this.width = width;
	        this.height = height;
	        this.pixelsToGLUnits = [
	            2 / width,
	            -2 / height
	        ];
	        this._constrain();
	        this._calcMatrices();
	    }
	    get unmodified() {
	        return this._unmodified;
	    }
	    zoomScale(zoom) {
	        return Math.pow(2, zoom);
	    }
	    scaleZoom(scale) {
	        return Math.log(scale) / Math.LN2;
	    }
	    project(lnglat) {
	        const lat = ref_properties.clamp(lnglat.lat, -ref_properties.MAX_MERCATOR_LATITUDE, ref_properties.MAX_MERCATOR_LATITUDE);
	        const projectedLngLat = this.projection.project(lnglat.lng, lat);
	        return new ref_properties.pointGeometry(projectedLngLat.x * this.worldSize, projectedLngLat.y * this.worldSize);
	    }
	    unproject(point) {
	        return this.projection.unproject(point.x / this.worldSize, point.y / this.worldSize);
	    }
	    get point() {
	        return this.project(this.center);
	    }
	    setLocationAtPoint(lnglat, point) {
	        let x, y;
	        const centerPoint = this.centerPoint;
	        if (this.projection.name === 'globe') {
	            const worldSize = this.worldSize;
	            x = (point.x - centerPoint.x) / worldSize;
	            y = (point.y - centerPoint.y) / worldSize;
	        } else {
	            const a = this.pointCoordinate(point);
	            const b = this.pointCoordinate(centerPoint);
	            x = a.x - b.x;
	            y = a.y - b.y;
	        }
	        const loc = this.locationCoordinate(lnglat);
	        this.setLocation(new ref_properties.MercatorCoordinate(loc.x - x, loc.y - y));
	    }
	    setLocation(location) {
	        this.center = this.coordinateLocation(location);
	        if (this.projection.wrap) {
	            this.center = this.center.wrap();
	        }
	    }
	    locationPoint(lnglat) {
	        return this.projection.locationPoint(this, lnglat);
	    }
	    locationPoint3D(lnglat) {
	        return this.projection.locationPoint(this, lnglat, true);
	    }
	    pointLocation(p) {
	        return this.coordinateLocation(this.pointCoordinate(p));
	    }
	    pointLocation3D(p) {
	        return this.coordinateLocation(this.pointCoordinate3D(p));
	    }
	    locationCoordinate(lngLat, altitude) {
	        const z = altitude ? ref_properties.mercatorZfromAltitude(altitude, lngLat.lat) : undefined;
	        const projectedLngLat = this.projection.project(lngLat.lng, lngLat.lat);
	        return new ref_properties.MercatorCoordinate(projectedLngLat.x, projectedLngLat.y, z);
	    }
	    coordinateLocation(coord) {
	        return this.projection.unproject(coord.x, coord.y);
	    }
	    pointRayIntersection(p, z) {
	        const targetZ = z !== undefined && z !== null ? z : this._centerAltitude;
	        const p0 = [
	            p.x,
	            p.y,
	            0,
	            1
	        ];
	        const p1 = [
	            p.x,
	            p.y,
	            1,
	            1
	        ];
	        ref_properties.transformMat4$1(p0, p0, this.pixelMatrixInverse);
	        ref_properties.transformMat4$1(p1, p1, this.pixelMatrixInverse);
	        const w0 = p0[3];
	        const w1 = p1[3];
	        ref_properties.scale$1(p0, p0, 1 / w0);
	        ref_properties.scale$1(p1, p1, 1 / w1);
	        const z0 = p0[2];
	        const z1 = p1[2];
	        const t = z0 === z1 ? 0 : (targetZ - z0) / (z1 - z0);
	        return {
	            p0,
	            p1,
	            t
	        };
	    }
	    screenPointToMercatorRay(p) {
	        const p0 = [
	            p.x,
	            p.y,
	            0,
	            1
	        ];
	        const p1 = [
	            p.x,
	            p.y,
	            1,
	            1
	        ];
	        ref_properties.transformMat4$1(p0, p0, this.pixelMatrixInverse);
	        ref_properties.transformMat4$1(p1, p1, this.pixelMatrixInverse);
	        ref_properties.scale$1(p0, p0, 1 / p0[3]);
	        ref_properties.scale$1(p1, p1, 1 / p1[3]);
	        p0[2] = ref_properties.mercatorZfromAltitude(p0[2], this._center.lat) * this.worldSize;
	        p1[2] = ref_properties.mercatorZfromAltitude(p1[2], this._center.lat) * this.worldSize;
	        ref_properties.scale$1(p0, p0, 1 / this.worldSize);
	        ref_properties.scale$1(p1, p1, 1 / this.worldSize);
	        return new ref_properties.Ray([
	            p0[0],
	            p0[1],
	            p0[2]
	        ], ref_properties.normalize([], ref_properties.sub([], p1, p0)));
	    }
	    rayIntersectionCoordinate(rayIntersection) {
	        const {p0, p1, t} = rayIntersection;
	        const z0 = ref_properties.mercatorZfromAltitude(p0[2], this._center.lat);
	        const z1 = ref_properties.mercatorZfromAltitude(p1[2], this._center.lat);
	        return new ref_properties.MercatorCoordinate(ref_properties.number(p0[0], p1[0], t) / this.worldSize, ref_properties.number(p0[1], p1[1], t) / this.worldSize, ref_properties.number(z0, z1, t));
	    }
	    pointCoordinate(p, z = this._centerAltitude) {
	        return this.projection.pointCoordinate(this, p.x, p.y, z);
	    }
	    pointCoordinate3D(p) {
	        if (!this.elevation)
	            return this.pointCoordinate(p);
	        let raycast = this.projection.pointCoordinate3D(this, p.x, p.y);
	        if (raycast)
	            return new ref_properties.MercatorCoordinate(raycast[0], raycast[1], raycast[2]);
	        let start = 0, end = this.horizonLineFromTop();
	        if (p.y > end)
	            return this.pointCoordinate(p);
	        const samples = 10;
	        const threshold = 0.02 * end;
	        const r = p.clone();
	        for (let i = 0; i < samples && end - start > threshold; i++) {
	            r.y = ref_properties.number(start, end, 0.66);
	            const rCast = this.projection.pointCoordinate3D(this, r.x, r.y);
	            if (rCast) {
	                end = r.y;
	                raycast = rCast;
	            } else {
	                start = r.y;
	            }
	        }
	        return raycast ? new ref_properties.MercatorCoordinate(raycast[0], raycast[1], raycast[2]) : this.pointCoordinate(p);
	    }
	    isPointAboveHorizon(p) {
	        return this.projection.isPointAboveHorizon(this, p);
	    }
	    _coordinatePoint(coord, sampleTerrainIn3D) {
	        const elevation = sampleTerrainIn3D && this.elevation ? this.elevation.getAtPointOrZero(coord, this._centerAltitude) : this._centerAltitude;
	        const p = [
	            coord.x * this.worldSize,
	            coord.y * this.worldSize,
	            elevation + coord.toAltitude(),
	            1
	        ];
	        ref_properties.transformMat4$1(p, p, this.pixelMatrix);
	        return p[3] > 0 ? new ref_properties.pointGeometry(p[0] / p[3], p[1] / p[3]) : new ref_properties.pointGeometry(Number.MAX_VALUE, Number.MAX_VALUE);
	    }
	    _getBounds(min, max) {
	        const topLeft = new ref_properties.pointGeometry(this._edgeInsets.left, this._edgeInsets.top);
	        const topRight = new ref_properties.pointGeometry(this.width - this._edgeInsets.right, this._edgeInsets.top);
	        const bottomRight = new ref_properties.pointGeometry(this.width - this._edgeInsets.right, this.height - this._edgeInsets.bottom);
	        const bottomLeft = new ref_properties.pointGeometry(this._edgeInsets.left, this.height - this._edgeInsets.bottom);
	        let tl = this.pointCoordinate(topLeft, min);
	        let tr = this.pointCoordinate(topRight, min);
	        const br = this.pointCoordinate(bottomRight, max);
	        const bl = this.pointCoordinate(bottomLeft, max);
	        const slope = (p1, p2) => (p2.y - p1.y) / (p2.x - p1.x);
	        if (tl.y > 1 && tr.y >= 0)
	            tl = new ref_properties.MercatorCoordinate((1 - bl.y) / slope(bl, tl) + bl.x, 1);
	        else if (tl.y < 0 && tr.y <= 1)
	            tl = new ref_properties.MercatorCoordinate(-bl.y / slope(bl, tl) + bl.x, 0);
	        if (tr.y > 1 && tl.y >= 0)
	            tr = new ref_properties.MercatorCoordinate((1 - br.y) / slope(br, tr) + br.x, 1);
	        else if (tr.y < 0 && tl.y <= 1)
	            tr = new ref_properties.MercatorCoordinate(-br.y / slope(br, tr) + br.x, 0);
	        return new ref_properties.LngLatBounds().extend(this.coordinateLocation(tl)).extend(this.coordinateLocation(tr)).extend(this.coordinateLocation(bl)).extend(this.coordinateLocation(br));
	    }
	    _getBounds3D() {
	        const elevation = this.elevation;
	        if (!elevation.visibleDemTiles.length) {
	            return this._getBounds(0, 0);
	        }
	        const minmax = elevation.visibleDemTiles.reduce((acc, t) => {
	            if (t.dem) {
	                const tree = t.dem.tree;
	                acc.min = Math.min(acc.min, tree.minimums[0]);
	                acc.max = Math.max(acc.max, tree.maximums[0]);
	            }
	            return acc;
	        }, {
	            min: Number.MAX_VALUE,
	            max: 0
	        });
	        return this._getBounds(minmax.min * elevation.exaggeration(), minmax.max * elevation.exaggeration());
	    }
	    getBounds() {
	        if (this._terrainEnabled())
	            return this._getBounds3D();
	        return this._getBounds(0, 0);
	    }
	    horizonLineFromTop(clampToTop = true) {
	        const h = this.height / 2 / Math.tan(this._fov / 2) / Math.tan(Math.max(this._pitch, 0.1)) + this.centerOffset.y;
	        const offset = this.height / 2 - h * (1 - this._horizonShift);
	        return clampToTop ? Math.max(0, offset) : offset;
	    }
	    getMaxBounds() {
	        return this.maxBounds;
	    }
	    setMaxBounds(bounds) {
	        this.maxBounds = bounds;
	        this.minLat = -ref_properties.MAX_MERCATOR_LATITUDE;
	        this.maxLat = ref_properties.MAX_MERCATOR_LATITUDE;
	        this.minLng = -180;
	        this.maxLng = 180;
	        if (bounds) {
	            this.minLat = bounds.getSouth();
	            this.maxLat = bounds.getNorth();
	            this.minLng = bounds.getWest();
	            this.maxLng = bounds.getEast();
	            if (this.maxLng < this.minLng)
	                this.maxLng += 360;
	        }
	        this.worldMinX = ref_properties.mercatorXfromLng(this.minLng) * this.tileSize;
	        this.worldMaxX = ref_properties.mercatorXfromLng(this.maxLng) * this.tileSize;
	        this.worldMinY = ref_properties.mercatorYfromLat(this.maxLat) * this.tileSize;
	        this.worldMaxY = ref_properties.mercatorYfromLat(this.minLat) * this.tileSize;
	        this._constrain();
	    }
	    calculatePosMatrix(unwrappedTileID, worldSize) {
	        return this.projection.createTileMatrix(this, worldSize, unwrappedTileID);
	    }
	    calculateDistanceTileData(unwrappedTileID) {
	        const distanceDataKey = unwrappedTileID.key;
	        const cache = this._distanceTileDataCache;
	        if (cache[distanceDataKey]) {
	            return cache[distanceDataKey];
	        }
	        const canonical = unwrappedTileID.canonical;
	        const windowScaleFactor = 1 / this.height;
	        const scale = this.cameraWorldSize / this.zoomScale(canonical.z);
	        const unwrappedX = canonical.x + Math.pow(2, canonical.z) * unwrappedTileID.wrap;
	        const tX = unwrappedX * scale;
	        const tY = canonical.y * scale;
	        const center = this.point;
	        const angle = this.angle;
	        const bX = Math.sin(-angle);
	        const bY = -Math.cos(-angle);
	        const cX = (center.x - tX) * windowScaleFactor;
	        const cY = (center.y - tY) * windowScaleFactor;
	        cache[distanceDataKey] = {
	            bearing: [
	                bX,
	                bY
	            ],
	            center: [
	                cX,
	                cY
	            ],
	            scale: scale / ref_properties.EXTENT * windowScaleFactor
	        };
	        return cache[distanceDataKey];
	    }
	    calculateFogTileMatrix(unwrappedTileID) {
	        const fogTileMatrixKey = unwrappedTileID.key;
	        const cache = this._fogTileMatrixCache;
	        if (cache[fogTileMatrixKey]) {
	            return cache[fogTileMatrixKey];
	        }
	        const posMatrix = this.projection.createTileMatrix(this, this.cameraWorldSize, unwrappedTileID);
	        ref_properties.multiply(posMatrix, this.worldToFogMatrix, posMatrix);
	        cache[fogTileMatrixKey] = new Float32Array(posMatrix);
	        return cache[fogTileMatrixKey];
	    }
	    calculateProjMatrix(unwrappedTileID, aligned = false) {
	        const projMatrixKey = unwrappedTileID.key;
	        const cache = aligned ? this._alignedProjMatrixCache : this._projMatrixCache;
	        if (cache[projMatrixKey]) {
	            return cache[projMatrixKey];
	        }
	        const posMatrix = this.calculatePosMatrix(unwrappedTileID, this.worldSize);
	        const projMatrix = this.projection.isReprojectedInTileSpace ? this.mercatorMatrix : aligned ? this.alignedProjMatrix : this.projMatrix;
	        ref_properties.multiply(posMatrix, projMatrix, posMatrix);
	        cache[projMatrixKey] = new Float32Array(posMatrix);
	        return cache[projMatrixKey];
	    }
	    calculatePixelsToTileUnitsMatrix(tile) {
	        const key = tile.tileID.key;
	        const cache = this._pixelsToTileUnitsCache;
	        if (cache[key]) {
	            return cache[key];
	        }
	        const matrix = getPixelsToTileUnitsMatrix(tile, this);
	        cache[key] = matrix;
	        return cache[key];
	    }
	    customLayerMatrix() {
	        return this.mercatorMatrix.slice();
	    }
	    recenterOnTerrain() {
	        if (!this._elevation || this.projection.name === 'globe')
	            return;
	        const elevation = this._elevation;
	        this._updateCameraState();
	        const mercPixelsPerMeter = ref_properties.mercatorZfromAltitude(1, this._center.lat) * this.worldSize;
	        const start = this._computeCameraPosition(mercPixelsPerMeter);
	        const dir = this._camera.forward();
	        const metersToMerc = ref_properties.mercatorZfromAltitude(1, this._center.lat);
	        start[2] /= metersToMerc;
	        dir[2] /= metersToMerc;
	        ref_properties.normalize(dir, dir);
	        const t = elevation.raycast(start, dir, elevation.exaggeration());
	        if (t) {
	            const point = ref_properties.scaleAndAdd([], start, dir, t);
	            const newCenter = new ref_properties.MercatorCoordinate(point[0], point[1], ref_properties.mercatorZfromAltitude(point[2], ref_properties.latFromMercatorY(point[1])));
	            const camToNew = [
	                newCenter.x - start[0],
	                newCenter.y - start[1],
	                newCenter.z - start[2] * metersToMerc
	            ];
	            const maxAltitude = (newCenter.z + ref_properties.length(camToNew)) * this._projectionScaler;
	            this._seaLevelZoom = this._zoomFromMercatorZ(maxAltitude);
	            this._centerAltitude = newCenter.toAltitude();
	            this._center = this.coordinateLocation(newCenter);
	            this._updateZoomFromElevation();
	            this._constrain();
	            this._calcMatrices();
	        }
	    }
	    _constrainCameraAltitude() {
	        if (!this._elevation)
	            return;
	        const elevation = this._elevation;
	        this._updateCameraState();
	        const mercPixelsPerMeter = ref_properties.mercatorZfromAltitude(1, this._center.lat) * this.worldSize;
	        const pos = this._computeCameraPosition(mercPixelsPerMeter);
	        const elevationAtCamera = elevation.getAtPointOrZero(new ref_properties.MercatorCoordinate(...pos));
	        const minHeight = this._minimumHeightOverTerrain() * Math.cos(ref_properties.degToRad(this._maxPitch));
	        const terrainElevation = this.pixelsPerMeter / this.worldSize * elevationAtCamera;
	        const cameraHeight = this._camera.position[2] - terrainElevation;
	        if (cameraHeight < minHeight) {
	            const center = this.locationCoordinate(this._center, this._centerAltitude);
	            const cameraToCenter = [
	                center.x - pos[0],
	                center.y - pos[1],
	                center.z - pos[2]
	            ];
	            const prevDistToCamera = ref_properties.length(cameraToCenter);
	            cameraToCenter[2] -= (minHeight - cameraHeight) / this._projectionScaler;
	            const newDistToCamera = ref_properties.length(cameraToCenter);
	            if (newDistToCamera === 0)
	                return;
	            ref_properties.scale$2(cameraToCenter, cameraToCenter, prevDistToCamera / newDistToCamera * this._projectionScaler);
	            this._camera.position = [
	                center.x - cameraToCenter[0],
	                center.y - cameraToCenter[1],
	                center.z * this._projectionScaler - cameraToCenter[2]
	            ];
	            this._camera.orientation = orientationFromFrame(cameraToCenter, this._camera.up());
	            this._updateStateFromCamera();
	        }
	    }
	    _constrain() {
	        if (!this.center || !this.width || !this.height || this._constraining)
	            return;
	        this._constraining = true;
	        if (this.projection.isReprojectedInTileSpace) {
	            const center = this.center;
	            center.lat = ref_properties.clamp(center.lat, this.minLat, this.maxLat);
	            if (this.maxBounds || !this.renderWorldCopies)
	                center.lng = ref_properties.clamp(center.lng, this.minLng, this.maxLng);
	            this.center = center;
	            this._constraining = false;
	            return;
	        }
	        const unmodified = this._unmodified;
	        const {x, y} = this.point;
	        let s = 0;
	        let x2 = x;
	        let y2 = y;
	        const w2 = this.width / 2;
	        const h2 = this.height / 2;
	        const minY = this.worldMinY * this.scale;
	        const maxY = this.worldMaxY * this.scale;
	        if (y - h2 < minY)
	            y2 = minY + h2;
	        if (y + h2 > maxY)
	            y2 = maxY - h2;
	        if (maxY - minY < this.height) {
	            s = Math.max(s, this.height / (maxY - minY));
	            y2 = (maxY + minY) / 2;
	        }
	        if (this.maxBounds || !this._renderWorldCopies || !this.projection.wrap) {
	            const minX = this.worldMinX * this.scale;
	            const maxX = this.worldMaxX * this.scale;
	            const shift = this.worldSize / 2 - (minX + maxX) / 2;
	            x2 = (x + shift + this.worldSize) % this.worldSize - shift;
	            if (x2 - w2 < minX)
	                x2 = minX + w2;
	            if (x2 + w2 > maxX)
	                x2 = maxX - w2;
	            if (maxX - minX < this.width) {
	                s = Math.max(s, this.width / (maxX - minX));
	                x2 = (maxX + minX) / 2;
	            }
	        }
	        if (x2 !== x || y2 !== y) {
	            this.center = this.unproject(new ref_properties.pointGeometry(x2, y2));
	        }
	        if (s) {
	            this.zoom += this.scaleZoom(s);
	        }
	        this._constrainCameraAltitude();
	        this._unmodified = unmodified;
	        this._constraining = false;
	    }
	    _minZoomForBounds() {
	        let minZoom = Math.max(0, this.scaleZoom(this.height / (this.worldMaxY - this.worldMinY)));
	        if (this.maxBounds) {
	            minZoom = Math.max(minZoom, this.scaleZoom(this.width / (this.worldMaxX - this.worldMinX)));
	        }
	        return minZoom;
	    }
	    _maxCameraBoundsDistance() {
	        return this._mercatorZfromZoom(this._minZoomForBounds());
	    }
	    _calcMatrices() {
	        if (!this.height)
	            return;
	        const offset = this.centerOffset;
	        const pixelsPerMeter = this.pixelsPerMeter;
	        if (this.projection.name === 'globe') {
	            const centerScale = ref_properties.mercatorZfromAltitude(1, this.center.lat) * this.worldSize;
	            const refScale = ref_properties.mercatorZfromAltitude(1, ref_properties.GLOBE_SCALE_MATCH_LATITUDE) * this.worldSize;
	            this._mercatorScaleRatio = centerScale / refScale;
	        }
	        const projectionT = getProjectionInterpolationT(this.projection, this.zoom, this.width, this.height, 1024);
	        this._projectionScaler = this.projection.pixelSpaceConversion(this.center.lat, this.worldSize, projectionT);
	        this.cameraToCenterDistance = this.getCameraToCenterDistance(this.projection);
	        this._updateCameraState();
	        this._farZ = this.projection.farthestPixelDistance(this);
	        this._nearZ = this.height / 50;
	        const zUnit = this.projection.zAxisUnit === 'meters' ? pixelsPerMeter : 1;
	        const worldToCamera = this._camera.getWorldToCamera(this.worldSize, zUnit);
	        const cameraToClip = this._camera.getCameraToClipPerspective(this._fov, this.width / this.height, this._nearZ, this._farZ);
	        cameraToClip[8] = -offset.x * 2 / this.width;
	        cameraToClip[9] = offset.y * 2 / this.height;
	        let m = ref_properties.mul([], cameraToClip, worldToCamera);
	        if (this.projection.isReprojectedInTileSpace) {
	            const mc = this.locationCoordinate(this.center);
	            const adjustments = ref_properties.identity([]);
	            ref_properties.translate(adjustments, adjustments, [
	                mc.x * this.worldSize,
	                mc.y * this.worldSize,
	                0
	            ]);
	            ref_properties.multiply(adjustments, adjustments, getProjectionAdjustments(this));
	            ref_properties.translate(adjustments, adjustments, [
	                -mc.x * this.worldSize,
	                -mc.y * this.worldSize,
	                0
	            ]);
	            ref_properties.multiply(m, m, adjustments);
	            this.inverseAdjustmentMatrix = getProjectionAdjustmentInverted(this);
	        } else {
	            this.inverseAdjustmentMatrix = [
	                1,
	                0,
	                0,
	                1
	            ];
	        }
	        this.mercatorMatrix = ref_properties.scale([], m, [
	            this.worldSize,
	            this.worldSize,
	            this.worldSize / pixelsPerMeter,
	            1
	        ]);
	        this.projMatrix = m;
	        this.invProjMatrix = ref_properties.invert(new Float64Array(16), this.projMatrix);
	        const clipToCamera = ref_properties.invert([], cameraToClip);
	        this.frustumCorners = ref_properties.FrustumCorners.fromInvProjectionMatrix(clipToCamera, this.horizonLineFromTop(), this.height);
	        const view = new Float32Array(16);
	        ref_properties.identity(view);
	        ref_properties.scale(view, view, [
	            1,
	            -1,
	            1
	        ]);
	        ref_properties.rotateX(view, view, this._pitch);
	        ref_properties.rotateZ(view, view, this.angle);
	        const projection = ref_properties.perspective(new Float32Array(16), this._fov, this.width / this.height, this._nearZ, this._farZ);
	        const skyboxHorizonShift = (Math.PI / 2 - this._pitch) * (this.height / this._fov) * this._horizonShift;
	        projection[8] = -offset.x * 2 / this.width;
	        projection[9] = (offset.y + skyboxHorizonShift) * 2 / this.height;
	        this.skyboxMatrix = ref_properties.multiply(view, projection, view);
	        const point = this.point;
	        const x = point.x, y = point.y;
	        const xShift = this.width % 2 / 2, yShift = this.height % 2 / 2, angleCos = Math.cos(this.angle), angleSin = Math.sin(this.angle), dx = x - Math.round(x) + angleCos * xShift + angleSin * yShift, dy = y - Math.round(y) + angleCos * yShift + angleSin * xShift;
	        const alignedM = new Float64Array(m);
	        ref_properties.translate(alignedM, alignedM, [
	            dx > 0.5 ? dx - 1 : dx,
	            dy > 0.5 ? dy - 1 : dy,
	            0
	        ]);
	        this.alignedProjMatrix = alignedM;
	        m = ref_properties.create();
	        ref_properties.scale(m, m, [
	            this.width / 2,
	            -this.height / 2,
	            1
	        ]);
	        ref_properties.translate(m, m, [
	            1,
	            -1,
	            0
	        ]);
	        this.labelPlaneMatrix = m;
	        m = ref_properties.create();
	        ref_properties.scale(m, m, [
	            1,
	            -1,
	            1
	        ]);
	        ref_properties.translate(m, m, [
	            -1,
	            -1,
	            0
	        ]);
	        ref_properties.scale(m, m, [
	            2 / this.width,
	            2 / this.height,
	            1
	        ]);
	        this.glCoordMatrix = m;
	        this.pixelMatrix = ref_properties.multiply(new Float64Array(16), this.labelPlaneMatrix, this.projMatrix);
	        this._calcFogMatrices();
	        this._distanceTileDataCache = {};
	        m = ref_properties.invert(new Float64Array(16), this.pixelMatrix);
	        if (!m)
	            throw new Error('failed to invert matrix');
	        this.pixelMatrixInverse = m;
	        if (this.projection.name === 'globe' || this.mercatorFromTransition) {
	            this.globeMatrix = ref_properties.calculateGlobeMatrix(this);
	            const globeCenter = [
	                this.globeMatrix[12],
	                this.globeMatrix[13],
	                this.globeMatrix[14]
	            ];
	            this.globeCenterInViewSpace = ref_properties.transformMat4(globeCenter, globeCenter, worldToCamera);
	            this.globeRadius = this.worldSize / 2 / Math.PI - 1;
	        } else {
	            this.globeMatrix = m;
	        }
	        this._projMatrixCache = {};
	        this._alignedProjMatrixCache = {};
	        this._pixelsToTileUnitsCache = {};
	    }
	    _calcFogMatrices() {
	        this._fogTileMatrixCache = {};
	        const cameraWorldSize = this.cameraWorldSize;
	        const cameraPixelsPerMeter = this.cameraPixelsPerMeter;
	        const cameraPos = this._camera.position;
	        const windowScaleFactor = 1 / this.height / this._projectionScaler;
	        const metersToPixel = [
	            cameraWorldSize,
	            cameraWorldSize,
	            cameraPixelsPerMeter
	        ];
	        ref_properties.scale$2(metersToPixel, metersToPixel, windowScaleFactor);
	        ref_properties.scale$2(cameraPos, cameraPos, -1);
	        ref_properties.multiply$2(cameraPos, cameraPos, metersToPixel);
	        const m = ref_properties.create();
	        ref_properties.translate(m, m, cameraPos);
	        ref_properties.scale(m, m, metersToPixel);
	        this.mercatorFogMatrix = m;
	        this.worldToFogMatrix = this._camera.getWorldToCameraPosition(cameraWorldSize, cameraPixelsPerMeter, windowScaleFactor);
	    }
	    _computeCameraPosition(targetPixelsPerMeter) {
	        targetPixelsPerMeter = targetPixelsPerMeter || this.pixelsPerMeter;
	        const pixelSpaceConversion = targetPixelsPerMeter / this.pixelsPerMeter;
	        const dir = this._camera.forward();
	        const center = this.point;
	        const zoom = this._seaLevelZoom ? this._seaLevelZoom : this._zoom;
	        const altitude = this._mercatorZfromZoom(zoom) * pixelSpaceConversion;
	        const distance = altitude - targetPixelsPerMeter / this.worldSize * this._centerAltitude;
	        return [
	            center.x / this.worldSize - dir[0] * distance,
	            center.y / this.worldSize - dir[1] * distance,
	            targetPixelsPerMeter / this.worldSize * this._centerAltitude - dir[2] * distance
	        ];
	    }
	    _updateCameraState() {
	        if (!this.height)
	            return;
	        this._camera.setPitchBearing(this._pitch, this.angle);
	        this._camera.position = this._computeCameraPosition();
	    }
	    _translateCameraConstrained(translation) {
	        const maxDistance = this._maxCameraBoundsDistance();
	        const maxZ = maxDistance * Math.cos(this._pitch);
	        const z = this._camera.position[2];
	        const deltaZ = translation[2];
	        let t = 1;
	        if (deltaZ > 0) {
	            t = Math.min((maxZ - z) / deltaZ, 1);
	        }
	        this._camera.position = ref_properties.scaleAndAdd([], this._camera.position, translation, t);
	        this._updateStateFromCamera();
	        if (this.projection.wrap)
	            this.center = this.center.wrap();
	    }
	    _updateStateFromCamera() {
	        const position = this._camera.position;
	        const dir = this._camera.forward();
	        const {pitch, bearing} = this._camera.getPitchBearing();
	        const centerAltitude = ref_properties.mercatorZfromAltitude(this._centerAltitude, this.center.lat) * this._projectionScaler;
	        const minHeight = this._mercatorZfromZoom(this._maxZoom) * Math.cos(ref_properties.degToRad(this._maxPitch));
	        const height = Math.max((position[2] - centerAltitude) / Math.cos(pitch), minHeight);
	        const zoom = this._zoomFromMercatorZ(height);
	        ref_properties.scaleAndAdd(position, position, dir, height);
	        this._pitch = ref_properties.clamp(pitch, ref_properties.degToRad(this.minPitch), ref_properties.degToRad(this.maxPitch));
	        this.angle = ref_properties.wrap(bearing, -Math.PI, Math.PI);
	        this._setZoom(ref_properties.clamp(zoom, this._minZoom, this._maxZoom));
	        this._updateSeaLevelZoom();
	        this._center = this.coordinateLocation(new ref_properties.MercatorCoordinate(position[0], position[1], position[2]));
	        this._unmodified = false;
	        this._constrain();
	        this._calcMatrices();
	    }
	    _worldSizeFromZoom(zoom) {
	        return Math.pow(2, zoom) * this.tileSize;
	    }
	    _mercatorZfromZoom(zoom) {
	        return this.cameraToCenterDistance / this._worldSizeFromZoom(zoom);
	    }
	    _minimumHeightOverTerrain() {
	        const MAX_DRAPE_OVERZOOM = 2;
	        const zoom = Math.min((this._seaLevelZoom != null ? this._seaLevelZoom : this._zoom) + MAX_DRAPE_OVERZOOM, this._maxZoom);
	        return this._mercatorZfromZoom(zoom);
	    }
	    _zoomFromMercatorZ(z) {
	        return this.scaleZoom(this.cameraToCenterDistance / (z * this.tileSize));
	    }
	    _terrainEnabled() {
	        if (!this._elevation)
	            return false;
	        if (!this.projection.supportsTerrain) {
	            ref_properties.warnOnce('Terrain is not yet supported with alternate projections. Use mercator or globe to enable terrain.');
	            return false;
	        }
	        return true;
	    }
	    anyCornerOffEdge(p0, p1) {
	        const minX = Math.min(p0.x, p1.x);
	        const maxX = Math.max(p0.x, p1.x);
	        const minY = Math.min(p0.y, p1.y);
	        const maxY = Math.max(p0.y, p1.y);
	        const horizon = this.horizonLineFromTop(false);
	        if (minY < horizon)
	            return true;
	        if (this.projection.name !== 'mercator') {
	            return false;
	        }
	        const min = new ref_properties.pointGeometry(minX, minY);
	        const max = new ref_properties.pointGeometry(maxX, maxY);
	        const corners = [
	            min,
	            max,
	            new ref_properties.pointGeometry(minX, maxY),
	            new ref_properties.pointGeometry(maxX, minY)
	        ];
	        const minWX = this.renderWorldCopies ? -NUM_WORLD_COPIES : 0;
	        const maxWX = this.renderWorldCopies ? 1 + NUM_WORLD_COPIES : 1;
	        const minWY = 0;
	        const maxWY = 1;
	        for (const corner of corners) {
	            const rayIntersection = this.pointRayIntersection(corner);
	            if (rayIntersection.t < 0) {
	                return true;
	            }
	            const coordinate = this.rayIntersectionCoordinate(rayIntersection);
	            if (coordinate.x < minWX || coordinate.y < minWY || coordinate.x > maxWX || coordinate.y > maxWY) {
	                return true;
	            }
	        }
	        return false;
	    }
	    isHorizonVisible() {
	        const horizonAngleEpsilon = 2;
	        if (this.pitch + ref_properties.radToDeg(this.fovAboveCenter) > 90 - horizonAngleEpsilon) {
	            return true;
	        }
	        return this.anyCornerOffEdge(new ref_properties.pointGeometry(0, 0), new ref_properties.pointGeometry(this.width, this.height));
	    }
	    zoomDeltaToMovement(center, zoomDelta) {
	        const distance = ref_properties.length(ref_properties.sub([], this._camera.position, center));
	        const relativeZoom = this._zoomFromMercatorZ(distance) + zoomDelta;
	        return distance - this._mercatorZfromZoom(relativeZoom);
	    }
	    getCameraPoint() {
	        if (this.projection.name === 'globe') {
	            const center = [
	                this.globeMatrix[12],
	                this.globeMatrix[13],
	                this.globeMatrix[14]
	            ];
	            const pos = projectClamped(center, this.pixelMatrix);
	            return new ref_properties.pointGeometry(pos[0], pos[1]);
	        } else {
	            const pitch = this._pitch;
	            const yOffset = Math.tan(pitch) * (this.cameraToCenterDistance || 1);
	            return this.centerPoint.add(new ref_properties.pointGeometry(0, yOffset));
	        }
	    }
	    getCameraToCenterDistance(projection) {
	        const t = getProjectionInterpolationT(projection, this.zoom, this.width, this.height, 1024);
	        const projectionScaler = projection.pixelSpaceConversion(this.center.lat, this.worldSize, t);
	        return 0.5 / Math.tan(this._fov * 0.5) * this.height * projectionScaler;
	    }
	}

	function throttle(fn, time) {
	    let pending = false;
	    let timerId = null;
	    const later = () => {
	        timerId = null;
	        if (pending) {
	            fn();
	            timerId = setTimeout(later, time);
	            pending = false;
	        }
	    };
	    return () => {
	        pending = true;
	        if (!timerId) {
	            later();
	        }
	        return timerId;
	    };
	}

	class Hash {
	    constructor(hashName) {
	        this._hashName = hashName && encodeURIComponent(hashName);
	        ref_properties.bindAll([
	            '_getCurrentHash',
	            '_onHashChange',
	            '_updateHash'
	        ], this);
	        this._updateHash = throttle(this._updateHashUnthrottled.bind(this), 30 * 1000 / 100);
	    }
	    addTo(map) {
	        this._map = map;
	        ref_properties.window.addEventListener('hashchange', this._onHashChange, false);
	        map.on('moveend', this._updateHash);
	        return this;
	    }
	    remove() {
	        if (!this._map)
	            return this;
	        this._map.off('moveend', this._updateHash);
	        ref_properties.window.removeEventListener('hashchange', this._onHashChange, false);
	        clearTimeout(this._updateHash());
	        this._map = undefined;
	        return this;
	    }
	    getHashString(mapFeedback) {
	        const map = this._map;
	        if (!map)
	            return '';
	        const center = map.getCenter(), zoom = Math.round(map.getZoom() * 100) / 100, precision = Math.ceil((zoom * Math.LN2 + Math.log(512 / 360 / 0.5)) / Math.LN10), m = Math.pow(10, precision), lng = Math.round(center.lng * m) / m, lat = Math.round(center.lat * m) / m, bearing = map.getBearing(), pitch = map.getPitch();
	        let hash = '';
	        if (mapFeedback) {
	            hash += `/${ lng }/${ lat }/${ zoom }`;
	        } else {
	            hash += `${ zoom }/${ lat }/${ lng }`;
	        }
	        if (bearing || pitch)
	            hash += `/${ Math.round(bearing * 10) / 10 }`;
	        if (pitch)
	            hash += `/${ Math.round(pitch) }`;
	        if (this._hashName) {
	            const hashName = this._hashName;
	            let found = false;
	            const parts = ref_properties.window.location.hash.slice(1).split('&').map(part => {
	                const key = part.split('=')[0];
	                if (key === hashName) {
	                    found = true;
	                    return `${ key }=${ hash }`;
	                }
	                return part;
	            }).filter(a => a);
	            if (!found) {
	                parts.push(`${ hashName }=${ hash }`);
	            }
	            return `#${ parts.join('&') }`;
	        }
	        return `#${ hash }`;
	    }
	    _getCurrentHash() {
	        const hash = ref_properties.window.location.hash.replace('#', '');
	        if (this._hashName) {
	            let keyval;
	            hash.split('&').map(part => part.split('=')).forEach(part => {
	                if (part[0] === this._hashName) {
	                    keyval = part;
	                }
	            });
	            return (keyval ? keyval[1] || '' : '').split('/');
	        }
	        return hash.split('/');
	    }
	    _onHashChange() {
	        const map = this._map;
	        if (!map)
	            return false;
	        const loc = this._getCurrentHash();
	        if (loc.length >= 3 && !loc.some(v => isNaN(v))) {
	            const bearing = map.dragRotate.isEnabled() && map.touchZoomRotate.isEnabled() ? +(loc[3] || 0) : map.getBearing();
	            map.jumpTo({
	                center: [
	                    +loc[2],
	                    +loc[1]
	                ],
	                zoom: +loc[0],
	                bearing,
	                pitch: +(loc[4] || 0)
	            });
	            return true;
	        }
	        return false;
	    }
	    _updateHashUnthrottled() {
	        const location = ref_properties.window.location.href.replace(/(#.+)?$/, this.getHashString());
	        ref_properties.window.history.replaceState(ref_properties.window.history.state, null, location);
	    }
	}

	const defaultInertiaOptions = {
	    linearity: 0.3,
	    easing: ref_properties.bezier(0, 0, 0.3, 1)
	};
	const defaultPanInertiaOptions = ref_properties.extend({
	    deceleration: 2500,
	    maxSpeed: 1400
	}, defaultInertiaOptions);
	const defaultZoomInertiaOptions = ref_properties.extend({
	    deceleration: 20,
	    maxSpeed: 1400
	}, defaultInertiaOptions);
	const defaultBearingInertiaOptions = ref_properties.extend({
	    deceleration: 1000,
	    maxSpeed: 360
	}, defaultInertiaOptions);
	const defaultPitchInertiaOptions = ref_properties.extend({
	    deceleration: 1000,
	    maxSpeed: 90
	}, defaultInertiaOptions);
	class HandlerInertia {
	    constructor(map) {
	        this._map = map;
	        this.clear();
	    }
	    clear() {
	        this._inertiaBuffer = [];
	    }
	    record(settings) {
	        this._drainInertiaBuffer();
	        this._inertiaBuffer.push({
	            time: ref_properties.exported.now(),
	            settings
	        });
	    }
	    _drainInertiaBuffer() {
	        const inertia = this._inertiaBuffer, now = ref_properties.exported.now(), cutoff = 160;
	        while (inertia.length > 0 && now - inertia[0].time > cutoff)
	            inertia.shift();
	    }
	    _onMoveEnd(panInertiaOptions) {
	        this._drainInertiaBuffer();
	        if (this._inertiaBuffer.length < 2) {
	            return;
	        }
	        const deltas = {
	            zoom: 0,
	            bearing: 0,
	            pitch: 0,
	            pan: new ref_properties.pointGeometry(0, 0),
	            pinchAround: undefined,
	            around: undefined
	        };
	        for (const {settings} of this._inertiaBuffer) {
	            deltas.zoom += settings.zoomDelta || 0;
	            deltas.bearing += settings.bearingDelta || 0;
	            deltas.pitch += settings.pitchDelta || 0;
	            if (settings.panDelta)
	                deltas.pan._add(settings.panDelta);
	            if (settings.around)
	                deltas.around = settings.around;
	            if (settings.pinchAround)
	                deltas.pinchAround = settings.pinchAround;
	        }
	        const lastEntry = this._inertiaBuffer[this._inertiaBuffer.length - 1];
	        const duration = lastEntry.time - this._inertiaBuffer[0].time;
	        const easeOptions = {};
	        if (deltas.pan.mag()) {
	            const result = calculateEasing(deltas.pan.mag(), duration, ref_properties.extend({}, defaultPanInertiaOptions, panInertiaOptions || {}));
	            easeOptions.offset = deltas.pan.mult(result.amount / deltas.pan.mag());
	            easeOptions.center = this._map.transform.center;
	            extendDuration(easeOptions, result);
	        }
	        if (deltas.zoom) {
	            const result = calculateEasing(deltas.zoom, duration, defaultZoomInertiaOptions);
	            easeOptions.zoom = this._map.transform.zoom + result.amount;
	            extendDuration(easeOptions, result);
	        }
	        if (deltas.bearing) {
	            const result = calculateEasing(deltas.bearing, duration, defaultBearingInertiaOptions);
	            easeOptions.bearing = this._map.transform.bearing + ref_properties.clamp(result.amount, -179, 179);
	            extendDuration(easeOptions, result);
	        }
	        if (deltas.pitch) {
	            const result = calculateEasing(deltas.pitch, duration, defaultPitchInertiaOptions);
	            easeOptions.pitch = this._map.transform.pitch + result.amount;
	            extendDuration(easeOptions, result);
	        }
	        if (easeOptions.zoom || easeOptions.bearing) {
	            const last = deltas.pinchAround === undefined ? deltas.around : deltas.pinchAround;
	            easeOptions.around = last ? this._map.unproject(last) : this._map.getCenter();
	        }
	        this.clear();
	        easeOptions.noMoveStart = true;
	        return easeOptions;
	    }
	}
	function extendDuration(easeOptions, result) {
	    if (!easeOptions.duration || easeOptions.duration < result.duration) {
	        easeOptions.duration = result.duration;
	        easeOptions.easing = result.easing;
	    }
	}
	function calculateEasing(amount, inertiaDuration, inertiaOptions) {
	    const {maxSpeed, linearity, deceleration} = inertiaOptions;
	    const speed = ref_properties.clamp(amount * linearity / (inertiaDuration / 1000), -maxSpeed, maxSpeed);
	    const duration = Math.abs(speed) / (deceleration * linearity);
	    return {
	        easing: inertiaOptions.easing,
	        duration: duration * 1000,
	        amount: speed * (duration / 2)
	    };
	}

	class MapMouseEvent extends ref_properties.Event {
	    preventDefault() {
	        this._defaultPrevented = true;
	    }
	    get defaultPrevented() {
	        return this._defaultPrevented;
	    }
	    constructor(type, map, originalEvent, data = {}) {
	        const point = mousePos(map.getCanvasContainer(), originalEvent);
	        const lngLat = map.unproject(point);
	        super(type, ref_properties.extend({
	            point,
	            lngLat,
	            originalEvent
	        }, data));
	        this._defaultPrevented = false;
	        this.target = map;
	    }
	}
	class MapTouchEvent extends ref_properties.Event {
	    preventDefault() {
	        this._defaultPrevented = true;
	    }
	    get defaultPrevented() {
	        return this._defaultPrevented;
	    }
	    constructor(type, map, originalEvent) {
	        const touches = type === 'touchend' ? originalEvent.changedTouches : originalEvent.touches;
	        const points = touchPos(map.getCanvasContainer(), touches);
	        const lngLats = points.map(t => map.unproject(t));
	        const point = points.reduce((prev, curr, i, arr) => {
	            return prev.add(curr.div(arr.length));
	        }, new ref_properties.pointGeometry(0, 0));
	        const lngLat = map.unproject(point);
	        super(type, {
	            points,
	            point,
	            lngLats,
	            lngLat,
	            originalEvent
	        });
	        this._defaultPrevented = false;
	    }
	}
	class MapWheelEvent extends ref_properties.Event {
	    preventDefault() {
	        this._defaultPrevented = true;
	    }
	    get defaultPrevented() {
	        return this._defaultPrevented;
	    }
	    constructor(type, map, originalEvent) {
	        super(type, { originalEvent });
	        this._defaultPrevented = false;
	    }
	}

	class MapEventHandler {
	    constructor(map, options) {
	        this._map = map;
	        this._clickTolerance = options.clickTolerance;
	    }
	    reset() {
	        this._mousedownPos = undefined;
	    }
	    wheel(e) {
	        return this._firePreventable(new MapWheelEvent(e.type, this._map, e));
	    }
	    mousedown(e, point) {
	        this._mousedownPos = point;
	        return this._firePreventable(new MapMouseEvent(e.type, this._map, e));
	    }
	    mouseup(e) {
	        this._map.fire(new MapMouseEvent(e.type, this._map, e));
	    }
	    preclick(e) {
	        const synth = ref_properties.extend({}, e);
	        synth.type = 'preclick';
	        this._map.fire(new MapMouseEvent(synth.type, this._map, synth));
	    }
	    click(e, point) {
	        if (this._mousedownPos && this._mousedownPos.dist(point) >= this._clickTolerance)
	            return;
	        this.preclick(e);
	        this._map.fire(new MapMouseEvent(e.type, this._map, e));
	    }
	    dblclick(e) {
	        return this._firePreventable(new MapMouseEvent(e.type, this._map, e));
	    }
	    mouseover(e) {
	        this._map.fire(new MapMouseEvent(e.type, this._map, e));
	    }
	    mouseout(e) {
	        this._map.fire(new MapMouseEvent(e.type, this._map, e));
	    }
	    touchstart(e) {
	        return this._firePreventable(new MapTouchEvent(e.type, this._map, e));
	    }
	    touchmove(e) {
	        this._map.fire(new MapTouchEvent(e.type, this._map, e));
	    }
	    touchend(e) {
	        this._map.fire(new MapTouchEvent(e.type, this._map, e));
	    }
	    touchcancel(e) {
	        this._map.fire(new MapTouchEvent(e.type, this._map, e));
	    }
	    _firePreventable(mapEvent) {
	        this._map.fire(mapEvent);
	        if (mapEvent.defaultPrevented) {
	            return {};
	        }
	    }
	    isEnabled() {
	        return true;
	    }
	    isActive() {
	        return false;
	    }
	    enable() {
	    }
	    disable() {
	    }
	}
	class BlockableMapEventHandler {
	    constructor(map) {
	        this._map = map;
	    }
	    reset() {
	        this._delayContextMenu = false;
	        this._contextMenuEvent = undefined;
	    }
	    mousemove(e) {
	        this._map.fire(new MapMouseEvent(e.type, this._map, e));
	    }
	    mousedown() {
	        this._delayContextMenu = true;
	    }
	    mouseup() {
	        this._delayContextMenu = false;
	        if (this._contextMenuEvent) {
	            this._map.fire(new MapMouseEvent('contextmenu', this._map, this._contextMenuEvent));
	            delete this._contextMenuEvent;
	        }
	    }
	    contextmenu(e) {
	        if (this._delayContextMenu) {
	            this._contextMenuEvent = e;
	        } else {
	            this._map.fire(new MapMouseEvent(e.type, this._map, e));
	        }
	        if (this._map.listens('contextmenu')) {
	            e.preventDefault();
	        }
	    }
	    isEnabled() {
	        return true;
	    }
	    isActive() {
	        return false;
	    }
	    enable() {
	    }
	    disable() {
	    }
	}

	class BoxZoomHandler {
	    constructor(map, options) {
	        this._map = map;
	        this._el = map.getCanvasContainer();
	        this._container = map.getContainer();
	        this._clickTolerance = options.clickTolerance || 1;
	    }
	    isEnabled() {
	        return !!this._enabled;
	    }
	    isActive() {
	        return !!this._active;
	    }
	    enable() {
	        if (this.isEnabled())
	            return;
	        this._enabled = true;
	    }
	    disable() {
	        if (!this.isEnabled())
	            return;
	        this._enabled = false;
	    }
	    mousedown(e, point) {
	        if (!this.isEnabled())
	            return;
	        if (!(e.shiftKey && e.button === 0))
	            return;
	        disableDrag();
	        this._startPos = this._lastPos = point;
	        this._active = true;
	    }
	    mousemoveWindow(e, point) {
	        if (!this._active)
	            return;
	        const pos = point;
	        if (this._lastPos.equals(pos) || !this._box && pos.dist(this._startPos) < this._clickTolerance) {
	            return;
	        }
	        const p0 = this._startPos;
	        this._lastPos = pos;
	        if (!this._box) {
	            this._box = create$2('div', 'mapboxgl-boxzoom', this._container);
	            this._container.classList.add('mapboxgl-crosshair');
	            this._fireEvent('boxzoomstart', e);
	        }
	        const minX = Math.min(p0.x, pos.x), maxX = Math.max(p0.x, pos.x), minY = Math.min(p0.y, pos.y), maxY = Math.max(p0.y, pos.y);
	        this._map._requestDomTask(() => {
	            if (this._box) {
	                this._box.style.transform = `translate(${ minX }px,${ minY }px)`;
	                this._box.style.width = `${ maxX - minX }px`;
	                this._box.style.height = `${ maxY - minY }px`;
	            }
	        });
	    }
	    mouseupWindow(e, point) {
	        if (!this._active)
	            return;
	        if (e.button !== 0)
	            return;
	        const p0 = this._startPos, p1 = point;
	        this.reset();
	        suppressClick();
	        if (p0.x === p1.x && p0.y === p1.y) {
	            this._fireEvent('boxzoomcancel', e);
	        } else {
	            this._map.fire(new ref_properties.Event('boxzoomend', { originalEvent: e }));
	            return { cameraAnimation: map => map.fitScreenCoordinates(p0, p1, this._map.getBearing(), { linear: false }) };
	        }
	    }
	    keydown(e) {
	        if (!this._active)
	            return;
	        if (e.keyCode === 27) {
	            this.reset();
	            this._fireEvent('boxzoomcancel', e);
	        }
	    }
	    blur() {
	        this.reset();
	    }
	    reset() {
	        this._active = false;
	        this._container.classList.remove('mapboxgl-crosshair');
	        if (this._box) {
	            this._box.remove();
	            this._box = null;
	        }
	        enableDrag();
	        delete this._startPos;
	        delete this._lastPos;
	    }
	    _fireEvent(type, e) {
	        return this._map.fire(new ref_properties.Event(type, { originalEvent: e }));
	    }
	}

	function indexTouches(touches, points) {
	    const obj = {};
	    for (let i = 0; i < touches.length; i++) {
	        obj[touches[i].identifier] = points[i];
	    }
	    return obj;
	}

	function getCentroid(points) {
	    const sum = new ref_properties.pointGeometry(0, 0);
	    for (const point of points) {
	        sum._add(point);
	    }
	    return sum.div(points.length);
	}
	const MAX_TAP_INTERVAL = 500;
	const MAX_TOUCH_TIME = 500;
	const MAX_DIST = 30;
	class SingleTapRecognizer {
	    constructor(options) {
	        this.reset();
	        this.numTouches = options.numTouches;
	    }
	    reset() {
	        this.centroid = undefined;
	        this.startTime = 0;
	        this.touches = {};
	        this.aborted = false;
	    }
	    touchstart(e, points, mapTouches) {
	        if (this.centroid || mapTouches.length > this.numTouches) {
	            this.aborted = true;
	        }
	        if (this.aborted) {
	            return;
	        }
	        if (this.startTime === 0) {
	            this.startTime = e.timeStamp;
	        }
	        if (mapTouches.length === this.numTouches) {
	            this.centroid = getCentroid(points);
	            this.touches = indexTouches(mapTouches, points);
	        }
	    }
	    touchmove(e, points, mapTouches) {
	        if (this.aborted || !this.centroid)
	            return;
	        const newTouches = indexTouches(mapTouches, points);
	        for (const id in this.touches) {
	            const prevPos = this.touches[id];
	            const pos = newTouches[id];
	            if (!pos || pos.dist(prevPos) > MAX_DIST) {
	                this.aborted = true;
	            }
	        }
	    }
	    touchend(e, points, mapTouches) {
	        if (!this.centroid || e.timeStamp - this.startTime > MAX_TOUCH_TIME) {
	            this.aborted = true;
	        }
	        if (mapTouches.length === 0) {
	            const centroid = !this.aborted && this.centroid;
	            this.reset();
	            if (centroid)
	                return centroid;
	        }
	    }
	}
	class TapRecognizer {
	    constructor(options) {
	        this.singleTap = new SingleTapRecognizer(options);
	        this.numTaps = options.numTaps;
	        this.reset();
	    }
	    reset() {
	        this.lastTime = Infinity;
	        this.lastTap = undefined;
	        this.count = 0;
	        this.singleTap.reset();
	    }
	    touchstart(e, points, mapTouches) {
	        this.singleTap.touchstart(e, points, mapTouches);
	    }
	    touchmove(e, points, mapTouches) {
	        this.singleTap.touchmove(e, points, mapTouches);
	    }
	    touchend(e, points, mapTouches) {
	        const tap = this.singleTap.touchend(e, points, mapTouches);
	        if (tap) {
	            const soonEnough = e.timeStamp - this.lastTime < MAX_TAP_INTERVAL;
	            const closeEnough = !this.lastTap || this.lastTap.dist(tap) < MAX_DIST;
	            if (!soonEnough || !closeEnough) {
	                this.reset();
	            }
	            this.count++;
	            this.lastTime = e.timeStamp;
	            this.lastTap = tap;
	            if (this.count === this.numTaps) {
	                this.reset();
	                return tap;
	            }
	        }
	    }
	}

	class TapZoomHandler {
	    constructor() {
	        this._zoomIn = new TapRecognizer({
	            numTouches: 1,
	            numTaps: 2
	        });
	        this._zoomOut = new TapRecognizer({
	            numTouches: 2,
	            numTaps: 1
	        });
	        this.reset();
	    }
	    reset() {
	        this._active = false;
	        this._zoomIn.reset();
	        this._zoomOut.reset();
	    }
	    touchstart(e, points, mapTouches) {
	        this._zoomIn.touchstart(e, points, mapTouches);
	        this._zoomOut.touchstart(e, points, mapTouches);
	    }
	    touchmove(e, points, mapTouches) {
	        this._zoomIn.touchmove(e, points, mapTouches);
	        this._zoomOut.touchmove(e, points, mapTouches);
	    }
	    touchend(e, points, mapTouches) {
	        const zoomInPoint = this._zoomIn.touchend(e, points, mapTouches);
	        const zoomOutPoint = this._zoomOut.touchend(e, points, mapTouches);
	        if (zoomInPoint) {
	            this._active = true;
	            e.preventDefault();
	            setTimeout(() => this.reset(), 0);
	            return {
	                cameraAnimation: map => map.easeTo({
	                    duration: 300,
	                    zoom: map.getZoom() + 1,
	                    around: map.unproject(zoomInPoint)
	                }, { originalEvent: e })
	            };
	        } else if (zoomOutPoint) {
	            this._active = true;
	            e.preventDefault();
	            setTimeout(() => this.reset(), 0);
	            return {
	                cameraAnimation: map => map.easeTo({
	                    duration: 300,
	                    zoom: map.getZoom() - 1,
	                    around: map.unproject(zoomOutPoint)
	                }, { originalEvent: e })
	            };
	        }
	    }
	    touchcancel() {
	        this.reset();
	    }
	    enable() {
	        this._enabled = true;
	    }
	    disable() {
	        this._enabled = false;
	        this.reset();
	    }
	    isEnabled() {
	        return this._enabled;
	    }
	    isActive() {
	        return this._active;
	    }
	}

	const LEFT_BUTTON = 0;
	const RIGHT_BUTTON = 2;
	const BUTTONS_FLAGS = {
	    [LEFT_BUTTON]: 1,
	    [RIGHT_BUTTON]: 2
	};
	function buttonStillPressed(e, button) {
	    const flag = BUTTONS_FLAGS[button];
	    return e.buttons === undefined || (e.buttons & flag) !== flag;
	}
	class MouseHandler {
	    constructor(options) {
	        this.reset();
	        this._clickTolerance = options.clickTolerance || 1;
	    }
	    blur() {
	        this.reset();
	    }
	    reset() {
	        this._active = false;
	        this._moved = false;
	        this._lastPoint = undefined;
	        this._eventButton = undefined;
	    }
	    _correctButton(e, button) {
	        return false;
	    }
	    _move(lastPoint, point) {
	        return {};
	    }
	    mousedown(e, point) {
	        if (this._lastPoint)
	            return;
	        const eventButton = mouseButton(e);
	        if (!this._correctButton(e, eventButton))
	            return;
	        this._lastPoint = point;
	        this._eventButton = eventButton;
	    }
	    mousemoveWindow(e, point) {
	        const lastPoint = this._lastPoint;
	        if (!lastPoint)
	            return;
	        e.preventDefault();
	        if (this._eventButton != null && buttonStillPressed(e, this._eventButton)) {
	            this.reset();
	            return;
	        }
	        if (!this._moved && point.dist(lastPoint) < this._clickTolerance)
	            return;
	        this._moved = true;
	        this._lastPoint = point;
	        return this._move(lastPoint, point);
	    }
	    mouseupWindow(e) {
	        if (!this._lastPoint)
	            return;
	        const eventButton = mouseButton(e);
	        if (eventButton !== this._eventButton)
	            return;
	        if (this._moved)
	            suppressClick();
	        this.reset();
	    }
	    enable() {
	        this._enabled = true;
	    }
	    disable() {
	        this._enabled = false;
	        this.reset();
	    }
	    isEnabled() {
	        return this._enabled;
	    }
	    isActive() {
	        return this._active;
	    }
	}
	class MousePanHandler extends MouseHandler {
	    mousedown(e, point) {
	        super.mousedown(e, point);
	        if (this._lastPoint)
	            this._active = true;
	    }
	    _correctButton(e, button) {
	        return button === LEFT_BUTTON && !e.ctrlKey;
	    }
	    _move(lastPoint, point) {
	        return {
	            around: point,
	            panDelta: point.sub(lastPoint)
	        };
	    }
	}
	class MouseRotateHandler extends MouseHandler {
	    _correctButton(e, button) {
	        return button === LEFT_BUTTON && e.ctrlKey || button === RIGHT_BUTTON;
	    }
	    _move(lastPoint, point) {
	        const degreesPerPixelMoved = 0.8;
	        const bearingDelta = (point.x - lastPoint.x) * degreesPerPixelMoved;
	        if (bearingDelta) {
	            this._active = true;
	            return { bearingDelta };
	        }
	    }
	    contextmenu(e) {
	        e.preventDefault();
	    }
	}
	class MousePitchHandler extends MouseHandler {
	    _correctButton(e, button) {
	        return button === LEFT_BUTTON && e.ctrlKey || button === RIGHT_BUTTON;
	    }
	    _move(lastPoint, point) {
	        const degreesPerPixelMoved = -0.5;
	        const pitchDelta = (point.y - lastPoint.y) * degreesPerPixelMoved;
	        if (pitchDelta) {
	            this._active = true;
	            return { pitchDelta };
	        }
	    }
	    contextmenu(e) {
	        e.preventDefault();
	    }
	}

	class TouchPanHandler {
	    constructor(map, options) {
	        this._map = map;
	        this._el = map.getCanvasContainer();
	        this._minTouches = 1;
	        this._clickTolerance = options.clickTolerance || 1;
	        this.reset();
	        ref_properties.bindAll([
	            '_addTouchPanBlocker',
	            '_showTouchPanBlockerAlert'
	        ], this);
	    }
	    reset() {
	        this._active = false;
	        this._touches = {};
	        this._sum = new ref_properties.pointGeometry(0, 0);
	    }
	    touchstart(e, points, mapTouches) {
	        return this._calculateTransform(e, points, mapTouches);
	    }
	    touchmove(e, points, mapTouches) {
	        if (!this._active || mapTouches.length < this._minTouches)
	            return;
	        if (this._map._cooperativeGestures && !this._map.isMoving()) {
	            if (mapTouches.length === 1) {
	                this._showTouchPanBlockerAlert();
	                return;
	            } else if (this._alertContainer.style.visibility !== 'hidden') {
	                this._alertContainer.style.visibility = 'hidden';
	                clearTimeout(this._alertTimer);
	            }
	        }
	        e.preventDefault();
	        return this._calculateTransform(e, points, mapTouches);
	    }
	    touchend(e, points, mapTouches) {
	        this._calculateTransform(e, points, mapTouches);
	        if (this._active && mapTouches.length < this._minTouches) {
	            this.reset();
	        }
	    }
	    touchcancel() {
	        this.reset();
	    }
	    _calculateTransform(e, points, mapTouches) {
	        if (mapTouches.length > 0)
	            this._active = true;
	        const touches = indexTouches(mapTouches, points);
	        const touchPointSum = new ref_properties.pointGeometry(0, 0);
	        const touchDeltaSum = new ref_properties.pointGeometry(0, 0);
	        let touchDeltaCount = 0;
	        for (const identifier in touches) {
	            const point = touches[identifier];
	            const prevPoint = this._touches[identifier];
	            if (prevPoint) {
	                touchPointSum._add(point);
	                touchDeltaSum._add(point.sub(prevPoint));
	                touchDeltaCount++;
	                touches[identifier] = point;
	            }
	        }
	        this._touches = touches;
	        if (touchDeltaCount < this._minTouches || !touchDeltaSum.mag())
	            return;
	        const panDelta = touchDeltaSum.div(touchDeltaCount);
	        this._sum._add(panDelta);
	        if (this._sum.mag() < this._clickTolerance)
	            return;
	        const around = touchPointSum.div(touchDeltaCount);
	        return {
	            around,
	            panDelta
	        };
	    }
	    enable() {
	        this._enabled = true;
	        if (this._map._cooperativeGestures) {
	            this._addTouchPanBlocker();
	            this._el.classList.add('mapboxgl-touch-pan-blocker-override', 'mapboxgl-scrollable-page');
	        }
	    }
	    disable() {
	        this._enabled = false;
	        if (this._map._cooperativeGestures) {
	            clearTimeout(this._alertTimer);
	            this._alertContainer.remove();
	            this._el.classList.remove('mapboxgl-touch-pan-blocker-override', 'mapboxgl-scrollable-page');
	        }
	        this.reset();
	    }
	    isEnabled() {
	        return this._enabled;
	    }
	    isActive() {
	        return this._active;
	    }
	    _addTouchPanBlocker() {
	        if (this._map && !this._alertContainer) {
	            this._alertContainer = create$2('div', 'mapboxgl-touch-pan-blocker', this._map._container);
	            this._alertContainer.textContent = this._map._getUIString('TouchPanBlocker.Message');
	            this._alertContainer.style.fontSize = `${ Math.max(10, Math.min(24, Math.floor(this._el.clientWidth * 0.05))) }px`;
	        }
	    }
	    _showTouchPanBlockerAlert() {
	        if (this._alertContainer.style.visibility === 'hidden')
	            this._alertContainer.style.visibility = 'visible';
	        this._alertContainer.classList.add('mapboxgl-touch-pan-blocker-show');
	        clearTimeout(this._alertTimer);
	        this._alertTimer = setTimeout(() => {
	            this._alertContainer.classList.remove('mapboxgl-touch-pan-blocker-show');
	        }, 500);
	    }
	}

	class TwoTouchHandler {
	    constructor() {
	        this.reset();
	    }
	    reset() {
	        this._active = false;
	        this._firstTwoTouches = undefined;
	    }
	    _start(points) {
	    }
	    _move(points, pinchAround, e) {
	        return {};
	    }
	    touchstart(e, points, mapTouches) {
	        if (this._firstTwoTouches || mapTouches.length < 2)
	            return;
	        this._firstTwoTouches = [
	            mapTouches[0].identifier,
	            mapTouches[1].identifier
	        ];
	        this._start([
	            points[0],
	            points[1]
	        ]);
	    }
	    touchmove(e, points, mapTouches) {
	        const firstTouches = this._firstTwoTouches;
	        if (!firstTouches)
	            return;
	        e.preventDefault();
	        const [idA, idB] = firstTouches;
	        const a = getTouchById(mapTouches, points, idA);
	        const b = getTouchById(mapTouches, points, idB);
	        if (!a || !b)
	            return;
	        const pinchAround = this._aroundCenter ? null : a.add(b).div(2);
	        return this._move([
	            a,
	            b
	        ], pinchAround, e);
	    }
	    touchend(e, points, mapTouches) {
	        if (!this._firstTwoTouches)
	            return;
	        const [idA, idB] = this._firstTwoTouches;
	        const a = getTouchById(mapTouches, points, idA);
	        const b = getTouchById(mapTouches, points, idB);
	        if (a && b)
	            return;
	        if (this._active)
	            suppressClick();
	        this.reset();
	    }
	    touchcancel() {
	        this.reset();
	    }
	    enable(options) {
	        this._enabled = true;
	        this._aroundCenter = !!options && options.around === 'center';
	    }
	    disable() {
	        this._enabled = false;
	        this.reset();
	    }
	    isEnabled() {
	        return this._enabled;
	    }
	    isActive() {
	        return this._active;
	    }
	}
	function getTouchById(mapTouches, points, identifier) {
	    for (let i = 0; i < mapTouches.length; i++) {
	        if (mapTouches[i].identifier === identifier)
	            return points[i];
	    }
	}
	const ZOOM_THRESHOLD = 0.1;
	function getZoomDelta(distance, lastDistance) {
	    return Math.log(distance / lastDistance) / Math.LN2;
	}
	class TouchZoomHandler extends TwoTouchHandler {
	    reset() {
	        super.reset();
	        this._distance = 0;
	        this._startDistance = 0;
	    }
	    _start(points) {
	        this._startDistance = this._distance = points[0].dist(points[1]);
	    }
	    _move(points, pinchAround) {
	        const lastDistance = this._distance;
	        this._distance = points[0].dist(points[1]);
	        if (!this._active && Math.abs(getZoomDelta(this._distance, this._startDistance)) < ZOOM_THRESHOLD)
	            return;
	        this._active = true;
	        return {
	            zoomDelta: getZoomDelta(this._distance, lastDistance),
	            pinchAround
	        };
	    }
	}
	const ROTATION_THRESHOLD = 25;
	function getBearingDelta(a, b) {
	    return a.angleWith(b) * 180 / Math.PI;
	}
	class TouchRotateHandler extends TwoTouchHandler {
	    reset() {
	        super.reset();
	        this._minDiameter = 0;
	        this._startVector = undefined;
	        this._vector = undefined;
	    }
	    _start(points) {
	        this._startVector = this._vector = points[0].sub(points[1]);
	        this._minDiameter = points[0].dist(points[1]);
	    }
	    _move(points, pinchAround) {
	        const lastVector = this._vector;
	        this._vector = points[0].sub(points[1]);
	        if (!this._active && this._isBelowThreshold(this._vector))
	            return;
	        this._active = true;
	        return {
	            bearingDelta: getBearingDelta(this._vector, lastVector),
	            pinchAround
	        };
	    }
	    _isBelowThreshold(vector) {
	        this._minDiameter = Math.min(this._minDiameter, vector.mag());
	        const circumference = Math.PI * this._minDiameter;
	        const threshold = ROTATION_THRESHOLD / circumference * 360;
	        const bearingDeltaSinceStart = getBearingDelta(vector, this._startVector);
	        return Math.abs(bearingDeltaSinceStart) < threshold;
	    }
	}
	function isVertical(vector) {
	    return Math.abs(vector.y) > Math.abs(vector.x);
	}
	const ALLOWED_SINGLE_TOUCH_TIME = 100;
	class TouchPitchHandler extends TwoTouchHandler {
	    constructor(map) {
	        super();
	        this._map = map;
	    }
	    reset() {
	        super.reset();
	        this._valid = undefined;
	        this._firstMove = undefined;
	        this._lastPoints = undefined;
	    }
	    _start(points) {
	        this._lastPoints = points;
	        if (isVertical(points[0].sub(points[1]))) {
	            this._valid = false;
	        }
	    }
	    _move(points, center, e) {
	        const lastPoints = this._lastPoints;
	        if (!lastPoints)
	            return;
	        const vectorA = points[0].sub(lastPoints[0]);
	        const vectorB = points[1].sub(lastPoints[1]);
	        if (this._map._cooperativeGestures && e.touches.length < 3)
	            return;
	        this._valid = this.gestureBeginsVertically(vectorA, vectorB, e.timeStamp);
	        if (!this._valid)
	            return;
	        this._lastPoints = points;
	        this._active = true;
	        const yDeltaAverage = (vectorA.y + vectorB.y) / 2;
	        const degreesPerPixelMoved = -0.5;
	        return { pitchDelta: yDeltaAverage * degreesPerPixelMoved };
	    }
	    gestureBeginsVertically(vectorA, vectorB, timeStamp) {
	        if (this._valid !== undefined)
	            return this._valid;
	        const threshold = 2;
	        const movedA = vectorA.mag() >= threshold;
	        const movedB = vectorB.mag() >= threshold;
	        if (!movedA && !movedB)
	            return;
	        if (!movedA || !movedB) {
	            if (this._firstMove == null) {
	                this._firstMove = timeStamp;
	            }
	            if (timeStamp - this._firstMove < ALLOWED_SINGLE_TOUCH_TIME) {
	                return undefined;
	            } else {
	                return false;
	            }
	        }
	        const isSameDirection = vectorA.y > 0 === vectorB.y > 0;
	        return isVertical(vectorA) && isVertical(vectorB) && isSameDirection;
	    }
	}

	const defaultOptions$5 = {
	    panStep: 100,
	    bearingStep: 15,
	    pitchStep: 10
	};
	class KeyboardHandler {
	    constructor() {
	        const stepOptions = defaultOptions$5;
	        this._panStep = stepOptions.panStep;
	        this._bearingStep = stepOptions.bearingStep;
	        this._pitchStep = stepOptions.pitchStep;
	        this._rotationDisabled = false;
	    }
	    blur() {
	        this.reset();
	    }
	    reset() {
	        this._active = false;
	    }
	    keydown(e) {
	        if (e.altKey || e.ctrlKey || e.metaKey)
	            return;
	        let zoomDir = 0;
	        let bearingDir = 0;
	        let pitchDir = 0;
	        let xDir = 0;
	        let yDir = 0;
	        switch (e.keyCode) {
	        case 61:
	        case 107:
	        case 171:
	        case 187:
	            zoomDir = 1;
	            break;
	        case 189:
	        case 109:
	        case 173:
	            zoomDir = -1;
	            break;
	        case 37:
	            if (e.shiftKey) {
	                bearingDir = -1;
	            } else {
	                e.preventDefault();
	                xDir = -1;
	            }
	            break;
	        case 39:
	            if (e.shiftKey) {
	                bearingDir = 1;
	            } else {
	                e.preventDefault();
	                xDir = 1;
	            }
	            break;
	        case 38:
	            if (e.shiftKey) {
	                pitchDir = 1;
	            } else {
	                e.preventDefault();
	                yDir = -1;
	            }
	            break;
	        case 40:
	            if (e.shiftKey) {
	                pitchDir = -1;
	            } else {
	                e.preventDefault();
	                yDir = 1;
	            }
	            break;
	        default:
	            return;
	        }
	        if (this._rotationDisabled) {
	            bearingDir = 0;
	            pitchDir = 0;
	        }
	        return {
	            cameraAnimation: map => {
	                const zoom = map.getZoom();
	                map.easeTo({
	                    duration: 300,
	                    easeId: 'keyboardHandler',
	                    easing: easeOut,
	                    zoom: zoomDir ? Math.round(zoom) + zoomDir * (e.shiftKey ? 2 : 1) : zoom,
	                    bearing: map.getBearing() + bearingDir * this._bearingStep,
	                    pitch: map.getPitch() + pitchDir * this._pitchStep,
	                    offset: [
	                        -xDir * this._panStep,
	                        -yDir * this._panStep
	                    ],
	                    center: map.getCenter()
	                }, { originalEvent: e });
	            }
	        };
	    }
	    enable() {
	        this._enabled = true;
	    }
	    disable() {
	        this._enabled = false;
	        this.reset();
	    }
	    isEnabled() {
	        return this._enabled;
	    }
	    isActive() {
	        return this._active;
	    }
	    disableRotation() {
	        this._rotationDisabled = true;
	    }
	    enableRotation() {
	        this._rotationDisabled = false;
	    }
	}
	function easeOut(t) {
	    return t * (2 - t);
	}

	const wheelZoomDelta = 4.000244140625;
	const defaultZoomRate = 1 / 100;
	const wheelZoomRate = 1 / 450;
	const maxScalePerFrame = 2;
	class ScrollZoomHandler {
	    constructor(map, handler) {
	        this._map = map;
	        this._el = map.getCanvasContainer();
	        this._handler = handler;
	        this._delta = 0;
	        this._defaultZoomRate = defaultZoomRate;
	        this._wheelZoomRate = wheelZoomRate;
	        ref_properties.bindAll([
	            '_onTimeout',
	            '_addScrollZoomBlocker',
	            '_showBlockerAlert',
	            '_isFullscreen'
	        ], this);
	    }
	    setZoomRate(zoomRate) {
	        this._defaultZoomRate = zoomRate;
	    }
	    setWheelZoomRate(wheelZoomRate) {
	        this._wheelZoomRate = wheelZoomRate;
	    }
	    isEnabled() {
	        return !!this._enabled;
	    }
	    isActive() {
	        return !!this._active || this._finishTimeout !== undefined;
	    }
	    isZooming() {
	        return !!this._zooming;
	    }
	    enable(options) {
	        if (this.isEnabled())
	            return;
	        this._enabled = true;
	        this._aroundCenter = !!options && options.around === 'center';
	        if (this._map._cooperativeGestures)
	            this._addScrollZoomBlocker();
	    }
	    disable() {
	        if (!this.isEnabled())
	            return;
	        this._enabled = false;
	        if (this._map._cooperativeGestures) {
	            clearTimeout(this._alertTimer);
	            this._alertContainer.remove();
	        }
	    }
	    wheel(e) {
	        if (!this.isEnabled())
	            return;
	        if (this._map._cooperativeGestures) {
	            if (!e.ctrlKey && !e.metaKey && !this.isZooming() && !this._isFullscreen()) {
	                this._showBlockerAlert();
	                return;
	            } else if (this._alertContainer.style.visibility !== 'hidden') {
	                this._alertContainer.style.visibility = 'hidden';
	                clearTimeout(this._alertTimer);
	            }
	        }
	        let value = e.deltaMode === ref_properties.window.WheelEvent.DOM_DELTA_LINE ? e.deltaY * 40 : e.deltaY;
	        const now = ref_properties.exported.now(), timeDelta = now - (this._lastWheelEventTime || 0);
	        this._lastWheelEventTime = now;
	        if (value !== 0 && value % wheelZoomDelta === 0) {
	            this._type = 'wheel';
	        } else if (value !== 0 && Math.abs(value) < 4) {
	            this._type = 'trackpad';
	        } else if (timeDelta > 400) {
	            this._type = null;
	            this._lastValue = value;
	            this._timeout = setTimeout(this._onTimeout, 40, e);
	        } else if (!this._type) {
	            this._type = Math.abs(timeDelta * value) < 200 ? 'trackpad' : 'wheel';
	            if (this._timeout) {
	                clearTimeout(this._timeout);
	                this._timeout = null;
	                value += this._lastValue;
	            }
	        }
	        if (e.shiftKey && value)
	            value = value / 4;
	        if (this._type) {
	            this._lastWheelEvent = e;
	            this._delta -= value;
	            if (!this._active) {
	                this._start(e);
	            }
	        }
	        e.preventDefault();
	    }
	    _onTimeout(initialEvent) {
	        this._type = 'wheel';
	        this._delta -= this._lastValue;
	        if (!this._active) {
	            this._start(initialEvent);
	        }
	    }
	    _start(e) {
	        if (!this._delta)
	            return;
	        if (this._frameId) {
	            this._frameId = null;
	        }
	        this._active = true;
	        if (!this.isZooming()) {
	            this._zooming = true;
	        }
	        if (this._finishTimeout) {
	            clearTimeout(this._finishTimeout);
	            delete this._finishTimeout;
	        }
	        const pos = mousePos(this._el, e);
	        this._aroundPoint = this._aroundCenter ? this._map.transform.centerPoint : pos;
	        this._aroundCoord = this._map.transform.pointCoordinate3D(this._aroundPoint);
	        this._targetZoom = undefined;
	        if (!this._frameId) {
	            this._frameId = true;
	            this._handler._triggerRenderFrame();
	        }
	    }
	    renderFrame() {
	        if (!this._frameId)
	            return;
	        this._frameId = null;
	        if (!this.isActive())
	            return;
	        const tr = this._map.transform;
	        const startingZoom = () => {
	            return tr._terrainEnabled() && this._aroundCoord ? tr.computeZoomRelativeTo(this._aroundCoord) : tr.zoom;
	        };
	        if (this._delta !== 0) {
	            const zoomRate = this._type === 'wheel' && Math.abs(this._delta) > wheelZoomDelta ? this._wheelZoomRate : this._defaultZoomRate;
	            let scale = maxScalePerFrame / (1 + Math.exp(-Math.abs(this._delta * zoomRate)));
	            if (this._delta < 0 && scale !== 0) {
	                scale = 1 / scale;
	            }
	            const startZoom = startingZoom();
	            const startScale = Math.pow(2, startZoom);
	            const fromScale = typeof this._targetZoom === 'number' ? tr.zoomScale(this._targetZoom) : startScale;
	            this._targetZoom = Math.min(tr.maxZoom, Math.max(tr.minZoom, tr.scaleZoom(fromScale * scale)));
	            if (this._type === 'wheel') {
	                this._startZoom = startingZoom();
	                this._easing = this._smoothOutEasing(200);
	            }
	            this._delta = 0;
	        }
	        const targetZoom = typeof this._targetZoom === 'number' ? this._targetZoom : startingZoom();
	        const startZoom = this._startZoom;
	        const easing = this._easing;
	        let finished = false;
	        let zoom;
	        if (this._type === 'wheel' && startZoom && easing) {
	            const t = Math.min((ref_properties.exported.now() - this._lastWheelEventTime) / 200, 1);
	            const k = easing(t);
	            zoom = ref_properties.number(startZoom, targetZoom, k);
	            if (t < 1) {
	                if (!this._frameId) {
	                    this._frameId = true;
	                }
	            } else {
	                finished = true;
	            }
	        } else {
	            zoom = targetZoom;
	            finished = true;
	        }
	        this._active = true;
	        if (finished) {
	            this._active = false;
	            this._finishTimeout = setTimeout(() => {
	                this._zooming = false;
	                this._handler._triggerRenderFrame();
	                delete this._targetZoom;
	                delete this._finishTimeout;
	            }, 200);
	        }
	        return {
	            noInertia: true,
	            needsRenderFrame: !finished,
	            zoomDelta: zoom - startingZoom(),
	            around: this._aroundPoint,
	            aroundCoord: this._aroundCoord,
	            originalEvent: this._lastWheelEvent
	        };
	    }
	    _smoothOutEasing(duration) {
	        let easing = ref_properties.ease;
	        if (this._prevEase) {
	            const ease = this._prevEase, t = (ref_properties.exported.now() - ease.start) / ease.duration, speed = ease.easing(t + 0.01) - ease.easing(t), x = 0.27 / Math.sqrt(speed * speed + 0.0001) * 0.01, y = Math.sqrt(0.27 * 0.27 - x * x);
	            easing = ref_properties.bezier(x, y, 0.25, 1);
	        }
	        this._prevEase = {
	            start: ref_properties.exported.now(),
	            duration,
	            easing
	        };
	        return easing;
	    }
	    blur() {
	        this.reset();
	    }
	    reset() {
	        this._active = false;
	    }
	    _addScrollZoomBlocker() {
	        if (this._map && !this._alertContainer) {
	            this._alertContainer = create$2('div', 'mapboxgl-scroll-zoom-blocker', this._map._container);
	            if (/(Mac|iPad)/i.test(ref_properties.window.navigator.userAgent)) {
	                this._alertContainer.textContent = this._map._getUIString('ScrollZoomBlocker.CmdMessage');
	            } else {
	                this._alertContainer.textContent = this._map._getUIString('ScrollZoomBlocker.CtrlMessage');
	            }
	            this._alertContainer.style.fontSize = `${ Math.max(10, Math.min(24, Math.floor(this._el.clientWidth * 0.05))) }px`;
	        }
	    }
	    _isFullscreen() {
	        return !!ref_properties.window.document.fullscreenElement || !!ref_properties.window.document.webkitFullscreenElement;
	    }
	    _showBlockerAlert() {
	        if (this._alertContainer.style.visibility === 'hidden')
	            this._alertContainer.style.visibility = 'visible';
	        this._alertContainer.classList.add('mapboxgl-scroll-zoom-blocker-show');
	        clearTimeout(this._alertTimer);
	        this._alertTimer = setTimeout(() => {
	            this._alertContainer.classList.remove('mapboxgl-scroll-zoom-blocker-show');
	        }, 200);
	    }
	}

	class DoubleClickZoomHandler {
	    constructor(clickZoom, TapZoom) {
	        this._clickZoom = clickZoom;
	        this._tapZoom = TapZoom;
	    }
	    enable() {
	        this._clickZoom.enable();
	        this._tapZoom.enable();
	    }
	    disable() {
	        this._clickZoom.disable();
	        this._tapZoom.disable();
	    }
	    isEnabled() {
	        return this._clickZoom.isEnabled() && this._tapZoom.isEnabled();
	    }
	    isActive() {
	        return this._clickZoom.isActive() || this._tapZoom.isActive();
	    }
	}

	class ClickZoomHandler {
	    constructor() {
	        this.reset();
	    }
	    reset() {
	        this._active = false;
	    }
	    blur() {
	        this.reset();
	    }
	    dblclick(e, point) {
	        e.preventDefault();
	        return {
	            cameraAnimation: map => {
	                map.easeTo({
	                    duration: 300,
	                    zoom: map.getZoom() + (e.shiftKey ? -1 : 1),
	                    around: map.unproject(point)
	                }, { originalEvent: e });
	            }
	        };
	    }
	    enable() {
	        this._enabled = true;
	    }
	    disable() {
	        this._enabled = false;
	        this.reset();
	    }
	    isEnabled() {
	        return this._enabled;
	    }
	    isActive() {
	        return this._active;
	    }
	}

	class TapDragZoomHandler {
	    constructor() {
	        this._tap = new TapRecognizer({
	            numTouches: 1,
	            numTaps: 1
	        });
	        this.reset();
	    }
	    reset() {
	        this._active = false;
	        this._swipePoint = undefined;
	        this._swipeTouch = 0;
	        this._tapTime = 0;
	        this._tap.reset();
	    }
	    touchstart(e, points, mapTouches) {
	        if (this._swipePoint)
	            return;
	        if (this._tapTime && e.timeStamp - this._tapTime > MAX_TAP_INTERVAL) {
	            this.reset();
	        }
	        if (!this._tapTime) {
	            this._tap.touchstart(e, points, mapTouches);
	        } else if (mapTouches.length > 0) {
	            this._swipePoint = points[0];
	            this._swipeTouch = mapTouches[0].identifier;
	        }
	    }
	    touchmove(e, points, mapTouches) {
	        if (!this._tapTime) {
	            this._tap.touchmove(e, points, mapTouches);
	        } else if (this._swipePoint) {
	            if (mapTouches[0].identifier !== this._swipeTouch) {
	                return;
	            }
	            const newSwipePoint = points[0];
	            const dist = newSwipePoint.y - this._swipePoint.y;
	            this._swipePoint = newSwipePoint;
	            e.preventDefault();
	            this._active = true;
	            return { zoomDelta: dist / 128 };
	        }
	    }
	    touchend(e, points, mapTouches) {
	        if (!this._tapTime) {
	            const point = this._tap.touchend(e, points, mapTouches);
	            if (point) {
	                this._tapTime = e.timeStamp;
	            }
	        } else if (this._swipePoint) {
	            if (mapTouches.length === 0) {
	                this.reset();
	            }
	        }
	    }
	    touchcancel() {
	        this.reset();
	    }
	    enable() {
	        this._enabled = true;
	    }
	    disable() {
	        this._enabled = false;
	        this.reset();
	    }
	    isEnabled() {
	        return this._enabled;
	    }
	    isActive() {
	        return this._active;
	    }
	}

	class DragPanHandler {
	    constructor(el, mousePan, touchPan) {
	        this._el = el;
	        this._mousePan = mousePan;
	        this._touchPan = touchPan;
	    }
	    enable(options) {
	        this._inertiaOptions = options || {};
	        this._mousePan.enable();
	        this._touchPan.enable();
	        this._el.classList.add('mapboxgl-touch-drag-pan');
	    }
	    disable() {
	        this._mousePan.disable();
	        this._touchPan.disable();
	        this._el.classList.remove('mapboxgl-touch-drag-pan');
	    }
	    isEnabled() {
	        return this._mousePan.isEnabled() && this._touchPan.isEnabled();
	    }
	    isActive() {
	        return this._mousePan.isActive() || this._touchPan.isActive();
	    }
	}

	class DragRotateHandler {
	    constructor(options, mouseRotate, mousePitch) {
	        this._pitchWithRotate = options.pitchWithRotate;
	        this._mouseRotate = mouseRotate;
	        this._mousePitch = mousePitch;
	    }
	    enable() {
	        this._mouseRotate.enable();
	        if (this._pitchWithRotate)
	            this._mousePitch.enable();
	    }
	    disable() {
	        this._mouseRotate.disable();
	        this._mousePitch.disable();
	    }
	    isEnabled() {
	        return this._mouseRotate.isEnabled() && (!this._pitchWithRotate || this._mousePitch.isEnabled());
	    }
	    isActive() {
	        return this._mouseRotate.isActive() || this._mousePitch.isActive();
	    }
	}

	class TouchZoomRotateHandler {
	    constructor(el, touchZoom, touchRotate, tapDragZoom) {
	        this._el = el;
	        this._touchZoom = touchZoom;
	        this._touchRotate = touchRotate;
	        this._tapDragZoom = tapDragZoom;
	        this._rotationDisabled = false;
	        this._enabled = true;
	    }
	    enable(options) {
	        this._touchZoom.enable(options);
	        if (!this._rotationDisabled)
	            this._touchRotate.enable(options);
	        this._tapDragZoom.enable();
	        this._el.classList.add('mapboxgl-touch-zoom-rotate');
	    }
	    disable() {
	        this._touchZoom.disable();
	        this._touchRotate.disable();
	        this._tapDragZoom.disable();
	        this._el.classList.remove('mapboxgl-touch-zoom-rotate');
	    }
	    isEnabled() {
	        return this._touchZoom.isEnabled() && (this._rotationDisabled || this._touchRotate.isEnabled()) && this._tapDragZoom.isEnabled();
	    }
	    isActive() {
	        return this._touchZoom.isActive() || this._touchRotate.isActive() || this._tapDragZoom.isActive();
	    }
	    disableRotation() {
	        this._rotationDisabled = true;
	        this._touchRotate.disable();
	    }
	    enableRotation() {
	        this._rotationDisabled = false;
	        if (this._touchZoom.isEnabled())
	            this._touchRotate.enable();
	    }
	}

	const isMoving = p => p.zoom || p.drag || p.pitch || p.rotate;
	class RenderFrameEvent extends ref_properties.Event {
	}
	class TrackingEllipsoid {
	    constructor() {
	        this.constants = [
	            1,
	            1,
	            0.01
	        ];
	        this.radius = 0;
	    }
	    setup(center, pointOnSurface) {
	        const centerToSurface = ref_properties.sub([], pointOnSurface, center);
	        if (centerToSurface[2] < 0) {
	            this.radius = ref_properties.length(ref_properties.div([], centerToSurface, this.constants));
	        } else {
	            this.radius = ref_properties.length([
	                centerToSurface[0],
	                centerToSurface[1],
	                0
	            ]);
	        }
	    }
	    projectRay(dir) {
	        ref_properties.div(dir, dir, this.constants);
	        ref_properties.normalize(dir, dir);
	        ref_properties.mul$1(dir, dir, this.constants);
	        const intersection = ref_properties.scale$2([], dir, this.radius);
	        if (intersection[2] > 0) {
	            const h = ref_properties.scale$2([], [
	                0,
	                0,
	                1
	            ], ref_properties.dot(intersection, [
	                0,
	                0,
	                1
	            ]));
	            const r = ref_properties.scale$2([], ref_properties.normalize([], [
	                intersection[0],
	                intersection[1],
	                0
	            ]), this.radius);
	            const p = ref_properties.add([], intersection, ref_properties.scale$2([], ref_properties.sub([], ref_properties.add([], r, h), intersection), 2));
	            intersection[0] = p[0];
	            intersection[1] = p[1];
	        }
	        return intersection;
	    }
	}
	function hasChange(result) {
	    return result.panDelta && result.panDelta.mag() || result.zoomDelta || result.bearingDelta || result.pitchDelta;
	}
	class HandlerManager {
	    constructor(map, options) {
	        this._map = map;
	        this._el = this._map.getCanvasContainer();
	        this._handlers = [];
	        this._handlersById = {};
	        this._changes = [];
	        this._inertia = new HandlerInertia(map);
	        this._bearingSnap = options.bearingSnap;
	        this._previousActiveHandlers = {};
	        this._trackingEllipsoid = new TrackingEllipsoid();
	        this._dragOrigin = null;
	        this._eventsInProgress = {};
	        this._addDefaultHandlers(options);
	        ref_properties.bindAll([
	            'handleEvent',
	            'handleWindowEvent'
	        ], this);
	        const el = this._el;
	        this._listeners = [
	            [
	                el,
	                'touchstart',
	                { passive: true }
	            ],
	            [
	                el,
	                'touchmove',
	                { passive: false }
	            ],
	            [
	                el,
	                'touchend',
	                undefined
	            ],
	            [
	                el,
	                'touchcancel',
	                undefined
	            ],
	            [
	                el,
	                'mousedown',
	                undefined
	            ],
	            [
	                el,
	                'mousemove',
	                undefined
	            ],
	            [
	                el,
	                'mouseup',
	                undefined
	            ],
	            [
	                ref_properties.window.document,
	                'mousemove',
	                { capture: true }
	            ],
	            [
	                ref_properties.window.document,
	                'mouseup',
	                undefined
	            ],
	            [
	                el,
	                'mouseover',
	                undefined
	            ],
	            [
	                el,
	                'mouseout',
	                undefined
	            ],
	            [
	                el,
	                'dblclick',
	                undefined
	            ],
	            [
	                el,
	                'click',
	                undefined
	            ],
	            [
	                el,
	                'keydown',
	                { capture: false }
	            ],
	            [
	                el,
	                'keyup',
	                undefined
	            ],
	            [
	                el,
	                'wheel',
	                { passive: false }
	            ],
	            [
	                el,
	                'contextmenu',
	                undefined
	            ],
	            [
	                ref_properties.window,
	                'blur',
	                undefined
	            ]
	        ];
	        for (const [target, type, listenerOptions] of this._listeners) {
	            const listener = target === ref_properties.window.document ? this.handleWindowEvent : this.handleEvent;
	            target.addEventListener(type, listener, listenerOptions);
	        }
	    }
	    destroy() {
	        for (const [target, type, listenerOptions] of this._listeners) {
	            const listener = target === ref_properties.window.document ? this.handleWindowEvent : this.handleEvent;
	            target.removeEventListener(type, listener, listenerOptions);
	        }
	    }
	    _addDefaultHandlers(options) {
	        const map = this._map;
	        const el = map.getCanvasContainer();
	        this._add('mapEvent', new MapEventHandler(map, options));
	        const boxZoom = map.boxZoom = new BoxZoomHandler(map, options);
	        this._add('boxZoom', boxZoom);
	        const tapZoom = new TapZoomHandler();
	        const clickZoom = new ClickZoomHandler();
	        map.doubleClickZoom = new DoubleClickZoomHandler(clickZoom, tapZoom);
	        this._add('tapZoom', tapZoom);
	        this._add('clickZoom', clickZoom);
	        const tapDragZoom = new TapDragZoomHandler();
	        this._add('tapDragZoom', tapDragZoom);
	        const touchPitch = map.touchPitch = new TouchPitchHandler(map);
	        this._add('touchPitch', touchPitch);
	        const mouseRotate = new MouseRotateHandler(options);
	        const mousePitch = new MousePitchHandler(options);
	        map.dragRotate = new DragRotateHandler(options, mouseRotate, mousePitch);
	        this._add('mouseRotate', mouseRotate, ['mousePitch']);
	        this._add('mousePitch', mousePitch, ['mouseRotate']);
	        const mousePan = new MousePanHandler(options);
	        const touchPan = new TouchPanHandler(map, options);
	        map.dragPan = new DragPanHandler(el, mousePan, touchPan);
	        this._add('mousePan', mousePan);
	        this._add('touchPan', touchPan, [
	            'touchZoom',
	            'touchRotate'
	        ]);
	        const touchRotate = new TouchRotateHandler();
	        const touchZoom = new TouchZoomHandler();
	        map.touchZoomRotate = new TouchZoomRotateHandler(el, touchZoom, touchRotate, tapDragZoom);
	        this._add('touchRotate', touchRotate, [
	            'touchPan',
	            'touchZoom'
	        ]);
	        this._add('touchZoom', touchZoom, [
	            'touchPan',
	            'touchRotate'
	        ]);
	        this._add('blockableMapEvent', new BlockableMapEventHandler(map));
	        const scrollZoom = map.scrollZoom = new ScrollZoomHandler(map, this);
	        this._add('scrollZoom', scrollZoom, ['mousePan']);
	        const keyboard = map.keyboard = new KeyboardHandler();
	        this._add('keyboard', keyboard);
	        for (const name of [
	                'boxZoom',
	                'doubleClickZoom',
	                'tapDragZoom',
	                'touchPitch',
	                'dragRotate',
	                'dragPan',
	                'touchZoomRotate',
	                'scrollZoom',
	                'keyboard'
	            ]) {
	            if (options.interactive && options[name]) {
	                map[name].enable(options[name]);
	            }
	        }
	    }
	    _add(handlerName, handler, allowed) {
	        this._handlers.push({
	            handlerName,
	            handler,
	            allowed
	        });
	        this._handlersById[handlerName] = handler;
	    }
	    stop(allowEndAnimation) {
	        if (this._updatingCamera)
	            return;
	        for (const {handler} of this._handlers) {
	            handler.reset();
	        }
	        this._inertia.clear();
	        this._fireEvents({}, {}, allowEndAnimation);
	        this._changes = [];
	    }
	    isActive() {
	        for (const {handler} of this._handlers) {
	            if (handler.isActive())
	                return true;
	        }
	        return false;
	    }
	    isZooming() {
	        return !!this._eventsInProgress.zoom || this._map.scrollZoom.isZooming();
	    }
	    isRotating() {
	        return !!this._eventsInProgress.rotate;
	    }
	    isMoving() {
	        return !!isMoving(this._eventsInProgress) || this.isZooming();
	    }
	    _blockedByActive(activeHandlers, allowed, myName) {
	        for (const name in activeHandlers) {
	            if (name === myName)
	                continue;
	            if (!allowed || allowed.indexOf(name) < 0) {
	                return true;
	            }
	        }
	        return false;
	    }
	    handleWindowEvent(e) {
	        this.handleEvent(e, `${ e.type }Window`);
	    }
	    _getMapTouches(touches) {
	        const mapTouches = [];
	        for (const t of touches) {
	            const target = t.target;
	            if (this._el.contains(target)) {
	                mapTouches.push(t);
	            }
	        }
	        return mapTouches;
	    }
	    handleEvent(e, eventName) {
	        this._updatingCamera = true;
	        const isRenderFrame = e.type === 'renderFrame';
	        const inputEvent = isRenderFrame ? undefined : e;
	        const mergedHandlerResult = { needsRenderFrame: false };
	        const eventsInProgress = {};
	        const activeHandlers = {};
	        const mapTouches = e.touches ? this._getMapTouches(e.touches) : undefined;
	        const points = mapTouches ? touchPos(this._el, mapTouches) : isRenderFrame ? undefined : mousePos(this._el, e);
	        for (const {handlerName, handler, allowed} of this._handlers) {
	            if (!handler.isEnabled())
	                continue;
	            let data;
	            if (this._blockedByActive(activeHandlers, allowed, handlerName)) {
	                handler.reset();
	            } else {
	                if (handler[eventName || e.type]) {
	                    data = handler[eventName || e.type](e, points, mapTouches);
	                    this.mergeHandlerResult(mergedHandlerResult, eventsInProgress, data, handlerName, inputEvent);
	                    if (data && data.needsRenderFrame) {
	                        this._triggerRenderFrame();
	                    }
	                }
	            }
	            if (data || handler.isActive()) {
	                activeHandlers[handlerName] = handler;
	            }
	        }
	        const deactivatedHandlers = {};
	        for (const name in this._previousActiveHandlers) {
	            if (!activeHandlers[name]) {
	                deactivatedHandlers[name] = inputEvent;
	            }
	        }
	        this._previousActiveHandlers = activeHandlers;
	        if (Object.keys(deactivatedHandlers).length || hasChange(mergedHandlerResult)) {
	            this._changes.push([
	                mergedHandlerResult,
	                eventsInProgress,
	                deactivatedHandlers
	            ]);
	            this._triggerRenderFrame();
	        }
	        if (Object.keys(activeHandlers).length || hasChange(mergedHandlerResult)) {
	            this._map._stop(true);
	        }
	        this._updatingCamera = false;
	        const {cameraAnimation} = mergedHandlerResult;
	        if (cameraAnimation) {
	            this._inertia.clear();
	            this._fireEvents({}, {}, true);
	            this._changes = [];
	            cameraAnimation(this._map);
	        }
	    }
	    mergeHandlerResult(mergedHandlerResult, eventsInProgress, handlerResult, name, e) {
	        if (!handlerResult)
	            return;
	        ref_properties.extend(mergedHandlerResult, handlerResult);
	        const eventData = {
	            handlerName: name,
	            originalEvent: handlerResult.originalEvent || e
	        };
	        if (handlerResult.zoomDelta !== undefined) {
	            eventsInProgress.zoom = eventData;
	        }
	        if (handlerResult.panDelta !== undefined) {
	            eventsInProgress.drag = eventData;
	        }
	        if (handlerResult.pitchDelta !== undefined) {
	            eventsInProgress.pitch = eventData;
	        }
	        if (handlerResult.bearingDelta !== undefined) {
	            eventsInProgress.rotate = eventData;
	        }
	    }
	    _applyChanges() {
	        const combined = {};
	        const combinedEventsInProgress = {};
	        const combinedDeactivatedHandlers = {};
	        for (const [change, eventsInProgress, deactivatedHandlers] of this._changes) {
	            if (change.panDelta)
	                combined.panDelta = (combined.panDelta || new ref_properties.pointGeometry(0, 0))._add(change.panDelta);
	            if (change.zoomDelta)
	                combined.zoomDelta = (combined.zoomDelta || 0) + change.zoomDelta;
	            if (change.bearingDelta)
	                combined.bearingDelta = (combined.bearingDelta || 0) + change.bearingDelta;
	            if (change.pitchDelta)
	                combined.pitchDelta = (combined.pitchDelta || 0) + change.pitchDelta;
	            if (change.around !== undefined)
	                combined.around = change.around;
	            if (change.aroundCoord !== undefined)
	                combined.aroundCoord = change.aroundCoord;
	            if (change.pinchAround !== undefined)
	                combined.pinchAround = change.pinchAround;
	            if (change.noInertia)
	                combined.noInertia = change.noInertia;
	            ref_properties.extend(combinedEventsInProgress, eventsInProgress);
	            ref_properties.extend(combinedDeactivatedHandlers, deactivatedHandlers);
	        }
	        this._updateMapTransform(combined, combinedEventsInProgress, combinedDeactivatedHandlers);
	        this._changes = [];
	    }
	    _updateMapTransform(combinedResult, combinedEventsInProgress, deactivatedHandlers) {
	        const map = this._map;
	        const tr = map.transform;
	        const eventStarted = type => {
	            const newEvent = combinedEventsInProgress[type];
	            return newEvent && !this._eventsInProgress[type];
	        };
	        const eventEnded = type => {
	            const event = this._eventsInProgress[type];
	            return event && !this._handlersById[event.handlerName].isActive();
	        };
	        const toVec3 = p => [
	            p.x,
	            p.y,
	            p.z
	        ];
	        if (eventEnded('drag') && !hasChange(combinedResult)) {
	            const preZoom = tr.zoom;
	            tr.cameraElevationReference = 'sea';
	            tr.recenterOnTerrain();
	            tr.cameraElevationReference = 'ground';
	            if (preZoom !== tr.zoom)
	                this._map._update(true);
	        }
	        if (!hasChange(combinedResult)) {
	            this._fireEvents(combinedEventsInProgress, deactivatedHandlers, true);
	            return;
	        }
	        let {panDelta, zoomDelta, bearingDelta, pitchDelta, around, aroundCoord, pinchAround} = combinedResult;
	        if (pinchAround !== undefined) {
	            around = pinchAround;
	        }
	        if (eventStarted('drag') && around) {
	            this._dragOrigin = toVec3(tr.pointCoordinate3D(around));
	            this._trackingEllipsoid.setup(tr._camera.position, this._dragOrigin);
	        }
	        tr.cameraElevationReference = 'sea';
	        map._stop(true);
	        around = around || map.transform.centerPoint;
	        if (bearingDelta)
	            tr.bearing += bearingDelta;
	        if (pitchDelta)
	            tr.pitch += pitchDelta;
	        tr._updateCameraState();
	        const panVec = [
	            0,
	            0,
	            0
	        ];
	        if (panDelta) {
	            const startPoint = tr.pointCoordinate(around);
	            if (tr.projection.name === 'globe') {
	                const startLat = ref_properties.latFromMercatorY(startPoint.y);
	                const centerLat = tr.center.lat;
	                const scale = Math.min(ref_properties.mercatorZfromAltitude(1, startLat) / ref_properties.mercatorZfromAltitude(1, centerLat), 2);
	                panDelta = panDelta.rotate(-tr.angle);
	                panVec[0] = -panDelta.x / tr.worldSize * scale;
	                panVec[1] = -panDelta.y / tr.worldSize * scale;
	            } else {
	                const endPoint = tr.pointCoordinate(around.sub(panDelta));
	                if (startPoint && endPoint) {
	                    panVec[0] = endPoint.x - startPoint.x;
	                    panVec[1] = endPoint.y - startPoint.y;
	                }
	            }
	        }
	        const originalZoom = tr.zoom;
	        const zoomVec = [
	            0,
	            0,
	            0
	        ];
	        if (zoomDelta) {
	            const pickedPosition = aroundCoord ? toVec3(aroundCoord) : toVec3(tr.pointCoordinate3D(around));
	            const aroundRay = { dir: ref_properties.normalize([], ref_properties.sub([], pickedPosition, tr._camera.position)) };
	            if (aroundRay.dir[2] < 0) {
	                const movement = tr.zoomDeltaToMovement(pickedPosition, zoomDelta);
	                ref_properties.scale$2(zoomVec, aroundRay.dir, movement);
	            }
	        }
	        const translation = ref_properties.add(panVec, panVec, zoomVec);
	        tr._translateCameraConstrained(translation);
	        if (zoomDelta && Math.abs(tr.zoom - originalZoom) > 0.0001) {
	            tr.recenterOnTerrain();
	        }
	        tr.cameraElevationReference = 'ground';
	        this._map._update();
	        if (!combinedResult.noInertia)
	            this._inertia.record(combinedResult);
	        this._fireEvents(combinedEventsInProgress, deactivatedHandlers, true);
	    }
	    _fireEvents(newEventsInProgress, deactivatedHandlers, allowEndAnimation) {
	        const wasMoving = isMoving(this._eventsInProgress);
	        const nowMoving = isMoving(newEventsInProgress);
	        const startEvents = {};
	        for (const eventName in newEventsInProgress) {
	            const {originalEvent} = newEventsInProgress[eventName];
	            if (!this._eventsInProgress[eventName]) {
	                startEvents[`${ eventName }start`] = originalEvent;
	            }
	            this._eventsInProgress[eventName] = newEventsInProgress[eventName];
	        }
	        if (!wasMoving && nowMoving) {
	            this._fireEvent('movestart', nowMoving.originalEvent);
	        }
	        for (const name in startEvents) {
	            this._fireEvent(name, startEvents[name]);
	        }
	        if (nowMoving) {
	            this._fireEvent('move', nowMoving.originalEvent);
	        }
	        for (const eventName in newEventsInProgress) {
	            const {originalEvent} = newEventsInProgress[eventName];
	            this._fireEvent(eventName, originalEvent);
	        }
	        const endEvents = {};
	        let originalEndEvent;
	        for (const eventName in this._eventsInProgress) {
	            const {handlerName, originalEvent} = this._eventsInProgress[eventName];
	            if (!this._handlersById[handlerName].isActive()) {
	                delete this._eventsInProgress[eventName];
	                originalEndEvent = deactivatedHandlers[handlerName] || originalEvent;
	                endEvents[`${ eventName }end`] = originalEndEvent;
	            }
	        }
	        for (const name in endEvents) {
	            this._fireEvent(name, endEvents[name]);
	        }
	        const stillMoving = isMoving(this._eventsInProgress);
	        if (allowEndAnimation && (wasMoving || nowMoving) && !stillMoving) {
	            this._updatingCamera = true;
	            const inertialEase = this._inertia._onMoveEnd(this._map.dragPan._inertiaOptions);
	            const shouldSnapToNorth = bearing => bearing !== 0 && -this._bearingSnap < bearing && bearing < this._bearingSnap;
	            if (inertialEase) {
	                if (shouldSnapToNorth(inertialEase.bearing || this._map.getBearing())) {
	                    inertialEase.bearing = 0;
	                }
	                this._map.easeTo(inertialEase, { originalEvent: originalEndEvent });
	            } else {
	                this._map.fire(new ref_properties.Event('moveend', { originalEvent: originalEndEvent }));
	                if (shouldSnapToNorth(this._map.getBearing())) {
	                    this._map.resetNorth();
	                }
	            }
	            this._updatingCamera = false;
	        }
	    }
	    _fireEvent(type, e) {
	        this._map.fire(new ref_properties.Event(type, e ? { originalEvent: e } : {}));
	    }
	    _requestFrame() {
	        this._map.triggerRepaint();
	        return this._map._renderTaskQueue.add(timeStamp => {
	            this._frameId = undefined;
	            this.handleEvent(new RenderFrameEvent('renderFrame', { timeStamp }));
	            this._applyChanges();
	        });
	    }
	    _triggerRenderFrame() {
	        if (this._frameId === undefined) {
	            this._frameId = this._requestFrame();
	        }
	    }
	}

	const freeCameraNotSupportedWarning = 'map.setFreeCameraOptions(...) and map.getFreeCameraOptions() are not yet supported for non-mercator projections.';
	class Camera extends ref_properties.Evented {
	    constructor(transform, options) {
	        super();
	        this._moving = false;
	        this._zooming = false;
	        this.transform = transform;
	        this._bearingSnap = options.bearingSnap;
	        ref_properties.bindAll(['_renderFrameCallback'], this);
	    }
	    getCenter() {
	        return new ref_properties.LngLat(this.transform.center.lng, this.transform.center.lat);
	    }
	    setCenter(center, eventData) {
	        return this.jumpTo({ center }, eventData);
	    }
	    panBy(offset, options, eventData) {
	        offset = ref_properties.pointGeometry.convert(offset).mult(-1);
	        return this.panTo(this.transform.center, ref_properties.extend({ offset }, options), eventData);
	    }
	    panTo(lnglat, options, eventData) {
	        return this.easeTo(ref_properties.extend({ center: lnglat }, options), eventData);
	    }
	    getZoom() {
	        return this.transform.zoom;
	    }
	    setZoom(zoom, eventData) {
	        this.jumpTo({ zoom }, eventData);
	        return this;
	    }
	    zoomTo(zoom, options, eventData) {
	        return this.easeTo(ref_properties.extend({ zoom }, options), eventData);
	    }
	    zoomIn(options, eventData) {
	        this.zoomTo(this.getZoom() + 1, options, eventData);
	        return this;
	    }
	    zoomOut(options, eventData) {
	        this.zoomTo(this.getZoom() - 1, options, eventData);
	        return this;
	    }
	    getBearing() {
	        return this.transform.bearing;
	    }
	    setBearing(bearing, eventData) {
	        this.jumpTo({ bearing }, eventData);
	        return this;
	    }
	    getPadding() {
	        return this.transform.padding;
	    }
	    setPadding(padding, eventData) {
	        this.jumpTo({ padding }, eventData);
	        return this;
	    }
	    rotateTo(bearing, options, eventData) {
	        return this.easeTo(ref_properties.extend({ bearing }, options), eventData);
	    }
	    resetNorth(options, eventData) {
	        this.rotateTo(0, ref_properties.extend({ duration: 1000 }, options), eventData);
	        return this;
	    }
	    resetNorthPitch(options, eventData) {
	        this.easeTo(ref_properties.extend({
	            bearing: 0,
	            pitch: 0,
	            duration: 1000
	        }, options), eventData);
	        return this;
	    }
	    snapToNorth(options, eventData) {
	        if (Math.abs(this.getBearing()) < this._bearingSnap) {
	            return this.resetNorth(options, eventData);
	        }
	        return this;
	    }
	    getPitch() {
	        return this.transform.pitch;
	    }
	    setPitch(pitch, eventData) {
	        this.jumpTo({ pitch }, eventData);
	        return this;
	    }
	    cameraForBounds(bounds, options) {
	        if (this.transform.projection.name === 'globe') {
	            ref_properties.warnOnce('Globe projection does not support cameraForBounds API, this API may behave unexpectedly."');
	        }
	        bounds = ref_properties.LngLatBounds.convert(bounds);
	        const bearing = options && options.bearing || 0;
	        return this._cameraForBoxAndBearing(bounds.getNorthWest(), bounds.getSouthEast(), bearing, options);
	    }
	    _extendCameraOptions(options) {
	        const defaultPadding = {
	            top: 0,
	            bottom: 0,
	            right: 0,
	            left: 0
	        };
	        options = ref_properties.extend({
	            padding: defaultPadding,
	            offset: [
	                0,
	                0
	            ],
	            maxZoom: this.transform.maxZoom
	        }, options);
	        if (typeof options.padding === 'number') {
	            const p = options.padding;
	            options.padding = {
	                top: p,
	                bottom: p,
	                right: p,
	                left: p
	            };
	        }
	        options.padding = ref_properties.extend(defaultPadding, options.padding);
	        return options;
	    }
	    _cameraForBoxAndBearing(p0, p1, bearing, options) {
	        const eOptions = this._extendCameraOptions(options);
	        const tr = this.transform;
	        const edgePadding = tr.padding;
	        const p0world = tr.project(ref_properties.LngLat.convert(p0));
	        const p1world = tr.project(ref_properties.LngLat.convert(p1));
	        const p2world = new ref_properties.pointGeometry(p0world.x, p1world.y);
	        const p3world = new ref_properties.pointGeometry(p1world.x, p0world.y);
	        const angleRadians = -ref_properties.degToRad(bearing);
	        const p0rotated = p0world.rotate(angleRadians);
	        const p1rotated = p1world.rotate(angleRadians);
	        const p2rotated = p2world.rotate(angleRadians);
	        const p3rotated = p3world.rotate(angleRadians);
	        const upperRight = new ref_properties.pointGeometry(Math.max(p0rotated.x, p1rotated.x, p2rotated.x, p3rotated.x), Math.max(p0rotated.y, p1rotated.y, p2rotated.y, p3rotated.y));
	        const lowerLeft = new ref_properties.pointGeometry(Math.min(p0rotated.x, p1rotated.x, p2rotated.x, p3rotated.x), Math.min(p0rotated.y, p1rotated.y, p2rotated.y, p3rotated.y));
	        const size = upperRight.sub(lowerLeft);
	        const scaleX = (tr.width - ((edgePadding.left || 0) + (edgePadding.right || 0) + eOptions.padding.left + eOptions.padding.right)) / size.x;
	        const scaleY = (tr.height - ((edgePadding.top || 0) + (edgePadding.bottom || 0) + eOptions.padding.top + eOptions.padding.bottom)) / size.y;
	        if (scaleY < 0 || scaleX < 0) {
	            ref_properties.warnOnce('Map cannot fit within canvas with the given bounds, padding, and/or offset.');
	            return;
	        }
	        const zoom = Math.min(tr.scaleZoom(tr.scale * Math.min(scaleX, scaleY)), eOptions.maxZoom);
	        const offset = typeof eOptions.offset.x === 'number' && typeof eOptions.offset.y === 'number' ? new ref_properties.pointGeometry(eOptions.offset.x, eOptions.offset.y) : ref_properties.pointGeometry.convert(eOptions.offset);
	        const paddingOffsetX = (eOptions.padding.left - eOptions.padding.right) / 2;
	        const paddingOffsetY = (eOptions.padding.top - eOptions.padding.bottom) / 2;
	        const paddingOffset = new ref_properties.pointGeometry(paddingOffsetX, paddingOffsetY);
	        const rotatedPaddingOffset = paddingOffset.rotate(bearing * Math.PI / 180);
	        const offsetAtInitialZoom = offset.add(rotatedPaddingOffset);
	        const offsetAtFinalZoom = offsetAtInitialZoom.mult(tr.scale / tr.zoomScale(zoom));
	        const center = tr.unproject(p0world.add(p1world).div(2).sub(offsetAtFinalZoom));
	        return {
	            center,
	            zoom,
	            bearing
	        };
	    }
	    _cameraForBox(p0, p1, minAltitude, maxAltitude, options) {
	        const eOptions = this._extendCameraOptions(options);
	        minAltitude = minAltitude || 0;
	        maxAltitude = maxAltitude || 0;
	        p0 = ref_properties.LngLat.convert(p0);
	        p1 = ref_properties.LngLat.convert(p1);
	        const tr = this.transform.clone();
	        tr.padding = eOptions.padding;
	        const camera = this.getFreeCameraOptions();
	        const focus = new ref_properties.LngLat((p0.lng + p1.lng) * 0.5, (p0.lat + p1.lat) * 0.5);
	        const focusAltitude = (minAltitude + maxAltitude) * 0.5;
	        if (tr._camera.position[2] < ref_properties.mercatorZfromAltitude(focusAltitude, focus.lat)) {
	            ref_properties.warnOnce('Map cannot fit within canvas with the given bounds, padding, and/or offset.');
	            return;
	        }
	        camera.lookAtPoint(focus);
	        tr.setFreeCameraOptions(camera);
	        const coord0 = ref_properties.MercatorCoordinate.fromLngLat(p0);
	        const coord1 = ref_properties.MercatorCoordinate.fromLngLat(p1);
	        const toVec3 = p => [
	            p.x,
	            p.y,
	            p.z
	        ];
	        const centerIntersectionPoint = tr.pointRayIntersection(tr.centerPoint, focusAltitude);
	        const centerIntersectionCoord = toVec3(tr.rayIntersectionCoordinate(centerIntersectionPoint));
	        const centerMercatorRay = tr.screenPointToMercatorRay(tr.centerPoint);
	        const zInMeters = tr.projection.name !== 'globe';
	        const maxMarchingSteps = 10;
	        let steps = 0;
	        let halfDistanceToGround;
	        do {
	            const z = Math.floor(tr.zoom);
	            const z2 = 1 << z;
	            const minX = Math.min(z2 * coord0.x, z2 * coord1.x);
	            const minY = Math.min(z2 * coord0.y, z2 * coord1.y);
	            const maxX = Math.max(z2 * coord0.x, z2 * coord1.x);
	            const maxY = Math.max(z2 * coord0.y, z2 * coord1.y);
	            const aabb = new ref_properties.Aabb([
	                minX,
	                minY,
	                minAltitude
	            ], [
	                maxX,
	                maxY,
	                maxAltitude
	            ]);
	            const frustum = ref_properties.Frustum.fromInvProjectionMatrix(tr.invProjMatrix, tr.worldSize, z, zInMeters);
	            if (aabb.intersects(frustum) !== 2) {
	                if (halfDistanceToGround) {
	                    tr._camera.position = ref_properties.scaleAndAdd([], tr._camera.position, centerMercatorRay.dir, -halfDistanceToGround);
	                    tr._updateStateFromCamera();
	                }
	                break;
	            }
	            const cameraPositionToGround = ref_properties.sub([], tr._camera.position, centerIntersectionCoord);
	            halfDistanceToGround = 0.5 * ref_properties.length(cameraPositionToGround);
	            tr._camera.position = ref_properties.scaleAndAdd([], tr._camera.position, centerMercatorRay.dir, halfDistanceToGround);
	            try {
	                tr._updateStateFromCamera();
	            } catch (e) {
	                ref_properties.warnOnce('Map cannot fit within canvas with the given bounds, padding, and/or offset.');
	                return;
	            }
	        } while (++steps < maxMarchingSteps);
	        return {
	            center: tr.center,
	            zoom: tr.zoom,
	            bearing: tr.bearing,
	            pitch: tr.pitch
	        };
	    }
	    fitBounds(bounds, options, eventData) {
	        if (this.transform.projection.name === 'globe') {
	            ref_properties.warnOnce('Globe projection does not support fitBounds API, this API may behave unexpectedly.');
	        }
	        return this._fitInternal(this.cameraForBounds(bounds, options), options, eventData);
	    }
	    _raycastElevationBox(point0, point1) {
	        const elevation = this.transform.elevation;
	        if (!elevation)
	            return;
	        const point2 = new ref_properties.pointGeometry(point0.x, point1.y);
	        const point3 = new ref_properties.pointGeometry(point1.x, point0.y);
	        const r0 = elevation.pointCoordinate(point0);
	        if (!r0)
	            return;
	        const r1 = elevation.pointCoordinate(point1);
	        if (!r1)
	            return;
	        const r2 = elevation.pointCoordinate(point2);
	        if (!r2)
	            return;
	        const r3 = elevation.pointCoordinate(point3);
	        if (!r3)
	            return;
	        const m0 = new ref_properties.MercatorCoordinate(r0[0], r0[1]).toLngLat();
	        const m1 = new ref_properties.MercatorCoordinate(r1[0], r1[1]).toLngLat();
	        const m2 = new ref_properties.MercatorCoordinate(r2[0], r2[1]).toLngLat();
	        const m3 = new ref_properties.MercatorCoordinate(r3[0], r3[1]).toLngLat();
	        const minLng = Math.min(m0.lng, Math.min(m1.lng, Math.min(m2.lng, m3.lng)));
	        const minLat = Math.min(m0.lat, Math.min(m1.lat, Math.min(m2.lat, m3.lat)));
	        const maxLng = Math.max(m0.lng, Math.max(m1.lng, Math.max(m2.lng, m3.lng)));
	        const maxLat = Math.max(m0.lat, Math.max(m1.lat, Math.max(m2.lat, m3.lat)));
	        const minAltitude = Math.min(r0[3], Math.min(r1[3], Math.min(r2[3], r3[3])));
	        const maxAltitude = Math.max(r0[3], Math.max(r1[3], Math.max(r2[3], r3[3])));
	        const minLngLat = new ref_properties.LngLat(minLng, minLat);
	        const maxLngLat = new ref_properties.LngLat(maxLng, maxLat);
	        return {
	            minLngLat,
	            maxLngLat,
	            minAltitude,
	            maxAltitude
	        };
	    }
	    fitScreenCoordinates(p0, p1, bearing, options, eventData) {
	        if (this.transform.projection.name === 'globe') {
	            ref_properties.warnOnce('Globe projection does not support fitScreenCoordinates API, this API may behave unexpectedly.');
	        }
	        let lngLat0, lngLat1, minAltitude, maxAltitude;
	        const point0 = ref_properties.pointGeometry.convert(p0);
	        const point1 = ref_properties.pointGeometry.convert(p1);
	        const raycast = this._raycastElevationBox(point0, point1);
	        if (!raycast) {
	            if (this.transform.anyCornerOffEdge(point0, point1)) {
	                return this;
	            }
	            lngLat0 = this.transform.pointLocation(point0);
	            lngLat1 = this.transform.pointLocation(point1);
	        } else {
	            lngLat0 = raycast.minLngLat;
	            lngLat1 = raycast.maxLngLat;
	            minAltitude = raycast.minAltitude;
	            maxAltitude = raycast.maxAltitude;
	        }
	        if (this.transform.pitch === 0) {
	            return this._fitInternal(this._cameraForBoxAndBearing(this.transform.pointLocation(ref_properties.pointGeometry.convert(p0)), this.transform.pointLocation(ref_properties.pointGeometry.convert(p1)), bearing, options), options, eventData);
	        }
	        return this._fitInternal(this._cameraForBox(lngLat0, lngLat1, minAltitude, maxAltitude, options), options, eventData);
	    }
	    _fitInternal(calculatedOptions, options, eventData) {
	        if (!calculatedOptions)
	            return this;
	        options = ref_properties.extend(calculatedOptions, options);
	        delete options.padding;
	        return options.linear ? this.easeTo(options, eventData) : this.flyTo(options, eventData);
	    }
	    jumpTo(options, eventData) {
	        this.stop();
	        const tr = options.preloadOnly ? this.transform.clone() : this.transform;
	        let zoomChanged = false, bearingChanged = false, pitchChanged = false;
	        if ('zoom' in options && tr.zoom !== +options.zoom) {
	            zoomChanged = true;
	            tr.zoom = +options.zoom;
	        }
	        if (options.center !== undefined) {
	            tr.center = ref_properties.LngLat.convert(options.center);
	        }
	        if ('bearing' in options && tr.bearing !== +options.bearing) {
	            bearingChanged = true;
	            tr.bearing = +options.bearing;
	        }
	        if ('pitch' in options && tr.pitch !== +options.pitch) {
	            pitchChanged = true;
	            tr.pitch = +options.pitch;
	        }
	        if (options.padding != null && !tr.isPaddingEqual(options.padding)) {
	            tr.padding = options.padding;
	        }
	        if (options.preloadOnly) {
	            this._preloadTiles(tr);
	            return this;
	        }
	        this.fire(new ref_properties.Event('movestart', eventData)).fire(new ref_properties.Event('move', eventData));
	        if (zoomChanged) {
	            this.fire(new ref_properties.Event('zoomstart', eventData)).fire(new ref_properties.Event('zoom', eventData)).fire(new ref_properties.Event('zoomend', eventData));
	        }
	        if (bearingChanged) {
	            this.fire(new ref_properties.Event('rotatestart', eventData)).fire(new ref_properties.Event('rotate', eventData)).fire(new ref_properties.Event('rotateend', eventData));
	        }
	        if (pitchChanged) {
	            this.fire(new ref_properties.Event('pitchstart', eventData)).fire(new ref_properties.Event('pitch', eventData)).fire(new ref_properties.Event('pitchend', eventData));
	        }
	        return this.fire(new ref_properties.Event('moveend', eventData));
	    }
	    getFreeCameraOptions() {
	        if (!this.transform.projection.supportsFreeCamera) {
	            ref_properties.warnOnce(freeCameraNotSupportedWarning);
	        }
	        return this.transform.getFreeCameraOptions();
	    }
	    setFreeCameraOptions(options, eventData) {
	        const tr = this.transform;
	        if (!tr.projection.supportsFreeCamera) {
	            ref_properties.warnOnce(freeCameraNotSupportedWarning);
	            return this;
	        }
	        this.stop();
	        const prevZoom = tr.zoom;
	        const prevPitch = tr.pitch;
	        const prevBearing = tr.bearing;
	        tr.setFreeCameraOptions(options);
	        const zoomChanged = prevZoom !== tr.zoom;
	        const pitchChanged = prevPitch !== tr.pitch;
	        const bearingChanged = prevBearing !== tr.bearing;
	        this.fire(new ref_properties.Event('movestart', eventData)).fire(new ref_properties.Event('move', eventData));
	        if (zoomChanged) {
	            this.fire(new ref_properties.Event('zoomstart', eventData)).fire(new ref_properties.Event('zoom', eventData)).fire(new ref_properties.Event('zoomend', eventData));
	        }
	        if (bearingChanged) {
	            this.fire(new ref_properties.Event('rotatestart', eventData)).fire(new ref_properties.Event('rotate', eventData)).fire(new ref_properties.Event('rotateend', eventData));
	        }
	        if (pitchChanged) {
	            this.fire(new ref_properties.Event('pitchstart', eventData)).fire(new ref_properties.Event('pitch', eventData)).fire(new ref_properties.Event('pitchend', eventData));
	        }
	        this.fire(new ref_properties.Event('moveend', eventData));
	        return this;
	    }
	    easeTo(options, eventData) {
	        this._stop(false, options.easeId);
	        options = ref_properties.extend({
	            offset: [
	                0,
	                0
	            ],
	            duration: 500,
	            easing: ref_properties.ease
	        }, options);
	        if (options.animate === false || !options.essential && ref_properties.exported.prefersReducedMotion)
	            options.duration = 0;
	        const tr = this.transform, startZoom = this.getZoom(), startBearing = this.getBearing(), startPitch = this.getPitch(), startPadding = this.getPadding(), zoom = 'zoom' in options ? +options.zoom : startZoom, bearing = 'bearing' in options ? this._normalizeBearing(options.bearing, startBearing) : startBearing, pitch = 'pitch' in options ? +options.pitch : startPitch, padding = 'padding' in options ? options.padding : tr.padding;
	        const offsetAsPoint = ref_properties.pointGeometry.convert(options.offset);
	        let pointAtOffset;
	        let from;
	        let delta;
	        if (tr.projection.name === 'globe') {
	            const centerCoord = ref_properties.MercatorCoordinate.fromLngLat(tr.center);
	            const rotatedOffset = offsetAsPoint.rotate(-tr.angle);
	            centerCoord.x += rotatedOffset.x / tr.worldSize;
	            centerCoord.y += rotatedOffset.y / tr.worldSize;
	            const locationAtOffset = centerCoord.toLngLat();
	            const center = ref_properties.LngLat.convert(options.center || locationAtOffset);
	            this._normalizeCenter(center);
	            pointAtOffset = tr.centerPoint.add(rotatedOffset);
	            from = new ref_properties.pointGeometry(centerCoord.x, centerCoord.y).mult(tr.worldSize);
	            delta = new ref_properties.pointGeometry(ref_properties.mercatorXfromLng(center.lng), ref_properties.mercatorYfromLat(center.lat)).mult(tr.worldSize).sub(from);
	        } else {
	            pointAtOffset = tr.centerPoint.add(offsetAsPoint);
	            const locationAtOffset = tr.pointLocation(pointAtOffset);
	            const center = ref_properties.LngLat.convert(options.center || locationAtOffset);
	            this._normalizeCenter(center);
	            from = tr.project(locationAtOffset);
	            delta = tr.project(center).sub(from);
	        }
	        const finalScale = tr.zoomScale(zoom - startZoom);
	        let around, aroundPoint;
	        if (options.around) {
	            around = ref_properties.LngLat.convert(options.around);
	            aroundPoint = tr.locationPoint(around);
	        }
	        const zoomChanged = this._zooming || zoom !== startZoom;
	        const bearingChanged = this._rotating || startBearing !== bearing;
	        const pitchChanged = this._pitching || pitch !== startPitch;
	        const paddingChanged = !tr.isPaddingEqual(padding);
	        const frame = tr => k => {
	            if (zoomChanged) {
	                tr.zoom = ref_properties.number(startZoom, zoom, k);
	            }
	            if (bearingChanged) {
	                tr.bearing = ref_properties.number(startBearing, bearing, k);
	            }
	            if (pitchChanged) {
	                tr.pitch = ref_properties.number(startPitch, pitch, k);
	            }
	            if (paddingChanged) {
	                tr.interpolatePadding(startPadding, padding, k);
	                pointAtOffset = tr.centerPoint.add(offsetAsPoint);
	            }
	            if (around) {
	                tr.setLocationAtPoint(around, aroundPoint);
	            } else {
	                const scale = tr.zoomScale(tr.zoom - startZoom);
	                const base = zoom > startZoom ? Math.min(2, finalScale) : Math.max(0.5, finalScale);
	                const speedup = Math.pow(base, 1 - k);
	                const newCenter = tr.unproject(from.add(delta.mult(k * speedup)).mult(scale));
	                tr.setLocationAtPoint(tr.renderWorldCopies ? newCenter.wrap() : newCenter, pointAtOffset);
	            }
	            if (!options.preloadOnly) {
	                this._fireMoveEvents(eventData);
	            }
	            return tr;
	        };
	        if (options.preloadOnly) {
	            const predictedTransforms = this._emulate(frame, options.duration, tr);
	            this._preloadTiles(predictedTransforms);
	            return this;
	        }
	        const currently = {
	            moving: this._moving,
	            zooming: this._zooming,
	            rotating: this._rotating,
	            pitching: this._pitching
	        };
	        this._zooming = zoomChanged;
	        this._rotating = bearingChanged;
	        this._pitching = pitchChanged;
	        this._padding = paddingChanged;
	        this._easeId = options.easeId;
	        this._prepareEase(eventData, options.noMoveStart, currently);
	        this._ease(frame(tr), interruptingEaseId => {
	            tr.recenterOnTerrain();
	            this._afterEase(eventData, interruptingEaseId);
	        }, options);
	        return this;
	    }
	    _prepareEase(eventData, noMoveStart, currently = {}) {
	        this._moving = true;
	        this.transform.cameraElevationReference = 'sea';
	        if (!noMoveStart && !currently.moving) {
	            this.fire(new ref_properties.Event('movestart', eventData));
	        }
	        if (this._zooming && !currently.zooming) {
	            this.fire(new ref_properties.Event('zoomstart', eventData));
	        }
	        if (this._rotating && !currently.rotating) {
	            this.fire(new ref_properties.Event('rotatestart', eventData));
	        }
	        if (this._pitching && !currently.pitching) {
	            this.fire(new ref_properties.Event('pitchstart', eventData));
	        }
	    }
	    _fireMoveEvents(eventData) {
	        this.fire(new ref_properties.Event('move', eventData));
	        if (this._zooming) {
	            this.fire(new ref_properties.Event('zoom', eventData));
	        }
	        if (this._rotating) {
	            this.fire(new ref_properties.Event('rotate', eventData));
	        }
	        if (this._pitching) {
	            this.fire(new ref_properties.Event('pitch', eventData));
	        }
	    }
	    _afterEase(eventData, easeId) {
	        if (this._easeId && easeId && this._easeId === easeId) {
	            return;
	        }
	        this._easeId = undefined;
	        this.transform.cameraElevationReference = 'ground';
	        const wasZooming = this._zooming;
	        const wasRotating = this._rotating;
	        const wasPitching = this._pitching;
	        this._moving = false;
	        this._zooming = false;
	        this._rotating = false;
	        this._pitching = false;
	        this._padding = false;
	        if (wasZooming) {
	            this.fire(new ref_properties.Event('zoomend', eventData));
	        }
	        if (wasRotating) {
	            this.fire(new ref_properties.Event('rotateend', eventData));
	        }
	        if (wasPitching) {
	            this.fire(new ref_properties.Event('pitchend', eventData));
	        }
	        this.fire(new ref_properties.Event('moveend', eventData));
	    }
	    flyTo(options, eventData) {
	        if (!options.essential && ref_properties.exported.prefersReducedMotion) {
	            const coercedOptions = ref_properties.pick(options, [
	                'center',
	                'zoom',
	                'bearing',
	                'pitch',
	                'around'
	            ]);
	            return this.jumpTo(coercedOptions, eventData);
	        }
	        this.stop();
	        options = ref_properties.extend({
	            offset: [
	                0,
	                0
	            ],
	            speed: 1.2,
	            curve: 1.42,
	            easing: ref_properties.ease
	        }, options);
	        const tr = this.transform, startZoom = this.getZoom(), startBearing = this.getBearing(), startPitch = this.getPitch(), startPadding = this.getPadding();
	        const zoom = 'zoom' in options ? ref_properties.clamp(+options.zoom, tr.minZoom, tr.maxZoom) : startZoom;
	        const bearing = 'bearing' in options ? this._normalizeBearing(options.bearing, startBearing) : startBearing;
	        const pitch = 'pitch' in options ? +options.pitch : startPitch;
	        const padding = 'padding' in options ? options.padding : tr.padding;
	        const scale = tr.zoomScale(zoom - startZoom);
	        const offsetAsPoint = ref_properties.pointGeometry.convert(options.offset);
	        let pointAtOffset = tr.centerPoint.add(offsetAsPoint);
	        const locationAtOffset = tr.pointLocation(pointAtOffset);
	        const center = ref_properties.LngLat.convert(options.center || locationAtOffset);
	        this._normalizeCenter(center);
	        const from = tr.project(locationAtOffset);
	        const delta = tr.project(center).sub(from);
	        let rho = options.curve;
	        const w0 = Math.max(tr.width, tr.height), w1 = w0 / scale, u1 = delta.mag();
	        if ('minZoom' in options) {
	            const minZoom = ref_properties.clamp(Math.min(options.minZoom, startZoom, zoom), tr.minZoom, tr.maxZoom);
	            const wMax = w0 / tr.zoomScale(minZoom - startZoom);
	            rho = Math.sqrt(wMax / u1 * 2);
	        }
	        const rho2 = rho * rho;
	        function r(i) {
	            const b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);
	            return Math.log(Math.sqrt(b * b + 1) - b);
	        }
	        function sinh(n) {
	            return (Math.exp(n) - Math.exp(-n)) / 2;
	        }
	        function cosh(n) {
	            return (Math.exp(n) + Math.exp(-n)) / 2;
	        }
	        function tanh(n) {
	            return sinh(n) / cosh(n);
	        }
	        const r0 = r(0);
	        let w = function (s) {
	            return cosh(r0) / cosh(r0 + rho * s);
	        };
	        let u = function (s) {
	            return w0 * ((cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2) / u1;
	        };
	        let S = (r(1) - r0) / rho;
	        if (Math.abs(u1) < 0.000001 || !isFinite(S)) {
	            if (Math.abs(w0 - w1) < 0.000001)
	                return this.easeTo(options, eventData);
	            const k = w1 < w0 ? -1 : 1;
	            S = Math.abs(Math.log(w1 / w0)) / rho;
	            u = function () {
	                return 0;
	            };
	            w = function (s) {
	                return Math.exp(k * rho * s);
	            };
	        }
	        if ('duration' in options) {
	            options.duration = +options.duration;
	        } else {
	            const V = 'screenSpeed' in options ? +options.screenSpeed / rho : +options.speed;
	            options.duration = 1000 * S / V;
	        }
	        if (options.maxDuration && options.duration > options.maxDuration) {
	            options.duration = 0;
	        }
	        const zoomChanged = true;
	        const bearingChanged = startBearing !== bearing;
	        const pitchChanged = pitch !== startPitch;
	        const paddingChanged = !tr.isPaddingEqual(padding);
	        const frame = tr => k => {
	            const s = k * S;
	            const scale = 1 / w(s);
	            tr.zoom = k === 1 ? zoom : startZoom + tr.scaleZoom(scale);
	            if (bearingChanged) {
	                tr.bearing = ref_properties.number(startBearing, bearing, k);
	            }
	            if (pitchChanged) {
	                tr.pitch = ref_properties.number(startPitch, pitch, k);
	            }
	            if (paddingChanged) {
	                tr.interpolatePadding(startPadding, padding, k);
	                pointAtOffset = tr.centerPoint.add(offsetAsPoint);
	            }
	            const newCenter = k === 1 ? center : tr.unproject(from.add(delta.mult(u(s))).mult(scale));
	            tr.setLocationAtPoint(tr.renderWorldCopies ? newCenter.wrap() : newCenter, pointAtOffset);
	            tr._updateCameraOnTerrain();
	            if (!options.preloadOnly) {
	                this._fireMoveEvents(eventData);
	            }
	            return tr;
	        };
	        if (options.preloadOnly) {
	            const predictedTransforms = this._emulate(frame, options.duration, tr);
	            this._preloadTiles(predictedTransforms);
	            return this;
	        }
	        this._zooming = zoomChanged;
	        this._rotating = bearingChanged;
	        this._pitching = pitchChanged;
	        this._padding = paddingChanged;
	        this._prepareEase(eventData, false);
	        this._ease(frame(tr), () => this._afterEase(eventData), options);
	        return this;
	    }
	    isEasing() {
	        return !!this._easeFrameId;
	    }
	    stop() {
	        return this._stop();
	    }
	    _stop(allowGestures, easeId) {
	        if (this._easeFrameId) {
	            this._cancelRenderFrame(this._easeFrameId);
	            this._easeFrameId = undefined;
	            this._onEaseFrame = undefined;
	        }
	        if (this._onEaseEnd) {
	            const onEaseEnd = this._onEaseEnd;
	            this._onEaseEnd = undefined;
	            onEaseEnd.call(this, easeId);
	        }
	        if (!allowGestures) {
	            const handlers = this.handlers;
	            if (handlers)
	                handlers.stop(false);
	        }
	        return this;
	    }
	    _ease(frame, finish, options) {
	        if (options.animate === false || options.duration === 0) {
	            frame(1);
	            finish();
	        } else {
	            this._easeStart = ref_properties.exported.now();
	            this._easeOptions = options;
	            this._onEaseFrame = frame;
	            this._onEaseEnd = finish;
	            this._easeFrameId = this._requestRenderFrame(this._renderFrameCallback);
	        }
	    }
	    _renderFrameCallback() {
	        const t = Math.min((ref_properties.exported.now() - this._easeStart) / this._easeOptions.duration, 1);
	        const frame = this._onEaseFrame;
	        if (frame)
	            frame(this._easeOptions.easing(t));
	        if (t < 1) {
	            this._easeFrameId = this._requestRenderFrame(this._renderFrameCallback);
	        } else {
	            this.stop();
	        }
	    }
	    _normalizeBearing(bearing, currentBearing) {
	        bearing = ref_properties.wrap(bearing, -180, 180);
	        const diff = Math.abs(bearing - currentBearing);
	        if (Math.abs(bearing - 360 - currentBearing) < diff)
	            bearing -= 360;
	        if (Math.abs(bearing + 360 - currentBearing) < diff)
	            bearing += 360;
	        return bearing;
	    }
	    _normalizeCenter(center) {
	        const tr = this.transform;
	        if (!tr.renderWorldCopies || tr.maxBounds)
	            return;
	        const delta = center.lng - tr.center.lng;
	        center.lng += delta > 180 ? -360 : delta < -180 ? 360 : 0;
	    }
	    _emulate(frame, duration, initialTransform) {
	        const frameRate = 15;
	        const numFrames = Math.ceil(duration * frameRate / 1000);
	        const transforms = [];
	        const emulateFrame = frame(initialTransform.clone());
	        for (let i = 0; i <= numFrames; i++) {
	            const transform = emulateFrame(i / numFrames);
	            transforms.push(transform.clone());
	        }
	        return transforms;
	    }
	}

	class AttributionControl {
	    constructor(options = {}) {
	        this.options = options;
	        ref_properties.bindAll([
	            '_toggleAttribution',
	            '_updateEditLink',
	            '_updateData',
	            '_updateCompact'
	        ], this);
	    }
	    getDefaultPosition() {
	        return 'bottom-right';
	    }
	    onAdd(map) {
	        const compact = this.options && this.options.compact;
	        this._map = map;
	        this._container = create$2('div', 'mapboxgl-ctrl mapboxgl-ctrl-attrib');
	        this._compactButton = create$2('button', 'mapboxgl-ctrl-attrib-button', this._container);
	        create$2('span', `mapboxgl-ctrl-icon`, this._compactButton).setAttribute('aria-hidden', 'true');
	        this._compactButton.type = 'button';
	        this._compactButton.addEventListener('click', this._toggleAttribution);
	        this._setElementTitle(this._compactButton, 'ToggleAttribution');
	        this._innerContainer = create$2('div', 'mapboxgl-ctrl-attrib-inner', this._container);
	        this._innerContainer.setAttribute('role', 'list');
	        if (compact) {
	            this._container.classList.add('mapboxgl-compact');
	        }
	        this._updateAttributions();
	        this._updateEditLink();
	        this._map.on('styledata', this._updateData);
	        this._map.on('sourcedata', this._updateData);
	        this._map.on('moveend', this._updateEditLink);
	        if (compact === undefined) {
	            this._map.on('resize', this._updateCompact);
	            this._updateCompact();
	        }
	        return this._container;
	    }
	    onRemove() {
	        this._container.remove();
	        this._map.off('styledata', this._updateData);
	        this._map.off('sourcedata', this._updateData);
	        this._map.off('moveend', this._updateEditLink);
	        this._map.off('resize', this._updateCompact);
	        this._map = undefined;
	        this._attribHTML = undefined;
	    }
	    _setElementTitle(element, title) {
	        const str = this._map._getUIString(`AttributionControl.${ title }`);
	        element.setAttribute('aria-label', str);
	        element.removeAttribute('title');
	        if (element.firstElementChild)
	            element.firstElementChild.setAttribute('title', str);
	    }
	    _toggleAttribution() {
	        if (this._container.classList.contains('mapboxgl-compact-show')) {
	            this._container.classList.remove('mapboxgl-compact-show');
	            this._compactButton.setAttribute('aria-expanded', 'false');
	        } else {
	            this._container.classList.add('mapboxgl-compact-show');
	            this._compactButton.setAttribute('aria-expanded', 'true');
	        }
	    }
	    _updateEditLink() {
	        let editLink = this._editLink;
	        if (!editLink) {
	            editLink = this._editLink = this._container.querySelector('.mapbox-improve-map');
	        }
	        const params = [
	            {
	                key: 'owner',
	                value: this.styleOwner
	            },
	            {
	                key: 'id',
	                value: this.styleId
	            },
	            {
	                key: 'access_token',
	                value: this._map._requestManager._customAccessToken || ref_properties.config.ACCESS_TOKEN
	            }
	        ];
	        if (editLink) {
	            const paramString = params.reduce((acc, next, i) => {
	                if (next.value) {
	                    acc += `${ next.key }=${ next.value }${ i < params.length - 1 ? '&' : '' }`;
	                }
	                return acc;
	            }, `?`);
	            editLink.href = `${ ref_properties.config.FEEDBACK_URL }/${ paramString }${ this._map._hash ? this._map._hash.getHashString(true) : '' }`;
	            editLink.rel = 'noopener nofollow';
	            this._setElementTitle(editLink, 'MapFeedback');
	        }
	    }
	    _updateData(e) {
	        if (e && (e.sourceDataType === 'metadata' || e.sourceDataType === 'visibility' || e.dataType === 'style')) {
	            this._updateAttributions();
	            this._updateEditLink();
	        }
	    }
	    _updateAttributions() {
	        if (!this._map.style)
	            return;
	        let attributions = [];
	        if (this._map.style.stylesheet) {
	            const stylesheet = this._map.style.stylesheet;
	            this.styleOwner = stylesheet.owner;
	            this.styleId = stylesheet.id;
	        }
	        const sourceCaches = this._map.style._sourceCaches;
	        for (const id in sourceCaches) {
	            const sourceCache = sourceCaches[id];
	            if (sourceCache.used) {
	                const source = sourceCache.getSource();
	                if (source.attribution && attributions.indexOf(source.attribution) < 0) {
	                    attributions.push(source.attribution);
	                }
	            }
	        }
	        attributions.sort((a, b) => a.length - b.length);
	        attributions = attributions.filter((attrib, i) => {
	            for (let j = i + 1; j < attributions.length; j++) {
	                if (attributions[j].indexOf(attrib) >= 0) {
	                    return false;
	                }
	            }
	            return true;
	        });
	        if (this.options.customAttribution) {
	            if (Array.isArray(this.options.customAttribution)) {
	                attributions = [
	                    ...this.options.customAttribution,
	                    ...attributions
	                ];
	            } else {
	                attributions.unshift(this.options.customAttribution);
	            }
	        }
	        const attribHTML = attributions.join(' | ');
	        if (attribHTML === this._attribHTML)
	            return;
	        this._attribHTML = attribHTML;
	        if (attributions.length) {
	            this._innerContainer.innerHTML = attribHTML;
	            this._container.classList.remove('mapboxgl-attrib-empty');
	        } else {
	            this._container.classList.add('mapboxgl-attrib-empty');
	        }
	        this._editLink = null;
	    }
	    _updateCompact() {
	        if (this._map.getCanvasContainer().offsetWidth <= 640) {
	            this._container.classList.add('mapboxgl-compact');
	        } else {
	            this._container.classList.remove('mapboxgl-compact', 'mapboxgl-compact-show');
	        }
	    }
	}

	class LogoControl {
	    constructor() {
	        ref_properties.bindAll([
	            '_updateLogo',
	            '_updateCompact'
	        ], this);
	    }
	    onAdd(map) {
	        this._map = map;
	        this._container = create$2('div', 'mapboxgl-ctrl');
	        const anchor = create$2('a', 'mapboxgl-ctrl-logo');
	        anchor.target = '_blank';
	        anchor.rel = 'noopener nofollow';
	        anchor.href = 'https://www.mapbox.com/';
	        anchor.setAttribute('aria-label', this._map._getUIString('LogoControl.Title'));
	        anchor.setAttribute('rel', 'noopener nofollow');
	        this._container.appendChild(anchor);
	        this._container.style.display = 'none';
	        this._map.on('sourcedata', this._updateLogo);
	        this._updateLogo();
	        this._map.on('resize', this._updateCompact);
	        this._updateCompact();
	        return this._container;
	    }
	    onRemove() {
	        this._container.remove();
	        this._map.off('sourcedata', this._updateLogo);
	        this._map.off('resize', this._updateCompact);
	    }
	    getDefaultPosition() {
	        return 'bottom-left';
	    }
	    _updateLogo(e) {
	        if (!e || e.sourceDataType === 'metadata') {
	            this._container.style.display = this._logoRequired() ? 'block' : 'none';
	        }
	    }
	    _logoRequired() {
	        if (!this._map.style)
	            return true;
	        const sourceCaches = this._map.style._sourceCaches;
	        if (Object.entries(sourceCaches).length === 0)
	            return true;
	        for (const id in sourceCaches) {
	            const source = sourceCaches[id].getSource();
	            if (source.hasOwnProperty('mapbox_logo') && !source.mapbox_logo) {
	                return false;
	            }
	        }
	        return true;
	    }
	    _updateCompact() {
	        const containerChildren = this._container.children;
	        if (containerChildren.length) {
	            const anchor = containerChildren[0];
	            if (this._map.getCanvasContainer().offsetWidth < 250) {
	                anchor.classList.add('mapboxgl-compact');
	            } else {
	                anchor.classList.remove('mapboxgl-compact');
	            }
	        }
	    }
	}

	class TaskQueue {
	    constructor() {
	        this._queue = [];
	        this._id = 0;
	        this._cleared = false;
	        this._currentlyRunning = false;
	    }
	    add(callback) {
	        const id = ++this._id;
	        const queue = this._queue;
	        queue.push({
	            callback,
	            id,
	            cancelled: false
	        });
	        return id;
	    }
	    remove(id) {
	        const running = this._currentlyRunning;
	        const queue = running ? this._queue.concat(running) : this._queue;
	        for (const task of queue) {
	            if (task.id === id) {
	                task.cancelled = true;
	                return;
	            }
	        }
	    }
	    run(timeStamp = 0) {
	        const queue = this._currentlyRunning = this._queue;
	        this._queue = [];
	        for (const task of queue) {
	            if (task.cancelled)
	                continue;
	            task.callback(timeStamp);
	            if (this._cleared)
	                break;
	        }
	        this._cleared = false;
	        this._currentlyRunning = false;
	    }
	    clear() {
	        if (this._currentlyRunning) {
	            this._cleared = true;
	        }
	        this._queue = [];
	    }
	}

	function smartWrap (lngLat, priorPos, transform) {
	    lngLat = new ref_properties.LngLat(lngLat.lng, lngLat.lat);
	    if (priorPos) {
	        const left = new ref_properties.LngLat(lngLat.lng - 360, lngLat.lat);
	        const right = new ref_properties.LngLat(lngLat.lng + 360, lngLat.lat);
	        const withinWrap = Math.ceil(Math.abs(lngLat.lng - transform.center.lng) / 360) * 360;
	        const delta = transform.locationPoint(lngLat).distSqr(priorPos);
	        const offscreen = priorPos.x < 0 || priorPos.y < 0 || priorPos.x > transform.width || priorPos.y > transform.height;
	        if (transform.locationPoint(left).distSqr(priorPos) < delta && (offscreen || Math.abs(left.lng - transform.center.lng) < withinWrap)) {
	            lngLat = left;
	        } else if (transform.locationPoint(right).distSqr(priorPos) < delta && (offscreen || Math.abs(right.lng - transform.center.lng) < withinWrap)) {
	            lngLat = right;
	        }
	    }
	    while (Math.abs(lngLat.lng - transform.center.lng) > 180) {
	        const pos = transform.locationPoint(lngLat);
	        if (pos.x >= 0 && pos.y >= 0 && pos.x <= transform.width && pos.y <= transform.height) {
	            break;
	        }
	        if (lngLat.lng > transform.center.lng) {
	            lngLat.lng -= 360;
	        } else {
	            lngLat.lng += 360;
	        }
	    }
	    return lngLat;
	}

	const anchorTranslate = {
	    'center': 'translate(-50%,-50%)',
	    'top': 'translate(-50%,0)',
	    'top-left': 'translate(0,0)',
	    'top-right': 'translate(-100%,0)',
	    'bottom': 'translate(-50%,-100%)',
	    'bottom-left': 'translate(0,-100%)',
	    'bottom-right': 'translate(-100%,-100%)',
	    'left': 'translate(0,-50%)',
	    'right': 'translate(-100%,-50%)'
	};

	const TERRAIN_OCCLUDED_OPACITY = 0.2;
	class Marker extends ref_properties.Evented {
	    constructor(options, legacyOptions) {
	        super();
	        if (options instanceof ref_properties.window.HTMLElement || legacyOptions) {
	            options = ref_properties.extend({ element: options }, legacyOptions);
	        }
	        ref_properties.bindAll([
	            '_update',
	            '_onMove',
	            '_onUp',
	            '_addDragHandler',
	            '_onMapClick',
	            '_onKeyPress',
	            '_clearFadeTimer'
	        ], this);
	        this._anchor = options && options.anchor || 'center';
	        this._color = options && options.color || '#3FB1CE';
	        this._scale = options && options.scale || 1;
	        this._draggable = options && options.draggable || false;
	        this._clickTolerance = options && options.clickTolerance || 0;
	        this._isDragging = false;
	        this._state = 'inactive';
	        this._rotation = options && options.rotation || 0;
	        this._rotationAlignment = options && options.rotationAlignment || 'auto';
	        this._pitchAlignment = options && options.pitchAlignment && options.pitchAlignment || 'auto';
	        this._updateMoving = () => this._update(true);
	        if (!options || !options.element) {
	            this._defaultMarker = true;
	            this._element = create$2('div');
	            const defaultHeight = 41;
	            const defaultWidth = 27;
	            const svg = createSVG('svg', {
	                display: 'block',
	                height: `${ defaultHeight * this._scale }px`,
	                width: `${ defaultWidth * this._scale }px`,
	                viewBox: `0 0 ${ defaultWidth } ${ defaultHeight }`
	            }, this._element);
	            const gradient = createSVG('radialGradient', { id: 'shadowGradient' }, createSVG('defs', {}, svg));
	            createSVG('stop', {
	                offset: '10%',
	                'stop-opacity': 0.4
	            }, gradient);
	            createSVG('stop', {
	                offset: '100%',
	                'stop-opacity': 0.05
	            }, gradient);
	            createSVG('ellipse', {
	                cx: 13.5,
	                cy: 34.8,
	                rx: 10.5,
	                ry: 5.25,
	                fill: 'url(#shadowGradient)'
	            }, svg);
	            createSVG('path', {
	                fill: this._color,
	                d: 'M27,13.5C27,19.07 20.25,27 14.75,34.5C14.02,35.5 12.98,35.5 12.25,34.5C6.75,27 0,19.22 0,13.5C0,6.04 6.04,0 13.5,0C20.96,0 27,6.04 27,13.5Z'
	            }, svg);
	            createSVG('path', {
	                opacity: 0.25,
	                d: 'M13.5,0C6.04,0 0,6.04 0,13.5C0,19.22 6.75,27 12.25,34.5C13,35.52 14.02,35.5 14.75,34.5C20.25,27 27,19.07 27,13.5C27,6.04 20.96,0 13.5,0ZM13.5,1C20.42,1 26,6.58 26,13.5C26,15.9 24.5,19.18 22.22,22.74C19.95,26.3 16.71,30.14 13.94,33.91C13.74,34.18 13.61,34.32 13.5,34.44C13.39,34.32 13.26,34.18 13.06,33.91C10.28,30.13 7.41,26.31 5.02,22.77C2.62,19.23 1,15.95 1,13.5C1,6.58 6.58,1 13.5,1Z'
	            }, svg);
	            createSVG('circle', {
	                fill: 'white',
	                cx: 13.5,
	                cy: 13.5,
	                r: 5.5
	            }, svg);
	            this._offset = ref_properties.pointGeometry.convert(options && options.offset || [
	                0,
	                -14
	            ]);
	        } else {
	            this._element = options.element;
	            this._offset = ref_properties.pointGeometry.convert(options && options.offset || [
	                0,
	                0
	            ]);
	        }
	        if (!this._element.hasAttribute('aria-label'))
	            this._element.setAttribute('aria-label', 'Map marker');
	        this._element.classList.add('mapboxgl-marker');
	        this._element.addEventListener('dragstart', e => {
	            e.preventDefault();
	        });
	        this._element.addEventListener('mousedown', e => {
	            e.preventDefault();
	        });
	        const classList = this._element.classList;
	        for (const key in anchorTranslate) {
	            classList.remove(`mapboxgl-marker-anchor-${ key }`);
	        }
	        classList.add(`mapboxgl-marker-anchor-${ this._anchor }`);
	        this._popup = null;
	    }
	    addTo(map) {
	        if (map === this._map) {
	            return this;
	        }
	        this.remove();
	        this._map = map;
	        map.getCanvasContainer().appendChild(this._element);
	        map.on('move', this._updateMoving);
	        map.on('moveend', this._update);
	        map.on('remove', this._clearFadeTimer);
	        map._addMarker(this);
	        this.setDraggable(this._draggable);
	        this._update();
	        map.on('click', this._onMapClick);
	        return this;
	    }
	    remove() {
	        const map = this._map;
	        if (map) {
	            map.off('click', this._onMapClick);
	            map.off('move', this._updateMoving);
	            map.off('moveend', this._update);
	            map.off('mousedown', this._addDragHandler);
	            map.off('touchstart', this._addDragHandler);
	            map.off('mouseup', this._onUp);
	            map.off('touchend', this._onUp);
	            map.off('mousemove', this._onMove);
	            map.off('touchmove', this._onMove);
	            map.off('remove', this._clearFadeTimer);
	            map._removeMarker(this);
	            this._map = undefined;
	        }
	        this._clearFadeTimer();
	        this._element.remove();
	        if (this._popup)
	            this._popup.remove();
	        return this;
	    }
	    getLngLat() {
	        return this._lngLat;
	    }
	    setLngLat(lnglat) {
	        this._lngLat = ref_properties.LngLat.convert(lnglat);
	        this._pos = null;
	        if (this._popup)
	            this._popup.setLngLat(this._lngLat);
	        this._update(true);
	        return this;
	    }
	    getElement() {
	        return this._element;
	    }
	    setPopup(popup) {
	        if (this._popup) {
	            this._popup.remove();
	            this._popup = null;
	            this._element.removeAttribute('role');
	            this._element.removeEventListener('keypress', this._onKeyPress);
	            if (!this._originalTabIndex) {
	                this._element.removeAttribute('tabindex');
	            }
	        }
	        if (popup) {
	            if (!('offset' in popup.options)) {
	                const markerHeight = 41 - 5.8 / 2;
	                const markerRadius = 13.5;
	                const linearOffset = Math.sqrt(Math.pow(markerRadius, 2) / 2);
	                popup.options.offset = this._defaultMarker ? {
	                    'top': [
	                        0,
	                        0
	                    ],
	                    'top-left': [
	                        0,
	                        0
	                    ],
	                    'top-right': [
	                        0,
	                        0
	                    ],
	                    'bottom': [
	                        0,
	                        -markerHeight
	                    ],
	                    'bottom-left': [
	                        linearOffset,
	                        (markerHeight - markerRadius + linearOffset) * -1
	                    ],
	                    'bottom-right': [
	                        -linearOffset,
	                        (markerHeight - markerRadius + linearOffset) * -1
	                    ],
	                    'left': [
	                        markerRadius,
	                        (markerHeight - markerRadius) * -1
	                    ],
	                    'right': [
	                        -markerRadius,
	                        (markerHeight - markerRadius) * -1
	                    ]
	                } : this._offset;
	            }
	            this._popup = popup;
	            popup._marker = this;
	            if (this._lngLat)
	                this._popup.setLngLat(this._lngLat);
	            this._element.setAttribute('role', 'button');
	            this._originalTabIndex = this._element.getAttribute('tabindex');
	            if (!this._originalTabIndex) {
	                this._element.setAttribute('tabindex', '0');
	            }
	            this._element.addEventListener('keypress', this._onKeyPress);
	            this._element.setAttribute('aria-expanded', 'false');
	        }
	        return this;
	    }
	    _onKeyPress(e) {
	        const code = e.code;
	        const legacyCode = e.charCode || e.keyCode;
	        if (code === 'Space' || code === 'Enter' || legacyCode === 32 || legacyCode === 13) {
	            this.togglePopup();
	        }
	    }
	    _onMapClick(e) {
	        const targetElement = e.originalEvent.target;
	        const element = this._element;
	        if (this._popup && (targetElement === element || element.contains(targetElement))) {
	            this.togglePopup();
	        }
	    }
	    getPopup() {
	        return this._popup;
	    }
	    togglePopup() {
	        const popup = this._popup;
	        if (!popup) {
	            return this;
	        } else if (popup.isOpen()) {
	            popup.remove();
	            this._element.setAttribute('aria-expanded', 'false');
	        } else if (this._map) {
	            popup.addTo(this._map);
	            this._element.setAttribute('aria-expanded', 'true');
	        }
	        return this;
	    }
	    _behindTerrain() {
	        const map = this._map;
	        if (!map)
	            return false;
	        const unprojected = map.unproject(this._pos);
	        const camera = map.getFreeCameraOptions();
	        if (!camera.position)
	            return false;
	        const cameraLngLat = camera.position.toLngLat();
	        const toClosestSurface = cameraLngLat.distanceTo(unprojected);
	        const toMarker = cameraLngLat.distanceTo(this._lngLat);
	        return toClosestSurface < toMarker * 0.9;
	    }
	    _evaluateOpacity() {
	        const map = this._map;
	        if (!map)
	            return;
	        const pos = this._pos;
	        if (!pos || pos.x < 0 || pos.x > map.transform.width || pos.y < 0 || pos.y > map.transform.height) {
	            this._clearFadeTimer();
	            return;
	        }
	        const mapLocation = map.unproject(pos);
	        let opacity;
	        if (map._usingGlobe() && ref_properties.isLngLatBehindGlobe(map.transform, this._lngLat)) {
	            opacity = 0;
	        } else {
	            opacity = 1 - map._queryFogOpacity(mapLocation);
	            if (map.transform._terrainEnabled() && map.getTerrain() && this._behindTerrain()) {
	                opacity *= TERRAIN_OCCLUDED_OPACITY;
	            }
	        }
	        this._element.style.opacity = `${ opacity }`;
	        this._element.style.pointerEvents = opacity > 0 ? 'auto' : 'none';
	        if (this._popup) {
	            this._popup._setOpacity(opacity);
	        }
	        this._fadeTimer = null;
	    }
	    _clearFadeTimer() {
	        if (this._fadeTimer) {
	            clearTimeout(this._fadeTimer);
	            this._fadeTimer = null;
	        }
	    }
	    _updateDOM() {
	        const pos = this._pos;
	        const map = this._map;
	        if (!pos || !map) {
	            return;
	        }
	        const rotation = this._calculateXYTransform() + this._calculateZTransform();
	        const offset = this._offset.mult(this._scale);
	        this._element.style.transform = `
	            translate(${ pos.x }px,${ pos.y }px) ${ anchorTranslate[this._anchor] }
	            ${ rotation }
	            translate(${ offset.x }px,${ offset.y }px)
	        `;
	    }
	    _calculateXYTransform() {
	        const pos = this._pos;
	        const map = this._map;
	        if (this.getPitchAlignment() !== 'map' || !map || !pos) {
	            return '';
	        }
	        if (!map._usingGlobe()) {
	            const pitch = map.getPitch();
	            return pitch ? `rotateX(${ pitch }deg)` : '';
	        }
	        const tilt = ref_properties.radToDeg(ref_properties.globeTiltAtLngLat(map.transform, this._lngLat));
	        const posFromCenter = pos.sub(ref_properties.globeCenterToScreenPoint(map.transform));
	        const tiltOverDist = tilt / (Math.abs(posFromCenter.x) + Math.abs(posFromCenter.y));
	        const yTilt = posFromCenter.x * tiltOverDist;
	        const xTilt = -posFromCenter.y * tiltOverDist;
	        if (!xTilt && !yTilt) {
	            return '';
	        }
	        return `rotateX(${ xTilt }deg) rotateY(${ yTilt }deg)`;
	    }
	    _calculateZTransform() {
	        const spin = this._calculateRotation();
	        return spin ? `rotateZ(${ spin }deg)` : ``;
	    }
	    _calculateRotation() {
	        if (this._rotationAlignment === 'viewport' || this._rotationAlignment === 'auto') {
	            return this._rotation;
	        }
	        if (this._map && this._rotationAlignment === 'map') {
	            const pos = this._pos;
	            const map = this._map;
	            if (pos && map && map._usingGlobe()) {
	                const north = map.project(new ref_properties.LngLat(this._lngLat.lng, this._lngLat.lat + 0.001));
	                const south = map.project(new ref_properties.LngLat(this._lngLat.lng, this._lngLat.lat - 0.001));
	                const diff = south.sub(north);
	                return this._rotation + ref_properties.radToDeg(Math.atan2(diff.y, diff.x)) - 90;
	            }
	            return this._rotation - this._map.getBearing();
	        }
	        return 0;
	    }
	    _update(delaySnap) {
	        ref_properties.window.cancelAnimationFrame(this._updateFrameId);
	        const map = this._map;
	        if (!map)
	            return;
	        if (map.transform.renderWorldCopies) {
	            this._lngLat = smartWrap(this._lngLat, this._pos, map.transform);
	        }
	        this._pos = map.project(this._lngLat);
	        if (delaySnap === true) {
	            this._updateFrameId = ref_properties.window.requestAnimationFrame(() => {
	                if (this._element && this._pos && this._anchor) {
	                    this._pos = this._pos.round();
	                    this._updateDOM();
	                }
	            });
	        } else {
	            this._pos = this._pos.round();
	        }
	        map._requestDomTask(() => {
	            if (!this._map)
	                return;
	            if (this._element && this._pos && this._anchor) {
	                this._updateDOM();
	            }
	            if ((map._usingGlobe() || map.getTerrain() || map.getFog()) && !this._fadeTimer) {
	                this._fadeTimer = setTimeout(this._evaluateOpacity.bind(this), 60);
	            }
	        });
	    }
	    getOffset() {
	        return this._offset;
	    }
	    setOffset(offset) {
	        this._offset = ref_properties.pointGeometry.convert(offset);
	        this._update();
	        return this;
	    }
	    _onMove(e) {
	        const map = this._map;
	        if (!map)
	            return;
	        if (!this._isDragging) {
	            const clickTolerance = this._clickTolerance || map._clickTolerance;
	            this._isDragging = e.point.dist(this._pointerdownPos) >= clickTolerance;
	        }
	        if (!this._isDragging)
	            return;
	        this._pos = e.point.sub(this._positionDelta);
	        this._lngLat = map.unproject(this._pos);
	        this.setLngLat(this._lngLat);
	        this._element.style.pointerEvents = 'none';
	        if (this._state === 'pending') {
	            this._state = 'active';
	            this.fire(new ref_properties.Event('dragstart'));
	        }
	        this.fire(new ref_properties.Event('drag'));
	    }
	    _onUp() {
	        this._element.style.pointerEvents = 'auto';
	        this._positionDelta = null;
	        this._pointerdownPos = null;
	        this._isDragging = false;
	        const map = this._map;
	        if (map) {
	            map.off('mousemove', this._onMove);
	            map.off('touchmove', this._onMove);
	        }
	        if (this._state === 'active') {
	            this.fire(new ref_properties.Event('dragend'));
	        }
	        this._state = 'inactive';
	    }
	    _addDragHandler(e) {
	        const map = this._map;
	        if (!map)
	            return;
	        if (this._element.contains(e.originalEvent.target)) {
	            e.preventDefault();
	            this._positionDelta = e.point.sub(this._pos);
	            this._pointerdownPos = e.point;
	            this._state = 'pending';
	            map.on('mousemove', this._onMove);
	            map.on('touchmove', this._onMove);
	            map.once('mouseup', this._onUp);
	            map.once('touchend', this._onUp);
	        }
	    }
	    setDraggable(shouldBeDraggable) {
	        this._draggable = !!shouldBeDraggable;
	        const map = this._map;
	        if (map) {
	            if (shouldBeDraggable) {
	                map.on('mousedown', this._addDragHandler);
	                map.on('touchstart', this._addDragHandler);
	            } else {
	                map.off('mousedown', this._addDragHandler);
	                map.off('touchstart', this._addDragHandler);
	            }
	        }
	        return this;
	    }
	    isDraggable() {
	        return this._draggable;
	    }
	    setRotation(rotation) {
	        this._rotation = rotation || 0;
	        this._update();
	        return this;
	    }
	    getRotation() {
	        return this._rotation;
	    }
	    setRotationAlignment(alignment) {
	        this._rotationAlignment = alignment || 'auto';
	        this._update();
	        return this;
	    }
	    getRotationAlignment() {
	        return this._rotationAlignment === `auto` ? 'viewport' : this._rotationAlignment;
	    }
	    setPitchAlignment(alignment) {
	        this._pitchAlignment = alignment || 'auto';
	        this._update();
	        return this;
	    }
	    getPitchAlignment() {
	        return this._pitchAlignment === `auto` ? this.getRotationAlignment() : this._pitchAlignment;
	    }
	}

	class EasedVariable {
	    constructor(initialValue) {
	        this.jumpTo(initialValue);
	    }
	    getValue(timeStamp) {
	        if (timeStamp <= this._startTime)
	            return this._start;
	        if (timeStamp >= this._endTime)
	            return this._end;
	        const t = ref_properties.easeCubicInOut((timeStamp - this._startTime) / (this._endTime - this._startTime));
	        return this._start * (1 - t) + this._end * t;
	    }
	    isEasing(timeStamp) {
	        return timeStamp >= this._startTime && timeStamp <= this._endTime;
	    }
	    jumpTo(value) {
	        this._startTime = -Infinity;
	        this._endTime = -Infinity;
	        this._start = value;
	        this._end = value;
	    }
	    easeTo(value, timeStamp, duration) {
	        this._start = this.getValue(timeStamp);
	        this._end = value;
	        this._startTime = timeStamp;
	        this._endTime = timeStamp + duration;
	    }
	}

	const defaultLocale = {
	    'AttributionControl.ToggleAttribution': 'Toggle attribution',
	    'AttributionControl.MapFeedback': 'Map feedback',
	    'FullscreenControl.Enter': 'Enter fullscreen',
	    'FullscreenControl.Exit': 'Exit fullscreen',
	    'GeolocateControl.FindMyLocation': 'Find my location',
	    'GeolocateControl.LocationNotAvailable': 'Location not available',
	    'LogoControl.Title': 'Mapbox logo',
	    'Map.Title': 'Map',
	    'NavigationControl.ResetBearing': 'Reset bearing to north',
	    'NavigationControl.ZoomIn': 'Zoom in',
	    'NavigationControl.ZoomOut': 'Zoom out',
	    'ScrollZoomBlocker.CtrlMessage': 'Use ctrl + scroll to zoom the map',
	    'ScrollZoomBlocker.CmdMessage': 'Use \u2318 + scroll to zoom the map',
	    'TouchPanBlocker.Message': 'Use two fingers to move the map'
	};

	const AVERAGE_ELEVATION_SAMPLING_INTERVAL = 500;
	const AVERAGE_ELEVATION_EASE_TIME = 300;
	const AVERAGE_ELEVATION_EASE_THRESHOLD = 1;
	const AVERAGE_ELEVATION_CHANGE_THRESHOLD = 0.0001;
	const defaultMinZoom = -2;
	const defaultMaxZoom = 22;
	const defaultMinPitch = 0;
	const defaultMaxPitch = 85;
	const defaultOptions$4 = {
	    center: [
	        0,
	        0
	    ],
	    zoom: 0,
	    bearing: 0,
	    pitch: 0,
	    minZoom: defaultMinZoom,
	    maxZoom: defaultMaxZoom,
	    minPitch: defaultMinPitch,
	    maxPitch: defaultMaxPitch,
	    interactive: true,
	    scrollZoom: true,
	    boxZoom: true,
	    dragRotate: true,
	    dragPan: true,
	    keyboard: true,
	    doubleClickZoom: true,
	    touchZoomRotate: true,
	    touchPitch: true,
	    cooperativeGestures: false,
	    bearingSnap: 7,
	    clickTolerance: 3,
	    pitchWithRotate: true,
	    hash: false,
	    attributionControl: true,
	    failIfMajorPerformanceCaveat: false,
	    preserveDrawingBuffer: false,
	    trackResize: true,
	    optimizeForTerrain: true,
	    renderWorldCopies: true,
	    refreshExpiredTiles: true,
	    minTileCacheSize: null,
	    maxTileCacheSize: null,
	    localIdeographFontFamily: 'sans-serif',
	    localFontFamily: null,
	    transformRequest: null,
	    accessToken: null,
	    fadeDuration: 300,
	    crossSourceCollisions: true
	};
	class Map extends Camera {
	    constructor(options) {
	        options = ref_properties.extend({}, defaultOptions$4, options);
	        if (options.minZoom != null && options.maxZoom != null && options.minZoom > options.maxZoom) {
	            throw new Error(`maxZoom must be greater than or equal to minZoom`);
	        }
	        if (options.minPitch != null && options.maxPitch != null && options.minPitch > options.maxPitch) {
	            throw new Error(`maxPitch must be greater than or equal to minPitch`);
	        }
	        if (options.minPitch != null && options.minPitch < defaultMinPitch) {
	            throw new Error(`minPitch must be greater than or equal to ${ defaultMinPitch }`);
	        }
	        if (options.maxPitch != null && options.maxPitch > defaultMaxPitch) {
	            throw new Error(`maxPitch must be less than or equal to ${ defaultMaxPitch }`);
	        }
	        if (options.antialias && ref_properties.isSafariWithAntialiasingBug(ref_properties.window)) {
	            options.antialias = false;
	            ref_properties.warnOnce('Antialiasing is disabled for this WebGL context to avoid browser bug: https://github.com/mapbox/mapbox-gl-js/issues/11609');
	        }
	        const transform = new Transform(options.minZoom, options.maxZoom, options.minPitch, options.maxPitch, options.renderWorldCopies);
	        super(transform, options);
	        this._interactive = options.interactive;
	        this._minTileCacheSize = options.minTileCacheSize;
	        this._maxTileCacheSize = options.maxTileCacheSize;
	        this._failIfMajorPerformanceCaveat = options.failIfMajorPerformanceCaveat;
	        this._preserveDrawingBuffer = options.preserveDrawingBuffer;
	        this._antialias = options.antialias;
	        this._trackResize = options.trackResize;
	        this._bearingSnap = options.bearingSnap;
	        this._refreshExpiredTiles = options.refreshExpiredTiles;
	        this._fadeDuration = options.fadeDuration;
	        this._isInitialLoad = true;
	        this._crossSourceCollisions = options.crossSourceCollisions;
	        this._crossFadingFactor = 1;
	        this._collectResourceTiming = options.collectResourceTiming;
	        this._optimizeForTerrain = options.optimizeForTerrain;
	        this._language = options.language === 'auto' ? ref_properties.window.navigator.language : options.language;
	        this._worldview = options.worldview;
	        this._renderTaskQueue = new TaskQueue();
	        this._domRenderTaskQueue = new TaskQueue();
	        this._controls = [];
	        this._markers = [];
	        this._mapId = ref_properties.uniqueId();
	        this._locale = ref_properties.extend({}, defaultLocale, options.locale);
	        this._clickTolerance = options.clickTolerance;
	        this._cooperativeGestures = options.cooperativeGestures;
	        this._containerWidth = 0;
	        this._containerHeight = 0;
	        this._averageElevationLastSampledAt = -Infinity;
	        this._averageElevationExaggeration = 0;
	        this._averageElevation = new EasedVariable(0);
	        this._explicitProjection = null;
	        this._requestManager = new ref_properties.RequestManager(options.transformRequest, options.accessToken, options.testMode);
	        this._silenceAuthErrors = !!options.testMode;
	        if (typeof options.container === 'string') {
	            this._container = ref_properties.window.document.getElementById(options.container);
	            if (!this._container) {
	                throw new Error(`Container '${ options.container }' not found.`);
	            }
	        } else if (options.container instanceof ref_properties.window.HTMLElement) {
	            this._container = options.container;
	        } else {
	            throw new Error(`Invalid type: 'container' must be a String or HTMLElement.`);
	        }
	        if (this._container.childNodes.length > 0) {
	            ref_properties.warnOnce(`The map container element should be empty, otherwise the map's interactivity will be negatively impacted. If you want to display a message when WebGL is not supported, use the Mapbox GL Supported plugin instead.`);
	        }
	        if (options.maxBounds) {
	            this.setMaxBounds(options.maxBounds);
	        }
	        ref_properties.bindAll([
	            '_onWindowOnline',
	            '_onWindowResize',
	            '_onMapScroll',
	            '_contextLost',
	            '_contextRestored'
	        ], this);
	        this._setupContainer();
	        this._setupPainter();
	        if (this.painter === undefined) {
	            throw new Error(`Failed to initialize WebGL.`);
	        }
	        this.on('move', () => this._update(false));
	        this.on('moveend', () => this._update(false));
	        this.on('zoom', () => this._update(true));
	        if (typeof ref_properties.window !== 'undefined') {
	            ref_properties.window.addEventListener('online', this._onWindowOnline, false);
	            ref_properties.window.addEventListener('resize', this._onWindowResize, false);
	            ref_properties.window.addEventListener('orientationchange', this._onWindowResize, false);
	            ref_properties.window.addEventListener('webkitfullscreenchange', this._onWindowResize, false);
	        }
	        this.handlers = new HandlerManager(this, options);
	        this._localFontFamily = options.localFontFamily;
	        this._localIdeographFontFamily = options.localIdeographFontFamily;
	        if (options.style) {
	            this.setStyle(options.style, {
	                localFontFamily: this._localFontFamily,
	                localIdeographFontFamily: this._localIdeographFontFamily
	            });
	        }
	        if (options.projection) {
	            this.setProjection(options.projection);
	        }
	        const hashName = typeof options.hash === 'string' && options.hash || undefined;
	        this._hash = options.hash && new Hash(hashName).addTo(this);
	        if (!this._hash || !this._hash._onHashChange()) {
	            this.jumpTo({
	                center: options.center,
	                zoom: options.zoom,
	                bearing: options.bearing,
	                pitch: options.pitch
	            });
	            if (options.bounds) {
	                this.resize();
	                this.fitBounds(options.bounds, ref_properties.extend({}, options.fitBoundsOptions, { duration: 0 }));
	            }
	        }
	        this.resize();
	        if (options.attributionControl)
	            this.addControl(new AttributionControl({ customAttribution: options.customAttribution }));
	        this._logoControl = new LogoControl();
	        this.addControl(this._logoControl, options.logoPosition);
	        this.on('style.load', () => {
	            if (this.transform.unmodified) {
	                this.jumpTo(this.style.stylesheet);
	            }
	        });
	        this.on('data', event => {
	            this._update(event.dataType === 'style');
	            this.fire(new ref_properties.Event(`${ event.dataType }data`, event));
	        });
	        this.on('dataloading', event => {
	            this.fire(new ref_properties.Event(`${ event.dataType }dataloading`, event));
	        });
	    }
	    _getMapId() {
	        return this._mapId;
	    }
	    addControl(control, position) {
	        if (position === undefined) {
	            if (control.getDefaultPosition) {
	                position = control.getDefaultPosition();
	            } else {
	                position = 'top-right';
	            }
	        }
	        if (!control || !control.onAdd) {
	            return this.fire(new ref_properties.ErrorEvent(new Error('Invalid argument to map.addControl(). Argument must be a control with onAdd and onRemove methods.')));
	        }
	        const controlElement = control.onAdd(this);
	        this._controls.push(control);
	        const positionContainer = this._controlPositions[position];
	        if (position.indexOf('bottom') !== -1) {
	            positionContainer.insertBefore(controlElement, positionContainer.firstChild);
	        } else {
	            positionContainer.appendChild(controlElement);
	        }
	        return this;
	    }
	    removeControl(control) {
	        if (!control || !control.onRemove) {
	            return this.fire(new ref_properties.ErrorEvent(new Error('Invalid argument to map.removeControl(). Argument must be a control with onAdd and onRemove methods.')));
	        }
	        const ci = this._controls.indexOf(control);
	        if (ci > -1)
	            this._controls.splice(ci, 1);
	        control.onRemove(this);
	        return this;
	    }
	    hasControl(control) {
	        return this._controls.indexOf(control) > -1;
	    }
	    getContainer() {
	        return this._container;
	    }
	    getCanvasContainer() {
	        return this._canvasContainer;
	    }
	    getCanvas() {
	        return this._canvas;
	    }
	    resize(eventData) {
	        this._updateContainerDimensions();
	        if (this._containerWidth === this.transform.width && this._containerHeight === this.transform.height)
	            return this;
	        this._resizeCanvas(this._containerWidth, this._containerHeight);
	        this.transform.resize(this._containerWidth, this._containerHeight);
	        this.painter.resize(Math.ceil(this._containerWidth), Math.ceil(this._containerHeight));
	        const fireMoving = !this._moving;
	        if (fireMoving) {
	            this.fire(new ref_properties.Event('movestart', eventData)).fire(new ref_properties.Event('move', eventData));
	        }
	        this.fire(new ref_properties.Event('resize', eventData));
	        if (fireMoving)
	            this.fire(new ref_properties.Event('moveend', eventData));
	        return this;
	    }
	    getBounds() {
	        if (this.transform.projection.name === 'globe') {
	            ref_properties.warnOnce('Globe projection does not support getBounds API, this API may behave unexpectedly."');
	        }
	        return this.transform.getBounds();
	    }
	    getMaxBounds() {
	        return this.transform.getMaxBounds() || null;
	    }
	    setMaxBounds(bounds) {
	        this.transform.setMaxBounds(ref_properties.LngLatBounds.convert(bounds));
	        return this._update();
	    }
	    setMinZoom(minZoom) {
	        minZoom = minZoom === null || minZoom === undefined ? defaultMinZoom : minZoom;
	        if (minZoom >= defaultMinZoom && minZoom <= this.transform.maxZoom) {
	            this.transform.minZoom = minZoom;
	            this._update();
	            if (this.getZoom() < minZoom) {
	                this.setZoom(minZoom);
	            } else {
	                this.fire(new ref_properties.Event('zoomstart')).fire(new ref_properties.Event('zoom')).fire(new ref_properties.Event('zoomend'));
	            }
	            return this;
	        } else
	            throw new Error(`minZoom must be between ${ defaultMinZoom } and the current maxZoom, inclusive`);
	    }
	    getMinZoom() {
	        return this.transform.minZoom;
	    }
	    setMaxZoom(maxZoom) {
	        maxZoom = maxZoom === null || maxZoom === undefined ? defaultMaxZoom : maxZoom;
	        if (maxZoom >= this.transform.minZoom) {
	            this.transform.maxZoom = maxZoom;
	            this._update();
	            if (this.getZoom() > maxZoom) {
	                this.setZoom(maxZoom);
	            } else {
	                this.fire(new ref_properties.Event('zoomstart')).fire(new ref_properties.Event('zoom')).fire(new ref_properties.Event('zoomend'));
	            }
	            return this;
	        } else
	            throw new Error(`maxZoom must be greater than the current minZoom`);
	    }
	    getMaxZoom() {
	        return this.transform.maxZoom;
	    }
	    setMinPitch(minPitch) {
	        minPitch = minPitch === null || minPitch === undefined ? defaultMinPitch : minPitch;
	        if (minPitch < defaultMinPitch) {
	            throw new Error(`minPitch must be greater than or equal to ${ defaultMinPitch }`);
	        }
	        if (minPitch >= defaultMinPitch && minPitch <= this.transform.maxPitch) {
	            this.transform.minPitch = minPitch;
	            this._update();
	            if (this.getPitch() < minPitch) {
	                this.setPitch(minPitch);
	            } else {
	                this.fire(new ref_properties.Event('pitchstart')).fire(new ref_properties.Event('pitch')).fire(new ref_properties.Event('pitchend'));
	            }
	            return this;
	        } else
	            throw new Error(`minPitch must be between ${ defaultMinPitch } and the current maxPitch, inclusive`);
	    }
	    getMinPitch() {
	        return this.transform.minPitch;
	    }
	    setMaxPitch(maxPitch) {
	        maxPitch = maxPitch === null || maxPitch === undefined ? defaultMaxPitch : maxPitch;
	        if (maxPitch > defaultMaxPitch) {
	            throw new Error(`maxPitch must be less than or equal to ${ defaultMaxPitch }`);
	        }
	        if (maxPitch >= this.transform.minPitch) {
	            this.transform.maxPitch = maxPitch;
	            this._update();
	            if (this.getPitch() > maxPitch) {
	                this.setPitch(maxPitch);
	            } else {
	                this.fire(new ref_properties.Event('pitchstart')).fire(new ref_properties.Event('pitch')).fire(new ref_properties.Event('pitchend'));
	            }
	            return this;
	        } else
	            throw new Error(`maxPitch must be greater than or equal to minPitch`);
	    }
	    getMaxPitch() {
	        return this.transform.maxPitch;
	    }
	    getRenderWorldCopies() {
	        return this.transform.renderWorldCopies;
	    }
	    setRenderWorldCopies(renderWorldCopies) {
	        this.transform.renderWorldCopies = renderWorldCopies;
	        return this._update();
	    }
	    getLanguage() {
	        return this._language;
	    }
	    setLanguage(language) {
	        this._language = language === 'auto' ? ref_properties.window.navigator.language : language;
	        if (this.style) {
	            for (const id in this.style._sourceCaches) {
	                const source = this.style._sourceCaches[id]._source;
	                if (source._setLanguage) {
	                    source._setLanguage(this._language);
	                }
	            }
	        }
	        for (const control of this._controls) {
	            if (control._setLanguage) {
	                control._setLanguage(this._language);
	            }
	        }
	        return this;
	    }
	    getWorldview() {
	        return this._worldview;
	    }
	    setWorldview(worldview) {
	        this._worldview = worldview;
	        if (this.style) {
	            for (const id in this.style._sourceCaches) {
	                const source = this.style._sourceCaches[id]._source;
	                if (source._setWorldview) {
	                    source._setWorldview(worldview);
	                }
	            }
	        }
	        return this;
	    }
	    getProjection() {
	        if (this._explicitProjection) {
	            return this._explicitProjection;
	        }
	        if (this.style && this.style.stylesheet && this.style.stylesheet.projection) {
	            return this.style.stylesheet.projection;
	        }
	        return {
	            name: 'mercator',
	            center: [
	                0,
	                0
	            ]
	        };
	    }
	    _usingGlobe() {
	        return this.transform.projection.name === 'globe';
	    }
	    setProjection(projection) {
	        this._lazyInitEmptyStyle();
	        if (!projection) {
	            projection = null;
	        } else if (typeof projection === 'string') {
	            projection = { name: projection };
	        }
	        return this._updateProjection(projection);
	    }
	    _updateProjection(explicitProjection) {
	        const prevProjection = this.getProjection();
	        if (explicitProjection === null) {
	            this._explicitProjection = null;
	        }
	        const projection = explicitProjection || this.getProjection();
	        let projectionHasChanged;
	        if (projection && projection.name === 'globe' && this.transform.zoom >= ref_properties.GLOBE_ZOOM_THRESHOLD_MAX) {
	            projectionHasChanged = this.transform.setProjection({ name: 'mercator' });
	            this.transform.mercatorFromTransition = true;
	        } else {
	            projectionHasChanged = this.transform.setProjection(projection);
	            this.transform.mercatorFromTransition = false;
	        }
	        if (explicitProjection) {
	            this._explicitProjection = explicitProjection.name === 'globe' ? {
	                name: 'globe',
	                center: [
	                    0,
	                    0
	                ]
	            } : this.transform.getProjection();
	        }
	        this.style.applyProjectionUpdate();
	        if (projectionHasChanged) {
	            if (prevProjection.name === 'globe' && this.getProjection().name === 'globe') {
	                this.style._forceSymbolLayerUpdate();
	            } else {
	                this.painter.clearBackgroundTiles();
	                for (const id in this.style._sourceCaches) {
	                    this.style._sourceCaches[id].clearTiles();
	                }
	            }
	            this._update(true);
	        }
	        return this;
	    }
	    project(lnglat) {
	        return this.transform.locationPoint3D(ref_properties.LngLat.convert(lnglat));
	    }
	    unproject(point) {
	        return this.transform.pointLocation3D(ref_properties.pointGeometry.convert(point));
	    }
	    isMoving() {
	        return this._moving || this.handlers && this.handlers.isMoving() || false;
	    }
	    isZooming() {
	        return this._zooming || this.handlers && this.handlers.isZooming() || false;
	    }
	    isRotating() {
	        return this._rotating || this.handlers && this.handlers.isRotating() || false;
	    }
	    _createDelegatedListener(type, layers, listener) {
	        if (type === 'mouseenter' || type === 'mouseover') {
	            let mousein = false;
	            const mousemove = e => {
	                const filteredLayers = layers.filter(layerId => this.getLayer(layerId));
	                const features = filteredLayers.length ? this.queryRenderedFeatures(e.point, { layers: filteredLayers }) : [];
	                if (!features.length) {
	                    mousein = false;
	                } else if (!mousein) {
	                    mousein = true;
	                    listener.call(this, new MapMouseEvent(type, this, e.originalEvent, { features }));
	                }
	            };
	            const mouseout = () => {
	                mousein = false;
	            };
	            return {
	                layers: new Set(layers),
	                listener,
	                delegates: {
	                    mousemove,
	                    mouseout
	                }
	            };
	        } else if (type === 'mouseleave' || type === 'mouseout') {
	            let mousein = false;
	            const mousemove = e => {
	                const filteredLayers = layers.filter(layerId => this.getLayer(layerId));
	                const features = filteredLayers.length ? this.queryRenderedFeatures(e.point, { layers: filteredLayers }) : [];
	                if (features.length) {
	                    mousein = true;
	                } else if (mousein) {
	                    mousein = false;
	                    listener.call(this, new MapMouseEvent(type, this, e.originalEvent));
	                }
	            };
	            const mouseout = e => {
	                if (mousein) {
	                    mousein = false;
	                    listener.call(this, new MapMouseEvent(type, this, e.originalEvent));
	                }
	            };
	            return {
	                layers: new Set(layers),
	                listener,
	                delegates: {
	                    mousemove,
	                    mouseout
	                }
	            };
	        } else {
	            const delegate = e => {
	                const filteredLayers = layers.filter(layerId => this.getLayer(layerId));
	                const features = filteredLayers.length ? this.queryRenderedFeatures(e.point, { layers: filteredLayers }) : [];
	                if (features.length) {
	                    e.features = features;
	                    listener.call(this, e);
	                    delete e.features;
	                }
	            };
	            return {
	                layers: new Set(layers),
	                listener,
	                delegates: { [type]: delegate }
	            };
	        }
	    }
	    on(type, layerIds, listener) {
	        if (listener === undefined) {
	            return super.on(type, layerIds);
	        }
	        if (!Array.isArray(layerIds)) {
	            layerIds = [layerIds];
	        }
	        const delegatedListener = this._createDelegatedListener(type, layerIds, listener);
	        this._delegatedListeners = this._delegatedListeners || {};
	        this._delegatedListeners[type] = this._delegatedListeners[type] || [];
	        this._delegatedListeners[type].push(delegatedListener);
	        for (const event in delegatedListener.delegates) {
	            this.on(event, delegatedListener.delegates[event]);
	        }
	        return this;
	    }
	    once(type, layerIds, listener) {
	        if (listener === undefined) {
	            return super.once(type, layerIds);
	        }
	        if (!Array.isArray(layerIds)) {
	            layerIds = [layerIds];
	        }
	        const delegatedListener = this._createDelegatedListener(type, layerIds, listener);
	        for (const event in delegatedListener.delegates) {
	            this.once(event, delegatedListener.delegates[event]);
	        }
	        return this;
	    }
	    off(type, layerIds, listener) {
	        if (listener === undefined) {
	            return super.off(type, layerIds);
	        }
	        layerIds = new Set(Array.isArray(layerIds) ? layerIds : [layerIds]);
	        const areLayerArraysEqual = (hash1, hash2) => {
	            if (hash1.size !== hash2.size) {
	                return false;
	            }
	            for (const value of hash1) {
	                if (!hash2.has(value))
	                    return false;
	            }
	            return true;
	        };
	        const removeDelegatedListeners = listeners => {
	            for (let i = 0; i < listeners.length; i++) {
	                const delegatedListener = listeners[i];
	                if (delegatedListener.listener === listener && areLayerArraysEqual(delegatedListener.layers, layerIds)) {
	                    for (const event in delegatedListener.delegates) {
	                        this.off(event, delegatedListener.delegates[event]);
	                    }
	                    listeners.splice(i, 1);
	                    return this;
	                }
	            }
	        };
	        const delegatedListeners = this._delegatedListeners ? this._delegatedListeners[type] : undefined;
	        if (delegatedListeners) {
	            removeDelegatedListeners(delegatedListeners);
	        }
	        return this;
	    }
	    queryRenderedFeatures(geometry, options) {
	        if (!this.style) {
	            return [];
	        }
	        if (options === undefined && geometry !== undefined && !(geometry instanceof ref_properties.pointGeometry) && !Array.isArray(geometry)) {
	            options = geometry;
	            geometry = undefined;
	        }
	        options = options || {};
	        geometry = geometry || [
	            [
	                0,
	                0
	            ],
	            [
	                this.transform.width,
	                this.transform.height
	            ]
	        ];
	        return this.style.queryRenderedFeatures(geometry, options, this.transform);
	    }
	    querySourceFeatures(sourceId, parameters) {
	        return this.style.querySourceFeatures(sourceId, parameters);
	    }
	    queryTerrainElevation(lnglat, options) {
	        const elevation = this.transform.elevation;
	        if (elevation) {
	            options = ref_properties.extend({}, { exaggerated: true }, options);
	            return elevation.getAtPoint(ref_properties.MercatorCoordinate.fromLngLat(lnglat), null, options.exaggerated);
	        }
	        return null;
	    }
	    setStyle(style, options) {
	        options = ref_properties.extend({}, {
	            localIdeographFontFamily: this._localIdeographFontFamily,
	            localFontFamily: this._localFontFamily
	        }, options);
	        if (options.diff !== false && options.localIdeographFontFamily === this._localIdeographFontFamily && options.localFontFamily === this._localFontFamily && this.style && style) {
	            this._diffStyle(style, options);
	            return this;
	        } else {
	            this._localIdeographFontFamily = options.localIdeographFontFamily;
	            this._localFontFamily = options.localFontFamily;
	            return this._updateStyle(style, options);
	        }
	    }
	    _getUIString(key) {
	        const str = this._locale[key];
	        if (str == null) {
	            throw new Error(`Missing UI string '${ key }'`);
	        }
	        return str;
	    }
	    _updateStyle(style, options) {
	        if (this.style) {
	            this.style.setEventedParent(null);
	            this.style._remove();
	            this.style = undefined;
	        }
	        if (style) {
	            this.style = new Style(this, options || {});
	            this.style.setEventedParent(this, { style: this.style });
	            if (typeof style === 'string') {
	                this.style.loadURL(style);
	            } else {
	                this.style.loadJSON(style);
	            }
	        }
	        this._updateTerrain();
	        return this;
	    }
	    _lazyInitEmptyStyle() {
	        if (!this.style) {
	            this.style = new Style(this, {});
	            this.style.setEventedParent(this, { style: this.style });
	            this.style.loadEmpty();
	        }
	    }
	    _diffStyle(style, options) {
	        if (typeof style === 'string') {
	            const url = this._requestManager.normalizeStyleURL(style);
	            const request = this._requestManager.transformRequest(url, ref_properties.ResourceType.Style);
	            ref_properties.getJSON(request, (error, json) => {
	                if (error) {
	                    this.fire(new ref_properties.ErrorEvent(error));
	                } else if (json) {
	                    this._updateDiff(json, options);
	                }
	            });
	        } else if (typeof style === 'object') {
	            this._updateDiff(style, options);
	        }
	    }
	    _updateDiff(style, options) {
	        try {
	            if (this.style.setState(style)) {
	                this._update(true);
	            }
	        } catch (e) {
	            ref_properties.warnOnce(`Unable to perform style diff: ${ e.message || e.error || e }.  Rebuilding the style from scratch.`);
	            this._updateStyle(style, options);
	        }
	    }
	    getStyle() {
	        if (this.style) {
	            return this.style.serialize();
	        }
	    }
	    isStyleLoaded() {
	        if (!this.style) {
	            ref_properties.warnOnce('There is no style added to the map.');
	            return false;
	        }
	        return this.style.loaded();
	    }
	    addSource(id, source) {
	        this._lazyInitEmptyStyle();
	        this.style.addSource(id, source);
	        return this._update(true);
	    }
	    isSourceLoaded(id) {
	        return !!this.style && this.style._isSourceCacheLoaded(id);
	    }
	    areTilesLoaded() {
	        const sources = this.style && this.style._sourceCaches;
	        for (const id in sources) {
	            const source = sources[id];
	            const tiles = source._tiles;
	            for (const t in tiles) {
	                const tile = tiles[t];
	                if (!(tile.state === 'loaded' || tile.state === 'errored'))
	                    return false;
	            }
	        }
	        return true;
	    }
	    addSourceType(name, SourceType, callback) {
	        this._lazyInitEmptyStyle();
	        this.style.addSourceType(name, SourceType, callback);
	    }
	    removeSource(id) {
	        this.style.removeSource(id);
	        this._updateTerrain();
	        return this._update(true);
	    }
	    getSource(id) {
	        return this.style.getSource(id);
	    }
	    addImage(id, image, {pixelRatio = 1, sdf = false, stretchX, stretchY, content} = {}) {
	        this._lazyInitEmptyStyle();
	        const version = 0;
	        if (image instanceof ref_properties.window.HTMLImageElement || ref_properties.window.ImageBitmap && image instanceof ref_properties.window.ImageBitmap) {
	            const {width, height, data} = ref_properties.exported.getImageData(image);
	            this.style.addImage(id, {
	                data: new ref_properties.RGBAImage({
	                    width,
	                    height
	                }, data),
	                pixelRatio,
	                stretchX,
	                stretchY,
	                content,
	                sdf,
	                version
	            });
	        } else if (image.width === undefined || image.height === undefined) {
	            this.fire(new ref_properties.ErrorEvent(new Error('Invalid arguments to map.addImage(). The second argument must be an `HTMLImageElement`, `ImageData`, `ImageBitmap`, ' + 'or object with `width`, `height`, and `data` properties with the same format as `ImageData`')));
	        } else {
	            const {width, height} = image;
	            const userImage = image;
	            const data = userImage.data;
	            this.style.addImage(id, {
	                data: new ref_properties.RGBAImage({
	                    width,
	                    height
	                }, new Uint8Array(data)),
	                pixelRatio,
	                stretchX,
	                stretchY,
	                content,
	                sdf,
	                version,
	                userImage
	            });
	            if (userImage.onAdd) {
	                userImage.onAdd(this, id);
	            }
	        }
	    }
	    updateImage(id, image) {
	        const existingImage = this.style.getImage(id);
	        if (!existingImage) {
	            this.fire(new ref_properties.ErrorEvent(new Error('The map has no image with that id. If you are adding a new image use `map.addImage(...)` instead.')));
	            return;
	        }
	        const imageData = image instanceof ref_properties.window.HTMLImageElement || ref_properties.window.ImageBitmap && image instanceof ref_properties.window.ImageBitmap ? ref_properties.exported.getImageData(image) : image;
	        const {width, height} = imageData;
	        const data = imageData.data;
	        if (width === undefined || height === undefined) {
	            this.fire(new ref_properties.ErrorEvent(new Error('Invalid arguments to map.updateImage(). The second argument must be an `HTMLImageElement`, `ImageData`, `ImageBitmap`, ' + 'or object with `width`, `height`, and `data` properties with the same format as `ImageData`')));
	            return;
	        }
	        if (width !== existingImage.data.width || height !== existingImage.data.height) {
	            this.fire(new ref_properties.ErrorEvent(new Error(`The width and height of the updated image (${ width }, ${ height })
	                must be that same as the previous version of the image
	                (${ existingImage.data.width }, ${ existingImage.data.height })`)));
	            return;
	        }
	        const copy = !(image instanceof ref_properties.window.HTMLImageElement || ref_properties.window.ImageBitmap && image instanceof ref_properties.window.ImageBitmap);
	        existingImage.data.replace(data, copy);
	        this.style.updateImage(id, existingImage);
	    }
	    hasImage(id) {
	        if (!id) {
	            this.fire(new ref_properties.ErrorEvent(new Error('Missing required image id')));
	            return false;
	        }
	        return !!this.style.getImage(id);
	    }
	    removeImage(id) {
	        this.style.removeImage(id);
	    }
	    loadImage(url, callback) {
	        ref_properties.getImage(this._requestManager.transformRequest(url, ref_properties.ResourceType.Image), (err, img) => {
	            callback(err, img instanceof ref_properties.window.HTMLImageElement ? ref_properties.exported.getImageData(img) : img);
	        });
	    }
	    listImages() {
	        return this.style.listImages();
	    }
	    addLayer(layer, beforeId) {
	        this._lazyInitEmptyStyle();
	        this.style.addLayer(layer, beforeId);
	        return this._update(true);
	    }
	    moveLayer(id, beforeId) {
	        this.style.moveLayer(id, beforeId);
	        return this._update(true);
	    }
	    removeLayer(id) {
	        this.style.removeLayer(id);
	        return this._update(true);
	    }
	    getLayer(id) {
	        return this.style.getLayer(id);
	    }
	    setLayerZoomRange(layerId, minzoom, maxzoom) {
	        this.style.setLayerZoomRange(layerId, minzoom, maxzoom);
	        return this._update(true);
	    }
	    setFilter(layerId, filter, options = {}) {
	        this.style.setFilter(layerId, filter, options);
	        return this._update(true);
	    }
	    getFilter(layerId) {
	        return this.style.getFilter(layerId);
	    }
	    setPaintProperty(layerId, name, value, options = {}) {
	        this.style.setPaintProperty(layerId, name, value, options);
	        return this._update(true);
	    }
	    getPaintProperty(layerId, name) {
	        return this.style.getPaintProperty(layerId, name);
	    }
	    setLayoutProperty(layerId, name, value, options = {}) {
	        this.style.setLayoutProperty(layerId, name, value, options);
	        return this._update(true);
	    }
	    getLayoutProperty(layerId, name) {
	        return this.style.getLayoutProperty(layerId, name);
	    }
	    setLight(light, options = {}) {
	        this._lazyInitEmptyStyle();
	        this.style.setLight(light, options);
	        return this._update(true);
	    }
	    getLight() {
	        return this.style.getLight();
	    }
	    setTerrain(terrain) {
	        this._lazyInitEmptyStyle();
	        if (!terrain && this.transform.projection.requiresDraping) {
	            this.style.setTerrainForDraping();
	        } else {
	            this.style.setTerrain(terrain);
	        }
	        this._averageElevationLastSampledAt = -Infinity;
	        return this._update(true);
	    }
	    getTerrain() {
	        return this.style ? this.style.getTerrain() : null;
	    }
	    setFog(fog) {
	        this._lazyInitEmptyStyle();
	        this.style.setFog(fog);
	        return this._update(true);
	    }
	    getFog() {
	        return this.style ? this.style.getFog() : null;
	    }
	    _queryFogOpacity(lnglat) {
	        if (!this.style || !this.style.fog)
	            return 0;
	        return this.style.fog.getOpacityAtLatLng(ref_properties.LngLat.convert(lnglat), this.transform);
	    }
	    setFeatureState(feature, state) {
	        this.style.setFeatureState(feature, state);
	        return this._update();
	    }
	    removeFeatureState(feature, key) {
	        this.style.removeFeatureState(feature, key);
	        return this._update();
	    }
	    getFeatureState(feature) {
	        return this.style.getFeatureState(feature);
	    }
	    _updateContainerDimensions() {
	        if (!this._container)
	            return;
	        const width = this._container.getBoundingClientRect().width || 400;
	        const height = this._container.getBoundingClientRect().height || 300;
	        let transformValues;
	        let transformScaleWidth;
	        let transformScaleHeight;
	        let el = this._container;
	        while (el && (!transformScaleWidth || !transformScaleHeight)) {
	            const transformMatrix = ref_properties.window.getComputedStyle(el).transform;
	            if (transformMatrix && transformMatrix !== 'none') {
	                transformValues = transformMatrix.match(/matrix.*\((.+)\)/)[1].split(', ');
	                if (transformValues[0] && transformValues[0] !== '0' && transformValues[0] !== '1')
	                    transformScaleWidth = transformValues[0];
	                if (transformValues[3] && transformValues[3] !== '0' && transformValues[3] !== '1')
	                    transformScaleHeight = transformValues[3];
	            }
	            el = el.parentElement;
	        }
	        this._containerWidth = transformScaleWidth ? Math.abs(width / transformScaleWidth) : width;
	        this._containerHeight = transformScaleHeight ? Math.abs(height / transformScaleHeight) : height;
	    }
	    _detectMissingCSS() {
	        const computedColor = ref_properties.window.getComputedStyle(this._missingCSSCanary).getPropertyValue('background-color');
	        if (computedColor !== 'rgb(250, 128, 114)') {
	            ref_properties.warnOnce('This page appears to be missing CSS declarations for ' + 'Mapbox GL JS, which may cause the map to display incorrectly. ' + 'Please ensure your page includes mapbox-gl.css, as described ' + 'in https://www.mapbox.com/mapbox-gl-js/api/.');
	        }
	    }
	    _setupContainer() {
	        const container = this._container;
	        container.classList.add('mapboxgl-map');
	        const missingCSSCanary = this._missingCSSCanary = create$2('div', 'mapboxgl-canary', container);
	        missingCSSCanary.style.visibility = 'hidden';
	        this._detectMissingCSS();
	        const canvasContainer = this._canvasContainer = create$2('div', 'mapboxgl-canvas-container', container);
	        if (this._interactive) {
	            canvasContainer.classList.add('mapboxgl-interactive');
	        }
	        this._canvas = create$2('canvas', 'mapboxgl-canvas', canvasContainer);
	        this._canvas.addEventListener('webglcontextlost', this._contextLost, false);
	        this._canvas.addEventListener('webglcontextrestored', this._contextRestored, false);
	        this._canvas.setAttribute('tabindex', '0');
	        this._canvas.setAttribute('aria-label', this._getUIString('Map.Title'));
	        this._canvas.setAttribute('role', 'region');
	        this._updateContainerDimensions();
	        this._resizeCanvas(this._containerWidth, this._containerHeight);
	        const controlContainer = this._controlContainer = create$2('div', 'mapboxgl-control-container', container);
	        const positions = this._controlPositions = {};
	        [
	            'top-left',
	            'top-right',
	            'bottom-left',
	            'bottom-right'
	        ].forEach(positionName => {
	            positions[positionName] = create$2('div', `mapboxgl-ctrl-${ positionName }`, controlContainer);
	        });
	        this._container.addEventListener('scroll', this._onMapScroll, false);
	    }
	    _resizeCanvas(width, height) {
	        const pixelRatio = ref_properties.exported.devicePixelRatio || 1;
	        this._canvas.width = pixelRatio * Math.ceil(width);
	        this._canvas.height = pixelRatio * Math.ceil(height);
	        this._canvas.style.width = `${ width }px`;
	        this._canvas.style.height = `${ height }px`;
	    }
	    _addMarker(marker) {
	        this._markers.push(marker);
	    }
	    _removeMarker(marker) {
	        const index = this._markers.indexOf(marker);
	        if (index !== -1) {
	            this._markers.splice(index, 1);
	        }
	    }
	    _setupPainter() {
	        const attributes = ref_properties.extend({}, supported.webGLContextAttributes, {
	            failIfMajorPerformanceCaveat: this._failIfMajorPerformanceCaveat,
	            preserveDrawingBuffer: this._preserveDrawingBuffer,
	            antialias: this._antialias || false
	        });
	        const gl = this._canvas.getContext('webgl', attributes) || this._canvas.getContext('experimental-webgl', attributes);
	        if (!gl) {
	            this.fire(new ref_properties.ErrorEvent(new Error('Failed to initialize WebGL')));
	            return;
	        }
	        ref_properties.storeAuthState(gl, true);
	        this.painter = new Painter(gl, this.transform);
	        this.on('data', event => {
	            if (event.dataType === 'source') {
	                this.painter.setTileLoadedFlag(true);
	            }
	        });
	        ref_properties.exported$1.testSupport(gl);
	    }
	    _contextLost(event) {
	        event.preventDefault();
	        if (this._frame) {
	            this._frame.cancel();
	            this._frame = null;
	        }
	        this.fire(new ref_properties.Event('webglcontextlost', { originalEvent: event }));
	    }
	    _contextRestored(event) {
	        this._setupPainter();
	        this.resize();
	        this._update();
	        this.fire(new ref_properties.Event('webglcontextrestored', { originalEvent: event }));
	    }
	    _onMapScroll(event) {
	        if (event.target !== this._container)
	            return;
	        this._container.scrollTop = 0;
	        this._container.scrollLeft = 0;
	        return false;
	    }
	    loaded() {
	        return !this._styleDirty && !this._sourcesDirty && !!this.style && this.style.loaded();
	    }
	    _update(updateStyle) {
	        if (!this.style)
	            return this;
	        this._styleDirty = this._styleDirty || updateStyle;
	        this._sourcesDirty = true;
	        this.triggerRepaint();
	        return this;
	    }
	    _requestRenderFrame(callback) {
	        this._update();
	        return this._renderTaskQueue.add(callback);
	    }
	    _cancelRenderFrame(id) {
	        this._renderTaskQueue.remove(id);
	    }
	    _requestDomTask(callback) {
	        if (!this.loaded() || this.loaded() && !this.isMoving()) {
	            callback();
	        } else {
	            this._domRenderTaskQueue.add(callback);
	        }
	    }
	    _render(paintStartTimeStamp) {
	        let gpuTimer;
	        const extTimerQuery = this.painter.context.extTimerQuery;
	        const frameStartTime = ref_properties.exported.now();
	        if (this.listens('gpu-timing-frame')) {
	            gpuTimer = extTimerQuery.createQueryEXT();
	            extTimerQuery.beginQueryEXT(extTimerQuery.TIME_ELAPSED_EXT, gpuTimer);
	        }
	        this.painter.context.setDirty();
	        this.painter.setBaseState();
	        this._renderTaskQueue.run(paintStartTimeStamp);
	        this._domRenderTaskQueue.run(paintStartTimeStamp);
	        if (this._removed)
	            return;
	        if (this.getProjection().name === 'globe') {
	            if (this.transform.zoom >= ref_properties.GLOBE_ZOOM_THRESHOLD_MAX) {
	                if (this.transform.projection.name === 'globe') {
	                    this._updateProjection();
	                }
	            } else if (this.transform.projection.name === 'mercator') {
	                this._updateProjection();
	            }
	        }
	        let crossFading = false;
	        const fadeDuration = this._isInitialLoad ? 0 : this._fadeDuration;
	        if (this.style && this._styleDirty) {
	            this._styleDirty = false;
	            const zoom = this.transform.zoom;
	            const pitch = this.transform.pitch;
	            const now = ref_properties.exported.now();
	            this.style.zoomHistory.update(zoom, now);
	            const parameters = new ref_properties.EvaluationParameters(zoom, {
	                now,
	                fadeDuration,
	                pitch,
	                zoomHistory: this.style.zoomHistory,
	                transition: this.style.getTransition()
	            });
	            const factor = parameters.crossFadingFactor();
	            if (factor !== 1 || factor !== this._crossFadingFactor) {
	                crossFading = true;
	                this._crossFadingFactor = factor;
	            }
	            this.style.update(parameters);
	        }
	        const fogIsTransitioning = this.style && this.style.fog && this.style.fog.hasTransition();
	        if (fogIsTransitioning) {
	            this.style._markersNeedUpdate = true;
	            this._sourcesDirty = true;
	        }
	        let averageElevationChanged = false;
	        if (this.style && this._sourcesDirty) {
	            this._sourcesDirty = false;
	            this.painter._updateFog(this.style);
	            this._updateTerrain();
	            averageElevationChanged = this._updateAverageElevation(frameStartTime);
	            this.style._updateSources(this.transform);
	            this._forceMarkerUpdate();
	        } else {
	            averageElevationChanged = this._updateAverageElevation(frameStartTime);
	        }
	        this._placementDirty = this.style && this.style._updatePlacement(this.painter.transform, this.showCollisionBoxes, fadeDuration, this._crossSourceCollisions);
	        if (this.style) {
	            this.painter.render(this.style, {
	                showTileBoundaries: this.showTileBoundaries,
	                showTerrainWireframe: this.showTerrainWireframe,
	                showOverdrawInspector: this._showOverdrawInspector,
	                showQueryGeometry: !!this._showQueryGeometry,
	                rotating: this.isRotating(),
	                zooming: this.isZooming(),
	                moving: this.isMoving(),
	                fadeDuration,
	                isInitialLoad: this._isInitialLoad,
	                showPadding: this.showPadding,
	                gpuTiming: !!this.listens('gpu-timing-layer'),
	                gpuTimingDeferredRender: !!this.listens('gpu-timing-deferred-render'),
	                speedIndexTiming: this.speedIndexTiming
	            });
	        }
	        this.fire(new ref_properties.Event('render'));
	        if (this.loaded() && !this._loaded) {
	            this._loaded = true;
	            this.fire(new ref_properties.Event('load'));
	        }
	        if (this.style && (this.style.hasTransitions() || crossFading)) {
	            this._styleDirty = true;
	        }
	        if (this.style && !this._placementDirty) {
	            this.style._releaseSymbolFadeTiles();
	        }
	        if (gpuTimer) {
	            const renderCPUTime = ref_properties.exported.now() - frameStartTime;
	            extTimerQuery.endQueryEXT(extTimerQuery.TIME_ELAPSED_EXT, gpuTimer);
	            setTimeout(() => {
	                const renderGPUTime = extTimerQuery.getQueryObjectEXT(gpuTimer, extTimerQuery.QUERY_RESULT_EXT) / (1000 * 1000);
	                extTimerQuery.deleteQueryEXT(gpuTimer);
	                this.fire(new ref_properties.Event('gpu-timing-frame', {
	                    cpuTime: renderCPUTime,
	                    gpuTime: renderGPUTime
	                }));
	                ref_properties.window.performance.mark('frame-gpu', {
	                    startTime: frameStartTime,
	                    detail: { gpuTime: renderGPUTime }
	                });
	            }, 50);
	        }
	        if (this.listens('gpu-timing-layer')) {
	            const frameLayerQueries = this.painter.collectGpuTimers();
	            setTimeout(() => {
	                const renderedLayerTimes = this.painter.queryGpuTimers(frameLayerQueries);
	                this.fire(new ref_properties.Event('gpu-timing-layer', { layerTimes: renderedLayerTimes }));
	            }, 50);
	        }
	        if (this.listens('gpu-timing-deferred-render')) {
	            const deferredRenderQueries = this.painter.collectDeferredRenderGpuQueries();
	            setTimeout(() => {
	                const gpuTime = this.painter.queryGpuTimeDeferredRender(deferredRenderQueries);
	                this.fire(new ref_properties.Event('gpu-timing-deferred-render', { gpuTime }));
	            }, 50);
	        }
	        const somethingDirty = this._sourcesDirty || this._styleDirty || this._placementDirty || averageElevationChanged;
	        if (somethingDirty || this._repaint) {
	            this.triggerRepaint();
	        } else {
	            const willIdle = !this.isMoving() && this.loaded();
	            if (willIdle) {
	                averageElevationChanged = this._updateAverageElevation(frameStartTime, true);
	            }
	            if (averageElevationChanged) {
	                this.triggerRepaint();
	            } else {
	                this._triggerFrame(false);
	                if (willIdle) {
	                    this.fire(new ref_properties.Event('idle'));
	                    this._isInitialLoad = false;
	                    if (this.speedIndexTiming) {
	                        const speedIndexNumber = this._calculateSpeedIndex();
	                        this.fire(new ref_properties.Event('speedindexcompleted', { speedIndex: speedIndexNumber }));
	                        this.speedIndexTiming = false;
	                    }
	                }
	            }
	        }
	        if (this._loaded && !this._fullyLoaded && !somethingDirty) {
	            this._fullyLoaded = true;
	            this._authenticate();
	        }
	    }
	    _forceMarkerUpdate() {
	        for (const marker of this._markers) {
	            marker._update();
	        }
	    }
	    _updateAverageElevation(timeStamp, ignoreTimeout = false) {
	        const applyUpdate = value => {
	            this.transform.averageElevation = value;
	            this._update(false);
	            return true;
	        };
	        if (!this.painter.averageElevationNeedsEasing()) {
	            if (this.transform.averageElevation !== 0)
	                return applyUpdate(0);
	            return false;
	        }
	        const timeoutElapsed = ignoreTimeout || timeStamp - this._averageElevationLastSampledAt > AVERAGE_ELEVATION_SAMPLING_INTERVAL;
	        if (timeoutElapsed && !this._averageElevation.isEasing(timeStamp)) {
	            const currentElevation = this.transform.averageElevation;
	            let newElevation = this.transform.sampleAverageElevation();
	            let exaggerationChanged = false;
	            if (this.transform.elevation) {
	                exaggerationChanged = this.transform.elevation.exaggeration() !== this._averageElevationExaggeration;
	                this._averageElevationExaggeration = this.transform.elevation.exaggeration();
	            }
	            if (isNaN(newElevation)) {
	                newElevation = 0;
	            } else {
	                this._averageElevationLastSampledAt = timeStamp;
	            }
	            const elevationChange = Math.abs(currentElevation - newElevation);
	            if (elevationChange > AVERAGE_ELEVATION_EASE_THRESHOLD) {
	                if (this._isInitialLoad || exaggerationChanged) {
	                    this._averageElevation.jumpTo(newElevation);
	                    return applyUpdate(newElevation);
	                } else {
	                    this._averageElevation.easeTo(newElevation, timeStamp, AVERAGE_ELEVATION_EASE_TIME);
	                }
	            } else if (elevationChange > AVERAGE_ELEVATION_CHANGE_THRESHOLD) {
	                this._averageElevation.jumpTo(newElevation);
	                return applyUpdate(newElevation);
	            }
	        }
	        if (this._averageElevation.isEasing(timeStamp)) {
	            return applyUpdate(this._averageElevation.getValue(timeStamp));
	        }
	        return false;
	    }
	    _authenticate() {
	        ref_properties.getMapSessionAPI(this._getMapId(), this._requestManager._skuToken, this._requestManager._customAccessToken, err => {
	            if (err) {
	                if (err.message === ref_properties.AUTH_ERR_MSG || err.status === 401) {
	                    const gl = this.painter.context.gl;
	                    ref_properties.storeAuthState(gl, false);
	                    if (this._logoControl instanceof LogoControl) {
	                        this._logoControl._updateLogo();
	                    }
	                    if (gl)
	                        gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
	                    if (!this._silenceAuthErrors) {
	                        this.fire(new ref_properties.ErrorEvent(new Error('A valid Mapbox access token is required to use Mapbox GL JS. To create an account or a new access token, visit https://account.mapbox.com/')));
	                    }
	                }
	            }
	        });
	        ref_properties.postMapLoadEvent(this._getMapId(), this._requestManager._skuToken, this._requestManager._customAccessToken, () => {
	        });
	    }
	    _updateTerrain() {
	        this.painter.updateTerrain(this.style, this.isMoving() || this.isRotating() || this.isZooming());
	    }
	    _calculateSpeedIndex() {
	        const finalFrame = this.painter.canvasCopy();
	        const canvasCopyInstances = this.painter.getCanvasCopiesAndTimestamps();
	        canvasCopyInstances.timeStamps.push(performance.now());
	        const gl = this.painter.context.gl;
	        const framebuffer = gl.createFramebuffer();
	        gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
	        function read(texture) {
	            gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
	            const pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);
	            gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
	            return pixels;
	        }
	        return this._canvasPixelComparison(read(finalFrame), canvasCopyInstances.canvasCopies.map(read), canvasCopyInstances.timeStamps);
	    }
	    _canvasPixelComparison(finalFrame, allFrames, timeStamps) {
	        let finalScore = timeStamps[1] - timeStamps[0];
	        const numPixels = finalFrame.length / 4;
	        for (let i = 0; i < allFrames.length; i++) {
	            const frame = allFrames[i];
	            let cnt = 0;
	            for (let j = 0; j < frame.length; j += 4) {
	                if (frame[j] === finalFrame[j] && frame[j + 1] === finalFrame[j + 1] && frame[j + 2] === finalFrame[j + 2] && frame[j + 3] === finalFrame[j + 3]) {
	                    cnt = cnt + 1;
	                }
	            }
	            const interval = timeStamps[i + 2] - timeStamps[i + 1];
	            const visualCompletness = cnt / numPixels;
	            finalScore += interval * (1 - visualCompletness);
	        }
	        return finalScore;
	    }
	    remove() {
	        if (this._hash)
	            this._hash.remove();
	        for (const control of this._controls)
	            control.onRemove(this);
	        this._controls = [];
	        if (this._frame) {
	            this._frame.cancel();
	            this._frame = null;
	        }
	        this._renderTaskQueue.clear();
	        this._domRenderTaskQueue.clear();
	        if (this.style) {
	            this.style.destroy();
	        }
	        this.painter.destroy();
	        if (this.handlers)
	            this.handlers.destroy();
	        this.handlers = undefined;
	        this.setStyle(null);
	        if (typeof ref_properties.window !== 'undefined') {
	            ref_properties.window.removeEventListener('resize', this._onWindowResize, false);
	            ref_properties.window.removeEventListener('orientationchange', this._onWindowResize, false);
	            ref_properties.window.removeEventListener('webkitfullscreenchange', this._onWindowResize, false);
	            ref_properties.window.removeEventListener('online', this._onWindowOnline, false);
	        }
	        const extension = this.painter.context.gl.getExtension('WEBGL_lose_context');
	        if (extension)
	            extension.loseContext();
	        removeNode(this._canvasContainer);
	        removeNode(this._controlContainer);
	        removeNode(this._missingCSSCanary);
	        this._container.classList.remove('mapboxgl-map');
	        ref_properties.removeAuthState(this.painter.context.gl);
	        this._removed = true;
	        this.fire(new ref_properties.Event('remove'));
	    }
	    triggerRepaint() {
	        this._triggerFrame(true);
	    }
	    _triggerFrame(render) {
	        this._renderNextFrame = this._renderNextFrame || render;
	        if (this.style && !this._frame) {
	            this._frame = ref_properties.exported.frame(paintStartTimeStamp => {
	                const isRenderFrame = !!this._renderNextFrame;
	                this._frame = null;
	                this._renderNextFrame = null;
	                if (isRenderFrame) {
	                    this._render(paintStartTimeStamp);
	                }
	            });
	        }
	    }
	    _preloadTiles(transform) {
	        const sources = this.style ? Object.values(this.style._sourceCaches) : [];
	        ref_properties.asyncAll(sources, (source, done) => source._preloadTiles(transform, done), () => {
	            this.triggerRepaint();
	        });
	        return this;
	    }
	    _onWindowOnline() {
	        this._update();
	    }
	    _onWindowResize(event) {
	        if (this._trackResize) {
	            this.resize({ originalEvent: event })._update();
	        }
	    }
	    get showTileBoundaries() {
	        return !!this._showTileBoundaries;
	    }
	    set showTileBoundaries(value) {
	        if (this._showTileBoundaries === value)
	            return;
	        this._showTileBoundaries = value;
	        this._update();
	    }
	    get showTerrainWireframe() {
	        return !!this._showTerrainWireframe;
	    }
	    set showTerrainWireframe(value) {
	        if (this._showTerrainWireframe === value)
	            return;
	        this._showTerrainWireframe = value;
	        this._update();
	    }
	    get speedIndexTiming() {
	        return !!this._speedIndexTiming;
	    }
	    set speedIndexTiming(value) {
	        if (this._speedIndexTiming === value)
	            return;
	        this._speedIndexTiming = value;
	        this._update();
	    }
	    get showPadding() {
	        return !!this._showPadding;
	    }
	    set showPadding(value) {
	        if (this._showPadding === value)
	            return;
	        this._showPadding = value;
	        this._update();
	    }
	    get showCollisionBoxes() {
	        return !!this._showCollisionBoxes;
	    }
	    set showCollisionBoxes(value) {
	        if (this._showCollisionBoxes === value)
	            return;
	        this._showCollisionBoxes = value;
	        if (value) {
	            this.style._generateCollisionBoxes();
	        } else {
	            this._update();
	        }
	    }
	    get showOverdrawInspector() {
	        return !!this._showOverdrawInspector;
	    }
	    set showOverdrawInspector(value) {
	        if (this._showOverdrawInspector === value)
	            return;
	        this._showOverdrawInspector = value;
	        this._update();
	    }
	    get repaint() {
	        return !!this._repaint;
	    }
	    set repaint(value) {
	        if (this._repaint !== value) {
	            this._repaint = value;
	            this.triggerRepaint();
	        }
	    }
	    get vertices() {
	        return !!this._vertices;
	    }
	    set vertices(value) {
	        this._vertices = value;
	        this._update();
	    }
	    _setCacheLimits(limit, checkThreshold) {
	        ref_properties.setCacheLimits(limit, checkThreshold);
	    }
	    get version() {
	        return ref_properties.version;
	    }
	}
	function removeNode(node) {
	    if (node.parentNode) {
	        node.parentNode.removeChild(node);
	    }
	}

	const defaultOptions$3 = {
	    showCompass: true,
	    showZoom: true,
	    visualizePitch: false
	};
	class NavigationControl {
	    constructor(options) {
	        this.options = ref_properties.extend({}, defaultOptions$3, options);
	        this._container = create$2('div', 'mapboxgl-ctrl mapboxgl-ctrl-group');
	        this._container.addEventListener('contextmenu', e => e.preventDefault());
	        if (this.options.showZoom) {
	            ref_properties.bindAll([
	                '_setButtonTitle',
	                '_updateZoomButtons'
	            ], this);
	            this._zoomInButton = this._createButton('mapboxgl-ctrl-zoom-in', e => {
	                if (this._map)
	                    this._map.zoomIn({}, { originalEvent: e });
	            });
	            create$2('span', `mapboxgl-ctrl-icon`, this._zoomInButton).setAttribute('aria-hidden', 'true');
	            this._zoomOutButton = this._createButton('mapboxgl-ctrl-zoom-out', e => {
	                if (this._map)
	                    this._map.zoomOut({}, { originalEvent: e });
	            });
	            create$2('span', `mapboxgl-ctrl-icon`, this._zoomOutButton).setAttribute('aria-hidden', 'true');
	        }
	        if (this.options.showCompass) {
	            ref_properties.bindAll(['_rotateCompassArrow'], this);
	            this._compass = this._createButton('mapboxgl-ctrl-compass', e => {
	                const map = this._map;
	                if (!map)
	                    return;
	                if (this.options.visualizePitch) {
	                    map.resetNorthPitch({}, { originalEvent: e });
	                } else {
	                    map.resetNorth({}, { originalEvent: e });
	                }
	            });
	            this._compassIcon = create$2('span', 'mapboxgl-ctrl-icon', this._compass);
	            this._compassIcon.setAttribute('aria-hidden', 'true');
	        }
	    }
	    _updateZoomButtons() {
	        const map = this._map;
	        if (!map)
	            return;
	        const zoom = map.getZoom();
	        const isMax = zoom === map.getMaxZoom();
	        const isMin = zoom === map.getMinZoom();
	        this._zoomInButton.disabled = isMax;
	        this._zoomOutButton.disabled = isMin;
	        this._zoomInButton.setAttribute('aria-disabled', isMax.toString());
	        this._zoomOutButton.setAttribute('aria-disabled', isMin.toString());
	    }
	    _rotateCompassArrow() {
	        const map = this._map;
	        if (!map)
	            return;
	        const rotate = this.options.visualizePitch ? `scale(${ 1 / Math.pow(Math.cos(map.transform.pitch * (Math.PI / 180)), 0.5) }) rotateX(${ map.transform.pitch }deg) rotateZ(${ map.transform.angle * (180 / Math.PI) }deg)` : `rotate(${ map.transform.angle * (180 / Math.PI) }deg)`;
	        map._requestDomTask(() => {
	            if (this._compassIcon) {
	                this._compassIcon.style.transform = rotate;
	            }
	        });
	    }
	    onAdd(map) {
	        this._map = map;
	        if (this.options.showZoom) {
	            this._setButtonTitle(this._zoomInButton, 'ZoomIn');
	            this._setButtonTitle(this._zoomOutButton, 'ZoomOut');
	            map.on('zoom', this._updateZoomButtons);
	            this._updateZoomButtons();
	        }
	        if (this.options.showCompass) {
	            this._setButtonTitle(this._compass, 'ResetBearing');
	            if (this.options.visualizePitch) {
	                map.on('pitch', this._rotateCompassArrow);
	            }
	            map.on('rotate', this._rotateCompassArrow);
	            this._rotateCompassArrow();
	            this._handler = new MouseRotateWrapper(map, this._compass, this.options.visualizePitch);
	        }
	        return this._container;
	    }
	    onRemove() {
	        const map = this._map;
	        if (!map)
	            return;
	        this._container.remove();
	        if (this.options.showZoom) {
	            map.off('zoom', this._updateZoomButtons);
	        }
	        if (this.options.showCompass) {
	            if (this.options.visualizePitch) {
	                map.off('pitch', this._rotateCompassArrow);
	            }
	            map.off('rotate', this._rotateCompassArrow);
	            if (this._handler)
	                this._handler.off();
	            this._handler = undefined;
	        }
	        this._map = undefined;
	    }
	    _createButton(className, fn) {
	        const a = create$2('button', className, this._container);
	        a.type = 'button';
	        a.addEventListener('click', fn);
	        return a;
	    }
	    _setButtonTitle(button, title) {
	        if (!this._map)
	            return;
	        const str = this._map._getUIString(`NavigationControl.${ title }`);
	        button.setAttribute('aria-label', str);
	        if (button.firstElementChild)
	            button.firstElementChild.setAttribute('title', str);
	    }
	}
	class MouseRotateWrapper {
	    constructor(map, element, pitch = false) {
	        this._clickTolerance = 10;
	        this.element = element;
	        this.mouseRotate = new MouseRotateHandler({ clickTolerance: map.dragRotate._mouseRotate._clickTolerance });
	        this.map = map;
	        if (pitch)
	            this.mousePitch = new MousePitchHandler({ clickTolerance: map.dragRotate._mousePitch._clickTolerance });
	        ref_properties.bindAll([
	            'mousedown',
	            'mousemove',
	            'mouseup',
	            'touchstart',
	            'touchmove',
	            'touchend',
	            'reset'
	        ], this);
	        element.addEventListener('mousedown', this.mousedown);
	        element.addEventListener('touchstart', this.touchstart, { passive: false });
	        element.addEventListener('touchmove', this.touchmove);
	        element.addEventListener('touchend', this.touchend);
	        element.addEventListener('touchcancel', this.reset);
	    }
	    down(e, point) {
	        this.mouseRotate.mousedown(e, point);
	        if (this.mousePitch)
	            this.mousePitch.mousedown(e, point);
	        disableDrag();
	    }
	    move(e, point) {
	        const map = this.map;
	        const r = this.mouseRotate.mousemoveWindow(e, point);
	        const delta = r && r.bearingDelta;
	        if (delta)
	            map.setBearing(map.getBearing() + delta);
	        if (this.mousePitch) {
	            const p = this.mousePitch.mousemoveWindow(e, point);
	            const delta = p && p.pitchDelta;
	            if (delta)
	                map.setPitch(map.getPitch() + delta);
	        }
	    }
	    off() {
	        const element = this.element;
	        element.removeEventListener('mousedown', this.mousedown);
	        element.removeEventListener('touchstart', this.touchstart, { passive: false });
	        element.removeEventListener('touchmove', this.touchmove);
	        element.removeEventListener('touchend', this.touchend);
	        element.removeEventListener('touchcancel', this.reset);
	        this.offTemp();
	    }
	    offTemp() {
	        enableDrag();
	        ref_properties.window.removeEventListener('mousemove', this.mousemove);
	        ref_properties.window.removeEventListener('mouseup', this.mouseup);
	    }
	    mousedown(e) {
	        this.down(ref_properties.extend({}, e, {
	            ctrlKey: true,
	            preventDefault: () => e.preventDefault()
	        }), mousePos(this.element, e));
	        ref_properties.window.addEventListener('mousemove', this.mousemove);
	        ref_properties.window.addEventListener('mouseup', this.mouseup);
	    }
	    mousemove(e) {
	        this.move(e, mousePos(this.element, e));
	    }
	    mouseup(e) {
	        this.mouseRotate.mouseupWindow(e);
	        if (this.mousePitch)
	            this.mousePitch.mouseupWindow(e);
	        this.offTemp();
	    }
	    touchstart(e) {
	        if (e.targetTouches.length !== 1) {
	            this.reset();
	        } else {
	            this._startPos = this._lastPos = touchPos(this.element, e.targetTouches)[0];
	            this.down({
	                type: 'mousedown',
	                button: 0,
	                ctrlKey: true,
	                preventDefault: () => e.preventDefault()
	            }, this._startPos);
	        }
	    }
	    touchmove(e) {
	        if (e.targetTouches.length !== 1) {
	            this.reset();
	        } else {
	            this._lastPos = touchPos(this.element, e.targetTouches)[0];
	            this.move({ preventDefault: () => e.preventDefault() }, this._lastPos);
	        }
	    }
	    touchend(e) {
	        if (e.targetTouches.length === 0 && this._startPos && this._lastPos && this._startPos.dist(this._lastPos) < this._clickTolerance) {
	            this.element.click();
	        }
	        this.reset();
	    }
	    reset() {
	        this.mouseRotate.reset();
	        if (this.mousePitch)
	            this.mousePitch.reset();
	        delete this._startPos;
	        delete this._lastPos;
	        this.offTemp();
	    }
	}

	const defaultOptions$2 = {
	    positionOptions: {
	        enableHighAccuracy: false,
	        maximumAge: 0,
	        timeout: 6000
	    },
	    fitBoundsOptions: { maxZoom: 15 },
	    trackUserLocation: false,
	    showAccuracyCircle: true,
	    showUserLocation: true,
	    showUserHeading: false
	};
	class GeolocateControl extends ref_properties.Evented {
	    constructor(options) {
	        super();
	        const geolocation = ref_properties.window.navigator.geolocation;
	        this.options = ref_properties.extend({ geolocation }, defaultOptions$2, options);
	        ref_properties.bindAll([
	            '_onSuccess',
	            '_onError',
	            '_onZoom',
	            '_finish',
	            '_setupUI',
	            '_updateCamera',
	            '_updateMarker',
	            '_updateMarkerRotation',
	            '_onDeviceOrientation'
	        ], this);
	        this._updateMarkerRotationThrottled = throttle(this._updateMarkerRotation, 20);
	        this._numberOfWatches = 0;
	    }
	    onAdd(map) {
	        this._map = map;
	        this._container = create$2('div', `mapboxgl-ctrl mapboxgl-ctrl-group`);
	        this._checkGeolocationSupport(this._setupUI);
	        return this._container;
	    }
	    onRemove() {
	        if (this._geolocationWatchID !== undefined) {
	            this.options.geolocation.clearWatch(this._geolocationWatchID);
	            this._geolocationWatchID = undefined;
	        }
	        if (this.options.showUserLocation && this._userLocationDotMarker) {
	            this._userLocationDotMarker.remove();
	        }
	        if (this.options.showAccuracyCircle && this._accuracyCircleMarker) {
	            this._accuracyCircleMarker.remove();
	        }
	        this._container.remove();
	        this._map.off('zoom', this._onZoom);
	        this._map = undefined;
	        this._numberOfWatches = 0;
	        this._noTimeout = false;
	    }
	    _checkGeolocationSupport(callback) {
	        if (this._supportsGeolocation !== undefined) {
	            callback(this._supportsGeolocation);
	        } else if (ref_properties.window.navigator.permissions !== undefined) {
	            ref_properties.window.navigator.permissions.query({ name: 'geolocation' }).then(p => {
	                this._supportsGeolocation = p.state !== 'denied';
	                callback(this._supportsGeolocation);
	            });
	        } else {
	            this._supportsGeolocation = !!this.geolocation;
	            callback(this._supportsGeolocation);
	        }
	    }
	    _isOutOfMapMaxBounds(position) {
	        const bounds = this._map.getMaxBounds();
	        const coordinates = position.coords;
	        return !!bounds && (coordinates.longitude < bounds.getWest() || coordinates.longitude > bounds.getEast() || coordinates.latitude < bounds.getSouth() || coordinates.latitude > bounds.getNorth());
	    }
	    _setErrorState() {
	        switch (this._watchState) {
	        case 'WAITING_ACTIVE':
	            this._watchState = 'ACTIVE_ERROR';
	            this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active');
	            this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active-error');
	            break;
	        case 'ACTIVE_LOCK':
	            this._watchState = 'ACTIVE_ERROR';
	            this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active');
	            this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active-error');
	            this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting');
	            break;
	        case 'BACKGROUND':
	            this._watchState = 'BACKGROUND_ERROR';
	            this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-background');
	            this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-background-error');
	            this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting');
	            break;
	        }
	    }
	    _onSuccess(position) {
	        if (!this._map) {
	            return;
	        }
	        if (this._isOutOfMapMaxBounds(position)) {
	            this._setErrorState();
	            this.fire(new ref_properties.Event('outofmaxbounds', position));
	            this._updateMarker();
	            this._finish();
	            return;
	        }
	        if (this.options.trackUserLocation) {
	            this._lastKnownPosition = position;
	            switch (this._watchState) {
	            case 'WAITING_ACTIVE':
	            case 'ACTIVE_LOCK':
	            case 'ACTIVE_ERROR':
	                this._watchState = 'ACTIVE_LOCK';
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-waiting');
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active-error');
	                this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active');
	                break;
	            case 'BACKGROUND':
	            case 'BACKGROUND_ERROR':
	                this._watchState = 'BACKGROUND';
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-waiting');
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-background-error');
	                this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-background');
	                break;
	            }
	        }
	        if (this.options.showUserLocation && this._watchState !== 'OFF') {
	            this._updateMarker(position);
	        }
	        if (!this.options.trackUserLocation || this._watchState === 'ACTIVE_LOCK') {
	            this._updateCamera(position);
	        }
	        if (this.options.showUserLocation) {
	            this._dotElement.classList.remove('mapboxgl-user-location-dot-stale');
	        }
	        this.fire(new ref_properties.Event('geolocate', position));
	        this._finish();
	    }
	    _updateCamera(position) {
	        const center = new ref_properties.LngLat(position.coords.longitude, position.coords.latitude);
	        const radius = position.coords.accuracy;
	        const bearing = this._map.getBearing();
	        const options = ref_properties.extend({ bearing }, this.options.fitBoundsOptions);
	        this._map.fitBounds(center.toBounds(radius), options, { geolocateSource: true });
	    }
	    _updateMarker(position) {
	        if (position) {
	            const center = new ref_properties.LngLat(position.coords.longitude, position.coords.latitude);
	            this._accuracyCircleMarker.setLngLat(center).addTo(this._map);
	            this._userLocationDotMarker.setLngLat(center).addTo(this._map);
	            this._accuracy = position.coords.accuracy;
	            if (this.options.showUserLocation && this.options.showAccuracyCircle) {
	                this._updateCircleRadius();
	            }
	        } else {
	            this._userLocationDotMarker.remove();
	            this._accuracyCircleMarker.remove();
	        }
	    }
	    _updateCircleRadius() {
	        const map = this._map;
	        const tr = map.transform;
	        const pixelsPerMeter = ref_properties.mercatorZfromAltitude(1, tr._center.lat) * tr.worldSize;
	        const circleDiameter = Math.ceil(2 * this._accuracy * pixelsPerMeter);
	        this._circleElement.style.width = `${ circleDiameter }px`;
	        this._circleElement.style.height = `${ circleDiameter }px`;
	    }
	    _onZoom() {
	        if (this.options.showUserLocation && this.options.showAccuracyCircle) {
	            this._updateCircleRadius();
	        }
	    }
	    _updateMarkerRotation() {
	        if (this._userLocationDotMarker && typeof this._heading === 'number') {
	            this._userLocationDotMarker.setRotation(this._heading);
	            this._dotElement.classList.add('mapboxgl-user-location-show-heading');
	        } else {
	            this._dotElement.classList.remove('mapboxgl-user-location-show-heading');
	            this._userLocationDotMarker.setRotation(0);
	        }
	    }
	    _onError(error) {
	        if (!this._map) {
	            return;
	        }
	        if (this.options.trackUserLocation) {
	            if (error.code === 1) {
	                this._watchState = 'OFF';
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-waiting');
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active');
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active-error');
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-background');
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-background-error');
	                this._geolocateButton.disabled = true;
	                const title = this._map._getUIString('GeolocateControl.LocationNotAvailable');
	                this._geolocateButton.setAttribute('aria-label', title);
	                if (this._geolocateButton.firstElementChild)
	                    this._geolocateButton.firstElementChild.setAttribute('title', title);
	                if (this._geolocationWatchID !== undefined) {
	                    this._clearWatch();
	                }
	            } else if (error.code === 3 && this._noTimeout) {
	                return;
	            } else {
	                this._setErrorState();
	            }
	        }
	        if (this._watchState !== 'OFF' && this.options.showUserLocation) {
	            this._dotElement.classList.add('mapboxgl-user-location-dot-stale');
	        }
	        this.fire(new ref_properties.Event('error', error));
	        this._finish();
	    }
	    _finish() {
	        if (this._timeoutId) {
	            clearTimeout(this._timeoutId);
	        }
	        this._timeoutId = undefined;
	    }
	    _setupUI(supported) {
	        this._container.addEventListener('contextmenu', e => e.preventDefault());
	        this._geolocateButton = create$2('button', `mapboxgl-ctrl-geolocate`, this._container);
	        create$2('span', `mapboxgl-ctrl-icon`, this._geolocateButton).setAttribute('aria-hidden', 'true');
	        this._geolocateButton.type = 'button';
	        if (supported === false) {
	            ref_properties.warnOnce('Geolocation support is not available so the GeolocateControl will be disabled.');
	            const title = this._map._getUIString('GeolocateControl.LocationNotAvailable');
	            this._geolocateButton.disabled = true;
	            this._geolocateButton.setAttribute('aria-label', title);
	            if (this._geolocateButton.firstElementChild)
	                this._geolocateButton.firstElementChild.setAttribute('title', title);
	        } else {
	            const title = this._map._getUIString('GeolocateControl.FindMyLocation');
	            this._geolocateButton.setAttribute('aria-label', title);
	            if (this._geolocateButton.firstElementChild)
	                this._geolocateButton.firstElementChild.setAttribute('title', title);
	        }
	        if (this.options.trackUserLocation) {
	            this._geolocateButton.setAttribute('aria-pressed', 'false');
	            this._watchState = 'OFF';
	        }
	        if (this.options.showUserLocation) {
	            this._dotElement = create$2('div', 'mapboxgl-user-location');
	            this._dotElement.appendChild(create$2('div', 'mapboxgl-user-location-dot'));
	            this._dotElement.appendChild(create$2('div', 'mapboxgl-user-location-heading'));
	            this._userLocationDotMarker = new Marker({
	                element: this._dotElement,
	                rotationAlignment: 'map',
	                pitchAlignment: 'map'
	            });
	            this._circleElement = create$2('div', 'mapboxgl-user-location-accuracy-circle');
	            this._accuracyCircleMarker = new Marker({
	                element: this._circleElement,
	                pitchAlignment: 'map'
	            });
	            if (this.options.trackUserLocation)
	                this._watchState = 'OFF';
	            this._map.on('zoom', this._onZoom);
	        }
	        this._geolocateButton.addEventListener('click', this.trigger.bind(this));
	        this._setup = true;
	        if (this.options.trackUserLocation) {
	            this._map.on('movestart', event => {
	                const fromResize = event.originalEvent && event.originalEvent.type === 'resize';
	                if (!event.geolocateSource && this._watchState === 'ACTIVE_LOCK' && !fromResize) {
	                    this._watchState = 'BACKGROUND';
	                    this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-background');
	                    this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active');
	                    this.fire(new ref_properties.Event('trackuserlocationend'));
	                }
	            });
	        }
	    }
	    _onDeviceOrientation(deviceOrientationEvent) {
	        if (this._userLocationDotMarker) {
	            if (deviceOrientationEvent.webkitCompassHeading) {
	                this._heading = deviceOrientationEvent.webkitCompassHeading;
	            } else if (deviceOrientationEvent.absolute === true) {
	                this._heading = deviceOrientationEvent.alpha * -1;
	            }
	            this._updateMarkerRotationThrottled();
	        }
	    }
	    trigger() {
	        if (!this._setup) {
	            ref_properties.warnOnce('Geolocate control triggered before added to a map');
	            return false;
	        }
	        if (this.options.trackUserLocation) {
	            switch (this._watchState) {
	            case 'OFF':
	                this._watchState = 'WAITING_ACTIVE';
	                this.fire(new ref_properties.Event('trackuserlocationstart'));
	                break;
	            case 'WAITING_ACTIVE':
	            case 'ACTIVE_LOCK':
	            case 'ACTIVE_ERROR':
	            case 'BACKGROUND_ERROR':
	                this._numberOfWatches--;
	                this._noTimeout = false;
	                this._watchState = 'OFF';
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-waiting');
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active');
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-active-error');
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-background');
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-background-error');
	                this.fire(new ref_properties.Event('trackuserlocationend'));
	                break;
	            case 'BACKGROUND':
	                this._watchState = 'ACTIVE_LOCK';
	                this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-background');
	                if (this._lastKnownPosition)
	                    this._updateCamera(this._lastKnownPosition);
	                this.fire(new ref_properties.Event('trackuserlocationstart'));
	                break;
	            }
	            switch (this._watchState) {
	            case 'WAITING_ACTIVE':
	                this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting');
	                this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active');
	                break;
	            case 'ACTIVE_LOCK':
	                this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active');
	                break;
	            case 'ACTIVE_ERROR':
	                this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting');
	                this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-active-error');
	                break;
	            case 'BACKGROUND':
	                this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-background');
	                break;
	            case 'BACKGROUND_ERROR':
	                this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting');
	                this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-background-error');
	                break;
	            }
	            if (this._watchState === 'OFF' && this._geolocationWatchID !== undefined) {
	                this._clearWatch();
	            } else if (this._geolocationWatchID === undefined) {
	                this._geolocateButton.classList.add('mapboxgl-ctrl-geolocate-waiting');
	                this._geolocateButton.setAttribute('aria-pressed', 'true');
	                this._numberOfWatches++;
	                let positionOptions;
	                if (this._numberOfWatches > 1) {
	                    positionOptions = {
	                        maximumAge: 600000,
	                        timeout: 0
	                    };
	                    this._noTimeout = true;
	                } else {
	                    positionOptions = this.options.positionOptions;
	                    this._noTimeout = false;
	                }
	                this._geolocationWatchID = this.options.geolocation.watchPosition(this._onSuccess, this._onError, positionOptions);
	                if (this.options.showUserHeading) {
	                    this._addDeviceOrientationListener();
	                }
	            }
	        } else {
	            this.options.geolocation.getCurrentPosition(this._onSuccess, this._onError, this.options.positionOptions);
	            this._timeoutId = setTimeout(this._finish, 10000);
	        }
	        return true;
	    }
	    _addDeviceOrientationListener() {
	        const addListener = () => {
	            if ('ondeviceorientationabsolute' in ref_properties.window) {
	                ref_properties.window.addEventListener('deviceorientationabsolute', this._onDeviceOrientation);
	            } else {
	                ref_properties.window.addEventListener('deviceorientation', this._onDeviceOrientation);
	            }
	        };
	        if (typeof ref_properties.window.DeviceMotionEvent !== 'undefined' && typeof ref_properties.window.DeviceMotionEvent.requestPermission === 'function') {
	            DeviceOrientationEvent.requestPermission().then(response => {
	                if (response === 'granted') {
	                    addListener();
	                }
	            }).catch(console.error);
	        } else {
	            addListener();
	        }
	    }
	    _clearWatch() {
	        this.options.geolocation.clearWatch(this._geolocationWatchID);
	        ref_properties.window.removeEventListener('deviceorientation', this._onDeviceOrientation);
	        ref_properties.window.removeEventListener('deviceorientationabsolute', this._onDeviceOrientation);
	        this._geolocationWatchID = undefined;
	        this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-waiting');
	        this._geolocateButton.setAttribute('aria-pressed', 'false');
	        if (this.options.showUserLocation) {
	            this._updateMarker(null);
	        }
	    }
	}

	const defaultOptions$1 = {
	    maxWidth: 100,
	    unit: 'metric'
	};
	class ScaleControl {
	    constructor(options) {
	        this.options = ref_properties.extend({}, defaultOptions$1, options);
	        ref_properties.bindAll([
	            '_update',
	            'setUnit'
	        ], this);
	    }
	    getDefaultPosition() {
	        return 'bottom-left';
	    }
	    _update() {
	        updateScale(this._map, this._container, this._language, this.options);
	    }
	    onAdd(map) {
	        this._map = map;
	        this._language = map.getLanguage();
	        this._container = create$2('div', 'mapboxgl-ctrl mapboxgl-ctrl-scale', map.getContainer());
	        this._container.dir = 'auto';
	        this._map.on('move', this._update);
	        this._update();
	        return this._container;
	    }
	    onRemove() {
	        this._container.remove();
	        this._map.off('move', this._update);
	        this._map = undefined;
	    }
	    _setLanguage(language) {
	        this._language = language;
	        this._update();
	    }
	    setUnit(unit) {
	        this.options.unit = unit;
	        this._update();
	    }
	}
	function updateScale(map, container, language, options) {
	    const maxWidth = options && options.maxWidth || 100;
	    const y = map._containerHeight / 2;
	    const x = map._containerWidth / 2 - maxWidth / 2;
	    const left = map.unproject([
	        x,
	        y
	    ]);
	    const right = map.unproject([
	        x + maxWidth,
	        y
	    ]);
	    const maxMeters = left.distanceTo(right);
	    if (options && options.unit === 'imperial') {
	        const maxFeet = 3.2808 * maxMeters;
	        if (maxFeet > 5280) {
	            const maxMiles = maxFeet / 5280;
	            setScale(container, maxWidth, maxMiles, language, 'mile', map);
	        } else {
	            setScale(container, maxWidth, maxFeet, language, 'foot', map);
	        }
	    } else if (options && options.unit === 'nautical') {
	        const maxNauticals = maxMeters / 1852;
	        setScale(container, maxWidth, maxNauticals, language, 'nautical-mile', map);
	    } else if (maxMeters >= 1000) {
	        setScale(container, maxWidth, maxMeters / 1000, language, 'kilometer', map);
	    } else {
	        setScale(container, maxWidth, maxMeters, language, 'meter', map);
	    }
	}
	function setScale(container, maxWidth, maxDistance, language, unit, map) {
	    const distance = getRoundNum(maxDistance);
	    const ratio = distance / maxDistance;
	    map._requestDomTask(() => {
	        container.style.width = `${ maxWidth * ratio }px`;
	        if (unit === 'nautical-mile') {
	            container.innerHTML = `${ distance }&nbsp;nm`;
	            return;
	        }
	        container.innerHTML = new Intl.NumberFormat(language, {
	            style: 'unit',
	            unitDisplay: 'narrow',
	            unit
	        }).format(distance);
	    });
	}
	function getDecimalRoundNum(d) {
	    const multiplier = Math.pow(10, Math.ceil(-Math.log(d) / Math.LN10));
	    return Math.round(d * multiplier) / multiplier;
	}
	function getRoundNum(num) {
	    const pow10 = Math.pow(10, `${ Math.floor(num) }`.length - 1);
	    let d = num / pow10;
	    d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 3 ? 3 : d >= 2 ? 2 : d >= 1 ? 1 : getDecimalRoundNum(d);
	    return pow10 * d;
	}

	class FullscreenControl {
	    constructor(options) {
	        this._fullscreen = false;
	        if (options && options.container) {
	            if (options.container instanceof ref_properties.window.HTMLElement) {
	                this._container = options.container;
	            } else {
	                ref_properties.warnOnce('Full screen control \'container\' must be a DOM element.');
	            }
	        }
	        ref_properties.bindAll([
	            '_onClickFullscreen',
	            '_changeIcon'
	        ], this);
	        if ('onfullscreenchange' in ref_properties.window.document) {
	            this._fullscreenchange = 'fullscreenchange';
	        } else if ('onwebkitfullscreenchange' in ref_properties.window.document) {
	            this._fullscreenchange = 'webkitfullscreenchange';
	        }
	    }
	    onAdd(map) {
	        this._map = map;
	        if (!this._container)
	            this._container = this._map.getContainer();
	        this._controlContainer = create$2('div', `mapboxgl-ctrl mapboxgl-ctrl-group`);
	        if (this._checkFullscreenSupport()) {
	            this._setupUI();
	        } else {
	            this._controlContainer.style.display = 'none';
	            ref_properties.warnOnce('This device does not support fullscreen mode.');
	        }
	        return this._controlContainer;
	    }
	    onRemove() {
	        this._controlContainer.remove();
	        this._map = null;
	        ref_properties.window.document.removeEventListener(this._fullscreenchange, this._changeIcon);
	    }
	    _checkFullscreenSupport() {
	        return !!(ref_properties.window.document.fullscreenEnabled || ref_properties.window.document.webkitFullscreenEnabled);
	    }
	    _setupUI() {
	        const button = this._fullscreenButton = create$2('button', `mapboxgl-ctrl-fullscreen`, this._controlContainer);
	        create$2('span', `mapboxgl-ctrl-icon`, button).setAttribute('aria-hidden', 'true');
	        button.type = 'button';
	        this._updateTitle();
	        this._fullscreenButton.addEventListener('click', this._onClickFullscreen);
	        ref_properties.window.document.addEventListener(this._fullscreenchange, this._changeIcon);
	    }
	    _updateTitle() {
	        const title = this._getTitle();
	        this._fullscreenButton.setAttribute('aria-label', title);
	        if (this._fullscreenButton.firstElementChild)
	            this._fullscreenButton.firstElementChild.setAttribute('title', title);
	    }
	    _getTitle() {
	        return this._map._getUIString(this._isFullscreen() ? 'FullscreenControl.Exit' : 'FullscreenControl.Enter');
	    }
	    _isFullscreen() {
	        return this._fullscreen;
	    }
	    _changeIcon() {
	        const fullscreenElement = ref_properties.window.document.fullscreenElement || ref_properties.window.document.webkitFullscreenElement;
	        if (fullscreenElement === this._container !== this._fullscreen) {
	            this._fullscreen = !this._fullscreen;
	            this._fullscreenButton.classList.toggle(`mapboxgl-ctrl-shrink`);
	            this._fullscreenButton.classList.toggle(`mapboxgl-ctrl-fullscreen`);
	            this._updateTitle();
	        }
	    }
	    _onClickFullscreen() {
	        if (this._isFullscreen()) {
	            if (ref_properties.window.document.exitFullscreen) {
	                ref_properties.window.document.exitFullscreen();
	            } else if (ref_properties.window.document.webkitCancelFullScreen) {
	                ref_properties.window.document.webkitCancelFullScreen();
	            }
	        } else if (this._container.requestFullscreen) {
	            this._container.requestFullscreen();
	        } else if (this._container.webkitRequestFullscreen) {
	            this._container.webkitRequestFullscreen();
	        }
	    }
	}

	const defaultOptions = {
	    closeButton: true,
	    closeOnClick: true,
	    focusAfterOpen: true,
	    className: '',
	    maxWidth: '240px'
	};
	const focusQuerySelector = [
	    'a[href]',
	    '[tabindex]:not([tabindex=\'-1\'])',
	    '[contenteditable]:not([contenteditable=\'false\'])',
	    'button:not([disabled])',
	    'input:not([disabled])',
	    'select:not([disabled])',
	    'textarea:not([disabled])'
	].join(', ');
	class Popup extends ref_properties.Evented {
	    constructor(options) {
	        super();
	        this.options = ref_properties.extend(Object.create(defaultOptions), options);
	        ref_properties.bindAll([
	            '_update',
	            '_onClose',
	            'remove',
	            '_onMouseEvent'
	        ], this);
	        this._classList = new Set(options && options.className ? options.className.trim().split(/\s+/) : []);
	    }
	    addTo(map) {
	        if (this._map)
	            this.remove();
	        this._map = map;
	        if (this.options.closeOnClick) {
	            map.on('preclick', this._onClose);
	        }
	        if (this.options.closeOnMove) {
	            map.on('move', this._onClose);
	        }
	        map.on('remove', this.remove);
	        this._update();
	        this._focusFirstElement();
	        if (this._trackPointer) {
	            map.on('mousemove', this._onMouseEvent);
	            map.on('mouseup', this._onMouseEvent);
	            map._canvasContainer.classList.add('mapboxgl-track-pointer');
	        } else {
	            map.on('move', this._update);
	        }
	        this.fire(new ref_properties.Event('open'));
	        return this;
	    }
	    isOpen() {
	        return !!this._map;
	    }
	    remove() {
	        if (this._content) {
	            this._content.remove();
	        }
	        if (this._container) {
	            this._container.remove();
	            this._container = undefined;
	        }
	        const map = this._map;
	        if (map) {
	            map.off('move', this._update);
	            map.off('move', this._onClose);
	            map.off('preclick', this._onClose);
	            map.off('click', this._onClose);
	            map.off('remove', this.remove);
	            map.off('mousemove', this._onMouseEvent);
	            map.off('mouseup', this._onMouseEvent);
	            map.off('drag', this._onMouseEvent);
	            this._map = undefined;
	        }
	        this.fire(new ref_properties.Event('close'));
	        return this;
	    }
	    getLngLat() {
	        return this._lngLat;
	    }
	    setLngLat(lnglat) {
	        this._lngLat = ref_properties.LngLat.convert(lnglat);
	        this._pos = null;
	        this._trackPointer = false;
	        this._update();
	        const map = this._map;
	        if (map) {
	            map.on('move', this._update);
	            map.off('mousemove', this._onMouseEvent);
	            map._canvasContainer.classList.remove('mapboxgl-track-pointer');
	        }
	        return this;
	    }
	    trackPointer() {
	        this._trackPointer = true;
	        this._pos = null;
	        this._update();
	        const map = this._map;
	        if (map) {
	            map.off('move', this._update);
	            map.on('mousemove', this._onMouseEvent);
	            map.on('drag', this._onMouseEvent);
	            map._canvasContainer.classList.add('mapboxgl-track-pointer');
	        }
	        return this;
	    }
	    getElement() {
	        return this._container;
	    }
	    setText(text) {
	        return this.setDOMContent(ref_properties.window.document.createTextNode(text));
	    }
	    setHTML(html) {
	        const frag = ref_properties.window.document.createDocumentFragment();
	        const temp = ref_properties.window.document.createElement('body');
	        let child;
	        temp.innerHTML = html;
	        while (true) {
	            child = temp.firstChild;
	            if (!child)
	                break;
	            frag.appendChild(child);
	        }
	        return this.setDOMContent(frag);
	    }
	    getMaxWidth() {
	        return this._container && this._container.style.maxWidth;
	    }
	    setMaxWidth(maxWidth) {
	        this.options.maxWidth = maxWidth;
	        this._update();
	        return this;
	    }
	    setDOMContent(htmlNode) {
	        let content = this._content;
	        if (content) {
	            while (content.hasChildNodes()) {
	                if (content.firstChild) {
	                    content.removeChild(content.firstChild);
	                }
	            }
	        } else {
	            content = this._content = create$2('div', 'mapboxgl-popup-content', this._container || undefined);
	        }
	        content.appendChild(htmlNode);
	        if (this.options.closeButton) {
	            const button = this._closeButton = create$2('button', 'mapboxgl-popup-close-button', content);
	            button.type = 'button';
	            button.setAttribute('aria-label', 'Close popup');
	            button.setAttribute('aria-hidden', 'true');
	            button.innerHTML = '&#215;';
	            button.addEventListener('click', this._onClose);
	        }
	        this._update();
	        this._focusFirstElement();
	        return this;
	    }
	    addClassName(className) {
	        this._classList.add(className);
	        this._updateClassList();
	        return this;
	    }
	    removeClassName(className) {
	        this._classList.delete(className);
	        this._updateClassList();
	        return this;
	    }
	    setOffset(offset) {
	        this.options.offset = offset;
	        this._update();
	        return this;
	    }
	    toggleClassName(className) {
	        let finalState;
	        if (this._classList.delete(className)) {
	            finalState = false;
	        } else {
	            this._classList.add(className);
	            finalState = true;
	        }
	        this._updateClassList();
	        return finalState;
	    }
	    _onMouseEvent(event) {
	        this._update(event.point);
	    }
	    _getAnchor(bottomY) {
	        if (this.options.anchor) {
	            return this.options.anchor;
	        }
	        const map = this._map;
	        const container = this._container;
	        const pos = this._pos;
	        if (!map || !container || !pos)
	            return 'bottom';
	        const width = container.offsetWidth;
	        const height = container.offsetHeight;
	        const isTop = pos.y + bottomY < height;
	        const isBottom = pos.y > map.transform.height - height;
	        const isLeft = pos.x < width / 2;
	        const isRight = pos.x > map.transform.width - width / 2;
	        if (isTop) {
	            if (isLeft)
	                return 'top-left';
	            if (isRight)
	                return 'top-right';
	            return 'top';
	        }
	        if (isBottom) {
	            if (isLeft)
	                return 'bottom-left';
	            if (isRight)
	                return 'bottom-right';
	        }
	        if (isLeft)
	            return 'left';
	        if (isRight)
	            return 'right';
	        return 'bottom';
	    }
	    _updateClassList() {
	        const container = this._container;
	        if (!container)
	            return;
	        const classes = [...this._classList];
	        classes.push('mapboxgl-popup');
	        if (this._anchor) {
	            classes.push(`mapboxgl-popup-anchor-${ this._anchor }`);
	        }
	        if (this._trackPointer) {
	            classes.push('mapboxgl-popup-track-pointer');
	        }
	        container.className = classes.join(' ');
	    }
	    _update(cursor) {
	        const hasPosition = this._lngLat || this._trackPointer;
	        const map = this._map;
	        const content = this._content;
	        if (!map || !hasPosition || !content) {
	            return;
	        }
	        let container = this._container;
	        if (!container) {
	            container = this._container = create$2('div', 'mapboxgl-popup', map.getContainer());
	            this._tip = create$2('div', 'mapboxgl-popup-tip', container);
	            container.appendChild(content);
	        }
	        if (this.options.maxWidth && container.style.maxWidth !== this.options.maxWidth) {
	            container.style.maxWidth = this.options.maxWidth;
	        }
	        if (map.transform.renderWorldCopies && !this._trackPointer) {
	            this._lngLat = smartWrap(this._lngLat, this._pos, map.transform);
	        }
	        if (!this._trackPointer || cursor) {
	            const pos = this._pos = this._trackPointer && cursor ? cursor : map.project(this._lngLat);
	            const offsetBottom = normalizeOffset(this.options.offset);
	            const anchor = this._anchor = this._getAnchor(offsetBottom.y);
	            const offset = normalizeOffset(this.options.offset, anchor);
	            const offsetedPos = pos.add(offset).round();
	            map._requestDomTask(() => {
	                if (this._container && anchor) {
	                    this._container.style.transform = `${ anchorTranslate[anchor] } translate(${ offsetedPos.x }px,${ offsetedPos.y }px)`;
	                }
	            });
	        }
	        if (!this._marker && map._usingGlobe()) {
	            const opacity = ref_properties.isLngLatBehindGlobe(map.transform, this._lngLat) ? 0 : 1;
	            this._setOpacity(opacity);
	        }
	        this._updateClassList();
	    }
	    _focusFirstElement() {
	        if (!this.options.focusAfterOpen || !this._container)
	            return;
	        const firstFocusable = this._container.querySelector(focusQuerySelector);
	        if (firstFocusable)
	            firstFocusable.focus();
	    }
	    _onClose() {
	        this.remove();
	    }
	    _setOpacity(opacity) {
	        if (this._container) {
	            this._container.style.opacity = `${ opacity }`;
	        }
	        if (this._content) {
	            this._content.style.pointerEvents = opacity ? 'auto' : 'none';
	        }
	    }
	}
	function normalizeOffset(offset = new ref_properties.pointGeometry(0, 0), anchor = 'bottom') {
	    if (typeof offset === 'number') {
	        const cornerOffset = Math.round(Math.sqrt(0.5 * Math.pow(offset, 2)));
	        switch (anchor) {
	        case 'top':
	            return new ref_properties.pointGeometry(0, offset);
	        case 'top-left':
	            return new ref_properties.pointGeometry(cornerOffset, cornerOffset);
	        case 'top-right':
	            return new ref_properties.pointGeometry(-cornerOffset, cornerOffset);
	        case 'bottom':
	            return new ref_properties.pointGeometry(0, -offset);
	        case 'bottom-left':
	            return new ref_properties.pointGeometry(cornerOffset, -cornerOffset);
	        case 'bottom-right':
	            return new ref_properties.pointGeometry(-cornerOffset, -cornerOffset);
	        case 'left':
	            return new ref_properties.pointGeometry(offset, 0);
	        case 'right':
	            return new ref_properties.pointGeometry(-offset, 0);
	        }
	        return new ref_properties.pointGeometry(0, 0);
	    }
	    if (offset instanceof ref_properties.pointGeometry || Array.isArray(offset)) {
	        return ref_properties.pointGeometry.convert(offset);
	    }
	    return ref_properties.pointGeometry.convert(offset[anchor] || [
	        0,
	        0
	    ]);
	}

	ref_properties.window.performance;

	const exported = {
	    version: ref_properties.version,
	    supported,
	    setRTLTextPlugin: ref_properties.setRTLTextPlugin,
	    getRTLTextPluginStatus: ref_properties.getRTLTextPluginStatus,
	    Map,
	    NavigationControl,
	    GeolocateControl,
	    AttributionControl,
	    ScaleControl,
	    FullscreenControl,
	    Popup,
	    Marker,
	    Style,
	    LngLat: ref_properties.LngLat,
	    LngLatBounds: ref_properties.LngLatBounds,
	    Point: ref_properties.pointGeometry,
	    MercatorCoordinate: ref_properties.MercatorCoordinate,
	    FreeCameraOptions,
	    Evented: ref_properties.Evented,
	    config: ref_properties.config,
	    prewarm,
	    clearPrewarmedResources,
	    get accessToken() {
	        return ref_properties.config.ACCESS_TOKEN;
	    },
	    set accessToken(token) {
	        ref_properties.config.ACCESS_TOKEN = token;
	    },
	    get baseApiUrl() {
	        return ref_properties.config.API_URL;
	    },
	    set baseApiUrl(url) {
	        ref_properties.config.API_URL = url;
	    },
	    get workerCount() {
	        return WorkerPool.workerCount;
	    },
	    set workerCount(count) {
	        WorkerPool.workerCount = count;
	    },
	    get maxParallelImageRequests() {
	        return ref_properties.config.MAX_PARALLEL_IMAGE_REQUESTS;
	    },
	    set maxParallelImageRequests(numRequests) {
	        ref_properties.config.MAX_PARALLEL_IMAGE_REQUESTS = numRequests;
	    },
	    clearStorage(callback) {
	        ref_properties.clearTileCache(callback);
	    },
	    workerUrl: '',
	    workerClass: null,
	    setNow: ref_properties.exported.setNow,
	    restoreNow: ref_properties.exported.restoreNow
	};

	return exported;

	}));

	//

	var mapboxgl$1 = mapboxgl;

	return mapboxgl$1;

	}));
	
} (mapboxGlUnminified$1));

var mapboxGlUnminified = mapboxGlUnminified$1.exports;

export { mapboxGlUnminified as default };
