WME BaseMap Basis-DLM Overlay

Waze BaseMap Basis-DLM Overlay für Deutschland

Pasang skrip ini?
Sugesti pemilik skrip

Kamu mungkin juga suka WME GeoPortal Overlay DACH Beta.

Pasang skrip ini
// ==UserScript==
// @name         WME BaseMap Basis-DLM Overlay
// @namespace    https://greasyfork.org/de/users/863740-horst-wittlich
// @version      2024.06.16
// @description  Waze BaseMap Basis-DLM Overlay für Deutschland
// @author       vertexcode, hiwi234
// @match        https://*.waze.com/editor*
// @match        https://*.waze.com/*/editor*
// @match        https://beta.waze.com/editor*
// @match        https://beta.waze.com/*/editor*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=waze.com
// @grant        GM_xmlhttpRequest
// @grant        GM_info
// @license      MIT
 
// ==/UserScript==
 
// Versions Format
// yyyy.mm.dd

(function () {
    'use strict';

    let uOpenLayers;
    let uWaze;
    let uLayer;

    const injectWMSCapabilities = () => {
        if (uOpenLayers.Layer.WMSCapabilities) return;

        /**
         * Class: OpenLayers.Format.OGCExceptionReport
         * Class to read exception reports for letious OGC services and versions.
         *
         * Inherits from:
         *  - <OpenLayers.Format.XML>
         */
        uOpenLayers.Format.OGCExceptionReport = uOpenLayers.Class(uOpenLayers.Format.XML, {

            /**
             * Property: namespaces
             * {Object} Mapping of namespace aliases to namespace URIs.
             */
            namespaces: {
                ogc: "http://www.opengis.net/ogc"
            },

            /**
             * Property: regExes
             * Compiled regular expressions for manipulating strings.
             */
            regExes: {
                trimSpace: (/^\s*|\s*$/g),
                removeSpace: (/\s*/g),
                splitSpace: (/\s+/),
                trimComma: (/\s*,\s*/g)
            },

            /**
             * Property: defaultPrefix
             */
            defaultPrefix: "ogc",

            /**
             * Constructor: OpenLayers.Format.OGCExceptionReport
             * Create a new parser for OGC exception reports.
             *
             * Parameters:
             * options - {Object} An optional object whose properties will be set on
             *     this instance.
             */

            /**
             * APIMethod: read
             * Read OGC exception report data from a string, and return an object with
             * information about the exceptions.
             *
             * Parameters:
             * data - {String} or {DOMElement} data to read/parse.
             *
             * Returns:
             * {Object} Information about the exceptions that occurred.
             */
            read: function (data) {
                if (typeof data == "string") {
                    data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
                }
                let root = data.documentElement;
                let exceptionInfo = {exceptionReport: null};
                if (root) {
                    this.readChildNodes(data, exceptionInfo);
                    if (exceptionInfo.exceptionReport === null) {
                        // fall-back to OWSCommon since this is a common output format for exceptions
                        // we cannot easily use the ows readers directly since they differ for 1.0 and 1.1
                        exceptionInfo = new OpenLayers.Format.OWSCommon().read(data);
                    }
                }
                return exceptionInfo;
            },

            /**
             * Property: readers
             * Contains public functions, grouped by namespace prefix, that will
             *     be applied when a namespaced node is found matching the function
             *     name.  The function will be applied in the scope of this parser
             *     with two arguments: the node being read and a context object passed
             *     from the parent.
             */
            readers: {
                "ogc": {
                    "ServiceExceptionReport": function (node, obj) {
                        obj.exceptionReport = {exceptions: []};
                        this.readChildNodes(node, obj.exceptionReport);
                    },
                    "ServiceException": function (node, exceptionReport) {
                        let exception = {
                            code: node.getAttribute("code"),
                            locator: node.getAttribute("locator"),
                            text: this.getChildValue(node)
                        };
                        exceptionReport.exceptions.push(exception);
                    }
                }
            },

            CLASS_NAME: "OpenLayers.Format.OGCExceptionReport"

        });

        /**
         * Class: OpenLayers.Format.XML.VersionedOGC
         * Base class for versioned formats, i.e. a format which supports multiple
         * versions.
         *
         * To enable checking if parsing succeeded, you will need to define a property
         * called errorProperty on the parser you want to check. The parser will then
         * check the returned object to see if that property is present. If it is, it
         * assumes the parsing was successful. If it is not present (or is null), it will
         * pass the document through an OGCExceptionReport parser.
         *
         * If errorProperty is undefined for the parser, this error checking mechanism
         * will be disabled.
         *
         *
         *
         * Inherits from:
         *  - <OpenLayers.Format.XML>
         */
        uOpenLayers.Format.XML.VersionedOGC = uOpenLayers.Class(uOpenLayers.Format.XML, {

            /**
             * APIProperty: defaultVersion
             * {String} Version number to assume if none found.
             */
            defaultVersion: null,

            /**
             * APIProperty: version
             * {String} Specify a version string if one is known.
             */
            version: null,

            /**
             * APIProperty: profile
             * {String} If provided, use a custom profile.
             */
            profile: null,

            /**
             * APIProperty: allowFallback
             * {Boolean} If a profiled parser cannot be found for the returned version,
             * use a non-profiled parser as the fallback. Application code using this
             * should take into account that the return object structure might be
             * missing the specifics of the profile. Defaults to false.
             */
            allowFallback: false,

            /**
             * Property: name
             * {String} The name of this parser, this is the part of the CLASS_NAME
             * except for "OpenLayers.Format."
             */
            name: null,

            /**
             * APIProperty: stringifyOutput
             * {Boolean} If true, write will return a string otherwise a DOMElement.
             * Default is false.
             */
            stringifyOutput: false,

            /**
             * Property: parser
             * {Object} Instance of the versioned parser.  Cached for multiple read and
             *     write calls of the same version.
             */
            parser: null,

            /**
             * Constructor: OpenLayers.Format.XML.VersionedOGC.
             * Constructor.
             *
             * Parameters:
             * options - {Object} Optional object whose properties will be set on
             *     the object.
             */
            initialize: function (options) {
                uOpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
                let className = this.CLASS_NAME;
                this.name = className.substring(className.lastIndexOf(".") + 1);
            },

            /**
             * Method: getVersion
             * Returns the version to use. Subclasses can override this function
             * if a different version detection is needed.
             *
             * Parameters:
             * root - {DOMElement}
             * options - {Object} Optional configuration object.
             *
             * Returns:
             * {String} The version to use.
             */
            getVersion: function (root, options) {
                let version;
                // read
                if (root) {
                    version = this.version;
                    if (!version) {
                        version = root.getAttribute("version");
                        if (!version) {
                            version = this.defaultVersion;
                        }
                    }
                } else { // write
                    version = (options && options.version) ||
                        this.version || this.defaultVersion;
                }
                return version;
            },

            /**
             * Method: getParser
             * Get an instance of the cached parser if available, otherwise create one.
             *
             * Parameters:
             * version - {String}
             *
             * Returns:
             * {<OpenLayers.Format>}
             */
            getParser: function (version) {
                version = version || this.defaultVersion;
                let profile = this.profile ? "_" + this.profile : "";
                if (!this.parser || this.parser.VERSION !== version) {
                    let format = uOpenLayers.Format[this.name][
                    "v" + version.replace(/\./g, "_") + profile
                        ];
                    if (!format) {
                        if (profile !== "" && this.allowFallback) {
                            // fallback to the non-profiled version of the parser
                            profile = "";
                            format = uOpenLayers.Format[this.name][
                            "v" + version.replace(/\./g, "_")
                                ];
                        }
                        if (!format) {
                            throw "Can't find a " + this.name + " parser for version " +
                            version + profile;
                        }
                    }
                    this.parser = new format(this.options);
                }
                return this.parser;
            },

            /**
             * APIMethod: write
             * Write a document.
             *
             * Parameters:
             * obj - {Object} An object representing the document.
             * options - {Object} Optional configuration object.
             *
             * Returns:
             * {String} The document as a string
             */
            write: function (obj, options) {
                let version = this.getVersion(null, options);
                this.parser = this.getParser(version);
                let root = this.parser.write(obj, options);
                if (this.stringifyOutput === false) {
                    return root;
                } else {
                    return uOpenLayers.Format.XML.prototype.write.apply(this, [root]);
                }
            },

            /**
             * APIMethod: read
             * Read a doc and return an object representing the document.
             *
             * Parameters:
             * data - {String | DOMElement} Data to read.
             * options - {Object} Options for the reader.
             *
             * Returns:
             * {Object} An object representing the document.
             */
            read: function (data, options) {
                if (typeof data == "string") {
                    data = uOpenLayers.Format.XML.prototype.read.apply(this, [data]);
                }
                let root = data.documentElement;
                let version = this.getVersion(root);
                this.parser = this.getParser(version);          // Select the parser
                let obj = this.parser.read(data, options);      // Parse the data

                let errorProperty = this.parser.errorProperty || null;
                if (errorProperty !== null && obj[errorProperty] === undefined) {
                    // an error must have happened, so parse it and report back
                    let format = new uOpenLayers.Format.OGCExceptionReport();
                    obj.error = format.read(data);
                }
                obj.version = version;
                return obj;
            },

            CLASS_NAME: "OpenLayers.Format.XML.VersionedOGC"
        });

        /**
         * Class: OpenLayers.Format.WMSCapabilities
         * Read WMS Capabilities.
         *
         * Inherits from:
         *  - <OpenLayers.Format.XML.VersionedOGC>
         */
        uOpenLayers.Format.WMSCapabilities = uOpenLayers.Class(uOpenLayers.Format.XML.VersionedOGC, {

            /**
             * APIProperty: defaultVersion
             * {String} Version number to assume if none found.  Default is "1.1.1".
             */
            defaultVersion: "1.1.1",

            /**
             * APIProperty: profile
             * {String} If provided, use a custom profile.
             *
             * Currently supported profiles:
             * - WMSC - parses vendor specific capabilities for WMS-C.
             */
            profile: null,

            /**
             * Constructor: OpenLayers.Format.WMSCapabilities
             * Create a new parser for WMS capabilities.
             *
             * Parameters:
             * options - {Object} An optional object whose properties will be set on
             *     this instance.
             */

            /**
             * APIMethod: read
             * Read capabilities data from a string, and return a list of layers.
             *
             * Parameters:
             * data - {String} or {DOMElement} data to read/parse.
             *
             * Returns:
             * {Array} List of named layers.
             */

            CLASS_NAME: "OpenLayers.Format.WMSCapabilities"

        });

        /**
         * Class: OpenLayers.Format.WMSCapabilities.v1
         * Abstract class not to be instantiated directly. Creates
         * the common parts for both WMS 1.1.X and WMS 1.3.X.
         *
         * Inherits from:
         *  - <OpenLayers.Format.XML>
         */
        uOpenLayers.Format.WMSCapabilities.v1 = uOpenLayers.Class(uOpenLayers.Format.XML, {

            /**
             * Property: namespaces
             * {Object} Mapping of namespace aliases to namespace URIs.
             */
            namespaces: {
                wms: "http://www.opengis.net/wms",
                xlink: "http://www.w3.org/1999/xlink",
                xsi: "http://www.w3.org/2001/XMLSchema-instance"
            },

            /**
             * Property: defaultPrefix
             */
            defaultPrefix: "wms",

            /**
             * Constructor: OpenLayers.Format.WMSCapabilities.v1
             * Create an instance of one of the subclasses.
             *
             * Parameters:
             * options - {Object} An optional object whose properties will be set on
             *     this instance.
             */

            /**
             * APIMethod: read
             * Read capabilities data from a string, and return a list of layers.
             *
             * Parameters:
             * data - {String} or {DOMElement} data to read/parse.
             *
             * Returns:
             * {Array} List of named layers.
             */
            read: function (data) {
                if (typeof data == "string") {
                    data = uOpenLayers.Format.XML.prototype.read.apply(this, [data]);
                }
                let raw = data;
                if (data && data.nodeType === 9) {
                    data = data.documentElement;
                }
                let capabilities = {};
                this.readNode(data, capabilities);
                if (capabilities.service === undefined) {
                    // an exception must have occurred, so parse it
                    let parser = new uOpenLayers.Format.OGCExceptionReport();
                    capabilities.error = parser.read(raw);
                }
                return capabilities;
            },

            /**
             * Property: readers
             * Contains public functions, grouped by namespace prefix, that will
             *     be applied when a namespaced node is found matching the function
             *     name.  The function will be applied in the scope of this parser
             *     with two arguments: the node being read and a context object passed
             *     from the parent.
             */
            readers: {
                "wms": {
                    "Service": function (node, obj) {
                        obj.service = {};
                        this.readChildNodes(node, obj.service);
                    },
                    "Name": function (node, obj) {
                        obj.name = this.getChildValue(node);
                    },
                    "Title": function (node, obj) {
                        obj.title = this.getChildValue(node);
                    },
                    "Abstract": function (node, obj) {
                        obj["abstract"] = this.getChildValue(node);
                    },
                    "BoundingBox": function (node, obj) {
                        let bbox = {};
                        bbox.bbox = [
                            parseFloat(node.getAttribute("minx")),
                            parseFloat(node.getAttribute("miny")),
                            parseFloat(node.getAttribute("maxx")),
                            parseFloat(node.getAttribute("maxy"))
                        ];
                        let res = {
                            x: parseFloat(node.getAttribute("resx")),
                            y: parseFloat(node.getAttribute("resy"))
                        };

                        if (!(isNaN(res.x) && isNaN(res.y))) {
                            bbox.res = res;
                        }
                        // return the bbox so that descendant classes can set the
                        // CRS and SRS and add it to the obj
                        return bbox;
                    },
                    "OnlineResource": function (node, obj) {
                        obj.href = this.getAttributeNS(node, this.namespaces.xlink,
                            "href");
                    },
                    "ContactInformation": function (node, obj) {
                        obj.contactInformation = {};
                        this.readChildNodes(node, obj.contactInformation);
                    },
                    "ContactPersonPrimary": function (node, obj) {
                        obj.personPrimary = {};
                        this.readChildNodes(node, obj.personPrimary);
                    },
                    "ContactPerson": function (node, obj) {
                        obj.person = this.getChildValue(node);
                    },
                    "ContactOrganization": function (node, obj) {
                        obj.organization = this.getChildValue(node);
                    },
                    "ContactPosition": function (node, obj) {
                        obj.position = this.getChildValue(node);
                    },
                    "ContactAddress": function (node, obj) {
                        obj.contactAddress = {};
                        this.readChildNodes(node, obj.contactAddress);
                    },
                    "AddressType": function (node, obj) {
                        obj.type = this.getChildValue(node);
                    },
                    "Address": function (node, obj) {
                        obj.address = this.getChildValue(node);
                    },
                    "City": function (node, obj) {
                        obj.city = this.getChildValue(node);
                    },
                    "StateOrProvince": function (node, obj) {
                        obj.stateOrProvince = this.getChildValue(node);
                    },
                    "PostCode": function (node, obj) {
                        obj.postcode = this.getChildValue(node);
                    },
                    "Country": function (node, obj) {
                        obj.country = this.getChildValue(node);
                    },
                    "ContactVoiceTelephone": function (node, obj) {
                        obj.phone = this.getChildValue(node);
                    },
                    "ContactFacsimileTelephone": function (node, obj) {
                        obj.fax = this.getChildValue(node);
                    },
                    "ContactElectronicMailAddress": function (node, obj) {
                        obj.email = this.getChildValue(node);
                    },
                    "Fees": function (node, obj) {
                        let fees = this.getChildValue(node);
                        if (fees && fees.toLowerCase() !== "none") {
                            obj.fees = fees;
                        }
                    },
                    "AccessConstraints": function (node, obj) {
                        let constraints = this.getChildValue(node);
                        if (constraints && constraints.toLowerCase() !== "none") {
                            obj.accessConstraints = constraints;
                        }
                    },
                    "Capability": function (node, obj) {
                        obj.capability = {
                            nestedLayers: [],
                            layers: []
                        };
                        this.readChildNodes(node, obj.capability);
                    },
                    "Request": function (node, obj) {
                        obj.request = {};
                        this.readChildNodes(node, obj.request);
                    },
                    "GetCapabilities": function (node, obj) {
                        obj.getcapabilities = {formats: []};
                        this.readChildNodes(node, obj.getcapabilities);
                    },
                    "Format": function (node, obj) {
                        if (uOpenLayers.Util.isArray(obj.formats)) {
                            obj.formats.push(this.getChildValue(node));
                        } else {
                            obj.format = this.getChildValue(node);
                        }
                    },
                    "DCPType": function (node, obj) {
                        this.readChildNodes(node, obj);
                    },
                    "HTTP": function (node, obj) {
                        this.readChildNodes(node, obj);
                    },
                    "Get": function (node, obj) {
                        obj.get = {};
                        this.readChildNodes(node, obj.get);
                        // backwards compatibility
                        if (!obj.href) {
                            obj.href = obj.get.href;
                        }
                    },
                    "Post": function (node, obj) {
                        obj.post = {};
                        this.readChildNodes(node, obj.post);
                        // backwards compatibility
                        if (!obj.href) {
                            obj.href = obj.get.href;
                        }
                    },
                    "GetMap": function (node, obj) {
                        obj.getmap = {formats: []};
                        this.readChildNodes(node, obj.getmap);
                    },
                    "GetFeatureInfo": function (node, obj) {
                        obj.getfeatureinfo = {formats: []};
                        this.readChildNodes(node, obj.getfeatureinfo);
                    },
                    "Exception": function (node, obj) {
                        obj.exception = {formats: []};
                        this.readChildNodes(node, obj.exception);
                    },
                    "Layer": function (node, obj) {
                        let parentLayer, capability;
                        if (obj.capability) {
                            capability = obj.capability;
                            parentLayer = obj;
                        } else {
                            capability = obj;
                        }
                        let attrNode = node.getAttributeNode("queryable");
                        let queryable = (attrNode && attrNode.specified) ?
                            node.getAttribute("queryable") : null;
                        attrNode = node.getAttributeNode("cascaded");
                        let cascaded = (attrNode && attrNode.specified) ?
                            node.getAttribute("cascaded") : null;
                        attrNode = node.getAttributeNode("opaque");
                        let opaque = (attrNode && attrNode.specified) ?
                            node.getAttribute('opaque') : null;
                        let noSubsets = node.getAttribute('noSubsets');
                        let fixedWidth = node.getAttribute('fixedWidth');
                        let fixedHeight = node.getAttribute('fixedHeight');
                        let parent = parentLayer || {},
                            extend = uOpenLayers.Util.extend;
                        let layer = {
                            nestedLayers: [],
                            styles: parentLayer ? [].concat(parentLayer.styles) : [],
                            srs: parentLayer ? extend({}, parent.srs) : {},
                            metadataURLs: [],
                            bbox: parentLayer ? extend({}, parent.bbox) : {},
                            llbbox: parent.llbbox,
                            dimensions: parentLayer ? extend({}, parent.dimensions) : {},
                            authorityURLs: parentLayer ? extend({}, parent.authorityURLs) : {},
                            identifiers: {},
                            keywords: [],
                            queryable: (queryable && queryable !== "") ?
                                (queryable === "1" || queryable === "true") :
                                (parent.queryable || false),
                            cascaded: (cascaded !== null) ? parseInt(cascaded) :
                                (parent.cascaded || 0),
                            opaque: opaque ?
                                (opaque === "1" || opaque === "true") :
                                (parent.opaque || false),
                            noSubsets: (noSubsets !== null) ?
                                (noSubsets === "1" || noSubsets === "true") :
                                (parent.noSubsets || false),
                            fixedWidth: (fixedWidth != null) ?
                                parseInt(fixedWidth) : (parent.fixedWidth || 0),
                            fixedHeight: (fixedHeight != null) ?
                                parseInt(fixedHeight) : (parent.fixedHeight || 0),
                            minScale: parent.minScale,
                            maxScale: parent.maxScale,
                            attribution: parent.attribution
                        };
                        obj.nestedLayers.push(layer);
                        layer.capability = capability;
                        this.readChildNodes(node, layer);
                        delete layer.capability;
                        if (layer.name) {
                            let parts = layer.name.split(":"),
                                request = capability.request,
                                gfi = request.getfeatureinfo;
                            if (parts.length > 0) {
                                layer.prefix = parts[0];
                            }
                            capability.layers.push(layer);
                            if (layer.formats === undefined) {
                                layer.formats = request.getmap.formats;
                            }
                            if (layer.infoFormats === undefined && gfi) {
                                layer.infoFormats = gfi.formats;
                            }
                        }
                    },
                    "Attribution": function (node, obj) {
                        obj.attribution = {};
                        this.readChildNodes(node, obj.attribution);
                    },
                    "LogoURL": function (node, obj) {
                        obj.logo = {
                            width: node.getAttribute("width"),
                            height: node.getAttribute("height")
                        };
                        this.readChildNodes(node, obj.logo);
                    },
                    "Style": function (node, obj) {
                        let style = {};
                        obj.styles.push(style);
                        this.readChildNodes(node, style);
                    },
                    "LegendURL": function (node, obj) {
                        let legend = {
                            width: node.getAttribute("width"),
                            height: node.getAttribute("height")
                        };
                        obj.legend = legend;
                        this.readChildNodes(node, legend);
                    },
                    "MetadataURL": function (node, obj) {
                        let metadataURL = {type: node.getAttribute("type")};
                        obj.metadataURLs.push(metadataURL);
                        this.readChildNodes(node, metadataURL);
                    },
                    "DataURL": function (node, obj) {
                        obj.dataURL = {};
                        this.readChildNodes(node, obj.dataURL);
                    },
                    "FeatureListURL": function (node, obj) {
                        obj.featureListURL = {};
                        this.readChildNodes(node, obj.featureListURL);
                    },
                    "AuthorityURL": function (node, obj) {
                        let name = node.getAttribute("name");
                        let authority = {};
                        this.readChildNodes(node, authority);
                        obj.authorityURLs[name] = authority.href;
                    },
                    "Identifier": function (node, obj) {
                        let authority = node.getAttribute("authority");
                        obj.identifiers[authority] = this.getChildValue(node);
                    },
                    "KeywordList": function (node, obj) {
                        this.readChildNodes(node, obj);
                    },
                    "SRS": function (node, obj) {
                        obj.srs[this.getChildValue(node)] = true;
                    }
                }
            },

            CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1"

        });

        /**
         * Class: OpenLayers.Format.WMSCapabilities.v1_1
         * Abstract class not to be instantiated directly.
         *
         * Inherits from:
         *  - <OpenLayers.Format.WMSCapabilities.v1>
         */
        uOpenLayers.Format.WMSCapabilities.v1_1 = uOpenLayers.Class(uOpenLayers.Format.WMSCapabilities.v1, {
            /**
             * Property: readers
             * Contains public functions, grouped by namespace prefix, that will
             *     be applied when a namespaced node is found matching the function
             *     name.  The function will be applied in the scope of this parser
             *     with two arguments: the node being read and a context object passed
             *     from the parent.
             */
            readers: {
                "wms": uOpenLayers.Util.applyDefaults({
                    "WMT_MS_Capabilities": function (node, obj) {
                        this.readChildNodes(node, obj);
                    },
                    "Keyword": function (node, obj) {
                        if (obj.keywords) {
                            obj.keywords.push(this.getChildValue(node));
                        }
                    },
                    "DescribeLayer": function (node, obj) {
                        obj.describelayer = {formats: []};
                        this.readChildNodes(node, obj.describelayer);
                    },
                    "GetLegendGraphic": function (node, obj) {
                        obj.getlegendgraphic = {formats: []};
                        this.readChildNodes(node, obj.getlegendgraphic);
                    },
                    "GetStyles": function (node, obj) {
                        obj.getstyles = {formats: []};
                        this.readChildNodes(node, obj.getstyles);
                    },
                    "PutStyles": function (node, obj) {
                        obj.putstyles = {formats: []};
                        this.readChildNodes(node, obj.putstyles);
                    },
                    "UserDefinedSymbolization": function (node, obj) {
                        obj.userSymbols = {
                            supportSLD: parseInt(node.getAttribute("SupportSLD")) === 1,
                            userLayer: parseInt(node.getAttribute("UserLayer")) === 1,
                            userStyle: parseInt(node.getAttribute("UserStyle")) === 1,
                            remoteWFS: parseInt(node.getAttribute("RemoteWFS")) === 1
                        };
                    },
                    "LatLonBoundingBox": function (node, obj) {
                        obj.llbbox = [
                            parseFloat(node.getAttribute("minx")),
                            parseFloat(node.getAttribute("miny")),
                            parseFloat(node.getAttribute("maxx")),
                            parseFloat(node.getAttribute("maxy"))
                        ];
                    },
                    "BoundingBox": function (node, obj) {
                        let bbox = uOpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"].BoundingBox.apply(this, [node, obj]);
                        bbox.srs = node.getAttribute("SRS");
                        obj.bbox[bbox.srs] = bbox;
                    },
                    "ScaleHint": function (node, obj) {
                        let min = node.getAttribute("min");
                        let max = node.getAttribute("max");
                        let rad2 = Math.pow(2, 0.5);
                        let ipm = uOpenLayers.INCHES_PER_UNIT["m"];
                        if (min !== 0) {
                            obj.maxScale = parseFloat(
                                ((min / rad2) * ipm *
                                    uOpenLayers.DOTS_PER_INCH).toPrecision(13)
                            );
                        }
                        if (max !== Number.POSITIVE_INFINITY) {
                            obj.minScale = parseFloat(
                                ((max / rad2) * ipm *
                                    uOpenLayers.DOTS_PER_INCH).toPrecision(13)
                            );
                        }
                    },
                    "Dimension": function (node, obj) {
                        let name = node.getAttribute("name").toLowerCase();
                        let dim = {
                            name: name,
                            units: node.getAttribute("units"),
                            unitsymbol: node.getAttribute("unitSymbol")
                        };
                        obj.dimensions[dim.name] = dim;
                    },
                    "Extent": function (node, obj) {
                        let name = node.getAttribute("name").toLowerCase();
                        if (name in obj["dimensions"]) {
                            let extent = obj.dimensions[name];
                            extent.nearestVal =
                                node.getAttribute("nearestValue") === "1";
                            extent.multipleVal =
                                node.getAttribute("multipleValues") === "1";
                            extent.current = node.getAttribute("current") === "1";
                            extent["default"] = node.getAttribute("default") || "";
                            let values = this.getChildValue(node);
                            extent.values = values.split(",");
                        }
                    }
                }, uOpenLayers.Format.WMSCapabilities.v1.prototype.readers["wms"])
            },

            CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1"

        });

        /**
         * Class: OpenLayers.Format.WMSCapabilities/v1_1_1
         * Read WMS Capabilities version 1.1.1.
         *
         * Note on <ScaleHint> parsing: If the 'min' attribute is set to "0", no
         * maxScale will be set on the layer object. If the 'max' attribute is set to
         * "Infinity", no minScale will be set. This makes it easy to create proper
         * {<OpenLayers.Layer.WMS>} configurations directly from the layer object
         * literals returned by this format, because no minScale/maxScale modifications
         * need to be made.
         *
         * Inherits from:
         *  - <OpenLayers.Format.WMSCapabilities.v1_1>
         */
        uOpenLayers.Format.WMSCapabilities.v1_1_1 = uOpenLayers.Class(uOpenLayers.Format.WMSCapabilities.v1_1, {
            /**
             * Property: version
             * {String} The specific parser version.
             */
            version: "1.1.1",

            /**
             * Constructor: OpenLayers.Format.WMSCapabilities.v1_1_1
             * Create a new parser for WMS capabilities version 1.1.1.
             *
             * Parameters:
             * options - {Object} An optional object whose properties will be set on
             *     this instance.
             */

            /**
             * Property: readers
             * Contains public functions, grouped by namespace prefix, that will
             *     be applied when a namespaced node is found matching the function
             *     name.  The function will be applied in the scope of this parser
             *     with two arguments: the node being read and a context object passed
             *     from the parent.
             */
            readers: {
                "wms": uOpenLayers.Util.applyDefaults({
                    "SRS": function (node, obj) {
                        obj.srs[this.getChildValue(node)] = true;
                    }
                }, uOpenLayers.Format.WMSCapabilities.v1_1.prototype.readers["wms"])
            },

            CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1"

        });
    };

    const initBaseMapLayer = () => {
        injectWMSCapabilities();

        let displayGroupSelector = document.getElementById('layer-switcher-group_display');
        if (displayGroupSelector != null) {
            let displayGroup = displayGroupSelector.parentNode.parentNode.getElementsByTagName("ul")[0];

            GM.xmlHttpRequest({
                method: "GET",
                url: 'https://sg.geodatenzentrum.de/gdz_getSession?bkg_appid=4cc455dc-a595-bbcf-0d00-c1d81caab5c3&domain=sg.geodatenzentrum.de',
                onload: (sessResp) => {
                    const sessionToken = sessResp.responseText;
                    GM.xmlHttpRequest({
                        method: "GET",
                        url: 'https://sg.geodatenzentrum.de/wms_bdlm_ov__' + sessionToken + '?request=GetCapabilities&service=WMS&version=1.1.1',
                        onload: (response) => {
                            let responseXML = response.responseXML;
                            if (!response.responseXML) {
                                responseXML = new DOMParser().parseFromString(response.responseText, "text/xml");
                            }

                            let format = new uOpenLayers.Format.WMSCapabilities({});
                            let capabilities = format.read(responseXML);

                            let layers = capabilities.capability.layers;
                            layers.splice(0, 2);
                            layers.splice(4);

                            uLayer = new uOpenLayers.Layer.WMS(
                                'BaseMap Overlay',
                                capabilities.service.href,
                                {
                                    layers: layers.map(layer => layer.name).join(','),
                                    styles: layers.map(layer => layer.styles[0].name).join(','),
                                    version: capabilities.version,
                                    transparent: true
                                },
                                {
                                    projection: 'EPSG:3857',
                                    isBaseLayer: false,
                                    opacity: 1.00,
                                    displayOutsideMaxExtent: false,
                                    tileOptions: {
                                        eventListeners: {
                                            'beforeload': function(evt) {
                                                this.getImage().setAttribute('referrerpolicy', 'no-referrer');
                                            }
                                        }
                                    },
                                },
                            );

                            uWaze.map.addLayer(uLayer);
                            uWaze.map.setLayerIndex(uLayer, 3);

                            // Check if layer was active previously
                            if (localStorage.DrawBaseMapOverlay) {
                                uLayer.setVisibility(localStorage.DrawBaseMapOverlay === "true");
                            }

                            // Make checkbox and add to "display" section
                            let toggleEntry = document.createElement('li');
                            let checkbox = document.createElement("wz-checkbox");
                            checkbox.id = 'layer-switcher-basemap-overlay-de';
                            checkbox.className = "hydrated";
                            checkbox.disabled = !displayGroupSelector.checked;
                            checkbox.checked = uLayer.getVisibility();
                            checkbox.appendChild(document.createTextNode('BaseMap Overlay'));

                            toggleEntry.appendChild(checkbox);
                            displayGroup.appendChild(toggleEntry);

                            checkbox.addEventListener('click', (e) => {
                                uLayer.setVisibility(e.target.checked);
                                localStorage.DrawBaseMapOverlay = uLayer.getVisibility();
                            });

                            displayGroupSelector.addEventListener('click', (e) => {
                                uLayer.setVisibility(e.target.checked && checkbox.checked);
                                checkbox.disabled = !e.target.checked;
                                localStorage.DrawBaseMapOverlay = uLayer.getVisibility();
                            });
                        }
                    });
                }
            });
        }
    };

    const bootstrapBaseMapLayer = () => {
        uWaze = window.W || unsafeWindow.W;
        uOpenLayers = window.OpenLayers || unsafeWindow.OpenLayers;
        if (typeof (uOpenLayers) === 'undefined' || typeof (uWaze) === 'undefined' || typeof (uWaze.map) === 'undefined' || document.querySelector('.list-unstyled.togglers .group') === null) {
            setTimeout(bootstrapBaseMapLayer, 500);
        } else {
            initBaseMapLayer();
        }
    };


    bootstrapBaseMapLayer();
})();