{"version":3,"sources":["../../../packages/core/base/utilities.ts"],"names":[],"mappings":"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","file":"utilities.d.ts","sourcesContent":["/* eslint-disable unused-imports/no-unused-vars */\r\n/* eslint-disable no-console */\r\n/* eslint-disable max-len */\r\n// this code has been worked on other platform, and refactoring may cause other problem so keeps as is.\r\nnamespace MsftSme {\r\n    'use strict';\r\n\r\n    const global: any = window;\r\n    const FunctionGlobal = Function;\r\n    const MathGlobal = Math;\r\n    const ObjectGlobal = Object;\r\n\r\n    // See Mark Miller’s explanation of what this does.\r\n    // http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming\r\n    //\r\n    // For example:\r\n    // const array_slice: <T>(target: T[]|IArguments, start?: number, end?: number) => T[] = MsPortalFx.uncurryThis(Array.prototype.slice);\r\n    // Then the call can be strong typed, rather than call/apply with only runtime check.\r\n    //\r\n    // This also **might** have the nice side-effect of reducing the size of\r\n    // the minified code by reducing x.call() to merely x()\r\n    const call = FunctionGlobal.call;\r\n    const apply = FunctionGlobal.apply;\r\n    export function uncurryThis(f: (...args: any[]) => any): (...args: any[]) => any {\r\n        return function () {\r\n            return call.apply(f, arguments);\r\n        };\r\n    }\r\n\r\n    const _applyCall: (f: (...args: any[]) => any, target: any, args: any[] | IArguments) => any = uncurryThis(apply);\r\n    export const applyCall = _applyCall;\r\n    export const applyUncurry = _applyCall; // most uncurry function can be call by _applyCall  except for array_concat; (see below.)\r\n\r\n    // declare variable such that  minimize better and code readibility\r\n    const array_prototype = Array.prototype;\r\n    const array_prototype_concat = array_prototype.concat; // array concat does not work well with uncurryThis since it flatten the arguments array.\r\n    const array_prototype_push = array_prototype.push;\r\n    const array_filter: <T>(target: T[] | IArguments, callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any) => T[] = uncurryThis(array_prototype.filter);\r\n    const array_forEach: <T>(target: T[] | IArguments, callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any) => void = uncurryThis(array_prototype.forEach);\r\n    const array_join: <T>(target: T[] | IArguments, separator?: string) => string = uncurryThis(array_prototype.join);\r\n    const array_push: <T>(target: T[] | IArguments, item: T) => number = uncurryThis(array_prototype_push);\r\n    const array_slice: <T>(target: T[] | IArguments, start?: number, end?: number) => T[] = uncurryThis(array_prototype.slice);\r\n    const array_splice: <T>(target: T[] | IArguments, start: number, deleteCount?: number, ...items: T[]) => T[] = uncurryThis(array_prototype.splice);\r\n    // eslint-disable-next-line unused-imports/no-unused-vars\r\n    const array_indexof: <T>(target: T[] | IArguments, searchElement: T, fromIndex?: number) => number = uncurryThis(array_prototype.indexOf);\r\n\r\n    const array_isArray = Array.isArray;\r\n\r\n    const string_prototype = String.prototype;\r\n    const string_concat: (target: string, ...items: string[]) => string = uncurryThis(string_prototype.concat);\r\n    const string_split: (target: string, separator: string, limit?: number) => string[] = uncurryThis(string_prototype.split);\r\n    const string_substring: (target: string, start: number, end?: number) => string = uncurryThis(string_prototype.substring);\r\n    const string_indexOf: (target: string, searchString: string, position?: number) => number = uncurryThis(string_prototype.indexOf);\r\n    const string_toLowerCase: (target: string) => string = uncurryThis(string_prototype.toLowerCase);\r\n\r\n    const object_hasOwnProperty: (target: Object, v: string) => boolean = uncurryThis(ObjectGlobal.prototype.hasOwnProperty);\r\n    const object_propertyIsEnumerable: (target: Object, v: PropertyKey) => boolean = uncurryThis(ObjectGlobal.prototype.propertyIsEnumerable);\r\n    const object_keys_original = ObjectGlobal.keys;\r\n    const _undefined: any = undefined;\r\n\r\n    const object_freeze = ObjectGlobal.freeze;\r\n\r\n    const functionType = \"function\";\r\n    const stringType = \"string\";\r\n    const numberType = \"number\";\r\n    const objectType = \"object\";\r\n    const undefinedType = \"undefined\";\r\n\r\n    export class LocalStorageHandler {\r\n        /**\r\n         * Gets the local storage.\r\n         * @param window the window object to get local storage from.\r\n         * @returns The local storage.\r\n         */\r\n        public static getLocalStorage(window?: Window): Storage  {\r\n            try {\r\n                return window ? window.localStorage : localStorage;\r\n            } catch (error) {\r\n                console.warn('Error getting the localStorage:', error);\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Sets the value for the localStorage by key.\r\n         * @param key The key to set value.\r\n         * @param value The value for the key.\r\n         */\r\n        public static setItem(key: string, value: string, window?: Window): void {\r\n            try {\r\n                const localStorageTarget = window ? window.localStorage : localStorage;\r\n                localStorageTarget.setItem(key, value);\r\n            } catch (error) {\r\n                console.warn('Error saving to localStorage:', error);\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Gets the value from localStorage by key.\r\n         * @param key The key to get value.\r\n         * @returns The value for the key passed in.\r\n         */\r\n        public static getItem(key: string, window?: Window): string {\r\n            try {\r\n                const localStorageTarget = window ? window.localStorage : localStorage;\r\n                return localStorageTarget.getItem(key);\r\n            } catch (error) {\r\n                console.warn('Error retrieving from localStorage:', error);\r\n            }\r\n\r\n            return undefined;\r\n        }\r\n\r\n        /**\r\n         * Removes the value for the localStorage by key.\r\n         * @param key The key to remove value.\r\n         */\r\n        public static removeItem(key: string, window?: Window): void {\r\n            try {\r\n                const localStorageTarget = window ? window.localStorage : localStorage;\r\n                localStorageTarget.removeItem(key);\r\n            } catch (error) {\r\n                console.warn('Error removing from localStorage:', error);\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Clears the current localStorage.\r\n         */\r\n        public static clear(window?: Window): void {\r\n            try {\r\n                const localStorageTarget = window ? window.localStorage : localStorage;\r\n                localStorageTarget.clear();\r\n            } catch (error) {\r\n                console.warn('Error clearing localStorage:', error);\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Gets the length of the local storage\r\n         */\r\n        public static getLength(window?: Window): number {\r\n            let length: number;\r\n            try {\r\n                const localStorageTarget = window ? window.localStorage : localStorage;\r\n                length = localStorageTarget.length;\r\n            } catch (error) {\r\n                console.warn('Error getting localStorage length:', error);\r\n            }\r\n\r\n            return length;\r\n        }\r\n\r\n        /*\r\n        * Gets the key by index.\r\n        */\r\n        public static getKey(index: number, window?: Window): string {\r\n            let value: string;\r\n            try {\r\n                const localStorageTarget = window ? window.localStorage : localStorage;\r\n                value = localStorageTarget.key(index);\r\n            } catch (error) {\r\n                console.warn('Error getting value from localStorage by key:', error);\r\n            }\r\n\r\n            return value;\r\n        }\r\n    }\r\n\r\n    export class SessionStorageHandler {\r\n        /**\r\n         * Gets the session storage.\r\n         * @returns The session storage.\r\n         */\r\n        public static getSessionStorage(): Storage {\r\n            try {\r\n                return sessionStorage;\r\n            } catch (error) {\r\n                console.warn('Error getting the sessionStorage:', error);\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Sets the value for the sessionStorage by key.\r\n         * @param key The key to set value.\r\n         * @param value The value for the key.\r\n         */\r\n        public static setItem(key: string, value: string): void {\r\n            try {\r\n                SessionStorageHandler.getSessionStorage().setItem(key, value);\r\n            } catch (error) {\r\n                console.warn('Error saving to sessionStorage:', error);\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Gets the value from sessionStorage by key.\r\n         * @param sessionStorageTarget The sessionStorage to use.\r\n         * @param key The key to get value.\r\n         * @returns The value for the key passed in.\r\n         */\r\n        public static getItem(key: string): string {\r\n            try {\r\n                return SessionStorageHandler.getSessionStorage().getItem(key);\r\n            } catch (error) {\r\n                console.warn('Error retrieving from sessionStorage:', error);\r\n            }\r\n\r\n            return '{}';\r\n        }\r\n\r\n        /**\r\n         * Removes the value for the sessionStorage by key.\r\n         * @param sessionStorageTarget The sessionStorage to use.\r\n         * @param key The key to remove value.\r\n         */\r\n        public static removeItem(key: string): void {\r\n            try {\r\n                SessionStorageHandler.getSessionStorage().removeItem(key);\r\n            } catch (error) {\r\n                console.warn('Error removing from sessionStorage:', error);\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Clears the current sessionStorage.\r\n         * @param sessionStorageTarget The sessionStorage to use.\r\n         */\r\n        public static clear(): void {\r\n            try {\r\n                SessionStorageHandler.getSessionStorage().clear();\r\n            } catch (error) {\r\n                console.warn('Error clearing sessionStorage:', error);\r\n            }\r\n        }\r\n\r\n        /**\r\n         * Gets the length of the sessionStorage\r\n         * @param sessionStorageTarget The sessionStorage to use.\r\n         * @returns\r\n         */\r\n        public static getLength(): number {\r\n            let length: number;\r\n            try {\r\n                length = SessionStorageHandler.getSessionStorage().length;\r\n            } catch (error) {\r\n                console.warn('Error getting sessionStorage length:', error);\r\n            }\r\n\r\n            return length;\r\n        }\r\n\r\n        /* Gets the key by index.\r\n        * @param sessionStorageTarget The sessionStorage to use.\r\n        * @returns\r\n        */\r\n        public static getKey(index: number): string {\r\n            let value: string;\r\n            try {\r\n                value = SessionStorageHandler.getSessionStorage().key(index);\r\n            } catch (error) {\r\n                console.warn('Error getting value from sessionStorage by key:', error);\r\n            }\r\n\r\n            return value;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * For testing only. Use Object.keys.\r\n     */\r\n    export function _objectKeysPolyfill(o: any) {\r\n        switch (typeof o) {\r\n            case stringType:\r\n                const arr: string[] = [];\r\n                for (let i in o) {\r\n                    array_push(arr, i);\r\n                }\r\n                return arr;\r\n            case functionType:\r\n            case objectType:\r\n            case undefinedType:\r\n                return object_keys_original(o);\r\n            default: // probably some other native type\r\n                return [];\r\n        }\r\n    }\r\n\r\n    // intentionally put inside an anonymous function.\r\n    // Presence of try-catch impacts the browser's ability\r\n    // to optimize code in the same function context.\r\n    (() => {\r\n        try {\r\n            object_keys_original(\"\");\r\n        } catch (err) {\r\n            // it threw so this browser is in ES5 mode (probably IE11)\r\n            // let's polyfill Object.keys\r\n            ObjectGlobal.keys = _objectKeysPolyfill;\r\n        }\r\n    })();\r\n\r\n    const object_keys = ObjectGlobal.keys;\r\n\r\n    function isTypeOf(obj: any, type: string) {\r\n        return typeof obj === type;\r\n    }\r\n\r\n    function isDate(obj: any) {\r\n        return obj instanceof Date;\r\n    }\r\n\r\n    export function isFunction(obj: any): boolean {\r\n        return isTypeOf(obj, functionType);\r\n    }\r\n\r\n    export function isNumber(obj: any): boolean {\r\n        return isTypeOf(obj, numberType);\r\n    }\r\n\r\n    const regex_NonSpace = /\\S/;\r\n    const regex_WhiteSpace = /\\s/;\r\n\r\n    function getDisposeFunc(value: any): Func<void> {\r\n        let dispose = value && value.dispose;\r\n        return isTypeOf(dispose, functionType) && dispose;\r\n    }\r\n\r\n    export function forEachKey<T>(obj: StringMap<T>, iterator: (key: string, value: T) => void): void;\r\n    export function forEachKey<T>(obj: NumberMap<T>, iterator: (key: number, value: T) => void): void;\r\n    export function forEachKey<T>(obj: any, iterator: (key: any, value: T) => void): void {\r\n        array_forEach(object_keys(obj), (k) => {\r\n            iterator(k, obj[k]);\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Shortcut for Object.keys(obj || {}).length.\r\n     * @return number.\r\n     */\r\n    export function keysLength(obj: Object) {\r\n        return object_keys(obj || {}).length;\r\n    }\r\n\r\n    /**\r\n     * Determines whether an object has properties on it.\r\n     * Will return true for the following inputs: [], {}, \"\", 0, 1, true, false, new Date(), function() {}.\r\n     * Will return false for the following inputs: [1], {a:1}, \"123\".\r\n     * @return boolean.\r\n     */\r\n    export function isEmpty(obj: Object) {\r\n        return !keysLength(obj);\r\n    }\r\n\r\n    /**\r\n     * Detect a value is Disposable.\r\n     *\r\n     * @param value The value to check against value.dispose is a function.\r\n     * @return boolean.\r\n     */\r\n    export function isDisposable(value: any): boolean {\r\n        return !!getDisposeFunc(value);\r\n    }\r\n\r\n    function _disposeDisposable(value: any): void {\r\n        if (array_isArray(value)) {\r\n            array_forEach(value, _disposeDisposable);\r\n        }\r\n\r\n        const dispose = getDisposeFunc(value);\r\n        if (dispose) {\r\n            dispose.call(value); //  dispose typically rely on this is the object.\r\n        }\r\n    }\r\n\r\n    /**\r\n     * call value.dispose() if a value is Disposable.\r\n     *\r\n     * @param value The value to call value.dispose()\r\n     * @return boolean;\r\n     */\r\n    export const disposeDisposable: (...values: any[]) => void = function (/*...values: any[]*/) {\r\n        array_forEach(arguments, _disposeDisposable);\r\n    };\r\n\r\n    /**\r\n     * Detect a value is null.\r\n     *\r\n     * @param value The value to check against null.\r\n     * @return boolean.\r\n     */\r\n    export function isNull(value: any): boolean {\r\n        return value === null;\r\n    }\r\n\r\n    /**\r\n     * Detect a value is undefined.\r\n     *\r\n     * @param value The value to check against undefined.\r\n     * @return boolean.\r\n     */\r\n    export function isUndefined(value: any): boolean {\r\n        return value === _undefined;\r\n    }\r\n\r\n    /**\r\n     * Indicates whether the specified object is null or undefined.\r\n     *\r\n     * @param value The value to test.\r\n     * @returns True if the value parameter is null or undefined; otherwise, false.\r\n     */\r\n    export function isNullOrUndefined(value: any): boolean {\r\n        return value === null || value === _undefined;\r\n    }\r\n\r\n    /**\r\n     * Indicates whether the specified object is not null or undefined.\r\n     *\r\n     * @param value The value to test.\r\n     * @returns True if the value parameter is null or undefined; otherwise, false.\r\n     */\r\n    export function notNullOrUndefined(value: any): boolean {\r\n        return value !== null && value !== _undefined;\r\n    }\r\n\r\n    /**\r\n     * Checks if the string is null, undefined or whitespace.\r\n     *\r\n     * @param  value The target string.\r\n     * @return true if the string is null, undefined or whitespace; otherwise, false.\r\n     */\r\n    export function isNullOrWhiteSpace(value: string): boolean {\r\n        // http://jsperf.com/empty-string-test-regex-vs-trim/4\r\n        return isNullOrUndefined(value) || (isTypeOf(value, stringType) && !regex_NonSpace.test(value)); // if can't find any characters other than space.\r\n    }\r\n\r\n    /**\r\n     * Checks if a string contains a white space\r\n     *\r\n     * Space, tab, line feed (newline), carriage return, form feed, and vertical tab characters are all\r\n     * considered white space characters - https://learn.microsoft.com/en-us/cpp/c-language/white-space-characters?view=msvc-170\r\n     * @param value the target string\r\n     * @returns true if string contains a white space character else false\r\n     */\r\n    export function containsWhiteSpace(value: string): boolean {\r\n        return regex_WhiteSpace.test(value);\r\n    }\r\n\r\n    //#region Array\r\n\r\n    /**\r\n     * Finds the index of the first element of an array that matches the predicate.\r\n     *\r\n     * @param predicate The Predicate function.\r\n     * @param startIndex The starting index.  If negative, it find from the end of the array.\r\n     *        If you want to continue the next search from the back you much pass in startIndex = (prevReturn - length -1)\r\n     *\r\n     * @return The first index that matches the predicate.\r\n     */\r\n    export function findIndex<T>(array: T[], predicate?: (value: T, index: number, array: T[]) => boolean, startIndex: number = 0): number {\r\n        if (array) {\r\n            let length = array.length;\r\n            let stop = length;\r\n            let step = 1;\r\n            let index = startIndex;\r\n\r\n            if (length) {\r\n                if (startIndex < 0) {\r\n                    index += length;\r\n                    step = stop = -1;\r\n                }\r\n                if (!predicate) {\r\n                    return index < length && index >= 0 ? index : -1;\r\n                }\r\n                while (index !== stop) {\r\n                    if (predicate(array[index], index, array)) {\r\n                        return index;\r\n                    }\r\n                    index += step;\r\n                }\r\n            }\r\n        }\r\n\r\n        return -1;\r\n    }\r\n\r\n    /**\r\n     * Finds the first element of an array that matches the predicate.\r\n     *\r\n     * @param predicate The Predicate function.\r\n     * @param startIndex The starting index.  If negative, it find from the end of the array.\r\n     *        If you want to continue the next search from the back you much pass in startIndex = (prevReturn - length -1)\r\n     *\r\n     * @return The first element that matches the predicate.\r\n     */\r\n    export function find<T>(array: T[], predicate?: (value: T, index: number, array: T[]) => boolean, startIndex?: number): T {\r\n        const index = findIndex(array, predicate, startIndex);\r\n        return index < 0 ? _undefined : array[index];\r\n    }\r\n\r\n    /**\r\n     * Returns the first element of the sequence.\r\n     *\r\n     * @return The element\r\n     */\r\n    export function first<T>(array: T[]): T {\r\n        return array ? array[0] : _undefined;\r\n    }\r\n\r\n    /**\r\n     * Returns the last element of the sequence.\r\n     *\r\n     * @return The element\r\n     */\r\n    export function last<T>(array: T[]): T {\r\n        const length = array ? array.length : 0;\r\n        return length ? array[length - 1] : _undefined;\r\n    }\r\n\r\n    /**\r\n     * Removes all values that equal the given item and returns them as an array\r\n     *\r\n     * @param item The value to be removed.\r\n     * @return The removed items.\r\n     */\r\n    export function remove<T>(array: T[], itemOrPredicate: T | ((value: T) => boolean), startIndex: number = 0): T[] {\r\n        const removedItems: T[] = [];\r\n        let removedCount = 0;\r\n        let predicate: (value: T) => boolean;\r\n\r\n        if (isTypeOf(itemOrPredicate, functionType)) {\r\n            predicate = <any>itemOrPredicate;\r\n        }\r\n        for (let i = startIndex, l = array.length; i < l; i++) {\r\n            const item = array[i];\r\n            if (removedCount) {\r\n                array[i - removedCount] = item; //shift the item to the offset\r\n            }\r\n            if (itemOrPredicate === item || (predicate && predicate(item))) {\r\n                removedCount++;\r\n                array_push(removedItems, item);\r\n            }\r\n        }\r\n\r\n        if (removedCount) {\r\n            array_splice(array, -1 * removedCount); // remove that many item form the end;\r\n        }\r\n\r\n        return removedItems;\r\n    }\r\n\r\n    // This function use findIndex, put it here for minimizer friendly\r\n    // sourceUnique is a flag to optimize the performance, set to  true if you know source is unique already.\r\n    export function pushUnique<T>(uniqueTarget: T[], source: T[], predicate?: (value1: T, value2: T) => boolean, sourceUnique = false): T[] {\r\n        if (array_isArray(source)) {\r\n            let getIndex = predicate ?\r\n                (value: T) => findIndex(uniqueTarget, (resultValue) => predicate(resultValue, value)) :\r\n                (value: T) => uniqueTarget.indexOf(value);\r\n            let appendTarget = (sourceUnique) ? [] : uniqueTarget; // if source is already unique, we accumlate to a sperated array to increase the perf.\r\n            for (let i = 0, l = source.length; i < l; i++) {\r\n                let value = source[i];\r\n                if (getIndex(value) < 0) {\r\n                    array_push(appendTarget, value);\r\n                }\r\n            }\r\n            if (sourceUnique) { // if source is unique, we append to a uniqueTarget .\r\n                array_prototype_push.apply(uniqueTarget, appendTarget);\r\n            }\r\n        }\r\n\r\n        return uniqueTarget;\r\n    }\r\n\r\n    /**\r\n     * Returns a unique set from this array based on the predicate.\r\n     *\r\n     * @param predicate The predicate function. Added to the result if the predicate returns false.\r\n     * @return A new array with the unique values.\r\n     */\r\n    export function unique<T>(array: T[], predicate?: (value1: T, value2: T) => boolean): T[] {\r\n        return pushUnique([], array, predicate);\r\n    }\r\n\r\n    /**\r\n     * Returns a unique concatenated set from this array and the given array based on the predicate.\r\n     *\r\n     * @param arrays The list of arrays to get union of.\r\n     * @return A new array with the unique values.\r\n     */\r\n    export function union<T>(...arrays: T[][]): T[];\r\n\r\n    /**\r\n     * Returns a unique concatenated set from this array and the given array based on the predicate.\r\n     *\r\n     * @param other The other array to concatenate with this one.\r\n     * @param predicate The predicate function. Added to the result if the predicate returns false.\r\n     * @return A new array with the unique values.\r\n     */\r\n    export function union<T>(array: T[], other: T[], predicate?: (value1: T, value2: T) => boolean): T[];\r\n    export function union<T>(): T[] {\r\n        const result: T[] = [];\r\n        let lastArrayIndex = arguments.length - 2;\r\n        let predicate = arguments[lastArrayIndex + 1];\r\n\r\n        // If the predicate is not a function, it means that it is the last array to union.\r\n        if (!isTypeOf(predicate, functionType)) {\r\n            predicate = _undefined;\r\n            lastArrayIndex++;\r\n        }\r\n\r\n        for (let i = 0; i <= lastArrayIndex; i++) {\r\n            let source = unique(arguments[i], predicate); // make a smaller set\r\n            pushUnique(result, source, predicate, true /* source Unique*/);\r\n        }\r\n\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * Merge multiple T, T[] into a combine T[] exclude null or undefined arguments.\r\n     *\r\n     * @param data, a list fo T, T[]\r\n     * @returns concattenated array.\r\n     */\r\n    export const merge: <T>(...data: (T | T[])[]) => T[] = function <T>(/*...data: T[]*/): T[] {\r\n        // Don't use TypeScript's built-in \"... rest\" args syntax for perf-critical\r\n        // paths because it constructs the args array even if you don't need it,\r\n        let ret: T[] = [];\r\n        let data = array_filter(arguments, notNullOrUndefined);\r\n        return array_prototype_concat.apply(ret, data);\r\n    };\r\n\r\n    /**\r\n     * Projects each element of a sequence to a sequence and flattens the resulting sequences into one sequence.\r\n     *\r\n     * @param selector The projection function.\r\n     * @return A flattened array.\r\n     */\r\n    export function mapMany<T, TResult>(array: T[], selector: (source: T) => TResult[]): TResult[] {\r\n        return merge.apply(null, array.map(selector));\r\n    }\r\n\r\n    /**\r\n     * Sorts an array using a stable sort algorithm.\r\n     *\r\n     * This method returns a new array, it does not sort in place.\r\n     *\r\n     * @param compare The Compare function.\r\n     * @return Sorted array.\r\n     */\r\n    export function stableSort<T>(array: T[], compare: (a: T, b: T) => number): T[] {\r\n        const array2 = array.map((v, i) => {\r\n            return { i: i, v: v };\r\n        });\r\n        array2.sort((a, b) => {\r\n            return compare(a.v, b.v) || (a.i - b.i);\r\n        });\r\n        return array2.map(v => v.v);\r\n    }\r\n\r\n    function toString<T>(item: T): string {\r\n        return item ? item.toString() : String(item);\r\n    }\r\n\r\n    /**\r\n     * Extends from  a source array into an existing string map of key => item.\r\n     *\r\n     * @param objToExtend The target object to be extended.\r\n     * @param sourceArray The source array to convert to a map properties of target object.\r\n     * @param getKeyCallback The callback used to provide the key for the item.\r\n     * @param getValueCallback The optional callback used to provide the key for the item, otherwise the item itself is used.\r\n     * @param onlyIfNotExist If true, only Extend the value in array if the existing slot is still undefine. (This behaves like type script argument default value, it only fill in if the value is undefined.)\r\n     *\r\n     * @return The string map of key => item for the source array.\r\n     */\r\n    export function extendArrayIntoMap<T, U>(objToExtend: StringMap<U>, sourceItems: T[], getKeyCallback?: (item: T, index?: number) => string, getValueCallback?: (item: T, index?: number, key?: string) => U, onlyIfNotExist?: boolean): void;\r\n    export function extendArrayIntoMap<T, U>(objToExtend: NumberMap<U>, sourceItems: T[], getKeyCallback?: (item: T, index?: number) => number, getValueCallback?: (item: T, index?: number, key?: string) => U, onlyIfNotExist?: boolean): void;\r\n    export function extendArrayIntoMap<T, U>(objToExtend: any, sourceItems: T[], getKeyCallback?: (item: T, index?: number) => string | number, getValueCallback?: (item: T, index?: number, key?: string) => U, onlyIfNotExist?: boolean): void {\r\n        getKeyCallback = getKeyCallback || toString;\r\n        // The use of args here is to reduce the array creation call and make sure the function context this is the sourceItems.\r\n        let args: any[] = [sourceItems, /*item*/, /*index*/, \"\"];\r\n        for (let i = 0, l = sourceItems.length; i < l; i++) {\r\n            let item = sourceItems[i];\r\n            args[1] = item;\r\n            args[2] = i;\r\n            args[3] = _undefined;\r\n            let key = call.apply(getKeyCallback, args);\r\n            if (!onlyIfNotExist || objToExtend[key] === _undefined) {\r\n                args[3] = key; // This is convient for the get value function to know the key that previous interpreted by getKeyCallback\r\n                let value = getValueCallback ? call.apply(getValueCallback, args) : item;\r\n                // Only extend this key if the value return is not undefined.\r\n                if (value !== _undefined) {\r\n                    objToExtend[key] = value;\r\n                }\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Extends from  a source array into an existing string map of key => item.\r\n     *\r\n     * @param objToExtend The target object to be extended.\r\n     * @param sourceArray The source array to convert to a map properties of target object.\r\n     * @param getKeyCallback The callback used to provide the key for the item.\r\n     * @param getValueCallback The optional callback used to provide the key for the item, otherwise the item itself is used.\r\n     * @param  onlyIfNotExist If true, only Extend the value in array if the existing slot is still undefine. (This behaves like type script argument default value, it only fill in if the value is undefined.)\r\n     *\r\n     * @return The string map of key => item for the source array.\r\n     */\r\n    export function extendStringMapIntoMap<T, U>(objToExtend: StringMap<U>, sourceItems: StringMap<T>, getValueCallback?: (item: T, key?: string) => U, onlyIfNotExist?: boolean): void;\r\n    export function extendStringMapIntoMap<T, U>(objToExtend: any, sourceItems: StringMap<T>, getValueCallback?: (item: T, key?: string) => U, onlyIfNotExist?: boolean): void {\r\n        // The use of args here is to reduce the array creation call and make sure the function context this is the sourceItems.\r\n        let args: any[] = [sourceItems, /*item*/, /*key*/];\r\n\r\n        forEachKey(sourceItems, (key, item) => {\r\n            if (!onlyIfNotExist || objToExtend[key] === _undefined) {\r\n                args[1] = item;\r\n                args[2] = key; // This is convient for the get value function to know the key that previous interpreted by getKeyCallback\r\n                let value = getValueCallback ? call.apply(getValueCallback, args) : (item || key);\r\n                // Only extend this key if the value return is not undefined.\r\n                if (value !== _undefined) {\r\n                    objToExtend[key] = value;\r\n                }\r\n            }\r\n        });\r\n    }\r\n\r\n    /**\r\n     * Helper function to create a object lightweight constructor\r\n     *\r\n     * @param keys the ordered argument keys\r\n     *\r\n     * @return The function that will return string map base on the arguments index order of keys\r\n     */\r\n    export function getStringMapFunc(...keys: string[]): Func<StringMap<any>>;\r\n    export function getStringMapFunc(keys: string[]): Func<StringMap<any>>;\r\n    export function getStringMapFunc(keys: any): Func<StringMap<any>> {\r\n\r\n        if (array_isArray(keys)) {\r\n            // make a copy of keys so that future changes to the input array do not impact the behavior of the returned function.\r\n            keys = array_slice(keys);\r\n        } else {\r\n            keys = arguments;\r\n        }\r\n\r\n        return function ( /* arguments*/) {\r\n            // Most people call .hasOwnProperty or .constructor (which it should not)\r\n            // since there is no guarantee that any object return to have those function -Expecially in generic function.\r\n            // http://stackoverflow.com/questions/12017693/why-use-object-prototype-hasownproperty-callmyobj-prop-instead-of-myobj-hasow\r\n            // Unfortunately, this need to be changed.\r\n            let ret: StringMap<any> = {};\r\n            array_forEach(arguments, (value, index) => {\r\n                let key = keys[index];\r\n                if (value !== _undefined) {\r\n                    ret[key] = value;\r\n                }\r\n            });\r\n            return ret;\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Helper funciton to create a object lightweight constructor\r\n     *\r\n     * @param keys the ordered argument keys\r\n     *\r\n     * @return The function that will return string map base on the arguments index order of keys\r\n     */\r\n    export function applyStringMapFunc(keys: string[]): Func<StringMap<any>> {\r\n        return getStringMapFunc.apply(_undefined, keys);\r\n    }\r\n\r\n    /**\r\n     * Helper funciton to create a object of type NameValue<N, T>\r\n     *\r\n     * @param name name\r\n     * @param value value\r\n     *\r\n     * @return an object of NameValue<N, T>\r\n     */\r\n    export const getNameValue: <N, T>(name: N, value: T) => NameValue<N, T> = <any>getStringMapFunc(\"name\", \"value\");\r\n\r\n    /**\r\n     * Get a list of typeScript Enum into Array\r\n     *\r\n     * @param tsEnumeration The Type script Enum Array\r\n     * @param sort optional whether to sort by enum's value\r\n     * @return all NameValue<string, number>[] for this typeScriptEnum\r\n     */\r\n    export function getEnumArray(tsEnumeration: any, sort?: boolean): NameValue<string, number>[] {\r\n        let retVal: { name: string; value: number }[] = [];\r\n\r\n        forEachKey(<StringMap<number>>tsEnumeration, (key, val) => {\r\n            if (isTypeOf(key, stringType) && isTypeOf(val, numberType)) {\r\n                array_push(retVal, getNameValue(key, val));\r\n            }\r\n        });\r\n\r\n        return sort ? retVal.sort((a, b) => {\r\n            return a.value - b.value;\r\n        }) : retVal;\r\n    }\r\n\r\n    /**\r\n     * Coerce an input into an array if it isn't already one.\r\n     */\r\n    export function makeArray<T>(input: T | T[]): T[] {\r\n        if (!array_isArray(input)) {\r\n            if (isNullOrUndefined(input)) {\r\n                input = [];\r\n            } else {\r\n                input = [<T>input];\r\n            }\r\n        }\r\n\r\n        return <T[]>input;\r\n    }\r\n\r\n    //#endregion Array\r\n\r\n    //#region Date\r\n\r\n    /**\r\n     * Checks if given dates are equal.\r\n     *\r\n     * @param left Left hand side date.\r\n     * @param left Right hand side date.\r\n     * @return True if left date is equal to right date.\r\n     */\r\n    export function areEqualDates(left: any, right: any): boolean {\r\n        return isDate(left) && isDate(right) && !(left > right || left < right);\r\n    }\r\n\r\n    /**\r\n     * Round down the date.getTime() to seconds\r\n     *\r\n     * @param date.\r\n     * @return the getTime in seconds\r\n     */\r\n    export function toSeconds(date: Date): number {\r\n        // The old function use toString to trim off microseconds to time comparsion for stablesort\r\n        // return new Date(x.toString()).getTime();  --- this is slow:\r\n\r\n        // http://jsperf.com/truncating-decimals\r\n        // x = new Date()\r\n        //Wed Feb 17 2016 12:15:39 GMT- 0800(Pacific Standard Time)\r\n        //y = new Date(x.toString()).getTime()\r\n        //1455740139000\r\n        //z = (x.getTime() / 1000) | 0\r\n        //1455740139\r\n        return (date.getTime() / 1000) | 0;\r\n    }\r\n\r\n    //#endregion Date\r\n\r\n    //#region Math\r\n\r\n    const hexCharsLowerCase = string_split(\"0123456789abcdef\", \"\");\r\n\r\n    const hexBytesLower: string[] = [];\r\n    array_forEach(hexCharsLowerCase, (upper) => {\r\n        array_forEach(hexCharsLowerCase, (lower) => {\r\n            array_push(hexBytesLower, upper + lower);\r\n        });\r\n    });\r\n\r\n    const sizeOfGuidInBytes = 20;\r\n    const tempUintArray = new Uint8Array(sizeOfGuidInBytes);\r\n    const tempStringArray: string[] = new Array(sizeOfGuidInBytes);\r\n\r\n    function applyAndOr(index: number, and: number, or: number) {\r\n        const temp = tempUintArray[index] & and;\r\n        tempUintArray[index] = temp | or;\r\n    }\r\n\r\n    ////// TODO: const globalCrypto = <Crypto>(window.crypto || (<any>window).msCrypto);\r\n    const globalCrypto = <RandomSource>(window.crypto || (<any>window).msCrypto);\r\n\r\n    // c.f. rfc4122 (UUID version 4 = xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)\r\n    //  xx  xx  xx  xx  -   xx  xx  -  4x  xx  -   yx  xx  -   xx  xx  xx  xx  xx  xx\r\n    //  00  11  22  33  4   55  66  7  88  99  10  11  12  13  14  15  16  17  18  19\r\n    function newGuidCrypto(): string {\r\n        globalCrypto.getRandomValues(tempUintArray);\r\n\r\n        applyAndOr(8, 0x0F, 0x40); // set upper half of the 8th byte to 0x4\r\n        applyAndOr(11, 0x3F, 0x80); // set the two most significant bits of the 11th byte to 10b\r\n\r\n        for (let i = 0; i < sizeOfGuidInBytes; i++) {\r\n            tempStringArray[i] = hexBytesLower[tempUintArray[i]];\r\n        }\r\n\r\n        tempStringArray[4] = tempStringArray[7] = tempStringArray[10] = tempStringArray[13] = \"-\";\r\n\r\n        return applyUncurry(string_concat, \"\", tempStringArray);\r\n    }\r\n\r\n    /**\r\n     * HelperReturns hex number string.\r\n     *\r\n     * @param len The number of the output string length\r\n     * @return a hexnumber string of length len\r\n     */\r\n    function getRandomHexString(len: number): string[] {\r\n        let tmp: number;\r\n        let ret: string[] = new Array(len);\r\n\r\n        // This implementation optimization of speed mimimize the cost of Math.random.\r\n        // equal chance for all number\r\n        while (len) {\r\n            tmp = 4294967296 * MathGlobal.random() | 0;  // get the max integer our of 32 digit.\r\n            let times = 8; // for every random number we can harvest 8 times.\r\n            while (times--) {\r\n                ret[--len] = hexCharsLowerCase[tmp & 0xF]; // fill from the back.\r\n                if (len < 0) {\r\n                    return ret; // we filled all the bucket, return now.\r\n                }\r\n                tmp >>>= 4; // zero fill right shift to ensure return is always positive number.\r\n            }\r\n        }\r\n    }\r\n\r\n    function newGuidFallback(): string {\r\n        // c.f. rfc4122 (UUID version 4 = xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)\r\n        const guid = getRandomHexString(36);\r\n        guid[8] = guid[13] = guid[18] = guid[23] = \"-\"; // fill in the dash.\r\n        guid[14] = \"4\"; // set the 4 in the guid.\r\n        // \"Set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively\"\r\n        // guid[19] = hexValues[8 + (Math.random() * 4) | 0]; /*clockSequenceHi*/\r\n        guid[19] = hexCharsLowerCase[8 + (hexCharsLowerCase.indexOf(guid[19]) & 0x3)]; // Since guid[19] is already random. reused the numbe by get its index rather than another Math.random call.\r\n\r\n        return _applyCall(string_concat, \"\", guid);\r\n    }\r\n\r\n    /**\r\n     * Returns a GUID such as xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx.\r\n     *\r\n     * @return New GUID.\r\n     */\r\n    export const newGuid: () => string = globalCrypto ? newGuidCrypto : newGuidFallback;\r\n\r\n    const maxCounter = 0xFFF;\r\n\r\n    function toHexString(counter: number) {\r\n        return hexBytesLower[counter >> 4] + hexCharsLowerCase[counter & 0xF];\r\n    }\r\n\r\n    export function toHex(str: string) {\r\n        let result = '';\r\n        for (let i = 0; i < str.length; i++) {\r\n            result += str.charCodeAt(i).toString(16);\r\n        }\r\n        return result;\r\n    }\r\n\r\n    /**\r\n     * Returns a function that can generate globally unique identifiers.\r\n     * Generates a new guid every 4096 calls and concatenates it with an\r\n     * auto incrementing number.  This maintains a complient GUID 4 format\r\n     * if no prefix is added.\r\n     *\r\n     * @return a globally unique string generating function.\r\n     */\r\n    export function getUniqueIdGenerator(prefix?: string) {\r\n        prefix = prefix ? (prefix + \"-\") : \"\";\r\n        // use a range for counter that gives us 3 digits with minimum effort\r\n        let guid = \"\";\r\n        let counter = maxCounter;\r\n\r\n        return () => {\r\n            if (++counter > maxCounter) {\r\n                counter = 0;\r\n            }\r\n\r\n            if (!counter) {\r\n                guid = prefix + newGuid().substring(0, 33);\r\n            }\r\n\r\n            return guid + toHexString(counter);\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Returns a function that can generate unique id under the prefix\r\n     * Concatenates prefix with an auto incrementing number.\r\n     *\r\n     * @return a unique string generating function which return a prefix with auto incrementing number\r\n     */\r\n    export function getIdGenerator(prefix: string) {\r\n        // use two counters and\r\n        // limit the size of the lower counter because\r\n        // toString is expensive for large numbers\r\n        let counterUpper = -1;\r\n        let counterLower = maxCounter;\r\n        let realPrefix = \"\";\r\n\r\n        return () => {\r\n            if (++counterLower > maxCounter) {\r\n                counterLower = 0;\r\n                counterUpper++;\r\n                realPrefix = prefix + counterUpper.toString(16) + \"-\";\r\n            }\r\n\r\n            return realPrefix + toHexString(counterLower);\r\n        };\r\n    }\r\n\r\n    /**\r\n     * Returns a globally unique identifier string.\r\n     * Lighter-weight than newGuid.\r\n     *\r\n     * @return a globally unique string.\r\n     */\r\n    export const getUniqueId = getUniqueIdGenerator();\r\n\r\n    /**\r\n     * Rounds a number to the specified precision.\r\n     *\r\n     * @param number The number to round.\r\n     * @param precision The precision to round the number to. Defaults to 0.\r\n     * @returns The rounded number.\r\n     */\r\n    export function round(number: number, precision?: number): number {\r\n        precision = MathGlobal.pow(10, precision || 0);\r\n        return MathGlobal.round(Number(number) * precision) / precision;\r\n    }\r\n\r\n    /**\r\n     * Truncates a number to the integer part.\r\n     *\r\n     * @param value The number to truncate.\r\n     * @return The integer number.\r\n     */\r\n    export function truncate(value: number): number {\r\n        // Converts to integer by bit operation\r\n        return value | 0;\r\n    }\r\n\r\n    /**\r\n     * Returns the result of the boolean exclusive-or operator.\r\n     *\r\n     * @param a First operand.\r\n     * @param b Second operand.\r\n     * @return true if the arguments have different values, false otherwise.\r\n     */\r\n    export function xor(a: boolean, b: boolean): boolean {\r\n        return a ? !b : b;\r\n    }\r\n\r\n    /**\r\n     * Returns the result of the bitwise and operator. Required because tslint disables\r\n     * bitwise operators by default.\r\n     *\r\n     * @param a First operand.\r\n     * @param b Second operand.\r\n     * @return numerical result of applying bitwise AND to a & b\r\n     */\r\n    export function applyBitwiseAnd(a: number, b: number): number {\r\n        return a & b;\r\n    }\r\n\r\n    /**\r\n     * Returns the result of the bitwise or operator. Required because tslint disables\r\n     * bitwise operators by default.\r\n     *\r\n     * @param a First operand.\r\n     * @param b Second operand.\r\n     * @return numerical result of applying bitwise OR to a & b\r\n     */\r\n    export function applyBitwiseOr(a: number, b: number): number {\r\n        return a | b;\r\n    }\r\n\r\n    //#endregion Map\r\n\r\n    //#region Number\r\n\r\n    /**\r\n     * Generates a random integer between min and max inclusive.\r\n     *\r\n     * @param min The minimum integer result.\r\n     * @param max The maximum integer result.\r\n     * @return A random integer.\r\n     */\r\n    export function random(min: number, max: number): number {\r\n        if (min === _undefined || max === _undefined || min > max) {\r\n            return;\r\n        }\r\n\r\n        return MathGlobal.floor(MathGlobal.random() * (max - min + 1)) + min;\r\n    }\r\n\r\n    //#endregion Number\r\n\r\n    //#region Object\r\n    /**\r\n     * Determines whether an object has a property with the specified name.\r\n     * @param target the object to check.\r\n     * @param v A property name.\r\n     */\r\n    export const hasOwnProperty = object_hasOwnProperty;\r\n\r\n    /**\r\n     * Determines whether an object has an enumerable property with the specified name.\r\n     * @param target the object to check.\r\n     * @param v A property name.\r\n     */\r\n    export const propertyIsEnumerable = object_propertyIsEnumerable;\r\n\r\n    /**\r\n     * Returns a boolean reflecting whether two scalar values (not object-typed, not array-typed, not function-typed)\r\n     * are equal.  Accounts for the fact that JavaScript Date derives from Object.\r\n     * The caller is responsible for supplying exclusively number-, string- or Date-typed values here.\r\n     *\r\n     * @param left The first scalar value.\r\n     * @param right The second scalar value.\r\n     * @return A boolean reflecting whether the two scalar values are equal.\r\n     */\r\n    export function areEqual<T>(left: T, right: T): boolean {\r\n        return left === right || areEqualDates(left, right);\r\n    }\r\n\r\n    /**\r\n     * Verifies that two arrays are equal.\r\n     *\r\n     * @param array1 The array to check.\r\n     * @param array2 The array to compare the first array to.\r\n     * @returns A value indicating whether or not the two arrays are equal.\r\n     */\r\n    export function arrayEquals<T>(array1: T[], array2: T[]): boolean {\r\n        if (array1 === array2) {\r\n            return true;\r\n        } else if (!array1 || !array2) {\r\n            return false;\r\n        } else if (array1.length !== array2.length) {\r\n            return false;\r\n        } else {\r\n            for (let i = 0; i < array1.length; i++) {\r\n                if (array1[i] !== array2[i]) {\r\n                    return false;\r\n                }\r\n            }\r\n\r\n            return true;\r\n        }\r\n    }\r\n\r\n    export function getTypeOf(x: any): string {\r\n        let typeOfX: string = typeof x;\r\n\r\n        if (typeOfX === objectType) {\r\n            if (x === null) {\r\n                typeOfX = \"null\";\r\n            } else if (array_isArray(x)) {\r\n                typeOfX = \"array\";\r\n            } else if (isDate(x)) {\r\n                typeOfX = \"date\";\r\n            }\r\n        }\r\n\r\n        return typeOfX;\r\n    }\r\n\r\n    /**\r\n    * Checks for deep equality of two object.\r\n    *\r\n    * @param a Object 1\r\n    * @param b Object 2\r\n    * @param mapFunc Optional parameter, used convert value conversion use on the value to compare\r\n    * @return true if both of the object contains the same information; false otherwise;\r\n    */\r\n    // eslint-disable-next-line unused-imports/no-unused-vars\r\n    function deepEqualsMap(a: any, b: any, mapFunc?: (v: any) => any): boolean {\r\n        if (mapFunc) {\r\n            a = mapFunc(a);\r\n            b = mapFunc(b);\r\n        }\r\n\r\n        if (a === b) {\r\n            return true;\r\n        } else if (!a || !b) {\r\n            return false;\r\n        }\r\n\r\n        let typeofInput = getTypeOf(a);\r\n        if (typeofInput !== getTypeOf(b)) {\r\n            return false;\r\n        }\r\n\r\n        switch (typeofInput) {\r\n            case \"array\":\r\n                const aArray: any[] = <any>a;\r\n                return a.length === b.length &&\r\n                    aArray.every((v, index) => deepEqualsMap(v, b[index], mapFunc));\r\n            case \"date\":\r\n                return a.getTime() === b.getTime();\r\n            case objectType:\r\n                const keysOfInput = object_keys(a);\r\n                return keysOfInput.length === keysLength(b) &&\r\n                    keysOfInput.every((key) => deepEqualsMap(a[key], b[key], mapFunc));\r\n            default:\r\n                // basic type that failed the === check\r\n                return false;\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Checks if a given value is a javascript object or not.\r\n     *\r\n     * @param value Value to test.\r\n     * @return True if value is an object, false otherwise.\r\n     */\r\n    export function isObject(value: any): boolean {\r\n        return typeof value === objectType;\r\n    }\r\n\r\n    /**\r\n     * Checks if a given value is a plain object or not.\r\n     *\r\n     * @param value Value to test.\r\n     * @return True if value is an object, false otherwise.\r\n     */\r\n    export function isPlainObject(value: any): boolean {\r\n        return getTypeOf(value) === objectType;\r\n    }\r\n\r\n    /**\r\n     * Maps each value of the input object. Values that map to null or undefined are skipped.\r\n     *\r\n     * @param obj Input object whose properties are to be mapped.\r\n     * @param callback Invoked for each property of the object to perform the mapping.\r\n     * @param arg An Optional value that can be passed to callback.\r\n     * @return An array of mapped values.\r\n     */\r\n    export function map<T, U>(obj: StringMap<T>, callback: (item: T, key?: string, arg?: any) => U, arg?: any): U[] {\r\n        let callBackArgs: any = [obj, /*item*/, /*key*/, arg];\r\n        let keys = object_keys(obj);\r\n        let ret = keys.map((key) => {\r\n            callBackArgs[1] = obj[key]; // item;\r\n            callBackArgs[2] = key; // key;\r\n            return call.apply(callback, callBackArgs);\r\n        });\r\n        // Flatten any nested arrays and exclude null, undefined items.\r\n        return merge.apply(null, ret);\r\n    }\r\n\r\n    /**\r\n     * Shallow copy from a key/value pairs object.\r\n     *\r\n     * @param to An un-typed object to be populated.\r\n     * @param from An un-typed object with values to populate.\r\n     * @param scopes Scoped down the list for shallowCopy\r\n     */\r\n    export function shallowCopyFromObject(to: Object, from: Object, scopes?: string[]): void {\r\n        // http://jsperf.com/shallowcopyobjects/3\r\n        scopes = scopes || object_keys(from);\r\n\r\n        for (let i = 0; i < scopes.length; i++) {\r\n            let key = scopes[i];\r\n            let value = (<any>from)[key];\r\n            if (value !== _undefined) {\r\n                (<any>to)[key] = value;\r\n            }\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Merges a property from a destination object from a source object\r\n     * @param dest The destination object\r\n     * @param src The source object\r\n     * @param propName The name of the property to assign\r\n     */\r\n    function deepAssignProperty(dest, src, propName) {\r\n        let value = src[propName];\r\n        // if there is no value, dont assign.\r\n        if (isNullOrUndefined(value)) {\r\n            return;\r\n        }\r\n\r\n        if (!isObject(value)) {\r\n            /**\r\n            * If the src prop is not an object then set the destination prop directly.\r\n            */\r\n            dest[propName] = value;\r\n        } else if (isObject(value) && isEmpty(value)) {\r\n            /**\r\n             * If the object has no children prop then set the destination prop directly.\r\n             *\r\n             * Handles a special case of a date object as it cannot be shallow copied in\r\n             * the same major as any other supported type.\r\n             * Shown here: https://github.com/davidmarkclements/rfdc/blob/master/index.js\r\n             */\r\n            if (value instanceof Date) {\r\n                dest[propName] = new Date(value);\r\n            } else {\r\n                // Generic object will be shallow copied as it has no properties.\r\n                dest[propName] = array_isArray(value) ? [...value] : { ...value };\r\n            }\r\n        } else if (isObject(value) && !hasOwnProperty(dest, propName) || (typeof (dest[propName]) !== typeof (value))) {\r\n            /** If the src prop is an object and the prop is not defined, create new object\r\n            * and copy over src.\r\n            *\r\n            * Or if the dest and src prop do not match types,\r\n            * pave over dest with src.\r\n            */\r\n\r\n            dest[propName] = deepAssignInternal(array_isArray(value) ? [] : {}, value);\r\n        } else {\r\n            // Otherwise merge to src prop with the dest prop.\r\n            dest[propName] = deepAssignInternal(dest[propName], value);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Internal method for merging one object with another\r\n     * @param dest The destination object\r\n     * @param src The source object\r\n     */\r\n    function deepAssignInternal(dest: any, src: any): any {\r\n        // if the to destination is the same object as the source, save some time by just returning\r\n        if (dest === src) {\r\n            return dest;\r\n        }\r\n\r\n        // loop through the src objects properties and merge them deeply to the dest\r\n        for (let propName in src) {\r\n            if (hasOwnProperty(src, propName)) {\r\n                deepAssignProperty(dest, src, propName);\r\n            }\r\n        }\r\n\r\n        // loop through the src symbols properties and merge them deeply to the dest\r\n        if (Object.getOwnPropertySymbols) {\r\n            let symbols = Object.getOwnPropertySymbols(src);\r\n            symbols.forEach(symbol => {\r\n                if (propertyIsEnumerable(src, symbol)) {\r\n                    deepAssignProperty(dest, src, symbol);\r\n                }\r\n            });\r\n        }\r\n\r\n        // return the destination object\r\n        return dest;\r\n    }\r\n\r\n    /**\r\n     * Merges a set of source objects to a destination object. Does not\r\n     * handle objects with circular references.\r\n     *\r\n     * Supported types:\r\n     * - Object\r\n     * - Array\r\n     * - Number\r\n     * - String\r\n     * - null\r\n     * - Date\r\n     *\r\n     * @param dest The destination object\r\n     * @param sources  the source objects\r\n     */\r\n    export function deepAssign(dest: any, ...sources: any[]): any {\r\n\r\n        // merge all sources into the dest object in order\r\n        sources.forEach(src => {\r\n            return deepAssignInternal(dest, src || {});\r\n        });\r\n        // return the dest object\r\n        return dest;\r\n    }\r\n\r\n    /**\r\n * Copies a source object with any nested objects. Does not\r\n * handle objects with circular references.\r\n * @param dest The source object\r\n *\r\n * Supported types:\r\n * - Object\r\n * - Array\r\n * - Number\r\n * - String\r\n * - null\r\n * - Date\r\n *\r\n * @return a new object that is a copy of the source object\r\n */\r\n    export function deepCopy(source: any): any {\r\n        return deepAssign({}, source);\r\n    }\r\n\r\n    /**\r\n     * Searches an object for a value at a given path.\r\n     * @param object The object to search in\r\n     * @param path the path to walk\r\n     * @param firstPass internal use, indicates that this is the first pass.\r\n     * @returns the object at the end of the path\r\n     */\r\n    function getValueInternal<T>(object: any, path: string | number, firstPass: boolean): T {\r\n        // return null if either argument is not provided\r\n        if (isNullOrUndefined(object) || isNullOrUndefined(path)) {\r\n            return null;\r\n        }\r\n\r\n        // always convert path to string\r\n        let strPath = '' + path;\r\n\r\n        // on the first pass, replace delimiters in the object path with *\r\n        if (firstPass) {\r\n            strPath = strPath.replace(/\\]\\.|\\.|\\[|\\]/g, \"*\");\r\n        }\r\n\r\n        // find the next delimiter\r\n        let index = strPath.indexOf('*');\r\n\r\n        // if there are no more delimiters, return the object at the path\r\n        if (index === -1) {\r\n            return object[strPath];\r\n        }\r\n\r\n        // split the path at the delimiter. Use the first segment as our next object and the second segment for the remaining path\r\n        let next = strPath.slice(0, index);\r\n        let remainingPath = strPath.slice(index + 1);\r\n        if (object[next] !== undefined && remainingPath.length > 0) {\r\n            // dive in recursively to the next object\r\n            return getValueInternal<T>(object[next], remainingPath, false);\r\n        }\r\n\r\n        // we found our target object. Return it\r\n        return object[next];\r\n    }\r\n\r\n    /**\r\n     * Searchs an object for a value at a given path.\r\n     * @param object The object to search in\r\n     * @param path the path to walk\r\n     * @returns the object at the end of the path\r\n     */\r\n    export function getValue<T>(object: any, path: string): T {\r\n        // call our internal get value function\r\n        return getValueInternal<T>(object, path, true);\r\n    }\r\n\r\n    /**\r\n     * Sets a value in an object at a given path\r\n     * @param object The object to search in\r\n     * @param path the path to walk\r\n     * @param value the value to set at object.path\r\n     * @param firstPass internal use, indicates that this is the first pass.\r\n     * @returns the object at the end of the path\r\n     */\r\n    function setValueInternal<T>(object: any, path: string | number, value: any, firstPass: boolean): T {\r\n        if (isNullOrUndefined(object)) {\r\n            object = {};\r\n        }\r\n        if (isNullOrUndefined(path)) {\r\n            return null;\r\n        }\r\n\r\n        // always convert path to string\r\n        let strPath = '' + path;\r\n\r\n        // on the first pass, replace delimiters in the object path with *\r\n        if (firstPass) {\r\n            strPath = strPath.replace(/\\]\\.|\\.|\\[|\\]/g, \"*\");\r\n        }\r\n\r\n        // find the next delimiter\r\n        let index = strPath.indexOf('*');\r\n\r\n        // if there are no more delimiters, return the object at the path\r\n        if (index === -1) {\r\n            object[strPath] = value;\r\n            return object;\r\n        }\r\n\r\n        // split the path at the delimiter. Use the first segment as our next object and the second segment for the remaining path\r\n        let next = strPath.slice(0, index);\r\n        let remainingPath = strPath.slice(index + 1);\r\n        if (remainingPath.length > 0) {\r\n            // dive in recursively to the next object\r\n            return setValueInternal<T>(object[next], remainingPath, value, false);\r\n        }\r\n\r\n        object[next] = value;\r\n        return object;\r\n    }\r\n\r\n    /**\r\n     * Sets a value in an object at a given path\r\n     * @param object The object to search in\r\n     * @param path the path to walk\r\n     * @param value the value to set at object.path\r\n     * @returns the object at the end of the path\r\n     */\r\n    export function setValue<T>(object: any, path: string, value: any): T {\r\n        // call our internal get value function\r\n        return setValueInternal<T>(object, path, value, true);\r\n    }\r\n\r\n    //#endregion Object\r\n\r\n    /**\r\n     * Preserves any existing document selection while performing an action that temporarily changes selection\r\n     * @param action The action to take\r\n     */\r\n    export function preserveDocumentSelection(action: Action): void {\r\n        let selectedRange: Range = null;\r\n        if (document.getSelection().rangeCount > 0) {\r\n            selectedRange = document.getSelection().getRangeAt(0);\r\n        }\r\n\r\n        action();\r\n\r\n        if (selectedRange) {\r\n            document.getSelection().removeAllRanges();\r\n            document.getSelection().addRange(selectedRange);\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Safely puts a value to the clipboard. This should always be called from a user driven context (such as click, keydown, etc...)\r\n     * @param value The value to put on the clipboard\r\n     */\r\n    export function copyToClipboard(value: any): void {\r\n        let stringValue = toString(value);\r\n        const el = document.createElement('textarea');\r\n        el.value = stringValue;\r\n        el.setAttribute('readonly', '');\r\n        el.classList.add('sme-screen-reader');\r\n        preserveDocumentSelection(() => {\r\n            document.body.appendChild(el);\r\n            el.select();\r\n            document.execCommand('copy');\r\n            document.body.removeChild(el);\r\n        });\r\n    };\r\n\r\n    //#region String\r\n\r\n    /**\r\n     * Determines if the current string ends with the given string.\r\n     * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith\r\n     * http://jsperf.com/string-prototype-endswith/18\r\n     *\r\n     * @param input The input string.\r\n     * @param searchString The characters to be searched for at the end of this string.\r\n     * @param position Optional. Search within this string as if this string were only this long; defaults to this string's actual length, clamped within the range established by this string's length.\r\n     * @return A value indicating whether or not the input string ends with the search string.\r\n     */\r\n    export function endsWith(input: string, searchString: string, position?: number): boolean {\r\n        if (!isTypeOf(searchString, stringType)) {\r\n            return false;\r\n        }\r\n\r\n        input = isNullOrUndefined(input) ? \"\" : String(input);\r\n        const strLen = input.length;\r\n        if (position === _undefined || position > strLen) {\r\n            position = strLen;\r\n        }\r\n        position -= searchString.length;\r\n        const lastIndex = string_indexOf(input, searchString, position);\r\n        return lastIndex !== -1 && lastIndex === position;\r\n    }\r\n\r\n    /**\r\n     * Compares the current string to another string and returns a value indicating their relative ordering.\r\n     *\r\n     * @param input The input string to compare.\r\n     * @param other The value to compare the input string to.\r\n     * @param locales The optional array of locale values that will be passed to localeCompare.\r\n     * @param options The options supported by localeCompare.\r\n     * @return 0, if the strings are equal; a negative number if the current string is ordered before value; a positive non-zero number if the current string is orered after value.\r\n     */\r\n    export function localeCompareIgnoreCase(input: string, other: string, locales?: string | string[], options?: CollatorOptions): number {\r\n        if (isNullOrUndefined(input)) {\r\n            return -1;\r\n        }\r\n\r\n        if (!isTypeOf(other, stringType)) {\r\n            return 1;\r\n        }\r\n\r\n        // take regional local Id to process.\r\n        locales = locales || MsftSme.self().Resources && MsftSme.self().Resources.localeRegionalId;\r\n        return input.toLocaleLowerCase().localeCompare(other.toLocaleLowerCase(), locales, options);\r\n    }\r\n\r\n    /**\r\n     * Repeats the string the specified number of times.\r\n     * @param input The input string.\r\n     * @param count The number of times to repeat the string.\r\n     * @returns The result string.\r\n     *  http://jsperf.com/repeatstring2\r\n     */\r\n    export function repeat(input: string, count: number): string {\r\n        let ret = \"\";\r\n        count = (count < 0) ? 0 : count;\r\n        while (count--) {\r\n            ret += input;\r\n        }\r\n        return ret;\r\n    }\r\n\r\n    /**\r\n     * reverse the string.\r\n     * @param input The input string.\r\n     * @returns The result string.\r\n     */\r\n    export function reverse(input: string) {\r\n        let ret = \"\";\r\n        let length = input.length;\r\n        while (length) {\r\n            ret += input[--length];\r\n        }\r\n        return ret;\r\n    }\r\n\r\n    /**\r\n     * Return a function that will perform join with that separator\r\n     *\r\n     * @returns a function that will join the parts together with the character, for example.\r\n     *   joinPaths = getJoinFunc(\"/\");\r\n     *   joinByDash = getJoinFunc(\"-\");\r\n     *\r\n     *  joinPaths(\"a\", \"b\", \"c\") will return  \"a/b/c\";\r\n     *  joinByDash(\"a\", \"b\", \"c\") will return  \"a-b-c\";\r\n     */\r\n    export function getJoinFunc(sep: string): (...parts: string[]) => string {\r\n        return function (): string {\r\n            return array_join(arguments, sep);\r\n        };\r\n    };\r\n\r\n    /**\r\n     * Return a function that will perform quote the input.  (Mimizer helper).\r\n     *\r\n     * @returns a function that will join the parts together with the character(s).\r\n        For example.\r\n            quote = getQuoteFunc(\"'\");\r\n            parenthesis = getQuoteFunc(\"(\", \")\");\r\n            poMarker = getQuoteFunc(\"####\");\r\n     *\r\n     * quote(\"abc\") will return \"'abc'\";\r\n     * parenthesis(\"abc\") will reutrn \"(abc)\";\r\n     * poMarker(\"abc\") will return \"####abc####\";\r\n     */\r\n    export function getQuoteFunc(prefix: string, suffix?: string): (input: string) => string {\r\n        prefix = prefix || \"\";\r\n        suffix = suffix || prefix;\r\n\r\n        return function (input: string): string {\r\n            return prefix + input + suffix;\r\n        };\r\n    };\r\n\r\n    /**\r\n     * Replaces all instances of a value in a string.\r\n     *\r\n     * @param input The input string.\r\n     * @param searchValue The value to replace.\r\n     * @param replaceValue The value to replace with.\r\n     * @return A new string with all instances of searchValue replaced with replaceValue.\r\n     */\r\n    export function replaceAll(input: string, searchValue: string, replaceValue: string): string {\r\n        return input.replace(new RegExp(regexEscape(searchValue), \"g\"), replaceValue);\r\n    }\r\n\r\n    /**\r\n     * Replaces multiple instances of search values and replacement values in a string.\r\n     *\r\n     * @param input The input string.\r\n     * @param replacementMap A string map where each key represents the string to replace, and that key's value represents the value to replace it with.\r\n     * @return A new string with replacementMap values replaced.\r\n     */\r\n    export function replaceMany(input: string, replacementMap: StringMap<string>): string {\r\n        let escapedMap: StringMap<string> = {},\r\n            hasValuesToReplace = false;\r\n\r\n        for (let searchValue in (replacementMap || {})) {\r\n            if (replacementMap.hasOwnProperty(searchValue)) {\r\n                escapedMap[regexEscape(searchValue)] = replacementMap[searchValue];\r\n                hasValuesToReplace = true;\r\n            }\r\n        }\r\n\r\n        if (!hasValuesToReplace) {\r\n            return input;\r\n        }\r\n\r\n        let regex = new RegExp(object_keys(escapedMap).join(\"|\"), \"g\");\r\n        return input.replace(regex, (match: string) => replacementMap[match]);\r\n    }\r\n\r\n    /**\r\n     * Splits a string into the specified number of parts.\r\n     * Differs from string.split in that it leaves the last part containing the remaining string (with separators in it).\r\n     * string.split truncates the extra parts.\r\n     * @param input The string to be split.\r\n     * @param separator A string that identifies the character or characters to be used as the separator.\r\n     * @param limit A value used to limit the number of elements returned in the array.\r\n     * @return An array of strings whose length is at most the value of limit.\r\n     */\r\n    export function split(input: string, separator: string, limit: number): string[] {\r\n        let retVal: string[] = [];\r\n\r\n        if (input && separator && limit) {\r\n            let startIndex = 0;\r\n            let seplength = separator.length;\r\n            let indexOf = 0;\r\n\r\n            // reduce the limit by one.\r\n            // we'll only break the string into limit - 1 parts\r\n            // and put the remaining in the last spot.\r\n            limit--;\r\n            while (true) {\r\n                // only one spot left in the array. push remaining string into array and exit.\r\n                // no more separators left. push remaining string into array and exit.\r\n                if (retVal.length >= limit || (indexOf = string_indexOf(input, separator, startIndex)) < 0) {\r\n                    array_push(retVal, string_substring(input, startIndex));\r\n                    break;\r\n                }\r\n\r\n                array_push(retVal, string_substring(input, startIndex, indexOf));\r\n                startIndex = indexOf + seplength;\r\n            }\r\n        }\r\n\r\n        return retVal;\r\n    }\r\n\r\n    /**\r\n     * Determines if the current string starts with the given string.\r\n     * http://jsperf.com/string-startswith/49\r\n     *\r\n     * @param input The input string.\r\n     * @param searchString The characters to be searched for at the start of this string.\r\n     * @param position Optional. The position in this string at which to begin searching for searchString; defaults to 0.\r\n     * @return A value indicating whether or not the input string begins with the search string.\r\n     */\r\n    export function startsWith(input: string, searchString: string, position?: number): boolean {\r\n        input = isNullOrUndefined(input) ? \"\" : String(input);\r\n        position = (isNullOrUndefined(position) || position < 0) ? 0 : MathGlobal.min(position, input.length);\r\n        return input.lastIndexOf(searchString, position) === position;\r\n    }\r\n\r\n    /**\r\n     * Trims all occurrences of the given set of strings off the end of the input.\r\n     */\r\n    export function trimEnd(input: string, ...values: string[]) {\r\n        input = input || \"\";\r\n        while (input) {\r\n            let match = values.first((value) => {\r\n                return value && endsWith(input, value);\r\n            });\r\n\r\n            if (!match) {\r\n                break;\r\n            }\r\n\r\n            input = string_substring(input, 0, input.length - match.length);\r\n        }\r\n\r\n        return input;\r\n    }\r\n\r\n    /**\r\n     * Trims all occurrences of the given set of strings off the start of the input.\r\n     */\r\n    export function trimStart(input: string, ...values: string[]) {\r\n        input = input || \"\";\r\n        while (input) {\r\n            let match = values.first((value) => {\r\n                return value && startsWith(input, value);\r\n            });\r\n\r\n            if (!match) {\r\n                break;\r\n            }\r\n\r\n            input = string_substring(input, match.length);\r\n        }\r\n\r\n        return input;\r\n    }\r\n\r\n    /**\r\n     * Ensures that the given string ends with the suffix provided.\r\n     * If it already does, it just returns the input string.\r\n     * If it does not, then the suffix is appended and the result is returned.\r\n     */\r\n    export function ensureSuffix(input: string, suffix: string) {\r\n        input = input || \"\";\r\n        if (!endsWith(input, suffix)) {\r\n            input += suffix;\r\n        }\r\n\r\n        return input;\r\n    }\r\n\r\n    /**\r\n     * Ensures that the given string starts with the prefix provided.\r\n     * If it already does, it just returns the input string.\r\n     * If it does not, then the prefix is applied and the result is returned.\r\n     */\r\n    export function ensurePrefix(input: string, prefix: string) {\r\n        input = input || \"\";\r\n        if (!startsWith(input, prefix)) {\r\n            input = prefix + input;\r\n        }\r\n\r\n        return input;\r\n    }\r\n\r\n    /**\r\n     * Joins strings in the components array with the specified separator between them.\r\n     * Ignores empty/falsy entries in the components array.\r\n     * If a leading (or trailing) separator is desired, prefix (or suffix)\r\n     * the array of components with an entry that is a separator.\r\n     */\r\n    export function pathJoin(pathSeparator: string, ...pathComponents: string[]): string;\r\n    export function pathJoin(pathSeparator: string, pathComponents: string[]): string;\r\n    export function pathJoin(pathSeparator: string, pathComponents: any): string {\r\n        if (!array_isArray(pathComponents)) {\r\n            pathComponents = array_slice(arguments, 1);\r\n        }\r\n\r\n        let output = \"\";\r\n        array_forEach(<string[]>(pathComponents || []), (current) => {\r\n            if (!output) { // first entry\r\n                output = current || \"\";\r\n            } else if (current) { // skip empty entries\r\n                output = trimEnd(output, pathSeparator) + ensurePrefix(current, pathSeparator);\r\n            }\r\n        });\r\n\r\n        return output;\r\n    }\r\n\r\n    //#endregion String\r\n\r\n    //#region Browser\r\n\r\n    export function isInternetExplorer() {\r\n        // IE Agent Example:\r\n        // \"Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; rv:11.0) like Gecko\"\r\n        const agent = window.navigator.userAgent;\r\n        return agent.indexOf('Trident') > 0;\r\n    }\r\n\r\n    export function isEdge() {\r\n        // Microsoft Edge Agent Example:\r\n        // \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299\"\r\n        const agent = window.navigator.userAgent;\r\n\r\n        // We should be able to reliably detect Microsoft Edge using the useragent, because there isn't any browser out there trying to pretend to be Microsoft Edge.\r\n        return /\\bEdge\\b/.test(agent);\r\n    }\r\n\r\n    /**\r\n     * Returns the windows origin in an manner that is safe for all our supported browsers.\r\n     * IE, for example, returns inconsistent results for window.location.origin\r\n     */\r\n    export function getSafeOrigin(): string {\r\n        let port = window.location.port ? `:${window.location.port}` : '';\r\n        let origin = `${window.location.protocol}//${window.location.hostname}${port}`;\r\n        return origin;\r\n    }\r\n\r\n    //#endregion Browser\r\n\r\n    //#region Uri\r\n\r\n    /**\r\n     * Gets a parameter from the locations query string\r\n     * @param parameterName\r\n     */\r\n    export function getLocationSearchParameter(parameterName: string) {\r\n        let query = decodeURIComponent(window.location.search.substring(1));\r\n        return query\r\n            .split('&')\r\n            .map(p => {\r\n                let kvp = p.split('=');\r\n                return { key: kvp[0], value: kvp[1] };\r\n            })\r\n            .find(p => p.key && p.key.toLowerCase() === parameterName.toLowerCase());\r\n    }\r\n\r\n    /**\r\n     * Parse an uri and return the Authority of the uri.\r\n     *\r\n     * @param uri The string of uri.\r\n     * @return Authority of the uri.\r\n     */\r\n    export function getUriAuthority(uri: string, includePort: boolean = true): string {\r\n        // If uri starts with \"//\" or \"https://\" or \"http://\", authority will start after that.\r\n        // Otherwise authority starts from very beginning.\r\n        // Authority will end before one of those characters \"?/#\" or end of string.\r\n        if (!uri) {\r\n            return uri;\r\n        }\r\n\r\n        let index = 0;\r\n        if (startsWith(uri, \"//\")) {\r\n            uri = string_substring(uri, index + 2);\r\n        } else {\r\n            index = string_indexOf(uri, \"://\");\r\n            if (index > -1) {\r\n                uri = string_substring(uri, index + 3);\r\n            }\r\n        }\r\n\r\n        let endChars = includePort ? /[?#/]/ : /[?#/:]/;\r\n        let endIndex = uri.search(endChars);\r\n        endIndex = endIndex > -1 ? endIndex : uri.length;\r\n\r\n        return string_substring(uri, 0, endIndex);\r\n    }\r\n\r\n    /**\r\n     * Verify if one Url is subdomain of another Url.\r\n     *\r\n     * @param domain The string of domain.\r\n     * @param subdomain The string of subdomain\r\n     * @return True if subdomain is subdomain of domain.\r\n     */\r\n    export function isSubdomain(domain: string, subdomain: string): boolean {\r\n        if (!domain || !subdomain || domain.length < subdomain.length) {\r\n            return false;\r\n        }\r\n\r\n        let lowerCaseDomain = string_toLowerCase(domain);\r\n        let lowerCaseSubdomain = string_toLowerCase(subdomain);\r\n\r\n        return (lowerCaseDomain === lowerCaseSubdomain) || endsWith(lowerCaseDomain, \".\" + lowerCaseSubdomain);\r\n    }\r\n\r\n    /**\r\n     * Returns whether the given URI is an absolute URI.\r\n     *\r\n     * @param uri The URI.\r\n     * @return A boolean value indicating whether the URI is absolute.\r\n     */\r\n    export function isUriAbsolute(uri: string): boolean {\r\n        return string_indexOf(uri, \"://\") !== -1 || startsWith(uri, \"//\");\r\n    }\r\n\r\n    //#endregion Uri\r\n\r\n    /**\r\n     * Escapes regular expression special characters -[]/{}()*+?.\\^$|\r\n     *\r\n     * @param str The string to escape.\r\n     * @return The escaped string.\r\n     */\r\n    export function regexEscape(str: string): string {\r\n        return str.replace(/[\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|]/g, \"\\\\$&\");\r\n    }\r\n\r\n    /**\r\n     * No-op function.\r\n     */\r\n    export const noop = function (): void {\r\n    };\r\n\r\n    const primitiveTypes: StringMap<boolean> = {};\r\n\r\n    array_forEach([\"boolean\", undefinedType, numberType, stringType, \"symbol\"], (item) => {\r\n        primitiveTypes[item] = true;\r\n    });\r\n\r\n    /**\r\n     * Returns whether the given data is primitive data type.\r\n     * ECMAScript 6 standard defines 6 primitive data types: Boolean, Null, Undefined, Number, String, Symbol(new in ECMAScript 6)\r\n     *\r\n     * @param data The input data.\r\n     * @return A boolean value indicating whether the data is primitive data type.\r\n     */\r\n    export function isPrimitive(data: any): boolean {\r\n        return data === null || typeof data in primitiveTypes;\r\n    }\r\n\r\n    /**\r\n     * Applies polyfills as properties to the prototype of the given object.\r\n     * If force is specified the polyfills will overwrite any existing properties.\r\n     */\r\n    export function polyfill(type: { prototype: Object }, fills: Object, force?: boolean) {\r\n        const proto = <any>type.prototype;\r\n        forEachKey(<StringMap<Function>>fills, (funcName, func) => {\r\n            if (force || !proto[funcName]) {\r\n                ObjectGlobal.defineProperty(proto, funcName, {\r\n                    value: func,\r\n                    configurable: true,\r\n                    enumerable: false,\r\n                    writable: true\r\n                });\r\n            }\r\n        });\r\n    }\r\n\r\n    const mapSupportedMaxInteger = 50;\r\n    const intToStringMap: string[] = [];\r\n    const stringToIntMap: StringMap<number> = {};\r\n\r\n    for (let index = 0; index <= mapSupportedMaxInteger; index++) {\r\n        let strVal = index + \"\";\r\n        intToStringMap[index] = strVal;\r\n        stringToIntMap[strVal] = index;\r\n    }\r\n\r\n    function validateRequiredMaxInteger(requiredMaxInteger: number) {\r\n        if (requiredMaxInteger > mapSupportedMaxInteger) {\r\n            throw new Error(\"The requiredMaxInteger(\" + requiredMaxInteger + \") should be less than \" + mapSupportedMaxInteger);\r\n        }\r\n\r\n        if (requiredMaxInteger <= 0) {\r\n            throw new Error(\"The requiredMaxInteger(\" + requiredMaxInteger + \") should be greater than zero.\");\r\n        }\r\n    }\r\n\r\n    /**\r\n     * Get a readonly map that is a faster alternative to cast a string to small and non-negative integers.\r\n     * - Doesn't support negative integer since the performance is significantly decreased for negative integer.\r\n     * - The JSperf links: http://jsperf.com/int-to-string-map/4, http://jsperf.com/cast-int-to-string-in-loop.\r\n     *\r\n     * The StringToIntMap is mainly used to convert string to const enum. For example:\r\n     * const enum Fruit {\r\n     *   Unknown = 0,\r\n     *   Apple = 1,\r\n     *   Banana = 2,\r\n     *   Max = 3\r\n     * }\r\n     * var stringToIntMap = utilities.getStringToIntMap(Fruit.Max);\r\n     * strictEqual(stringToIntMap[\"1\"], Fruit.Apple);\r\n     * strictEqual(stringToIntMap[\"2\"], Fruit.Banana);\r\n     *\r\n     * @param requiredMaxInteger The required max integer.\r\n     * @returns The object have one to one mapping between the string and the corresponding integer. e.g. {\"0\":0,\"1\":1,\"2\":2,\"3\":3,\"4\":4, ... }.\r\n     */\r\n    export function getIntToStringMap(requiredMaxInteger: number): string[] {\r\n        validateRequiredMaxInteger(requiredMaxInteger);\r\n        return intToStringMap;\r\n    }\r\n\r\n    /**\r\n     * Get a readonly map that is a faster alternative to cast a small and non-negative integer to string.\r\n     * - Doesn't support negative integer since the performance is significantly decreased for negative integer.\r\n     * - The JSperf links: http://jsperf.com/parseint-vs-map-lookup/2, http://jsperf.com/parseint-vs-map-lookup-2\r\n     *\r\n     * The intToStringMap is mainly used to convert const enum to string. For example:\r\n     * const enum Fruit {\r\n     *     Unknown = 0,\r\n     *     Apple = 1,\r\n     *     Banana = 2,\r\n     *     Max = 3\r\n     * }\r\n     *\r\n     * var stringToIntMap = utilities.getStringToIntMap(Fruit.Max);\r\n     * strictEqual(intToStringMap[Fruit.Unknown], \"0\");\r\n     * strictEqual(intToStringMap[Fruit.Apple], \"1\");\r\n     *\r\n     * @param requiredMaxInteger The required max integer.\r\n     * @returns The array to have increment integer in string representation. e.g. [\"0\",\"1\",\"2\",\"3\",\"4\", ...].\r\n     */\r\n    export function getStringToIntMap(requiredMaxInteger: number): StringMap<number> {\r\n        validateRequiredMaxInteger(requiredMaxInteger);\r\n        return stringToIntMap;\r\n    }\r\n\r\n    /**\r\n     * Makes a shallow clone of the source object with the same prototype and rebinds all functions\r\n     * on the clone to use the source object as 'this'.\r\n     *\r\n     * @param object The source object.\r\n     * @return The cloned object.\r\n     */\r\n    export function cloneAndRebindFunctions<T>(object: T): T {\r\n        const clone = ObjectGlobal.create(ObjectGlobal.getPrototypeOf(object));\r\n        for (const key in object) {\r\n            const value = (<any>object)[key];\r\n            if (isTypeOf(value, functionType)) {\r\n                clone[key] = value.bind(object); // This preserves ko_isObservable(value).\r\n            } else if (object_hasOwnProperty(object, key)) {\r\n                clone[key] = value;\r\n            }\r\n        }\r\n        return clone;\r\n    }\r\n\r\n    function toLowerCaseOnlyWithValue(value: string): string {\r\n        return value && value.toLowerCase();\r\n    }\r\n\r\n    /**\r\n     * Takes a value and lower cases recursively.\r\n     * For a string, returns the lower case string (non-value remains non-value).\r\n     * For an object, recursively converts all string properties to lower case strings, including arrays of values.\r\n     * For an array, returns an array with all string values converted to lower case.\r\n     *\r\n     * @param source The source value to make lower case.\r\n     * @returns The lower case value.\r\n     */\r\n    export function lowerCaseAllStrings(source: any): any {\r\n        if (source) {\r\n            const type = typeof source;\r\n            if (type === \"string\") {\r\n                return toLowerCaseOnlyWithValue(source);\r\n            } else if (Array.isArray(source)) {\r\n                return source.map((arrayValue: any) => lowerCaseAllStrings(arrayValue));\r\n            } else if (type === \"object\") {\r\n                const sourceAsStringMap = <any>source;\r\n                MsftSme.forEachKey(sourceAsStringMap, function (key) {\r\n                    sourceAsStringMap[key] = lowerCaseAllStrings(sourceAsStringMap[key]);\r\n                });\r\n                return sourceAsStringMap;\r\n            }\r\n        }\r\n        return source;\r\n    }\r\n\r\n    /**\r\n     * Enum of environment mode.\r\n     */\r\n    export const enum EnvironmentMode {\r\n        NotUse,\r\n        LoadEmbedded,\r\n        Load\r\n    }\r\n\r\n    /**\r\n     * Side load setting interface.\r\n     */\r\n    export interface SideLoad {\r\n        origin: string;\r\n    }\r\n\r\n    const sideLoadKey = 'MsftSme.SideLoad@';\r\n\r\n    /**\r\n     * Read all side-loading settings on current loaded domain.\r\n     */\r\n    function sideLoadRead(): { [name: string]: SideLoad } {\r\n        // Read side-load data from localStorage\r\n        let global = window;\r\n        let length = LocalStorageHandler.getLength(global);\r\n        let keys: string[] = [];\r\n        for (let index = 0; index < length; index++) {\r\n            let key = LocalStorageHandler.getKey(index, global);\r\n            if (key.startsWith(sideLoadKey)) {\r\n                keys.push(key);\r\n            }\r\n        }\r\n\r\n        let data: { [name: string]: SideLoad } = {};\r\n        for (let key of keys) {\r\n            let item = <SideLoad>JSON.parse(LocalStorageHandler.getItem(key, global) ?? '{}');\r\n\r\n            // trim last \"/\"\r\n            if (item.origin[item.origin.length - 1] === '/') {\r\n                item.origin = item.origin.substring(0, item.origin.length - 1);\r\n            }\r\n\r\n            data[item.origin] = item;\r\n        }\r\n\r\n        // Read sideload data from 'sideload' url parameter\r\n        let sideloadParam = getLocationSearchParameter('sideload');\r\n\r\n        // if we found the parameter and it has a value, then process the sideload data\r\n        if (sideloadParam && sideloadParam.value) {\r\n            // sideload parameter should be a comma seperated list\r\n            sideloadParam.value.split(',')\r\n                // add sidloads to data, overriding local storage\r\n                .forEach(origin => {\r\n                    // trim last \"/\"\r\n                    if (origin[origin.length - 1] === '/') {\r\n                        origin = origin.substring(0, origin.length - 1);\r\n                    }\r\n\r\n                    data[origin] = { origin };\r\n                });\r\n        }\r\n\r\n        return data;\r\n    }\r\n\r\n    /**\r\n     * Override environment setting with side-loading setting on current loaded domain.\r\n     * - update information to local storage key and overridden when loading the manifest.\r\n     * - use sideLoadReset to reset all sideLoading settings.\r\n     *\r\n     * @param originUri the origin url of the module.\r\n     */\r\n    export function sideLoad(originUri?: string): { [name: string]: SideLoad } {\r\n        if (arguments.length > 1) {\r\n            throw new Error(`Incorrect syntax for side loading. Please use 'MsftSme.sideload(<origin>);' where '<originUri>' is similar to 'http://localhost:4201'. The new syntax will load any module from the manifest at <originUri>/manifest.json at runtime.`);\r\n        }\r\n\r\n        if (originUri) {\r\n            if (!['http://', 'https://'].some(prefix => originUri.startsWith(prefix))) {\r\n                throw new Error(`Incorrect syntax for side loading. To ensure cross origin sideloads support, please begin your sideload origin with \"http://\" or \"https://\". Ex. \"MsftSme.sideload('http://${originUri}')\"`);\r\n            }\r\n\r\n            let item = <SideLoad>{\r\n                origin: originUri\r\n            };\r\n            LocalStorageHandler.setItem(sideLoadKey + originUri, JSON.stringify(item), global);\r\n            let data: { [name: string]: SideLoad } = {};\r\n            data[originUri] = item;\r\n            return data;\r\n        }\r\n\r\n        return sideLoadRead();\r\n    }\r\n\r\n    /**\r\n     * Reset all side-loading settings on current loaded domain.\r\n     */\r\n    export function sideLoadReset(): void {\r\n        let global = window;\r\n        let length = LocalStorageHandler.getLength(global);\r\n        let keys: string[] = [];\r\n        for (let index = 0; index < length; index++) {\r\n            let key = LocalStorageHandler.getKey(index, global);\r\n            if (key.startsWith(sideLoadKey)) {\r\n                keys.push(key);\r\n            }\r\n        }\r\n\r\n        for (let key of keys) {\r\n            LocalStorageHandler.removeItem(key, global);\r\n        }\r\n    }\r\n\r\n    const consoleDebugKey = 'MsftSme.ConsoleDebug';\r\n\r\n    /**\r\n     * Read debug console setting.\r\n     */\r\n    function consoleDebugRead(): number {\r\n        // first check for a query parameter that tells us what debug level to use\r\n        let consoleDebugParam = getLocationSearchParameter('consoledebug');\r\n\r\n        // if we found the parameter and it has a value, then process that as our sideload setting data\r\n        if (consoleDebugParam && consoleDebugParam.value) {\r\n            try {\r\n                let level = parseInt(consoleDebugParam.value);\r\n                return level;\r\n            } catch (ex) {\r\n                console.error(`Error reading \"consoleDebug\" parameter: ${ex.message}`);\r\n            }\r\n        }\r\n\r\n        // then we fallback to what is saved in localStorage\r\n        let data = <{ level: number }>JSON.parse(\r\n            LocalStorageHandler.getItem(consoleDebugKey) ?? '{}', global);\r\n        if (data && data.level) {\r\n            return data.level;\r\n        }\r\n\r\n        // fallback again to whatever was passed into the Init call\r\n        let smeWindow = (<SMEWindow>global);\r\n        if (smeWindow && smeWindow.MsftSme && smeWindow.MsftSme.Init) {\r\n            return smeWindow.MsftSme.Init.logLevel;\r\n        }\r\n\r\n        // return null if not set yet. using default see at core-enviromnent.\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * Override environment setting with side-loadig setting on current loaded domain.\r\n     * - update information to local storage key and overriden when loading the manifest.\r\n     * - use sideLoadReset to reset all sideLoading settings.\r\n     *\r\n     * @param level the debug level. 1:Critical, 2:Error, 3:Warning, 4:Success, 5:Informational, 6:Verbose, 7:Debug.\r\n     *\r\n     */\r\n    export function consoleDebug(level?: number): number {\r\n        if (level) {\r\n            // console.log('1:Critical, 2:Error, 3:Warning, 4:Success, 5:Informational, 6:Verbose, 7:Debug');\r\n            LocalStorageHandler.setItem(consoleDebugKey, JSON.stringify({ level: level }), global);\r\n            (<SMEWindow>global).MsftSme.Init.logLevel = level;\r\n            return level;\r\n        }\r\n\r\n        return consoleDebugRead();\r\n    }\r\n\r\n    /**\r\n     * Reset all side-loading settings on current loaded domain.\r\n     */\r\n    export function consoleDebugReset(): void {\r\n        LocalStorageHandler.removeItem(consoleDebugKey, global);\r\n    }\r\n\r\n    // #region Performance Profile management\r\n    /**\r\n     * Performance Profile management.\r\n     */\r\n    const performanceProfileStorageKey = '@msft-sme/shell:performanceProfile';\r\n\r\n    export function getPerformanceProfile(): boolean {\r\n        const profile = LocalStorageHandler.getItem(performanceProfileStorageKey);\r\n        return profile === \"1\";\r\n    }\r\n\r\n    export function setPerformanceProfile(profile: boolean) {\r\n        if (profile) {\r\n            LocalStorageHandler.setItem(performanceProfileStorageKey, \"1\");\r\n        } else {\r\n            LocalStorageHandler.removeItem(performanceProfileStorageKey);\r\n        }\r\n    }\r\n\r\n    // #endregion // Performance Profile management\r\n\r\n    // #region Developer guide management\r\n    /**\r\n     * Developer guide management\r\n     */\r\n    const developerGuideStorageKey = '@msft-sme/shell:developerGuide';\r\n    const developerGuideExperimentKey = 'msft.sme.shell.devguide';\r\n\r\n    export function getDeveloperGuide(): boolean {\r\n        const experiments = this.experiments();\r\n        // If they have the developer guide experiment key, remove and set storage key to true\r\n        if (experiments.some(experiment => experiment === developerGuideExperimentKey)) {\r\n            const filteredExperiments = experiments.filter(experiment => experiment !== developerGuideExperimentKey);\r\n            // remove experiment key\r\n            this.experiments(filteredExperiments);\r\n            // set storage key\r\n            this.setDeveloperGuide(true);\r\n            return true;\r\n        } else {\r\n            const developerGuide = LocalStorageHandler.getItem(developerGuideStorageKey);\r\n            return developerGuide === \"1\";\r\n        }\r\n    }\r\n\r\n    export function setDeveloperGuide(developerGuide: boolean) {\r\n        if (developerGuide) {\r\n            LocalStorageHandler.setItem(developerGuideStorageKey, \"1\");\r\n        } else {\r\n            LocalStorageHandler.removeItem(developerGuideStorageKey);\r\n        }\r\n    }\r\n\r\n    // #endregion // Developer guide management\r\n\r\n    /**\r\n     * Constants for experiment flags\r\n     */\r\n    const experimentsKey = 'MsftSme.Experiments';\r\n    const experimentsSplitChar = ',';\r\n\r\n    /**\r\n     * Read experiment setting.\r\n     */\r\n    function experimentsRead(): string[] {\r\n        // first check for a query parameter that tells us what debug level to use\r\n        let experimentsParam = getLocationSearchParameter('experiments');\r\n\r\n        // if we found the parameter and it has a value, then process that as our sideload setting data\r\n        if (experimentsParam && experimentsParam.value) {\r\n            try {\r\n                return experimentsParam.value.split(experimentsSplitChar);\r\n            } catch (ex) {\r\n                console.error(`Error reading \"experiments\" parameter: ${ex.message}`);\r\n            }\r\n        }\r\n\r\n        // then we fallback to what is saved in localStorage\r\n        let data = <string>LocalStorageHandler.getItem(experimentsKey);\r\n        if (!MsftSme.isNullOrWhiteSpace(data)) {\r\n            return data.split(experimentsSplitChar);\r\n        }\r\n\r\n        // fallback again to whatever was passed into the Init call\r\n        let smeWindow = (<SMEWindow>global);\r\n        if (smeWindow && smeWindow.MsftSme && smeWindow.MsftSme.Init) {\r\n            return smeWindow.MsftSme.Init.experiments;\r\n        }\r\n\r\n        // return empty array if not set yet.\r\n        return [];\r\n    }\r\n\r\n    /**\r\n     * Override environment setting with experiment setting on current loaded domain. requires reload to really be effective     *\r\n     * @param value The experiments to turn on. Each entry should be in the format: <extension name>.<key>\r\n     */\r\n    export function experiments(value?: string[]): string[] {\r\n        if (Array.isArray(value)) {\r\n            LocalStorageHandler.setItem(experimentsKey, value.join(experimentsSplitChar), global);\r\n            (<SMEWindow>global).MsftSme.Init.experiments = value;\r\n            return value;\r\n        }\r\n\r\n        return experimentsRead();\r\n    }\r\n\r\n    /**\r\n     * Reset all experiment settings on current loaded domain.*\r\n     */\r\n    export function experimentsReset(): void {\r\n        LocalStorageHandler.removeItem(experimentsKey, global);\r\n    }\r\n\r\n    /**\r\n     * Returns true if the given experiment key is set relative to the current module or to shell\r\n     * @param key the experiment key to check. This is without the module name. i.e. msft.sme.shell.experiment should be checked with isExperimentEnabled('experiment')\r\n     * @param shellExperiment if true, indicates that we should check for global shell experiments instead of local module experiments. Defaults to false\r\n     */\r\n    export function isExperimentEnabled(key: string, shellExperiment: boolean = false): boolean {\r\n        let moduleName = shellExperiment ? MsftSme.self().Environment.shell.name : MsftSme.self().Environment.name;\r\n        let experimentKey = `${moduleName}.${key}`;\r\n        return MsftSme.experiments().some(x => x.toLowerCase() === experimentKey.toLowerCase());\r\n    }\r\n\r\n    /**\r\n     * Returns true if the given experiment key is set.\r\n     * @param key the experiment key to check.\r\n\r\n     */\r\n    export function isExperimentEnabledRaw(key: string): boolean {\r\n        const lowerCaseKey = key.toLowerCase();\r\n        return MsftSme.experiments().some(x => x.toLowerCase() === lowerCaseKey);\r\n    }\r\n\r\n    /**\r\n     * Gets the localized strings initialized by localization manager. The LocalizationManager should have\r\n     * been used to get the localized strings.\r\n     *\r\n     * @returns an object containing all the localized strings, or null if noe localized strings have been fetched yet\r\n     */\r\n    export function getStrings<T>(): T {\r\n        if (!global.MsftSme.Resources || !global.MsftSme.Resources.strings) {\r\n            throw new Error('Unable to access localized resource strings.');\r\n        }\r\n\r\n        return <T>MsftSme.self().Resources.strings;\r\n    }\r\n\r\n    /**\r\n     * @deprecated Use MsftSme.getStrings<T>() instead.\r\n     *\r\n     * Gets the localized strings initialized by localization manager. The LocalizationManager should have\r\n     * been used to get the localized strings.\r\n     *\r\n     * @returns an object containing all the localized strings, or null if noe localized strings have been fetched yet\r\n     */\r\n    export function resourcesStrings<T>(): T {\r\n        if (!global.MsftSme.Resources || !global.MsftSme.Resources.strings) {\r\n            throw new Error('Unable to access localized ResourcesStrings data.');\r\n        }\r\n\r\n        return <T>global.MsftSme.Resources.strings;\r\n    }\r\n\r\n    /**\r\n     * Gets current session identification.\r\n     * Within the same browser session, the session ID is the same on shell and all modules.\r\n     */\r\n    export function sessionId(): string {\r\n        let global: MsftSme.SMEWindow = <any>window;\r\n        return global.MsftSme.Init.sessionId;\r\n    }\r\n\r\n    /**\r\n     * Gets the self object of global MsftSme.\r\n     */\r\n    export function self(): MsftSme.MsftSmeWindowContext {\r\n        let self = (<MsftSme.SMEWindow><any>window).MsftSme;\r\n        if (!self.Host) {\r\n            /* IsElectron and IsWeb are opposites today, but may not always be. (Example,: if we ever went with a UWP or Ibiza approach. )\r\n            think of it this way:\r\n            \"electron\" is the reference to electron or null\r\n            \"isElectron\" is a shortcut to know if we are running in an electron context\r\n            \"isWeb\" is a shortcut to knowing if we are running in the default \"web\" context. */\r\n            let electron: MsftSme.MsftSmeElectron = window['require'] ? window['require']('electron') : null;\r\n            self.Host = {\r\n                isElectron: !!electron,\r\n                isWeb: !electron,\r\n                electron: electron\r\n            };\r\n        }\r\n        return self;\r\n    }\r\n\r\n    /**\r\n     * Returns the window that is hosting the current window or null if the current window is not hosted.\r\n     */\r\n    export function getHostWindow(): Window {\r\n        if (window.opener) {\r\n            return window.opener;\r\n        }\r\n        if (window.parent !== window.self) {\r\n            return window.parent;\r\n        }\r\n        if (window.top !== window.self) {\r\n            return window.top;\r\n        }\r\n        return null;\r\n    }\r\n\r\n    /**\r\n     * Returns true if the current window is the top window. Otherwise returns false\r\n     */\r\n    export function isHostedWindow(): boolean {\r\n        return !MsftSme.isNullOrUndefined(MsftSme.getHostWindow());\r\n    }\r\n\r\n    /**\r\n     * returns true if the current window is the shell instance.\r\n     */\r\n    export function isShell(): boolean {\r\n        return MsftSme.self().Init.isShell;\r\n    }\r\n\r\n    /**\r\n     * returns true if the current window is the an extension instance.\r\n     */\r\n    export function isExtension(): boolean {\r\n        return !MsftSme.isShell();\r\n    }\r\n\r\n    /**\r\n     * returns the entry point type string.\r\n     * - 'solution'\r\n     * - 'tool'\r\n     * - 'service'\r\n     * - 'settingsForm'\r\n     * - 'worker'\r\n     * - 'dialog'\r\n     * - 'snapIn'\r\n     */\r\n    export function entryPointType(): string {\r\n        return MsftSme.self().Init.entryPointType;\r\n    }\r\n\r\n    /**\r\n     * Writes helpful debug information to the console\r\n     */\r\n    export function help(): void {\r\n        console.log(`\r\nAvailable Debug Commands:\r\n\r\nGet/Set The log level:\r\n    MsftSme.consoleDebug()                  -- Gets the current logging level\r\n    MsftSme.consoleDebugReset()             -- Restores the default console log level\r\n    MsftSme.consoleDebug(level: number)   -- Sets the current logging level\r\n\r\n    Log Levels\r\n        1: Critical\r\n        2: Error\r\n        3: Warning\r\n        4: Success\r\n        5: Informational\r\n        6: Verbose\r\n        7: Debug\r\n\r\nGet/Set sideload setting\r\n    MsftSme.sideload()                      -- Gets the current sideload settings\r\n    MsftSme.sideloadReset()                 -- Removes all sideload settings\r\n    MsftSme.sideload(origin: string)        -- Adds a new sideload settings to the origin uri where a module is hosted.\r\n\r\nGet/Set experiment flags:\r\n    MsftSme.experiments()                   -- Gets the currently enabled experiment keys\r\n    MsftSme.experimentsReset()              -- Removes all enabled experiment keys\r\n    MsftSme.experiments(keys: string[])     -- Enables a set of experiment keys.\r\n\r\n\r\nGet Environmental Information\r\n    MsftSme.listVersions()                  -- list the versions of all ux modules currently installed\r\n    MsftSme.self()                          -- Gets the global environment configuration.\r\n\r\n`\r\n        );\r\n    }\r\n\r\n    /**\r\n     * List the versions of all UX components in windows admin center\r\n     */\r\n    export function listVersions(): void {\r\n        let environment = MsftSme.self().Environment;\r\n        let result = {};\r\n        result[environment.name] = environment.version;\r\n        result = environment.modules.reduce((map, module) => {\r\n            map[module.name] = module.version;\r\n            return map;\r\n        }, result);\r\n\r\n        console.log(result);\r\n    }\r\n\r\n    /** array.ts */\r\n    polyfill(Array, <ArrayPolyfills<any>>{\r\n        concatUnique: function (other, predicate) {\r\n            return union(this, other, predicate);\r\n        },\r\n        first: function (predicate, startIndex) {\r\n            // Intentionally not using _.find here, since here if we don't find the element\r\n            // we return null. In _.find when this happens we return undefined.\r\n            let index = findIndex(this, predicate, startIndex);\r\n            return index < 0 ? null : this[index];\r\n        },\r\n        firstIndex: function (predicate, startIndex) {\r\n            return findIndex(this, predicate, startIndex);\r\n        },\r\n        last: function () {\r\n            if (this.length < 1) {\r\n                throw new Error(\"Cannot get the last element because the array is empty.\");\r\n            }\r\n\r\n            return this[this.length - 1];\r\n        },\r\n        mapMany: function (selector: (value: any) => any[]): any[] {\r\n            return mapMany(this, selector);\r\n        },\r\n        remove: function (item) {\r\n            return remove(this, current => current === item);\r\n        },\r\n        stableSort: function (compare) {\r\n            return stableSort(this, compare);\r\n        },\r\n        // Deprecated. Remove on or after 2016/02/01.\r\n        toNumberMap: function (keySelector: (value: any) => number) {\r\n            let ret: NumberMap<any> = [];\r\n            (<any[]>this).forEach((value) => {\r\n                ret[keySelector(value)] = value;\r\n            });\r\n            return ret;\r\n        },\r\n        unique: function (predicate) {\r\n            return unique(this, predicate);\r\n        }\r\n    });\r\n\r\n    /** string.ts */\r\n    const namedFormatSpecifierRegex = /\\{[a-zA-Z$_\\d]*\\}/g;\r\n    const numberedFormatSpecifierRegex = /\\{(\\d+)\\}/g;\r\n\r\n    function format() {\r\n        let restArgs = arguments,\r\n            value = this;\r\n\r\n        let matched = false,\r\n            retVal: string;\r\n\r\n        let isFormatObject = restArgs.length === 1 && restArgs[0] && typeof restArgs[0] === \"object\";\r\n        let isFormatObjectWithTokenFormatter = restArgs.length === 2 && restArgs[0] && typeof restArgs[0] === \"object\" && (typeof restArgs[1] === \"function\" || restArgs[1] === null);\r\n        let tokenFormatter = isFormatObjectWithTokenFormatter ? restArgs[1] : null;\r\n\r\n        if (isFormatObject || isFormatObjectWithTokenFormatter) {\r\n            let actualArg = restArgs[0];\r\n            retVal = value.replace(namedFormatSpecifierRegex, (match: string) => {\r\n                let name = match.substring(1, match.length - 1);\r\n                if (actualArg.hasOwnProperty(name)) {\r\n                    matched = true;\r\n                    let tokenValue = actualArg[name];\r\n                    return tokenFormatter ? tokenFormatter(tokenValue) : tokenValue;\r\n                } else {\r\n                    return match;\r\n                }\r\n            });\r\n        }\r\n\r\n        // we get here in two cases:\r\n        //    1. we don't have a format object\r\n        //    2. we do have a format object but it's properties didn't match any of the named parameters.\r\n        //       this often happens when developers write code like:\r\n        //          try {\r\n        //              ...\r\n        //          } catch(err) {\r\n        //              log(\"abc: {0}\".format(err));\r\n        //          }\r\n        //       in this scenario also we want to match by number.\r\n        //\r\n        if (!matched) {\r\n            retVal = value.replace(numberedFormatSpecifierRegex, (match: string, num: number) => {\r\n                if (num < restArgs.length) {\r\n                    let tokenValue = restArgs[num];\r\n                    return tokenFormatter ? tokenFormatter(tokenValue) : tokenValue;\r\n                } else {\r\n                    return match;\r\n                }\r\n            });\r\n        }\r\n\r\n        return retVal;\r\n    }\r\n\r\n    polyfill(String, <StringPolyfills>{\r\n        format: format,\r\n        localeCompareIgnoreCase: function (value, locales, options) {\r\n            return localeCompareIgnoreCase(this, value, locales, options);\r\n        },\r\n        replaceAll: function (searchValue, replaceValue) {\r\n            return replaceAll(this, searchValue, replaceValue);\r\n        },\r\n        replaceMany: function (replacementMap) {\r\n            return replaceMany(this, replacementMap);\r\n        },\r\n        repeat: function (count) {\r\n            return repeat(this, count);\r\n        },\r\n        startsWith: function (searchString, position) {\r\n            return startsWith(this, searchString, position);\r\n        },\r\n        endsWith: function (searchString, position) {\r\n            return endsWith(this, searchString, position);\r\n        }\r\n    }, /* force */ true);\r\n\r\n    global.MsftSme = MsftSme;\r\n}\r\n"]}