# Source: core/Utils.js

    /**
     * The copyright in this software is being made available under the BSD License,
     * included below. This software may be subject to other third party and contributor
     * rights, including patent rights, and no such rights are granted under this license.
     *
     * Copyright (c) 2013, Dash Industry Forum.
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *  * Redistributions of source code must retain the above copyright notice, this
     *  list of conditions and the following disclaimer.
     *  * Redistributions in binary form must reproduce the above copyright notice,
     *  this list of conditions and the following disclaimer in the documentation and/or
     *  other materials provided with the distribution.
     *  * Neither the name of Dash Industry Forum nor the names of its
     *  contributors may be used to endorse or promote products derived from this software
     *  without specific prior written permission.
     *
     *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS AS IS AND ANY
     *  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     *  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
     *  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     *  POSSIBILITY OF SUCH DAMAGE.
     */

    /**
     * @class
     * @ignore
     */

    import path from 'path-browserify'
    import { UAParser } from 'ua-parser-js'

    class Utils {
        static mixin(dest, source, copy) {
            let s;
            let empty = {};
            if (dest) {
                for (let name in source) {
                    if (source.hasOwnProperty(name)) {
                        s = source[name];
                        if (!(name in dest) || (dest[name] !== s && (!(name in empty) || empty[name] !== s))) {
                            if (typeof dest[name] === 'object' && dest[name] !== null) {
                                dest[name] = Utils.mixin(dest[name], s, copy);
                            } else {
                                dest[name] = copy(s);
                            }
                        }
                    }
                }
            }
            return dest;
        }

        static clone(src) {
            if (!src || typeof src !== 'object') {
                return src; // anything
            }
            let r;
            if (src instanceof Array) {
                // array
                r = [];
                for (let i = 0, l = src.length; i < l; ++i) {
                    if (i in src) {
                        r.push(Utils.clone(src[i]));
                    }
                }
            } else {
                r = {};
            }
            return Utils.mixin(r, src, Utils.clone);
        }

        static addAditionalQueryParameterToUrl(url, params) {
            try {
                if (!params || params.length === 0) {
                    return url;
                }

                let modifiedUrl = new URL(url);

                params.forEach((param) => {
                    if (param.key && param.value) {
                        modifiedUrl.searchParams.set(param.key, param.value);
                    }
                });

                return modifiedUrl.href;

            } catch (e) {
                return url;
            }
        }

        static parseHttpHeaders(headerStr) {
            let headers = {};
            if (!headerStr) {
                return headers;
            }

            // Trim headerStr to fix a MS Edge bug with xhr.getAllResponseHeaders method
            // which send a string starting with a "\n" character
            let headerPairs = headerStr.trim().split('\u000d\u000a');
            for (let i = 0, ilen = headerPairs.length; i < ilen; i++) {
                let headerPair = headerPairs[i];
                let index = headerPair.indexOf('\u003a\u0020');
                if (index > 0) {
                    headers[headerPair.substring(0, index)] = headerPair.substring(index + 2);
                }
            }
            return headers;
        }

        static generateUuid() {
            let dt = new Date().getTime();
            const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                const r = (dt + Math.random() * 16) % 16 | 0;
                dt = Math.floor(dt / 16);
                return (c == 'x' ? r : (r & 0x3 | 0x8)).toString(16);
            });
            return uuid;
        }

        static generateHashCode(string) {
            let hash = 0;

            if (string.length === 0) {
                return hash;
            }

            for (let i = 0; i < string.length; i++) {
                const chr = string.charCodeAt(i);
                hash = ((hash << 5) - hash) + chr;
                hash |= 0;
            }
            return hash;
        }

        /**
         * Compares both urls and returns a relative url (target relative to original)
         * @param {string} originalUrl
         * @param {string} targetUrl
         * @return {string|*}
         */
        static getRelativeUrl(originalUrl, targetUrl) {
            try {
                const original = new URL(originalUrl);
                const target = new URL(targetUrl);

                // Unify the protocol to compare the origins
                original.protocol = target.protocol;
                if (original.origin !== target.origin) {
                    return targetUrl;
                }

                // Use the relative path implementation of the path library. We need to cut off the actual filename in the end to get the relative path
                let relativePath = path.relative(original.pathname.substr(0, original.pathname.lastIndexOf('/')), target.pathname.substr(0, target.pathname.lastIndexOf('/')));

                // In case the relative path is empty (both path are equal) return the filename only. Otherwise add a slash in front of the filename
                const startIndexOffset = relativePath.length === 0 ? 1 : 0;
                relativePath += target.pathname.substr(target.pathname.lastIndexOf('/') + startIndexOffset, target.pathname.length - 1);

                // Build the other candidate, e.g. the 'host relative' path that starts with "/", and return the shortest of the two candidates.
                if (target.pathname.length < relativePath.length) {
                    return target.pathname;
                }
                return relativePath;
            } catch (e) {
                return targetUrl
            }
        }

        static parseUserAgent(ua = null) {
            try {
                const uaString = ua === null ? typeof navigator !== 'undefined' ? navigator.userAgent.toLowerCase() : '' : '';

                return UAParser(uaString);
            }
            catch(e) {
                return {};
            }
        }

        /**
         * Checks for existence of "http" or "https" in a string
         * @param string
         * @returns {boolean}
         */
        static stringHasProtocol(string) {
            return (/(http(s?)):\/\//i.test(string))
        }
    }

    export default Utils;

#### Search results