/********************************************************************
 * @author:      Kaven
 * @email:       kaven@wuwenkai.com
 * @website:     http://kavenblog.com
 * @file:        [Kaven-Basic] /src/libs/KavenBasic.ts
 * @create:      2018-08-30 16:08:33.658
 * @modify:      2019-08-03 21:25:23.365
 * @version:     1.1.22
 * @times:       121
 * @lines:       1594
 * @copyright:   Copyright © 2018 Kaven. All Rights Reserved.
 * @description: [description]
 * @license:
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 ********************************************************************/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
import moment from "moment";
import { DateTimeFormat } from "./Enums";
import { KavenCRC } from "./hashing_algorithms/KavenCRC";
import { KavenMD5 } from "./hashing_algorithms/KavenMD5";
import { KavenSHA } from "./hashing_algorithms/KavenSHA";
import { KavenSHA3 } from "./hashing_algorithms/KavenSHA3";
import { MemoryCache } from "./MemoryCache";
import { MIME } from "./MIME";
import { StringPosition } from "./StringPosition";
import { Strings } from "./Strings";
var KavenBasic = /** @class */ (function () {
    function KavenBasic() {
        this.memoryCacheCollection = [];
        this.memoryCollection = {};
    }
    Object.defineProperty(KavenBasic.prototype, "SHA3", {
        get: function () {
            var name = Strings.Names.SHA3Instance;
            var sha3 = this.GetValue(name, undefined);
            if (sha3 === undefined) {
                sha3 = new KavenSHA3();
                this.SetValue(name, sha3);
            }
            return sha3;
        },
        enumerable: true,
        configurable: true
    });
    //#region MemoryCache
    /**
     *
     * @param name
     * @param value
     * @param absoluteExpiration
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.SetCacheWithDate = function (name, value, absoluteExpiration) {
        var item = this.memoryCacheCollection.find(function (p) { return p.name === name; });
        if (item === undefined) {
            item = new MemoryCache(name, value, absoluteExpiration);
        }
        else {
            item.value = value;
            item.absoluteExpiration = absoluteExpiration;
        }
        console.info("Set Cache: " + name);
        this.memoryCacheCollection.push(item);
    };
    /**
     *
     * @param name
     * @param value
     * @param millisecond
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.SetCacheWithMilliseconds = function (name, value, millisecond) {
        this.SetCacheWithDate(name, value, moment()
            .add(millisecond, "milliseconds")
            .toDate());
    };
    /**
     *
     * @param name
     * @param value
     * @param minute
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.SetCacheWithMinute = function (name, value, minute) {
        var milliseconds = moment
            .duration({ minutes: minute })
            .asMilliseconds();
        this.SetCacheWithMilliseconds(name, value, milliseconds);
    };
    /**
     *
     * @param name
     * @param value
     * @param hour
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.SetCacheWithHour = function (name, value, hour) {
        var milliseconds = moment.duration({ hours: hour }).asMilliseconds();
        this.SetCacheWithMilliseconds(name, value, milliseconds);
    };
    /**
     *
     * @param name
     * @since 1.0.5
     * @version 2018-11-02
     */
    KavenBasic.prototype.GetCache = function (name) {
        var index = this.memoryCacheCollection.findIndex(function (p) { return p.name === name; });
        if (index === -1) {
            return undefined;
        }
        var item = this.memoryCacheCollection[index];
        if (item.IsExpired()) {
            this.memoryCacheCollection.Remove(index);
            return undefined;
        }
        return item.value;
    };
    /**
     *
     * @param name
     * @param removeExpired
     * @since 1.0.5
     * @version 2018-11-02
     */
    KavenBasic.prototype.RemoveCache = function (name, removeExpired) {
        var _this = this;
        if (removeExpired === void 0) { removeExpired = true; }
        if (removeExpired) {
            var arr = [];
            for (var i = 0; i < this.memoryCacheCollection.length; i++) {
                var item = this.memoryCacheCollection[i];
                if (item.name === name || item.IsExpired()) {
                    arr.push(i);
                }
            }
            arr.forEach(function (p) { return _this.memoryCacheCollection.Remove(p); });
        }
        else {
            var index = this.memoryCacheCollection.findIndex(function (p) { return p.name === name; });
            if (index !== -1) {
                this.memoryCacheCollection.Remove(index);
            }
        }
    };
    //#endregion
    /**
     *
     * @param dt
     * @param format
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.FormatDate = function (dt, format) {
        dt = dt || new Date();
        return dt.Format(format);
    };
    /**
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.GetFileNameByDateTime = function () {
        return this.FormatDate(undefined, DateTimeFormat.ForFileName);
    };
    /**
     * Module wrapper of @substack's `caller.js`
     * @original: https://github.com/substack/node-resolve/blob/master/lib/caller.js
     * @blessings: https://twitter.com/eriktoth/statuses/413719312273125377
     * @see https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.GetStackInfo = function (depth, type) {
        if (type === void 0) { type = "getFileName"; }
        var pst;
        var stack;
        var file;
        var frame;
        pst = Error.prepareStackTrace;
        Error.prepareStackTrace = function (_, s) {
            Error.prepareStackTrace = pst;
            return s;
        };
        stack = new Error().stack;
        if (stack) {
            var temp = 2;
            depth =
                !depth || isNaN(depth)
                    ? 1
                    : depth > stack.length - temp
                        ? stack.length - temp
                        : depth;
            stack = stack.slice(depth + 1);
        }
        if (stack) {
            do {
                // @ts-ignore
                frame = stack.shift();
                file = frame && frame[type](); // .getFileName();
            } while (stack.length && file === "module.js");
        }
        return file;
    };
    /**
     * Returns a random number between min (inclusive) and max (exclusive)
     * @param min
     * @param max
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.GetRandomArbitrary = function (min, max) {
        return Math.random() * (max - min) + min;
    };
    /**
     * Returns a random integer between min (inclusive) and max (inclusive)
     * Using Math.round() will give you a non-uniform distribution!
     * @param min
     * @param max
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.GetRandomInt = function (min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    };
    /**
     *
     * @param length
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.GenerateNumberString = function (length) {
        var result = Strings.Empty;
        var max = 9;
        for (var i = 0; i < length; i++) {
            if (result === Strings.Empty) {
                result = this.GetRandomInt(0, max).toString();
            }
            else {
                result += this.GetRandomInt(0, max).toString();
            }
        }
        return result;
    };
    /**
     * just for backward-compatible with earlier versions, recommend use {@link GenerateYearMonthIdAsync} instead
     * @param randomLength
     * @param validFunc
     * @param ignoreIDs
     * @param candidatesGUID
     * @version 1.0.0
     * @since 1.0.1
     * @example
     */
    KavenBasic.prototype.GenerateYearMonthId = function (randomLength, validFunc, ignoreIDs, candidatesGUID) {
        if (randomLength === void 0) { randomLength = 4; }
        var id = Strings.Empty;
        var ym = this.FormatDate(undefined, DateTimeFormat.YearMonth);
        //#region Implementation 1
        if (typeof validFunc === "function") {
            while (true) {
                // tslint:disable-next-line:no-shadowed-variable
                var randomNumberStr_1 = this.GenerateNumberString(randomLength);
                id = ym + randomNumberStr_1;
                if (validFunc(id)) {
                    return id;
                }
            }
        }
        //#endregion
        //#region Implementation 2
        if (ignoreIDs && ignoreIDs.IsNotEmpty()) {
            var temp = "1";
            for (var i = 0; i < randomLength; i++) {
                temp += "0";
            }
            var max = parseInt(temp, 10) - 1;
            var cacheName = "GenerateYearMonthId_" + randomLength + "_candidates";
            var candidates = this.GetCache(cacheName);
            if (candidates === undefined) {
                candidates = Array.apply(undefined, new Array(max)).map(function (_, index) {
                    return index.toString().padStart(randomLength, "0");
                }); // .map(Function.call, Number);
                this.SetCacheWithMinute(cacheName, candidates, 1);
            }
            //#region Old
            // const candidates: string[] = [];
            // for (let i = 0; i <= max; i++) {
            //     const tempID = i.toString().padStart(randomLength, "0");
            //     if (ignoreIDs.includes(tempID)) {
            //         continue;
            //     }
            //     candidates.push(tempID);
            // }
            //#endregion
            if (candidates && candidatesGUID) {
                var callCandidates = this.GetCache(candidatesGUID);
                if (callCandidates === undefined) {
                    callCandidates = candidates.filter(function (p) { return !ignoreIDs.includes(p); });
                    // tslint:disable-next-line:no-magic-numbers
                    this.SetCacheWithMinute(candidatesGUID, callCandidates, 5);
                }
                var idIndex = this.GetRandomInt(0, callCandidates.length - 1);
                id = ym + callCandidates[idIndex];
                callCandidates.Remove(idIndex);
            }
            return id;
        }
        //#endregion
        var randomNumberStr = this.GenerateNumberString(randomLength);
        id = ym + randomNumberStr;
        return id;
    };
    /**
     *
     * @param randomLength
     * @param validFunc
     * @param ignoreIDs
     * @param candidatesGUID
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.GenerateYearMonthIdAsync = function (randomLength, validFunc, ignoreIDs, candidatesGUID) {
        if (randomLength === void 0) { randomLength = 4; }
        return __awaiter(this, void 0, void 0, function () {
            var id, ym, randomNumberStr_2, temp, i, max, cacheName, candidates, callCandidates, idIndex, randomNumberStr;
            return __generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        id = Strings.Empty;
                        ym = this.FormatDate(undefined, DateTimeFormat.YearMonth);
                        if (!(typeof validFunc === "function")) return [3 /*break*/, 3];
                        _a.label = 1;
                    case 1:
                        if (!true) return [3 /*break*/, 3];
                        randomNumberStr_2 = this.GenerateNumberString(randomLength);
                        id = ym + randomNumberStr_2;
                        return [4 /*yield*/, validFunc(id)];
                    case 2:
                        if (_a.sent()) {
                            return [2 /*return*/, id];
                        }
                        return [3 /*break*/, 1];
                    case 3:
                        //#endregion
                        //#region Implementation 2
                        if (ignoreIDs && ignoreIDs.IsNotEmpty()) {
                            temp = "1";
                            for (i = 0; i < randomLength; i++) {
                                temp += "0";
                            }
                            max = parseInt(temp, 10) - 1;
                            cacheName = "GenerateYearMonthId_" + randomLength + "_candidates";
                            candidates = this.GetCache(cacheName);
                            if (candidates === undefined) {
                                candidates = Array.apply(undefined, new Array(max)).map(function (_, index) {
                                    return index.toString().padStart(randomLength, "0");
                                }); // .map(Function.call, Number);
                                this.SetCacheWithMinute(cacheName, candidates, 1);
                            }
                            //#region Old
                            // const candidates: string[] = [];
                            // for (let i = 0; i <= max; i++) {
                            //     const tempID = i.toString().padStart(randomLength, "0");
                            //     if (ignoreIDs.includes(tempID)) {
                            //         continue;
                            //     }
                            //     candidates.push(tempID);
                            // }
                            //#endregion
                            if (candidatesGUID && candidates) {
                                callCandidates = this.GetCache(candidatesGUID);
                                if (callCandidates === undefined) {
                                    callCandidates = candidates.filter(function (p) { return !ignoreIDs.includes(p); });
                                    // tslint:disable-next-line:no-magic-numbers
                                    this.SetCacheWithMinute(candidatesGUID, callCandidates, 5);
                                }
                                idIndex = this.GetRandomInt(0, callCandidates.length - 1);
                                id = ym + callCandidates[idIndex];
                                callCandidates.Remove(idIndex);
                            }
                            return [2 /*return*/, id];
                        }
                        randomNumberStr = this.GenerateNumberString(randomLength);
                        id = ym + randomNumberStr;
                        return [2 /*return*/, id];
                }
            });
        });
    };
    /**
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.GenerateGuid = function () {
        // cSpell:ignore yxxx
        return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
            // tslint:disable-next-line:one-variable-per-declaration no-bitwise no-magic-numbers
            var r = (Math.random() * 16) | 0, 
            // tslint:disable-next-line:one-variable-per-declaration no-bitwise no-magic-numbers
            v = c === "x" ? r : (r & 0x3) | 0x8;
            // tslint:disable-next-line:no-magic-numbers
            return v.toString(16);
        });
    };
    /**
     *
     * @param length
     * @param validCharacters
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.GenerateRandomString = function (length, validCharacters) {
        var str = Strings.Empty;
        // tslint:disable-next-line:no-magic-numbers
        if (validCharacters === undefined || validCharacters.length < 2) {
            validCharacters =
                Strings.LowercaseLetters +
                    Strings.UppercaseLetters +
                    Strings.Numbers;
        }
        for (var i = 0; i < length; i++) {
            var char = validCharacters[this.GetRandomInt(0, validCharacters.length - 1)];
            if (str === Strings.Empty) {
                str = char;
            }
            else {
                str += char;
            }
        }
        return str;
    };
    /**
     *
     * @param length
     * @param numbers
     * @param lowercaseLetters
     * @param uppercaseLetters
     * @param specialCharacters
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.GeneratePassword = function (length, numbers, lowercaseLetters, uppercaseLetters, specialCharacters) {
        if (numbers === void 0) { numbers = true; }
        if (lowercaseLetters === void 0) { lowercaseLetters = true; }
        if (uppercaseLetters === void 0) { uppercaseLetters = true; }
        if (specialCharacters === void 0) { specialCharacters = true; }
        // tslint:disable-next-line:no-magic-numbers
        if (length < 10) {
            console.warn("Your Password is Too Damn Short: " + length);
        }
        var chars = Strings.Empty;
        if (numbers) {
            chars += Strings.Numbers;
        }
        if (lowercaseLetters) {
            chars += Strings.LowercaseLetters;
        }
        if (uppercaseLetters) {
            chars += Strings.UppercaseLetters;
        }
        if (specialCharacters) {
            chars += Strings.PasswordSpecialCharacters;
        }
        if (chars.IsNotEmpty()) {
            return this.GenerateRandomString(length, chars);
        }
        else {
            throw new Error("Invalid parameters: " + arguments);
        }
    };
    /**
     *
     * @param func
     * @param times
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.RunTest = function (func, times) {
        while (times-- > 0) {
            func();
        }
    };
    /**
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.RandomBoolean = function () {
        // tslint:disable-next-line:no-magic-numbers
        return Math.random() >= 0.5;
    };
    /**
     * @version 1.0.0
     * @since 1.0.5
     * @example C:/a/b/c  return C:/a/b
     */
    KavenBasic.prototype.GetBaseDir = function (pathStr) {
        if (!pathStr) {
            return Strings.Empty;
        }
        var index = pathStr.lastIndexOf(Strings.Slash);
        if (index !== -1) {
            return pathStr.substring(0, index + 1);
        }
        else {
            index = pathStr.lastIndexOf(Strings.BackSlash);
            if (index !== -1) {
                return pathStr.substring(0, index + 1);
            }
        }
        return pathStr;
    };
    /**
     *
     * @param fileName
     * @version 1.0.0
     * @since 1.0.5
     * @example "c:/a/b.xyz" => "xyz"
     */
    KavenBasic.prototype.GetFileExtension = function (fileName) {
        if (fileName && fileName.lastIndexOf(".") !== -1) {
            return fileName.split(".").pop() || Strings.Empty;
        }
        else {
            return Strings.Empty;
        }
    };
    /**
     *
     * @param fileName
     * @since 1.1.7
     * @version 2018-08-31
     * @example "c:/a/b.xyz" => "b"
     */
    KavenBasic.prototype.GetFileNameWithoutExtension = function (fileName) {
        return this.GetFileName(fileName)
            .TrimEnd(this.GetFileExtension(fileName))
            .TrimEnd(".");
    };
    /**
     *
     * @param fileName
     * @version 2018-08-31
     * @since 1.0.5
     * @example
     * "c:/a/b.xyz" => "b.xyz"
     * "b.xyz" => "b.xyz"
     */
    KavenBasic.prototype.GetFileName = function (fileName) {
        var base = this.GetBaseDir(fileName);
        if (base === fileName) {
            return fileName;
        }
        return fileName.replace(base, Strings.Empty);
    };
    /**
     *
     * @param fileName
     * @param extension
     * @version 2018-08-31
     * @since 1.0.5
     */
    KavenBasic.prototype.ChangeFileExtension = function (fileName, extension) {
        var ext = this.GetFileExtension(fileName);
        var root = fileName.TrimEnd(ext); // fileName.substring(0, fileName.length - ext.length);
        ext = extension.TrimStart(".");
        root = root.TrimEnd(".");
        return root + "." + ext;
    };
    //#region Memory Values
    /**
     *
     * @param name
     * @param value
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.SetValue = function (name, value) {
        this.memoryCollection[name] = value;
    };
    /**
     *
     * @param name
     * @param defaultValueIfNotExist
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.GetValue = function (name, defaultValueIfNotExist) {
        var val = this.memoryCollection[name];
        if (val === undefined) {
            return defaultValueIfNotExist;
        }
        return val;
    };
    /**
     *
     * @param name
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.RemoveValue = function (name) {
        this.memoryCollection[name] = undefined;
    };
    //#endregion
    /**
     *
     * @param obj
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.RemoveEmpty = function (obj) {
        Object.keys(obj).forEach(function (k) { return !obj[k] && obj[k] !== undefined && delete obj[k]; });
        return obj;
    };
    /**
     *
     * @param obj
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.SortByKey = function (obj) {
        var newObj = {};
        Object.keys(obj)
            .sort()
            .forEach(function (key) {
            newObj[key] = obj[key];
        });
        return newObj;
    };
    /**
     *
     * @param length
     * @param start
     * @param step
     * @version 1.0.0
     * @since 1.0.5
     */
    KavenBasic.prototype.CreateArray = function (length, start, step) {
        var arr = [];
        for (var i = 0; i < length; i++) {
            if (step !== undefined) {
                arr.push(start + step * i);
            }
            else {
                arr.push(start);
            }
        }
        return arr;
    };
    /**
     *
     *
     * @export
     * @param {string} str
     * @param {string} strStart
     * @param {string} strEnd
     * @returns
     * @version 2018-09-01
     * @since 1.0.6
     */
    KavenBasic.prototype.GetStringBetween = function (str, strStart, strEnd, max) {
        if (max === void 0) { max = -1; }
        return this.GetStringPositionBetween(str, strStart, strEnd, max).map(function (p) { return str.substring(p.Start, p.End); });
    };
    /**
     * @param {string} str
     * @param {string} strStart
     * @param {string} strEnd
     * @returns
     * @version 2018-09-02
     * @since 1.1.7
     */
    KavenBasic.prototype.GetStringPositionBetween = function (str, strStart, strEnd, max, startIndex) {
        if (max === void 0) { max = -1; }
        if (startIndex === void 0) { startIndex = 0; }
        var list = [];
        if (str &&
            strStart &&
            strEnd &&
            str.IsNotEmpty() &&
            strStart.IsNotEmpty() &&
            strEnd.IsNotEmpty()) {
            var current = startIndex;
            while (true) {
                var index = str.indexOf(strStart, current);
                if (index !== -1) {
                    var endIndex = str.indexOf(strEnd, index + strStart.length + 1);
                    if (endIndex !== -1) {
                        var pos = new StringPosition(index + strStart.length, endIndex);
                        pos.RelatedString = str.GetSubstring(pos);
                        list.push(
                        // str.substring(index + strStart.length, endIndex)
                        pos);
                        if (max > 0 && list.length >= max) {
                            break;
                        }
                        current = endIndex + strEnd.length + 1;
                    }
                    else {
                        break;
                    }
                }
                else {
                    break;
                }
            }
        }
        return list;
    };
    /**
     *
     * @param replaceMethod
     * @param str
     * @param strStart
     * @param strEnd
     * @since 1.1.7
     * @version 2018-09-01
     */
    KavenBasic.prototype.ReplaceAllStringBetween = function (replaceMethod, str, strStart, strEnd) {
        var current = 0;
        while (true) {
            var pos = this.GetStringPositionBetween(str, strStart, strEnd, 1, current);
            if (pos && pos.IsNotEmpty()) {
                var p = pos[0];
                if (p.RelatedString) {
                    str = str.ReplaceAtPos(p, replaceMethod(p.RelatedString));
                }
                if (p.End === undefined) {
                    throw new Error();
                }
                current = p.End + 1;
            }
            else {
                break;
            }
        }
        return str;
    };
    /**
     *
     *
     * @export
     * @param {string} str
     * @returns
     * @version 2019-03-21
     * @since 1.0.8
     */
    KavenBasic.prototype.SplitStringByNewline = function (str) {
        if (str && str.IsNotEmpty()) {
            // return str.split(/\r?\n/);
            return str.split(Strings.BREAK_LINE_REGEXP);
        }
        return undefined;
    };
    /**
     *
     * @param pathStr
     * @version 1.0.0
     * @since 1.0.9
     */
    KavenBasic.prototype.RemoveInvalidCharactersForPath = function (pathStr) {
        if (pathStr.IsNotEmpty()) {
            return pathStr.replace(/[|&;$%@"<>()+,/]/g, "");
        }
        return pathStr;
    };
    /**
     *
     *
     * @export
     * @param {string} version
     * @returns
     * @version 1.0.0
     * @since 1.0.12
     */
    KavenBasic.prototype.GetNextVersion = function (version) {
        if (!version) {
            return undefined;
        }
        var temp = Number(version);
        if (!isNaN(temp)) {
            return temp + 1;
        }
        if (version.OnlyContains(Strings.Numbers, Strings.Dot)) {
            var items = version.split(Strings.Dot);
            var last = items.Last();
            if (last) {
                temp = Number(last);
                if (!isNaN(temp)) {
                    version = version.TrimEnd(last) + (temp + 1).toString();
                    return version;
                }
            }
        }
        return undefined;
    };
    /**
     *
     *
     * @export
     * @param {string} camelCaseStr
     * @version 1.0.0
     * @since 1.1.1
     * @see {@link https://stackoverflow.com/questions/7225407/convert-camelcasetext-to-sentence-case-text}
     */
    KavenBasic.prototype.SplitCamelCaseString = function (camelCaseStr) {
        // return camelCaseStr.replace(/([a-z])([A-Z])/g, ' $1 $2');
        return camelCaseStr
            .replace(/([A-Z]+)/g, " $1")
            .replace(/([A-Z][a-z])/g, " $1");
    };
    /**
     *
     * @param action
     * @param timeout
     * @param retryCount
     * @param startImmediately
     * @version 2018-08-19 14:03:00.932
     * @since 1.1.5
     */
    KavenBasic.prototype.DoUntilSuccess = function (action, timeout, retryCount, startImmediately) {
        var _this = this;
        if (timeout === void 0) { timeout = 500; }
        if (retryCount === void 0) { retryCount = 5; }
        if (startImmediately === void 0) { startImmediately = false; }
        if (retryCount < 1) {
            console.warn("function exec failed.");
            return;
        }
        if (startImmediately) {
            retryCount--;
            if (action()) {
                return;
            }
        }
        setTimeout(function () {
            _this.DoUntilSuccess(action, timeout, retryCount, true);
        }, timeout);
    };
    /**
     *
     * @param action
     * @param count
     * @param interval
     * @param completeAction
     * @version 2018-08-19 15:59:52.369
     * @since 1.1.5
     */
    KavenBasic.prototype.Countdown = function (action, count, interval, runWhenStart, completeAction) {
        if (interval === void 0) { interval = 1000; }
        if (runWhenStart === void 0) { runWhenStart = true; }
        if (runWhenStart) {
            if (action) {
                action(count);
            }
            // count--;
        }
        var id = setInterval(function () {
            if (count > 0) {
                if (action) {
                    action(count);
                }
                count--;
            }
            else {
                clearInterval(id);
                if (completeAction) {
                    completeAction();
                }
            }
        }, interval);
    };
    /**
     * RFC3986: https://tools.ietf.org/html/rfc3986
     *
     * 字符A~Z、a~z、0~9以及字符 -、_、.、~ 不编码。
     *
     * 其它字符编码成%XY的格式，其中XY是字符对应ASCII码的16进制。示例：半角双引号（"）对应%22。
     *
     * 扩展的UTF-8字符，编码成%XY%ZA…的格式。
     *
     * 空格（ ）编码成 %20，而不是加号（+）。
     *
     * 该编码方式与application/x-www-form-urlencoded MIME格式编码算法相似，但又有所不同。
     *
     * encodeURIComponent:
     * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
     * Not Escaped: A-Z a-z 0-9 - _ . ! ~ * ' ( )
     *
     * !*()'
     * %21 %2A %28 %29 %27
     *
     * @since 2018-08-20
     * @version 1.1.6
     */
    KavenBasic.prototype.EncodeByRFC3986 = function (str) {
        var result = encodeURIComponent(str)
            .ReplaceAll("!", "%21")
            .ReplaceAll("*", "%2A")
            .ReplaceAll("(", "%28")
            .ReplaceAll(")", "%29")
            .ReplaceAll("'", "%27");
        return result;
    };
    /**
     *
     * @param str
     * @version 1.1.11
     * @since 2018-10-19
     */
    KavenBasic.prototype.DecodeByRFC3986 = function (str) {
        var temp = str
            .ReplaceAll("%21", "!")
            .ReplaceAll("%2A", "*")
            .ReplaceAll("%28", "(")
            .ReplaceAll("%29", ")")
            .ReplaceAll("%27", "'");
        return decodeURIComponent(temp);
    };
    /**
     *
     * @see
     * {
     * @link
     * https://stackoverflow.com/questions/7640270/adding-modify-query-string-get-variables-in-a-url-with-javascript
     * }
     * @static
     * @param {string} key
     * @param {string} value
     * @param {string} url
     * @returns
     * @memberof KavenBasic
     * @since 1.1.6
     * @version 2018-08-27
     */
    KavenBasic.prototype.UpdateQueryString = function (param, value, url) {
        var newURL = url;
        // Using a positive lookahead (?=\=) to find the
        // given parameter, preceded by a ? or &, and followed
        // by a = with a value after than (using a non-greedy selector)
        // and then followed by a & or the end of the string
        var val = new RegExp("(\\?|\\&)" + param + "=.*?(?=(&|$))");
        var parts = url.toString().split("#");
        url = parts[0];
        var hash = parts[1];
        var queryString = /\?.+$/;
        // Check if the parameter exists
        if (val.test(url)) {
            // if it does, replace it, using the captured group
            // to determine & or ? at the beginning
            newURL = url.replace(val, "$1" + param + "=" + value);
        }
        else if (queryString.test(url)) {
            // otherwise, if there is a query string at all
            // add the param to the end of it
            newURL = url + "&" + param + "=" + value;
        }
        else {
            // if there's no query string, add one
            newURL = url + "?" + param + "=" + value;
        }
        if (hash) {
            newURL += "#" + hash;
        }
        return newURL;
    };
    /**
     * @static
     * @param {number} time
     * @returns
     * @memberof KavenBasic
     * @version 1.1.7
     * @since 2018-08-30
     */
    KavenBasic.prototype.Sleep = function (time) {
        return new Promise(function (resolve) { return setTimeout(resolve, time); });
    };
    /**
     * @static
     * @param {string} url
     * @returns
     * @memberof KavenBasic
     * @version 1.1.7
     * @since 2018-08-30
     */
    KavenBasic.prototype.RemoveHashFromURL = function (url) {
        var index = url.indexOf("#");
        if (index !== -1) {
            return url.substring(0, index);
        }
        return url;
    };
    /**
     *
     * @param url
     * @since 1.1.7
     * @version 2018-08-30
     */
    KavenBasic.prototype.RemoveQueriesFromURL = function (url) {
        return url.split("?")[0];
    };
    /**
     *
     * @param url
     * @param names
     * @since 1.1.17
     * @version 2019-02-19
     */
    KavenBasic.prototype.RemoveQueryFromURL = function (url) {
        var names = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            names[_i - 1] = arguments[_i];
        }
        var hash = Strings.Empty;
        var index = url.indexOf("#");
        if (index !== -1) {
            hash = url.substring(index);
        }
        for (var _a = 0, names_1 = names; _a < names_1.length; _a++) {
            var name_1 = names_1[_a];
            // prefer to use l.search if you have a location/link object
            var urlParts = url.split("?");
            if (urlParts.length >= 2) {
                var prefix = encodeURIComponent(name_1) + "=";
                var pars = urlParts[1].split(/[&;]/g);
                // reverse iteration as may be destructive
                for (var i = pars.length; i-- > 0;) {
                    // idiom for string.startsWith
                    if (pars[i].lastIndexOf(prefix, 0) !== -1) {
                        pars.splice(i, 1);
                    }
                }
                url =
                    urlParts[0] + (pars.length > 0 ? "?" + pars.join("&") : "");
            }
        }
        return url + hash;
    };
    /**
     *
     * @param url
     * @since 1.1.7
     * @version 2018-08-30
     */
    KavenBasic.prototype.GetFileNameFromURL = function (url) {
        url = this.RemoveQueriesFromURL(url);
        return url.substring(url.lastIndexOf(Strings.Slash) + 1);
    };
    /**
     *
     * @param base
     * @param paths
     * @since 1.1.7
     * @version 2018-08-31
     */
    KavenBasic.prototype.CombinePath = function (base) {
        var paths = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            paths[_i - 1] = arguments[_i];
        }
        var result = base.TrimEnd(Strings.Slash).TrimEnd(Strings.BackSlash);
        return paths
            .reduce(function (accumulator, currentValue) {
            return (accumulator +
                Strings.Slash +
                currentValue
                    .TrimAll(Strings.Slash)
                    .TrimAll(Strings.BackSlash));
        }, result)
            .TrimEnd(Strings.Slash)
            .TrimEnd(Strings.BackSlash);
    };
    /**
     *
     * @param str
     * @version 1.1.13
     * @since 2018-10-21
     */
    KavenBasic.prototype.GetMD5 = function (str) {
        var name = Strings.Names.MD5Instance;
        var md5 = this.GetValue(name, undefined);
        if (md5 === undefined) {
            md5 = new KavenMD5();
            this.SetValue(name, md5);
        }
        return md5.Compute(str);
    };
    /**
     *
     * @param fileExtension
     * @version 1.1.14
     * @since 2018-10-26
     */
    KavenBasic.prototype.GetMIMEByExtension = function (fileExtension) {
        return MIME.All.filter(function (p) {
            return p.Extension.TrimStart(".") ===
                fileExtension.TrimStart(".").toLowerCase();
        });
    };
    /**
     *
     * @param contentType
     * @version 1.1.14
     * @since 2018-10-26
     */
    KavenBasic.prototype.GetMIMEByContentType = function (contentType) {
        return MIME.All.filter(function (p) { return p.Type === contentType.toLowerCase(); });
    };
    /**
     * Assign the enumerable es6 Symbol properties from one or more objects to
     * the first object passed on the arguments.
     * Can be used as a supplement to other extend,
     * assign or merge methods as a polyfill for the Symbols part of the es6 Object.assign method.
     * @param target
     * @param args
     * @since 1.1.15
     * @version 2018-11-02
     * @see https://github.com/jonschlinkert/assign-symbols/blob/master/index.js
     */
    KavenBasic.prototype.AssignSymbols = function (target) {
        var args = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            args[_i - 1] = arguments[_i];
        }
        function isObject(val) {
            return (typeof val === "function" ||
                toString.call(val) === "[object Object]" ||
                Array.isArray(val));
        }
        var toString = Object.prototype.toString;
        var isEnumerable = Object.prototype.propertyIsEnumerable;
        var getSymbols = Object.getOwnPropertySymbols;
        if (!isObject(target)) {
            throw new TypeError("expected the first argument to be an object");
        }
        if (args.length === 0 // ||
        // typeof Symbol !== "function" ||
        // typeof getSymbols !== "function"
        ) {
            return target;
        }
        for (var _a = 0, args_1 = args; _a < args_1.length; _a++) {
            var arg = args_1[_a];
            var names = getSymbols(arg);
            for (var _b = 0, names_2 = names; _b < names_2.length; _b++) {
                var key = names_2[_b];
                if (isEnumerable.call(arg, key)) {
                    target[key] = arg[key];
                }
            }
        }
        return target;
    };
    /**
     * Deeply assign the values of all enumerable-own-properties and symbols f
     * rom one or more source objects to a target object. Returns the target object.
     * @param target
     * @param args
     * @since 1.1.15
     * @version 2018-11-02
     * @see https://github.com/jonschlinkert/assign-deep/blob/master/index.js
     */
    KavenBasic.prototype.AssignDeep = function (target) {
        var args = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            args[_i - 1] = arguments[_i];
        }
        function isObject(val) {
            return (typeof val === "function" ||
                toString.call(val) === "[object Object]");
        }
        function isPrimitive(val) {
            return typeof val === "object"
                ? val === null
                : typeof val !== "function";
        }
        var toString = Object.prototype.toString;
        var i = 0;
        if (isPrimitive(target)) {
            target = args[i++];
        }
        if (!target) {
            target = {};
        }
        for (; i < args.length; i++) {
            if (isObject(args[i])) {
                for (var _a = 0, _b = Object.keys(args[i]); _a < _b.length; _a++) {
                    var key = _b[_a];
                    if (isObject(target[key]) && isObject(args[i][key])) {
                        this.AssignDeep(target[key], args[i][key]);
                    }
                    else {
                        target[key] = args[i][key];
                    }
                }
                this.AssignSymbols(target, args[i]);
            }
        }
        return target;
    };
    /**
     *
     * @param url
     * @since 1.1.17
     * @version 2019-02-26
     */
    KavenBasic.prototype.GetQueryStringFromURL = function (url) {
        var index = url.indexOf("?");
        if (index !== -1) {
            return url.substring(index + 1);
        }
        return undefined;
    };
    /**
     *
     * @param str
     * @version 1.1.20
     * @version 2019-03-29
     */
    KavenBasic.prototype.GetCRC32 = function (str) {
        var name = Strings.Names.CRC32Instance;
        var crc = this.GetValue(name, undefined);
        if (crc === undefined) {
            crc = new KavenCRC(KavenCRC.CRC32);
            this.SetValue(name, crc);
        }
        return crc.Compute(str);
    };
    KavenBasic.prototype.GetCRC64 = function (str) {
        var name = Strings.Names.CRC64Instance;
        var crc = this.GetValue(name, undefined);
        if (crc === undefined) {
            crc = new KavenCRC(KavenCRC.CRC64_ECMA_XZ);
            this.SetValue(name, crc);
        }
        return crc.Compute(str);
    };
    /**
     * Warning: This algorithm is now considered vulnerable and should not be used.
     * @param str
     * @param separator
     * @since 1.1.20
     * @version 2019-03-30
     */
    KavenBasic.prototype.GetSHA1 = function (str) {
        var name = Strings.Names.SHAInstance;
        var sha = this.GetValue(name, undefined);
        if (sha === undefined) {
            sha = new KavenSHA();
            this.SetValue(name, sha);
        }
        return sha.ComputeSHA1(str);
    };
    KavenBasic.prototype.GetSHA256 = function (str) {
        var name = Strings.Names.SHAInstance;
        var sha = this.GetValue(name, undefined);
        if (sha === undefined) {
            sha = new KavenSHA();
            this.SetValue(name, sha);
        }
        return sha.ComputeSHA256(str);
    };
    KavenBasic.prototype.GetSHA224 = function (str) {
        var name = Strings.Names.SHAInstance;
        var sha = this.GetValue(name, undefined);
        if (sha === undefined) {
            sha = new KavenSHA();
            this.SetValue(name, sha);
        }
        return sha.ComputeSHA224(str);
    };
    KavenBasic.prototype.GetSHA512 = function (str) {
        var name = Strings.Names.SHAInstance;
        var sha = this.GetValue(name, undefined);
        if (sha === undefined) {
            sha = new KavenSHA();
            this.SetValue(name, sha);
        }
        return sha.ComputeSHA512(str);
    };
    KavenBasic.prototype.GetSHA384 = function (str) {
        var name = Strings.Names.SHAInstance;
        var sha = this.GetValue(name, undefined);
        if (sha === undefined) {
            sha = new KavenSHA();
            this.SetValue(name, sha);
        }
        return sha.ComputeSHA384(str);
    };
    KavenBasic.prototype.GetSHA512T = function (str, t) {
        var name = Strings.Names.SHAInstance;
        var sha = this.GetValue(name, undefined);
        if (sha === undefined) {
            sha = new KavenSHA();
            this.SetValue(name, sha);
        }
        return sha.ComputeSHA512T(str, t);
    };
    /**
     * @returns `true` if little endian, `false` if big endian
     */
    KavenBasic.prototype.CheckEndian = function () {
        var arrayBuffer = new ArrayBuffer(2);
        var uint8Array = new Uint8Array(arrayBuffer);
        var uint16array = new Uint16Array(arrayBuffer);
        uint8Array[0] = 0xAA; // set first byte
        uint8Array[1] = 0xBB; // set second byte
        if (uint16array[0] === 0xBBAA) {
            // little endian
            return true;
        }
        if (uint16array[0] === 0xAABB) {
            // big endian
            return false;
        }
        else {
            return undefined;
        }
    };
    return KavenBasic;
}());
export { KavenBasic };
export default new KavenBasic();
//# sourceMappingURL=KavenBasic.js.map