# wsemi

#### new wsemi()

Source:
  - _class.mjs, line 1

### Members

#### (static) color

Source:
  - color.mjs, line 1444

顏色轉換

Unit Test: Github

##### Example

Try in Codepen

    import oc from 'wsemi/src/color.mjs'

    let c
    let c1
    let c2
    let r

    c = '#cd'
    r = oc.toRgbaString(c)
    console.log(r)
    // => rgba(205, 205, 205, 1)

    c = '#6a3'
    r = oc.toRgbaString(c)
    console.log(r)
    // => rgba(102, 170, 51, 1)

    c = '#6b8e23'
    r = oc.toRgbaString(c)
    console.log(r)
    // => rgba(107, 142, 35, 1)

    c1 = '#cd'
    c2 = 'hsl (320, 50%, 40%)'
    r = oc.mix(c1, 0.5, c2, 0.5, 'toRgbString')
    console.log(r)
    // => rgb(179, 128, 162)

    c1 = '#cd'
    c2 = 'hsl (320, 50%, 40%)' //rgb(153, 51, 119)
    r = oc.mix(c1, 0, c2, 1, 'toRgbString')
    console.log(r)
    // => rgb(153, 51, 119)

    c1 = 'rgb(250, 120, 50)'
    c2 = 'hsva (320, 100%, 50%, 0.1)'
    r = oc.mix(c1, 0.5, c2, 0.5, 'toRgba')
    console.log(r)
    // => { r: 189, g: 60, b: 68, a: 0.55 }

    c = 'rgb(250, 120, 50)'
    r = oc.toRgbaString(c)
    console.log(r)
    // => rgba(250, 120, 50, 1)

    c = 'rgb(250, 120, 50)'
    r = oc.toHslaString(c)
    console.log(r)
    // => hsla(21, 0.952, 0.588, 1)

    c = 'rgb(250, 120, 50)'
    r = oc.toHsvaString(c)
    console.log(r)
    // => hsva(21, 0.8, 0.98, 1)

    c = 'rgb(250, 120, 50)'
    r = oc.toHexString(c)
    console.log(r)
    // => #fa7832

    c = 'skyblue'
    r = oc.toRgbaString(c)
    console.log(r)
    // => rgba(135, 206, 235, 1)

    c = 'hsl (320, 50%, 40%)'
    r = oc.toRgba(c)
    console.log(r)
    // => { r: 153, g: 51, b: 119, a: 1 }

    c = 'hsva (320, 100%, 50%, 0.1)'
    r = oc.toRgba(c)
    console.log(r)
    // => { r: 128, g: 0, b: 85, a: 0.1 }

    c = { r: 255, g: 150, b: 50 }
    r = oc.toHsla(c)
    console.log(r)
    // => { h: 29, s: 0.672, l: 0.002, a: 1 }

    c = { r: '50%', g: 150, b: 50, a: 0.1 }
    r = oc.toHsva(c)
    console.log(r)
    // => { h: 74, s: 0.667, v: 0.002, a: 0.1 }

    c = { h: 320, s: 0.2, l: 0.15 }
    r = oc.toRgba(c)
    console.log(r)
    // => { r: 46, g: 31, b: 31, a: 1 }

    c = { h: 320, s: '12%', l: '8%', a: 0.1 }
    r = oc.toRgba(c)
    console.log(r)
    // => { r: 23, g: 18, b: 18, a: 0.1 }

    c = { h: 320, s: 0.2, v: 0.15 }
    r = oc.toRgba(c)
    console.log(r)
    // => { r: 38, g: 31, b: 31, a: 1 }

    c = { h: '50%', s: 0.2, l: 0.15 }
    r = oc.toHexString(c)
    console.log(r)
    // => #1f2e2e

    c = { h: '50%', s: 0.2, l: 0.15 }
    r = oc.toRgbaString(c)
    console.log(r)
    // => rgba(31, 46, 46, 1)

    c = { h: '50%', s: 0.2, l: 0.15 }
    r = oc.toRgba(c)
    console.log(r)
    // => { r: 31, g: 46, b: 46, a: 1 }

    c = { h: 180, s: 0.2, l: 0.15 }
    r = oc.toHexString(c)
    console.log(r)
    // => #1f2e2e

    c = { h: '50%', s: '12%', v: '8%', a: 0.1 }
    r = oc.toRgba(c)
    console.log(r)
    // => { r: 20, g: 18, b: 18, a: 0.1 }

### Methods

#### (static) ab2blob(ab) → {Blob}

Source:
  - ab2blob.mjs, line 19

ArrayBuffer資料轉Blob資料

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ab = (new Uint8Array([66, 97, 115])).buffer
    console.log(ab2blob(ab))
    // => Blob {size: 3, type: ""}

##### Parameters:

Name | Type | Description
--- | --- | ---
`ab` | ArrayBuffer | 輸入ArrayBuffer資料

##### Returns:

回傳Blob資料

Type
  Blob

#### (static) ab2u8arr(ab) → {Unit8Array}

Source:
  - ab2u8arr.mjs, line 18

ArrayBuffer轉Unit8Array

Unit Test: Github

##### Example

Try in Codepen

    let ab = (new Uint8Array([66, 97, 115])).buffer
    console.log(ab2u8arr(ab))
    // => new Uint8Array([66, 97, 115])

##### Parameters:

Name | Type | Description
--- | --- | ---
`ab` | ArrayBuffer | 輸入ArrayBuffer

##### Returns:

回傳Unit8Array

Type
  Unit8Array

#### (static) addMonth(g, n) → {String}

Source:
  - addMonth.mjs, line 23

輸入年月並增加/減少月份數量

Unit Test: Github

##### Example

Try in Codepen

    console.log(addMonth('2019-01', 2))
    // => '2019-03'

    console.log(addMonth('2018-12', -1))
    // => '2018-11'

##### Parameters:

Name | Type | Description
--- | --- | ---
`g` | String | 輸入月時間字串
`n` | Integer | 輸入要增加的月份數量整數，可為正負值

##### Returns:

回傳新的月時間字串

Type
  String

#### (static) aes2str(str, key, base64opt) → {String}

Source:
  - aes2str.mjs, line 29

一般字串轉AES字串 使用AES-128-CBC加密，字串採用PKCS#7填充

Unit Test: Github

##### Example

Try in Codepen

    let str = '53616c7465645f5f47214797ac01bc03cceb69ebced4948501ab94ca9644a6dfd277456aead4432cb9c9d74c38c42c79'
    let key = '1234567890abcdefghijk'
    console.log(aes2str(str, key))
    // => 'test中文abcdefghijklmn'

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`str` | String |  |  | 輸入一般字串
`key` | String |  |  | 輸入加密key
`base64` | Boolean | <optional> | `false` | 輸入是否轉為base64字串，預設為false

##### Returns:

回傳經AES轉換後字串，採Hex/base64顯示

Type
  String

#### (static) alive(timeAliveopt) → {Object}

Source:
  - alive.mjs, line 84

偵測單元是否在線

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        function test1() {
            return new Promise((resolve, reject) => {
                let ms = []

                let oAL = alive(1500)
                let t = Date.now()

                let a = { data: 123 }
                let b = { data: '34.56' }

                setTimeout(() => {
                    console.log(parseInt((Date.now() - t)) + 'ms', 'trigger a1')
                    oAL.trigger('a', a)
                }, 500)

                setTimeout(() => {
                    console.log(parseInt((Date.now() - t)) + 'ms', 'trigger a2')
                    oAL.trigger('a', a)
                }, 1900)

                setTimeout(() => {
                    console.log(parseInt((Date.now() - t)) + 'ms', 'trigger b1')
                    oAL.trigger('b', b)
                }, 1000)

                setTimeout(() => {
                    console.log(parseInt((Date.now() - t)) + 'ms', 'trigger b2')
                    oAL.trigger('b', b)
                }, 3000)

                oAL.on('message', function({ eventName, key, data, now }) {
                    console.log(parseInt((Date.now() - t)) + 'ms', { eventName, key, data, now })
                    ms.push(eventName + '|' + key)
                })

                setTimeout(() => {
                    resolve(ms)
                }, 5000)

            })
        }
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // 503ms trigger a1
        // 508ms { eventName: 'enter', key: 'a', data: { data: 123 }, now: 1 }
        // 1001ms trigger b1
        // 1003ms { eventName: 'enter', key: 'b', data: { data: '34.56' }, now: 2 }
        // 1901ms trigger a2
        // 2523ms { eventName: 'leave', key: 'b', data: { data: '34.56' }, now: 1 }
        // 3002ms trigger b2
        // 3004ms { eventName: 'enter', key: 'b', data: { data: '34.56' }, now: 2 }
        // 3430ms { eventName: 'leave', key: 'a', data: { data: 123 }, now: 1 }
        // 4544ms { eventName: 'leave', key: 'b', data: { data: '34.56' }, now: 0 }
        // ["enter|a","enter|b","leave|b","enter|b","leave|a","leave|b"]

    }
    topAsync().catch(() => {})

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`timeAlive` | Integer | <optional> | `10000` | 輸入判斷單元是否斷線之延時整數，單位為毫秒ms，預設為10000

##### Returns:

回傳事件物件，可呼叫事件on、trigger、get。trigger給予單元的唯一key字串與攜帶數據data物件，on為監聽事件，需自行監聽message事件取得單元進出事件。get事件可取得alive內視為存活的單元清單

Type
  Object

#### (static) arr2dt(keys, valuesopt) → {Object}

Source:
  - arr2dt.mjs, line 40

結合keys與values成為物件

Unit Test: Github

##### Example

Try in Codepen

    console.log(arr2dt(['a', 'b']))
    // => { 'a': '', 'b': '' }

    console.log(arr2dt(['a', 'b'], 'xyz'))
    // => { a: 'xyz', b: 'xyz' }

    console.log(arr2dt(['a', 'b'], null))
    // => { a: null, b: null }

    console.log(arr2dt(['a', 'b'], [12.3, '456a']))
    // => { 'a': 12.3, 'b': '456a' }

    console.log(arr2dt(['a', 'b'], [null, '456a']))
    // => { 'a': null, 'b': '456a' }

    console.log(arr2dt(['a', 'b'], [12.3]))
    // => {}

    console.log(arr2dt(['a', 'b'], {}))
    // => { a: {}, b: {} }

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`keys` | Array |  |  | 輸入keys字串陣列
`values` | Array | * | <optional> | `''` | 輸入values物件陣列或需自動展開values成為的陣列，預設''

##### Returns:

回傳組合後物件

Type
  Object

#### (static) arrAccum(vec) → {Array}

Source:
  - arrAccum.mjs, line 20

回傳累加後陣列

Unit Test: Github

##### Example

Try in Codepen

    console.log(arrAccum([1, 2, 3, 4]))
    // => [1, 3, 6, 10]

##### Parameters:

Name | Type | Description
--- | --- | ---
`vec` | Array | 輸入要被累加計算的陣列

##### Returns:

回傳各元素累加後之陣列

Type
  Array

#### (static) arrAdd(arguments) → {Array}

Source:
  - arrAdd.mjs, line 52

各陣列內元素相加，可輸入n個同長度陣列，若需輸入之陣列長度不同則回傳空陣列

Unit Test: Github

##### Example

Try in Codepen

    let v1 = [1, 2, 3, 4]
    let v2 = [0.1, 0.1, 0.1, 0.1]
    let v3 = [11, 22, 33, 44]

    console.log(arrAdd(v1, v2))
    // => [ 1.1, 2.1, 3.1, 4.1 ]

    console.log(arrAdd(v1, v2, v3))
    // => [ 12.1, 24.1, 36.1, 48.1 ]

##### Parameters:

Name | Type | Description
--- | --- | ---
`arguments` | Array | 輸入n個陣列，需同長度，其內元素皆會轉為浮點數，各陣列針對各元素進行相加總

##### Returns:

回傳各元素相加後陣列

Type
  Array

#### (static) arrAt(vall, istart, iendopt) → {Array}

Source:
  - arrAt.mjs, line 29

由vall陣列提取指定欄位(或欄位範圍)之資料 若istart與iend有效, 提取istart~iend欄位 若僅istart有效, 提取istart欄位

Unit Test: Github

##### Example

Try in Codepen

    console.log(arrAt([1, 2, 3, '4', 5, 'abc'], 1))
    // => [2]

    console.log(arrAt([1, 2, 3, '4', 5, 'abc'], 1, 4))
    // => [2, 3, '4', 5]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`vall` | Array |  |  | 輸入要被提取的任意資料陣列
`istart` | Integer |  |  | 輸入起始的欄位指標整數
`iend` | Integer | <optional> | `null` | 輸入結束的欄位指標整數，若不使用則等同於istart，預設null

##### Returns:

回傳提取的任意資料陣列

Type
  Array

#### (static) arrFilter(arr, keywords) → {Array}

Source:
  - arrFilter.mjs, line 121

對arr陣列內各字串進行關鍵字計算，計算是否含有關鍵字與程度，多關鍵字用空白區隔，必要關鍵字可於字首添加「+」，不要關鍵字可於字首添加「-」

Unit Test: Github

##### Example

Try in Codepen

    let arr = [
        'abc def xyz',
        '測試abc中文mnop',
        'Instead of creating yet another opinionated application',
        'Node.js module which can be integrated into a larger application',
    ]
    let kws = null
    let r = null

    kws = 'abc'
    r = arrFilter(arr, kws)
    console.log(r)
    // => [
    //     { hasKeyword: true, weight: 1 },
    //     { hasKeyword: true, weight: 1 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 }
    // ]

    kws = 'def'
    r = arrFilter(arr, kws)
    console.log(r)
    // => [
    //     { hasKeyword: true, weight: 1 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 }
    // ]

    kws = 'def 中文'
    r = arrFilter(arr, kws)
    console.log(r)
    // => [
    //     { hasKeyword: true, weight: 1 },
    //     { hasKeyword: true, weight: 0.25 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 }
    // ]

    kws = 'def 中文 mnop'
    r = arrFilter(arr, kws)
    console.log(r)
    // => [
    //     { hasKeyword: true, weight: 1 },
    //     { hasKeyword: true, weight: 0.5555555555555557 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 }
    // ]

    kws = 'def +yet'
    r = arrFilter(arr, kws)
    console.log(r)
    // => [
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: true, weight: 0.25 },
    //     { hasKeyword: false, weight: 0 }
    // ]

    kws = 'def of module -yet'
    r = arrFilter(arr, kws)
    console.log(r)
    // => [
    //     { hasKeyword: true, weight: 1 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: true, weight: 0.25 }
    // ]

    kws = '+'
    r = arrFilter(arr, kws)
    console.log(r)
    // => [
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 }
    // ]

    kws = '-'
    r = arrFilter(arr, kws)
    console.log(r)
    // => [
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 }
    // ]

    kws = 'def +'
    r = arrFilter(arr, kws)
    console.log(r)
    // => [
    //     { hasKeyword: true, weight: 1 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 },
    //     { hasKeyword: false, weight: 0 }
    // ]

##### Parameters:

Name | Type | Description
--- | --- | ---
`arr` | Array | 輸入要被尋找的字串陣列
`keywords` | String | 輸入要尋找的關鍵字字串

##### Returns:

回傳結果物件陣列

Type
  Array

#### (static) arrFind(vall, vfind) → {Array}

Source:
  - arrFind.mjs, line 48

由vall陣列找尋vfind內各元素之第1位置

Unit Test: Github

##### Example

Try in Codepen

    console.log(arrFind([1, 2, 3, '4', 5, 'abc'], 2))
    // => [ 1 ]

    console.log(arrFind([1, 2, 3, '4', 5, 'abc'], 12))
    // => [ -1 ]

    console.log(arrFind([1, 2, 3, '4', 5, 'abc'], [2]))
    // => [ 1 ]

    console.log(arrFind([1, 2, 3, '4', 5, 'abc'], ['4', 2]))
    // => [ 3, 1 ]

    console.log(arrFind([1, true, 2, 3, '4', true, 5, 'abc'], true))
    // => [ 1 ]

    console.log(arrFind([1, true, 2, 3, '4', true, 5, 'abc'], [true]))
    // => [ 1 ]

    console.log(arrFind([1, 2, { x: 'xyz' }, 3, '4', 5, 'abc'], { x: 'xyz' }))
    // => [ 2 ]

    console.log(arrFind([1, 2, { x: 'xyz' }, 3, '4', 5, 'abc'], [{ x: 'xyz' }]))
    // => [ 2 ]

    console.log(arrFind([1, 2, { x: 'xyz' }, 3, '4', 5, 'abc'], ['4', { x: 'xyz' }]))
    // => [ 4, 2 ]

    console.log(arrFind([1, 2, { x: 'xyz' }, 3, '4', 5, 'abc'], [7, { x: 'xyz' }]))
    // => [-1, 2]

##### Parameters:

Name | Type | Description
--- | --- | ---
`vall` | String | Number | Object | Boolean | Array | 輸入要被尋找的任意資料陣列
`vfind` | String | Number | Object | Boolean | Array | 輸入要尋找的任意資料陣列

##### Returns:

回傳所找到各元素第1位置之陣列

Type
  Array

#### (static) arrGroupByMaxmin(arr, maxmins, optopt) → {Array}

Source:
  - arrGroupByMaxmin.mjs, line 254

依照指定最大最小值物件陣列切分陣列

Unit Test: Github

##### Example

Try in Codepen

    let arr1 = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6]
    let mm1 = [
        {
            min: 0,
            max: 2,
        },
        {
            min: 2,
            max: 5,
        },
    ]
    console.log(arrGroupByMaxmin(arr1, mm1))
    // => [
    //   { min: 0, max: 2, items: [ 1.1 ] },
    //   { min: 2, max: 5, items: [ 2.2, 3.3, 4.4 ] }
    // ]

    let arr2 = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6]
    let mm2 = [
        {
            min: 0,
            max: 2,
        },
        {
            min: 2.5,
            max: 5,
        },
    ]
    console.log(arrGroupByMaxmin(arr2, mm2))
    // => [
    //   { min: 0, max: 2, items: [ 1.1 ] },
    //   { min: 2.5, max: 5, items: [ 3.3, 4.4 ] }
    // ]

    let arr3 = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6]
    let mm3 = [
        {
            min: -1e20,
            max: 2,
        },
        {
            min: 2.5,
            max: 5,
        },
        {
            min: 6,
            max: 1e20,
        },
    ]
    console.log(arrGroupByMaxmin(arr3, mm3))
    // => [
    //   { min: -100000000000000000000, max: 2, items: [ 1.1 ] },
    //   { min: 2.5, max: 5, items: [ 3.3, 4.4 ] },
    //   { min: 6, max: 100000000000000000000, items: [ 6.6 ] }
    // ]

    let arr4 = [
        {
            name: 'a',
            value: 1.1,
        },
        {
            name: 'b',
            value: 2.2,
        },
        {
            name: 'c',
            value: 3.3,
        },
        {
            name: 'd',
            value: 4.4,
        },
        {
            name: 'e',
            value: 5.5,
        },
        {
            name: 'f',
            value: 6.6,
        },
    ]
    let mm4 = [
        {
            min: 0,
            max: 2,
        },
        {
            min: 2,
            max: 5,
        },
    ]
    console.log(JSON.stringify(arrGroupByMaxmin(arr4, mm4), null, 2))
    // => [
    //   {
    //     "min": 0,
    //     "max": 2,
    //     "items": [
    //       {
    //         "name": "a",
    //         "value": 1.1
    //       }
    //     ]
    //   },
    //   {
    //     "min": 2,
    //     "max": 5,
    //     "items": [
    //       {
    //         "name": "b",
    //         "value": 2.2
    //       },
    //       {
    //         "name": "c",
    //         "value": 3.3
    //       },
    //       {
    //         "name": "d",
    //         "value": 4.4
    //       }
    //     ]
    //   }
    // ]

    let arr5 = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6]
    let mm5 = [
        {
            rmin: 0,
            rmax: 2,
        },
        {
            rmin: 2,
            rmax: 5,
        },
    ]
    console.log(arrGroupByMaxmin(arr5, mm5, { keyMin: 'rmin', keyMax: 'rmax' }))
    // => [
    //   { rmin: 0, rmax: 2, items: [ 1.1 ] },
    //   { rmin: 2, rmax: 5, items: [ 2.2, 3.3, 4.4 ] }
    // ]

    let arr6 = [
        {
            name: 'a',
            data: 1.1,
        },
        {
            name: 'b',
            data: 2.2,
        },
        {
            name: 'c',
            data: 3.3,
        },
        {
            name: 'd',
            data: 4.4,
        },
        {
            name: 'e',
            data: 5.5,
        },
        {
            name: 'f',
            data: 6.6,
        },
    ]
    let mm6 = [
        {
            min: 0,
            max: 2,
        },
        {
            min: 2,
            max: 5,
        },
    ]
    console.log(JSON.stringify(arrGroupByMaxmin(arr6, mm6, { keyValue: 'data' }), null, 2))
    // => [
    //   {
    //     "min": 0,
    //     "max": 2,
    //     "items": [
    //       {
    //         "name": "a",
    //         "data": 1.1
    //       }
    //     ]
    //   },
    //   {
    //     "min": 2,
    //     "max": 5,
    //     "items": [
    //       {
    //         "name": "b",
    //         "data": 2.2
    //       },
    //       {
    //         "name": "c",
    //         "data": 3.3
    //       },
    //       {
    //         "name": "d",
    //         "data": 4.4
    //       }
    //     ]
    //   }
    // ]

    let arr7 = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6]
    let mm7 = [
        {
            min: 0,
            max: 2,
        },
        {
            min: 2,
            max: 5,
        },
    ]
    console.log(arrGroupByMaxmin(arr7, mm7, { keyItems: 'result' }))
    // => [
    //   { min: 0, max: 2, result: [ 1.1 ] },
    //   { min: 2, max: 5, result: [ 2.2, 3.3, 4.4 ] }
    // ]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`arr` | Array |  |  | 輸入要被切割的陣列
`maxmins` | Array |  |  | 輸入要切分的最大最小值物件陣列，每個元素需為物件，至少得要包含keyMax與keyMin欄位

`opt`

Object

<optional>

`{}`

輸入設定物件

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`keyMax` | String | <optional> | `'max'` | 輸入maxmins內各元素中，儲存最大值欄位字串，預設'max'
`keyMin` | String | <optional> | `'min'` | 輸入maxmins內各元素中，儲存最小值欄位字串，預設'min'
`keyValue` | String | <optional> | `'value'` | 輸入arr內各元素中，若為物件，則儲存欲判斷數值之欄位字串，預設'value'
`keyItems` | String | <optional> | `'items'` | 輸入回傳maxmins物件陣列中，儲存所屬arr元素之欄位字串，預設'items'

##### Returns:

回傳切割後的陣列

Type
  Array

#### (static) arrHas(vtar, vhas) → {Boolean}

Source:
  - arrHas.mjs, line 65

判斷任一字串陣列vtar內元素，是否「等於」任一字串陣列vhas內元素

Unit Test: Github

##### Example

Try in Codepen

    console.log(arrHas([1, 2, 3, '4', 5, 'abc'], 2))
    // => true

    console.log(arrHas([1, 2, 3, '4', 5, 'abc'], 6))
    // => false

    console.log(arrHas([1, 2, 3, '4', 5, 'abc'], [2]))
    // => true

    console.log(arrHas([1, 2, 3, '4', 5, 'abc'], [6]))
    // => false

    console.log(arrHas([1, 2, 3, '4', 5, 'abc'], ['4', 2]))
    // => true

    console.log(arrHas([1, 2, 3, '4', 5, 'abc'], ['7', 6]))
    // => false

    console.log(arrHas([1, true, 2, 3, '4', true, 5, 'abc'], true))
    // => true

    console.log(arrHas([1, true, 2, 3, '4', true, 5, 'abc'], false))
    // => false

    console.log(arrHas([1, true, 2, 3, '4', true, 5, 'abc'], [true]))
    // => true

    console.log(arrHas([1, true, 2, 3, '4', true, 5, 'abc'], [false]))
    // => false

    console.log(arrHas([1, 2, { x: 'xyz' }, 3, '4', 5, 'abc'], { x: 'xyz' }))
    // => true

    console.log(arrHas([1, 2, { x: 'xyz' }, 3, '4', 5, 'abc'], { x: 'opqr' }))
    // => false

    console.log(arrHas([1, 2, { x: 'xyz' }, 3, '4', 5, 'abc'], [{ x: 'xyz' }]))
    // => true

    console.log(arrHas([1, 2, { x: 'xyz' }, 3, '4', 5, 'abc'], [{ x: 'opqr' }]))
    // => false

    console.log(arrHas([1, 2, { x: 'xyz' }, 3, '4', 5, 'abc'], ['4', { x: 'xyz' }]))
    // => true

    console.log(arrHas([1, 2, { x: 'xyz' }, 3, '4', 5, 'abc'], ['7', { x: 'opqr' }]))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`vtar` | String | Number | Object | Boolean | Array | 輸入被查找的字串陣列或字串
`vhas` | String | Number | Object | Boolean | Array | 輸入查找字串陣列或字串

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) arrInsert(vtar, vhas) → {Boolean}

Source:
  - arrInsert.mjs, line 46

判斷任一字串陣列vtar內元素，是否「等於」任一字串陣列vhas內元素

Unit Test: Github

##### Example

Try in Codepen

    let arr = [1, 2.5, '123']
    let r

    r = arrInsert(arr, 0, 'abc')
    console.log(r)
    // => [ 'abc', 1, 2.5, '123' ]

    r = arrInsert(arr, 1, 'abc')
    console.log(r)
    // => [ 1, 'abc', 2.5, '123' ]

    r = arrInsert(arr, 3, 'abc')
    console.log(r)
    // => [ 1, 2.5, '123', 'abc' ]

    r = arrInsert(arr, 4, 'abc')
    console.log(r)
    // => [ 1, 2.5, '123' ]

    r = arrInsert(arr, 1, null)
    console.log(r)
    // => [ 1, null, 2.5, '123' ]

    r = arrInsert(arr, 1, ['abc', null, 'xyz'])
    console.log(r)
    // => [ 1, 'abc', null, 'xyz', 2.5, '123' ]

##### Parameters:

Name | Type | Description
--- | --- | ---
`vtar` | String | Number | Object | Boolean | Array | 輸入被查找的字串陣列或字串
`vhas` | String | Number | Object | Boolean | Array | 輸入查找字串陣列或字串

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) arrLookupByMaxmin(arr, maxmins, optopt) → {Array}

Source:
  - arrLookupByMaxmin.mjs, line 267

依照指定最大最小值物件陣列，查找陣列內各元素之所屬值

Unit Test: Github

##### Example

Try in Codepen

    let arr1 = [
        {
            name: 'a',
            value: 1.1,
        },
        {
            name: 'b',
            value: 2.2,
        },
        {
            name: 'c',
            value: 3.3,
        },
        {
            name: 'd',
            value: 4.4,
        },
        {
            name: 'e',
            value: 5.5,
        },
        {
            name: 'f',
            value: 6.6,
        },
    ]
    let mm1 = [
        {
            min: 0,
            max: 2,
        },
        {
            min: 2,
            max: 5,
        },
    ]
    console.log(arrLookupByMaxmin(arr1, mm1))
    // => [
    //   { name: 'a', value: 1.1, result: { min: 0, max: 2 } },
    //   { name: 'b', value: 2.2, result: { min: 2, max: 5 } },
    //   { name: 'c', value: 3.3, result: { min: 2, max: 5 } },
    //   { name: 'd', value: 4.4, result: { min: 2, max: 5 } },
    //   { name: 'e', value: 5.5 },
    //   { name: 'f', value: 6.6 }
    // ]

    let arr2 = [
        {
            name: 'a',
            value: 1.1,
        },
        {
            name: 'b',
            value: 2.2,
        },
        {
            name: 'c',
            value: 3.3,
        },
        {
            name: 'd',
            value: 4.4,
        },
        {
            name: 'e',
            value: 5.5,
        },
        {
            name: 'f',
            value: 6.6,
        },
    ]
    let mm2 = [
        {
            rmin: 0,
            rmax: 2,
        },
        {
            rmin: 2,
            rmax: 5,
        },
    ]
    console.log(arrLookupByMaxmin(arr2, mm2, { keyMin: 'rmin', keyMax: 'rmax' }))
    // => [
    //   { name: 'a', value: 1.1, result: { rmin: 0, rmax: 2 } },
    //   { name: 'b', value: 2.2, result: { rmin: 2, rmax: 5 } },
    //   { name: 'c', value: 3.3, result: { rmin: 2, rmax: 5 } },
    //   { name: 'd', value: 4.4, result: { rmin: 2, rmax: 5 } },
    //   { name: 'e', value: 5.5 },
    //   { name: 'f', value: 6.6 }
    // ]

    let arr3 = [
        {
            name: 'a',
            data: 1.1,
        },
        {
            name: 'b',
            data: 2.2,
        },
        {
            name: 'c',
            data: 3.3,
        },
        {
            name: 'd',
            data: 4.4,
        },
        {
            name: 'e',
            data: 5.5,
        },
        {
            name: 'f',
            data: 6.6,
        },
    ]
    let mm3 = [
        {
            min: 0,
            max: 2,
        },
        {
            min: 2,
            max: 5,
        },
    ]
    console.log(arrLookupByMaxmin(arr3, mm3, { keyValue: 'data' }))
    // => [
    //   { name: 'a', data: 1.1, result: { min: 0, max: 2 } },
    //   { name: 'b', data: 2.2, result: { min: 2, max: 5 } },
    //   { name: 'c', data: 3.3, result: { min: 2, max: 5 } },
    //   { name: 'd', data: 4.4, result: { min: 2, max: 5 } },
    //   { name: 'e', data: 5.5 },
    //   { name: 'f', data: 6.6 }
    // ]

    let arr4 = [
        {
            name: 'a',
            value: 1.1,
        },
        {
            name: 'b',
            value: 2.2,
        },
        {
            name: 'c',
            value: 3.3,
        },
        {
            name: 'd',
            value: 4.4,
        },
        {
            name: 'e',
            value: 5.5,
        },
        {
            name: 'f',
            value: 6.6,
        },
    ]
    let mm4 = [
        {
            min: 0,
            max: 2,
        },
        {
            min: 2,
            max: 5,
        },
    ]
    console.log(arrLookupByMaxmin(arr4, mm4, { keyResult: 'res' }))
    // => [
    //   { name: 'a', value: 1.1, res: { min: 0, max: 2 } },
    //   { name: 'b', value: 2.2, res: { min: 2, max: 5 } },
    //   { name: 'c', value: 3.3, res: { min: 2, max: 5 } },
    //   { name: 'd', value: 4.4, res: { min: 2, max: 5 } },
    //   { name: 'e', value: 5.5 },
    //   { name: 'f', value: 6.6 }
    // ]

    let arr5 = [
        {
            name: 'a',
            value: 1.1,
        },
        {
            name: 'b',
            value: 2.2,
        },
        {
            name: 'c',
            value: 3.3,
        },
        {
            name: 'd',
            value: 4.4,
        },
        {
            name: 'e',
            value: 5.5,
        },
        {
            name: 'f',
            value: 6.6,
        },
    ]
    let mm5 = [
        {
            name: 'x1',
            min: 0,
            max: 2,
        },
        {
            name: 'x2',
            min: 2,
            max: 5,
        },
    ]
    console.log(arrLookupByMaxmin(arr5, mm5, {
        keyResult: 'res',
        beforeAddResult: (m) => {
            return m.name
        }
    }))
    // => [
    //   { name: 'a', value: 1.1, res: 'x1' },
    //   { name: 'b', value: 2.2, res: 'x2' },
    //   { name: 'c', value: 3.3, res: 'x2' },
    //   { name: 'd', value: 4.4, res: 'x2' },
    //   { name: 'e', value: 5.5 },
    //   { name: 'f', value: 6.6 }
    // ]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`arr` | Array |  |  | 輸入要被切割的陣列，需為物件陣列，否則無法添加查找結果
`maxmins` | Array |  |  | 輸入要切分的最大最小值物件陣列，每個元素需為物件，至少得要包含keyMax與keyMin欄位

`opt`

Object

<optional>

`{}`

輸入設定物件

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`keyMax` | String | <optional> | `'max'` | 輸入maxmins內各元素中，儲存最大值欄位字串，預設'max'
`keyMin` | String | <optional> | `'min'` | 輸入maxmins內各元素中，儲存最小值欄位字串，預設'min'
`keyValue` | String | <optional> | `'value'` | 輸入arr內各元素中，若為物件，則儲存欲判斷數值之欄位字串，預設'value'
`keyResult` | String | <optional> | `'result'` | 輸入回傳arr物件陣列中，儲存所屬maxmins元素之欄位字串，預設'result'
`beforeAddResult` | function | <optional> | `null` | 輸入儲存至arr物件陣列前的處理函數，預設null

##### Returns:

回傳切割後的陣列

Type
  Array

#### (static) arrSep(arr, num) → {Array}

Source:
  - arrSep.mjs, line 34

依照指定數量切分陣列

Unit Test: Github

##### Example

Try in Codepen

    let arr = ['a', 123, 'xyz', 5.678, null, 'd', [], { x: 'x1', y: 'y1' }]

    console.log(arrSep(arr, 2))
    // => [
    //   [ 'a', 123 ],
    //   [ 'xyz', 5.678 ],
    //   [ null, 'd' ],
    //   [ [], { x: 'x1', y: 'y1' } ]
    // ]

    console.log(arrSep(arr, 3))
    // => [
    //   [ 'a', 123, 'xyz' ],
    //   [ 5.678, null, 'd' ],
    //   [ [], { x: 'x1', y: 'y1' } ]
    // ]

##### Parameters:

Name | Type | Description
--- | --- | ---
`arr` | Array | 輸入要被切割的陣列
`num` | Integer | 輸入要切分數量的整數

##### Returns:

回傳切割後的陣列

Type
  Array

#### (static) arrSort(vall, returnIndexopt, compareKeyopt) → {Array}

Source:
  - arrSort.mjs, line 210

排序vall陣列，可針對純數字、純字串、含固定開頭字元的數字字串、物件陣列進行排列

Unit Test: Github

##### Example

Try in Codepen

    let r

    r = arrSort([1, 30, 4, 21, 100000])
    console.log(r)
    // => [ 1, 4, 21, 30, 100000 ]

    r = arrSort([1, 30, 4, 21, 100000], { returnIndex: true })
    console.log(r)
    // => [ 0, 2, 3, 1, 4 ]

    r = arrSort(['March', 'Jan', 'Feb', 'Dec'])
    console.log(r)
    // => [ 'Dec', 'Feb', 'Jan', 'March' ]

    r = arrSort(['1', '30', '  4  ', '21', '100000'])
    console.log(r)
    // => [ '1', '  4  ', '21', '30', '100000' ]

    r = arrSort(['1', '30', '  4  ', 21, '100000'])
    console.log(r)
    // => [ '1', '  4  ', 21, '30', '100000' ]

    r = arrSort(['abc1', 'abc30', 'abc4', 'abc21', 'abc100000'])
    console.log(r)
    // => [ 'abc1', 'abc4', 'abc21', 'abc30', 'abc100000' ]

    r = arrSort(['1a', '30c', '  4 abc ', '21d', '100000xy'])
    console.log(r)
    // => [ '  4 abc ', '100000xy', '1a', '21d', '30c' ]

    r = arrSort([{ s: 'March', i: 1, }, { s: 'Jan', i: 4, }, { s: 'Feb', i: 100000, }, { s: 'Dec', i: 30, }], { compareKey: 's' })
    console.log(r)
    // => [
    //   { s: 'Dec', i: 30 },
    //   { s: 'Feb', i: 100000 },
    //   { s: 'Jan', i: 4 },
    //   { s: 'March', i: 1 }
    // ]

    r = arrSort([{ s: 'abc1', i: 1, }, { s: 'abc30', i: 4, }, { s: 'abc4', i: 100000, }, { s: 'abc100000', i: 30, }], { compareKey: 's' })
    console.log(r)
    // => [
    //   { s: 'abc1', i: 1 },
    //   { s: 'abc4', i: 100000 },
    //   { s: 'abc30', i: 4 },
    //   { s: 'abc100000', i: 30 }
    // ]

    r = arrSort([{ s: 'March', i: 1, }, { s: 'Jan', i: 4, }, { s: 'Feb', i: 100000, }, { s: 'Dec', i: 30, }], { compareKey: 'i' })
    console.log(r)
    // => [
    //   { s: 'March', i: 1 },
    //   { s: 'Jan', i: 4 },
    //   { s: 'Dec', i: 30 },
    //   { s: 'Feb', i: 100000 }
    // ]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`vall` | Array |  |  | 輸入要被提取的任意資料陣列
`returnIndex` | Boolean | <optional> | `false` | 輸入是否回傳排序指標陣列，預設false
`compareKey` | String | <optional> | `null` | 輸入當vall為物件陣列時，指定取compareKey欄位出來排序，compareKey需為有效字串，預設null

##### Returns:

回傳排序後陣列或指標陣列

Type
  Array

#### (static) b642obj(b64) → {*}

Source:
  - b642obj.mjs, line 19

base64字串轉物件

Unit Test: Github

##### Example

Try in Codepen

    console.log(b642obj('WzEsIjMiLCJhYmMiXQ=='))
    // => [1, '3', 'abc']

##### Parameters:

Name | Type | Description
--- | --- | ---
`b64` | String | 輸入base64字串

##### Returns:

回傳任意物件

Type
  *

#### (static) b642str(b64) → {String}

Source:
  - b642str.mjs, line 19

base64字串轉一般字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(b642str('dGVzdOS4reaWhw=='))
    // => 'test中文'

##### Parameters:

Name | Type | Description
--- | --- | ---
`b64` | String | 輸入base64字串

##### Returns:

回傳一般字串

Type
  String

#### (static) b642u8arr(b64) → {Uint8Array}

Source:
  - b642u8arr.mjs, line 18

base64字串轉Uint8Array

Unit Test: Github

##### Example

Try in Codepen

    console.log(b642u8arr('AQItAA=='))
    // => new Uint8Array([1, 2.3, '45', 'abc'])

##### Parameters:

Name | Type | Description
--- | --- | ---
`b64` | String | 輸入base64字串

##### Returns:

回傳Uint8Array

Type
  Uint8Array

#### (static) b642u16arr(b64) → {Uint16Array}

Source:
  - b642u16arr.mjs, line 19

base64字串轉Uint16Array

Unit Test: Github

##### Example

Try in Codepen

    console.log(b642u16arr('AQItAA=='))
    // => new Uint16Array([1, 2.3, '45', 'abc'])

##### Parameters:

Name | Type | Description
--- | --- | ---
`b64` | String | 輸入base64字串

##### Returns:

回傳Uint16Array

Type
  Uint16Array

#### (static) binstr(s, keys, mode) → {Boolean}

Source:
  - binstr.mjs, line 22

判斷字串s是否「任一出現於、全部包含於」字串陣列keys內元素

Unit Test: Github

##### Example

Try in Codepen

    console.log(binstr('1.25abc', 'ab'))
    // => true

##### Parameters:

Name | Type | Default | Description
--- | --- | --- | ---
`s` | String |  | 輸入要判斷的字串
`keys` | Array | String |  | 輸入字串陣列或字串
`mode` | String | `anyone` | 輸入模式，可選'anyone'與'all'，預設為'anyone'

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) blob2ab(bb) → {Promise}

Source:
  - blob2ab.mjs, line 63

前端Blob或input檔案物件轉ArrayBuffer資料陣列

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let bb = new Blob([new Uint8Array([66, 97, 115])])
    blob2ab(b)
        .then(function(ab){
            console.log(ab)
            // => ArrayBuffer(3) {
            //     [[Int8Array]]: Int8Array(3) [66, 97, 115]
            //     [[Uint8Array]]: Uint8Array(3) [66, 97, 115]
            //     byteLength: 3
            // }
        })

##### Parameters:

Name | Type | Description
--- | --- | ---
`bb` | Blob | File | 輸入Blob或File

##### Returns:

回傳Promise，resolve回傳Blob或File的ArrayBuffer資料陣列，reject回傳錯誤訊息

Type
  Promise

#### (static) blob2b64(bb) → {Promise}

Source:
  - blob2b64.mjs, line 24

前端Blob或input檔案物件轉Base64字串

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let b64 = 'YWJj5ris6Kmm'
    let u8a = b642u8arr(b64)
    let bb = new Blob([u8a])
    blob2b64(bb)
        .then(function(b64Out){
            console.log(b64Out)
            // => data:application/octet-stream;base64,YWJj5ris6Kmm
        })

##### Parameters:

Name | Type | Description
--- | --- | ---
`bb` | Blob | File | 輸入Blob或File

##### Returns:

回傳Promise，resolve回傳Blob或File的Base64字串，reject回傳錯誤訊息

Type
  Promise

#### (static) blob2str(bb) → {Promise}

Source:
  - blob2str.mjs, line 25

前端Blob或input檔案物件轉字串

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let strIn = 'abc測試'
    let b64 = str2b64(strIn)
    let u8a = b642u8arr(b64)
    let bb = new Blob([u8a])
    blob2str(bb)
        .then(function(strOut){
            console.log(strOut)
            // => abc測試
        })

##### Parameters:

Name | Type | Description
--- | --- | ---
`bb` | Blob | File | 輸入Blob或File

##### Returns:

回傳Promise，resolve回傳Blob或File的字串，reject回傳錯誤訊息

Type
  Promise

#### (static) blob2u8arr(bb) → {Promise}

Source:
  - blob2u8arr.mjs, line 24

前端Blob或input檔案物件轉Uint8Array資料陣列

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let u8aIn = new Uint8Array([97, 98, 99, 230, 184, 172, 232, 169, 166])
    let bb = new Blob([u8aIn])
    blob2u8arr(bb)
        .then(function(u8aOut){
            console.log(u8aOut)
            // => Uint8Array(9) [97, 98, 99, 230, 184, 172, 232, 169, 166]
        })

##### Parameters:

Name | Type | Description
--- | --- | ---
`bb` | Blob | File | 輸入Blob或File

##### Returns:

回傳Promise，resolve回傳Blob或File的Uint8Array資料陣列，reject回傳錯誤訊息

Type
  Promise

#### (static) blobs2b64s(bbs) → {Promise}

Source:
  - blobs2b64s.mjs, line 26

前端Blob或input檔案物件陣列，逐一轉為各檔案之Base64資料

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let b64 = 'YWJj5ris6Kmm'
    let u8a = b642u8arr(b64)
    let bb = new Blob([u8a])
    let bbs = [bb]
    blobs2b64s(bbs)
        .then(function(b64){
            console.log(b64)
            // => ["data:application/octet-stream;base64,YWJj5ris6Kmm"]
        })

##### Parameters:

Name | Type | Description
--- | --- | ---
`bbs` | Blob | File | 輸入Blob或File陣列

##### Returns:

回傳Promise，resolve回傳各Blob或File的Base64資料，reject回傳錯誤訊息

Type
  Promise

#### (static) blobs2u8arrs(bbs) → {Promise}

Source:
  - blobs2u8arrs.mjs, line 27

前端Blob或input檔案物件陣列，逐一轉為各檔案之Uint8Array資料陣列

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let u8a = new Uint8Array([97, 98, 99, 230, 184, 172, 232, 169, 166])
    let bb = new Blob([u8a])
    let bbs = [bb]
    blobs2u8arrs(bbs)
        .then(function(u8as){
            console.log(u8as)
            // => [Uint8Array(9)]
            //      0: Uint8Array(9) [97, 98, 99, 230, 184, 172, 232, 169, 166]
            //      length: 1
        })

##### Parameters:

Name | Type | Description
--- | --- | ---
`bbs` | Blob | File | 輸入Blob或File陣列

##### Returns:

回傳Promise，resolve回傳各Blob或File的Uint8Array資料陣列，reject回傳錯誤訊息

Type
  Promise

#### (static) bodyLog(c)

Source:
  - bodyLog.mjs, line 18

前端顯示log訊息，預設插入至body

Unit Test: Github

##### Example

Try in Codepen

    bodyLog('show訊息')
    // => 由html顯示'show訊息'

##### Parameters:

Name | Type | Description
--- | --- | ---
`c` | String | 輸入字串

#### (static) browserView(data, type)

Source:
  - browserView.mjs, line 20

前端瀏覽器以分頁開啟指定數據如文字、圖片、影片、pdf等

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let text = 'abc'
    browserView(u8a, 'text/plain')

    let u8a = new Uint8Array([66, 97, 115])
    browserView(u8a, 'application/pdf')

##### Parameters:

Name | Type | Description
--- | --- | ---
`data` | * | 輸入數據
`type` | String | 輸入數據MIME Type字串，例如'application/pdf'或'text/plain'等，詳見[https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types]

#### (static) browserViewFromBlob(bb, type)

Source:
  - browserViewFromBlob.mjs, line 20

前端瀏覽器以分頁開啟blob數據如文字、圖片、影片、pdf等

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let u8a = new Uint8Array([66, 97, 115])
    let bb = new Blob([u8a])
    browserView(bb, 'application/pdf')

##### Parameters:

Name | Type | Description
--- | --- | ---
`bb` | Blob | 輸入blob數據
`type` | String | 輸入數據MIME Type字串，例如'application/pdf'或'text/plain'等，詳見[https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types]

#### (static) browserViewFromText(text)

Source:
  - browserViewFromText.mjs, line 18

前端瀏覽器以分頁開啟文字資料

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let text = 'abc'
    browserViewFromText(u8a)

##### Parameters:

Name | Type | Description
--- | --- | ---
`text` | String | 輸入文字字串

#### (static) browserViewFromU8arr(u8a, type)

Source:
  - browserViewFromU8arr.mjs, line 19

前端瀏覽器以分頁開啟Uint8Array數據如文字、圖片、影片、pdf等

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let u8a = new Uint8Array([66, 97, 115])
    browserView(u8a, 'application/pdf')

##### Parameters:

Name | Type | Description
--- | --- | ---
`u8a` | Uint8Array | 輸入Uint8Array數據
`type` | String | 輸入數據MIME Type字串，例如'application/pdf'或'text/plain'等，詳見[https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types]

#### (static) bs2u8arr(bs) → {Unit8Array}

Source:
  - bs2u8arr.mjs, line 17

BinaryString轉Unit8Array，BinaryString為UTF-16編碼

Unit Test: Github

##### Example

Try in Codepen

    console.log(bs2u8arr('abc'))
    // => new Uint8Array([97, 98, 99])

##### Parameters:

Name | Type | Description
--- | --- | ---
`bs` | String | 輸入BinaryString字串

##### Returns:

回傳Unit8Array資料

Type
  Unit8Array

#### (static) bufRead(buffer, offset, isBE, mLen, nBytes) → {Number}

Source:
  - bufRead.mjs, line 31

讀取Uint8Array(Nodejs,Browser)或Buffer(Nodejs)資料

Fork: buffer_ieee754

Unit Test: Github

##### Example

Try in Codepen

    let offset = 0
    let isBE = true
    let mLen = 52
    let nBytes = 8
    let b = new Uint8Array([66, 117, 16, 240, 246, 48, 64, 0]) //1447656645380
    let j = bufRead(b, offset, isBE, mLen, nBytes)
    console.log(j)
    // => 1447656645380

##### Parameters:

Name | Type | Description
--- | --- | ---
`buffer` | Uint8Array | Buffer | 輸入Uint8Array(Nodejs,Browser)或Buffer(Nodejs)資料
`offset` | Integer | 輸入平移整數
`isBE` | Boolean | 輸入是否為大端序Big-Endian
`mLen` | Integer | 輸入有效位數整數
`nBytes` | Integer | 輸入使用位元組整數

##### Returns:

回傳數字

Type
  Number

#### (static) bufReadDbl(buffer, offsetopt, isBEopt, mLenopt, nBytesopt) → {Number}

Source:
  - bufReadDbl.mjs, line 23

讀取Uint8Array(Nodejs,Browser)或Buffer(Nodejs)內的浮點數資料

Unit Test: Github

##### Example

Try in Codepen

    let b = new Uint8Array([66, 117, 16, 240, 246, 48, 64, 0]) //1447656645380
    let j = bufReadDbl(b)
    console.log(j)
    // => 1447656645380

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`buffer` | Uint8Array | Buffer |  |  | 輸入Uint8Array(Nodejs,Browser)或Buffer(Nodejs)資料
`offset` | Integer | <optional> | `0` | 輸入平移整數，預設0
`isBE` | Boolean | <optional> | `true` | 輸入是否為大端序Big-Endian，預設true
`mLen` | Integer | <optional> | `52` | 輸入有效位數整數，預設52
`nBytes` | Integer | <optional> | `8` | 輸入使用位元組整數，預設8

##### Returns:

回傳數字

Type
  Number

#### (static) bufWrite(value, buffer, offset, isBE, mLen, nBytes)

Source:
  - bufWrite.mjs, line 37

寫入Uint8Array(Nodejs,Browser)或Buffer(Nodejs)資料

Fork: buffer_ieee754

Unit Test: Github

##### Example

Try in Codepen

    let offset = 0
    let isBE = true
    let mLen = 52
    let nBytes = 8

    let i = 1447656645380 //new Uint8Array([66, 117, 16, 240, 246, 48, 64, 0])
    let b = Buffer.alloc(8)
    bufWrite(i, b, offset, isBE, mLen, nBytes)
    console.log(b)
    // >= <Buffer 42 75 10 f0 f6 30 40 00>
    console.log(new Uint8Array(b))
    // => Uint8Array [66, 117, 16, 240, 246, 48, 64, 0]

##### Parameters:

Name | Type | Description
--- | --- | ---
`value` | Number | 輸入數字
`buffer` | Uint8Array | Buffer | 輸入被寫入的Uint8Array(Nodejs,Browser)或Buffer(Nodejs)資料
`offset` | Integer | 輸入平移整數
`isBE` | Boolean | 輸入是否為大端序Big-Endian
`mLen` | Integer | 輸入有效位數整數
`nBytes` | Integer | 輸入使用位元組整數

#### (static) bufWriteDbl(value, buffer, offsetopt, isBEopt, mLenopt, nBytesopt) → {Number}

Source:
  - bufWriteDbl.mjs, line 27

寫入Uint8Array(Nodejs,Browser)或Buffer(Nodejs)內的浮點數資料，需先依照nBytes宣告Uint8Array或Buffer空間

Unit Test: Github

##### Example

Try in Codepen

    let i = 1447656645380 //new Uint8Array([66, 117, 16, 240, 246, 48, 64, 0])
    let b = Buffer.alloc(8)
    bufWriteDbl(i, b)
    console.log(b)
    // >= <Buffer 42 75 10 f0 f6 30 40 00>
    console.log(new Uint8Array(b))
    // => Uint8Array [66, 117, 16, 240, 246, 48, 64, 0]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`value` | Number |  |  | 輸入數字
`buffer` | Uint8Array | Buffer |  |  | 輸入Uint8Array(Nodejs,Browser)或Buffer(Nodejs)資料
`offset` | Integer | <optional> | `0` | 輸入平移整數，預設0
`isBE` | Boolean | <optional> | `true` | 輸入是否為大端序Big-Endian，預設true
`mLen` | Integer | <optional> | `52` | 輸入有效位數整數，預設52
`nBytes` | Integer | <optional> | `8` | 輸入使用位元組整數，預設8

##### Returns:

回傳數字

Type
  Number

#### (static) cache() → {Object}

Source:
  - cache.mjs, line 299

非同步函數快取

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        function test1() {
            return new Promise((resolve, reject) => {
                let ms = []

                let oc = cache()

                // oc.on('message', function(msg) {
                //     console.log('message', msg)
                // })
                // oc.on('error', function(msg) {
                //     console.log('error', msg)
                // })

                let i = 0
                let j = 0
                function fun(v1, v2) {
                    i++
                    console.log('call fun, count=' + i)
                    ms.push('call fun, count=' + i)
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            j++
                            ms.push(v1 + '|' + v2 + ', count=' + j)
                            resolve(v1 + '|' + v2 + ', count=' + j)
                        }, 300)
                    })
                }

                oc.set('fun', { execFun: fun, inputFun: ['inp1', 'inp2'], timeExpired: 1200 }) //快取1200ms, 但第1次執行就需要300ms, 故執行完畢後只會再保留800ms
                setTimeout(function() {
                    //第1次呼叫, 此時沒有快取只能執行取值
                    oc.get('fun')
                        .then(function(msg) {
                            console.log('fun 1st', msg)
                            ms.push('fun 1st', msg)
                        })
                }, 1)
                setTimeout(function() {
                    //第2次呼叫(50ms), 此時第1次呼叫還沒完成(要到300ms), 故get會偵測並等待, 偵測週期為1000ms, 下次偵測是1050ms, 此時第1次快取尚未過期(1200ms), 故1050ms取值時會拿到第1次快取(count=1)
                    oc.get('fun')
                        .then(function(msg) {
                            console.log('fun 2nd', msg)
                            ms.push('fun 2nd', msg)
                        })
                }, 50)
                setTimeout(function() {
                    //第3次呼叫(250ms), 此時第1次呼叫還沒完成(要到300ms), 故get會偵測並等待, 偵測週期為1000ms, 下次偵測是1250ms, 此時第1次快取已過期(1200ms), 故1250ms取值時會重新執行取值(count=2)
                    oc.get('fun')
                        .then(function(msg) {
                            console.log('fun 3rd', msg)
                            ms.push('fun 3rd', msg)
                        })
                }, 250)
                setTimeout(function() {
                    //第4次呼叫(500ms), 此時第1次呼叫已結束(300ms), 且第1次快取(count=1)未過期(要到1200ms), 故get可拿到第1次計算的快取(count=1)
                    oc.get('fun')
                        .then(function(msg) {
                            console.log('fun 4th', msg)
                            ms.push('fun 4th', msg)
                        })
                }, 500)
                setTimeout(function() {
                    //第5次呼叫(1300ms), 此時第1次快取(count=1)已過期(1200ms), 但第3次已重新執行取值(1250~1550ms執行, 2450ms過期), 故get會偵測並等待, 偵測週期為1000ms, 下次偵測是2300ms, 且此時第3次所得快取(count=2)尚未過期(2450ms), 此時就會拿到第3次所得快取(count=2)
                    oc.get('fun')
                        .then(function(msg) {
                            console.log('fun 5th', msg)
                            ms.push('fun 5th', msg)
                        })
                }, 1300)
                setTimeout(function() {
                    //第6次呼叫(1600ms), 此時第3次所得快取(count=2)還在有效期(1550ms執行結束, 2450ms過期), 故get會拿到第3次所得快取(count=2)
                    oc.get('fun')
                        .then(function(msg) {
                            console.log('fun 6th', msg)
                            ms.push('fun 6th', msg)
                        })
                }, 1600)

                setTimeout(function() {
                    resolve(ms)
                }, 2400)

            })
        }
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // call fun, count=1
        // fun 1st inp1|inp2, count=1
        // fun 4th inp1|inp2, count=1
        // fun 2nd inp1|inp2, count=1
        // call fun, count=2
        // fun 3rd inp1|inp2, count=2
        // fun 6th inp1|inp2, count=2
        // fun 5th inp1|inp2, count=2
        // ["call fun, count=1","inp1|inp2, count=1","fun 1st","inp1|inp2, count=1","fun 4th","inp1|inp2, count=1","fun 2nd","inp1|inp2, count=1","call fun, count=2","inp1|inp2, count=2","fun 3rd","inp1|inp2, count=2","fun 6th","inp1|inp2, count=2","fun 5th","inp1|inp2, count=2"]

        function test2() {
            return new Promise((resolve, reject) => {
                let ms = []

                let oc = cache()

                // oc.on('message', function(msg) {
                //     console.log('message', msg)
                // })
                // oc.on('error', function(msg) {
                //     console.log('error', msg)
                // })

                let i = 0
                let j = 0
                function fun(v1, v2) {
                    i++
                    console.log('call fun, count=' + i)
                    ms.push('call fun, count=' + i)
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            j++
                            ms.push(v1 + '|' + v2 + ', count=' + j)
                            resolve(v1 + '|' + v2 + ', count=' + j)
                        }, 300)
                    })
                }

                oc.getProxy('fun', { execFun: fun, inputFun: ['inp1', 'inp2'], timeExpired: 1200 }) //快取1200ms, 但第1次執行就需要300ms, 故執行完畢後只會再保留800ms
                setTimeout(function() {
                    //第1次呼叫, 此時沒有快取只能執行取值, 因偵測週期為1000ms故得要1001ms才會回應, 會取得第1次結果(count=1)
                    oc.getProxy('fun', { execFun: fun, inputFun: ['inp1', 'inp2'], timeExpired: 1200 })
                        .then(function(msg) {
                            console.log('fun 1st', msg)
                            ms.push('fun 1st', msg)
                        })
                }, 1)
                setTimeout(function() {
                    //第2次呼叫, 此時執行中會等待, 因偵測週期為1000ms, 故得等到下次偵測1100ms才會回應, 此時會取得第1次結果(count=1)
                    oc.getProxy('fun', { execFun: fun, inputFun: ['inp1', 'inp2'], timeExpired: 1200 })
                        .then(function(msg) {
                            console.log('fun 2nd', msg)
                            ms.push('fun 2nd', msg)
                        })
                }, 100)
                setTimeout(function() {
                    //第3次呼叫, 此時已有快取, 故此時500ms就會先回應, 會取得第1次結果(count=1)
                    oc.getProxy('fun', { execFun: fun, inputFun: ['inp1', 'inp2'], timeExpired: 1200 })
                        .then(function(msg) {
                            console.log('fun 3rd', msg)
                            ms.push('fun 3rd', msg)
                        })
                }, 500)
                setTimeout(function() {
                    //第4次呼叫, 此時第1次快取(count=1)已失效, 會重新呼叫函數取值, 取得第2次結果(count=2)
                    oc.getProxy('fun', { execFun: fun, inputFun: ['inp1', 'inp2'], timeExpired: 1200 })
                        .then(function(msg) {
                            console.log('fun 4th', msg)
                            ms.push('fun 4th', msg)
                        })
                }, 1300)

                setTimeout(function() {
                    resolve(ms)
                }, 1700)

            })
        }
        console.log('test2')
        let r2 = await test2()
        console.log(JSON.stringify(r2))
        // test2
        // call fun, count=1
        // fun 3rd inp1|inp2, count=1
        // fun 1st inp1|inp2, count=1
        // fun 2nd inp1|inp2, count=1
        // call fun, count=2
        // fun 4th inp1|inp2, count=2
        // ["call fun, count=1","inp1|inp2, count=1","fun 3rd","inp1|inp2, count=1","fun 1st","inp1|inp2, count=1","fun 2nd","inp1|inp2, count=1","call fun, count=2","inp1|inp2, count=2","fun 4th","inp1|inp2, count=2"]

        function test3() {
            return new Promise((resolve, reject) => {
                let ms = []

                let oc = cache()

                // oc.on('message', function(msg) {
                //     console.log('message', msg)
                // })
                // oc.on('error', function(msg) {
                //     console.log('error', msg)
                // })

                let i = 0
                let j = 0
                function fun(v1, v2) {
                    i++
                    console.log('call fun, count=' + i)
                    ms.push('call fun, count=' + i)
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            j++
                            ms.push(v1 + '|' + v2 + ', count=' + j)
                            resolve(v1 + '|' + v2 + ', count=' + j)
                        }, 300)
                    })
                }

                oc.getProxy('fun', { execFun: fun, inputFun: ['inp1', 'inp2'], timeExpired: 1500 }) //快取1500ms, 但第1次執行就需要300ms, 故執行完畢後只會再保留800ms
                setTimeout(function() {
                    //第1次呼叫(延遲1ms), 此時沒有快取只能執行取值, 因偵測週期為1000ms故得要1001ms才會回應, 回應時為被強制更新(1100ms)之前, 會取得第1次結果(count=1)
                    oc.getProxy('fun', { execFun: fun, inputFun: ['inp1', 'inp2'], timeExpired: 1500 })
                        .then(function(msg) {
                            console.log('fun 1st', msg)
                            ms.push('fun 1st', msg)
                        })
                }, 1)
                setTimeout(function() {
                    //第2次呼叫(延遲200ms), 此時執行中會等待, 因偵測週期為1000ms, 故得等到下次偵測1200ms才會回應, 回應時為被強制更新(1100ms)之後, 此時會取得被強制更新的結果(abc)
                    oc.getProxy('fun', { execFun: fun, inputFun: ['inp1', 'inp2'], timeExpired: 1500 })
                        .then(function(msg) {
                            console.log('fun 2nd', msg)
                            ms.push('fun 2nd', msg)
                        })
                }, 200)
                setTimeout(function() {
                    //第3次呼叫, 此時已有快取, 故此時500ms就會先回應, 會取得第1次結果(count=1)
                    oc.getProxy('fun', { execFun: fun, inputFun: ['inp1', 'inp2'], timeExpired: 1500 })
                        .then(function(msg) {
                            console.log('fun 3rd', msg)
                            ms.push('fun 3rd', msg)
                        })
                }, 500)
                setTimeout(function() {
                    //更新快取值(延遲1100ms), 快取值為abc, 快取時間也被更新至此時, 故會重新計算1500ms才會失效
                    oc.update('fun', 'abc')
                    console.log('fun update', 'abc')
                    ms.push('fun update', 'abc')
                }, 1100)
                setTimeout(function() {
                    //第4次呼叫(延遲1300ms), 此時會取得被強制更新之快取值(abc), 快取還剩1300ms才失效(也就是在2600ms失效)
                    oc.getProxy('fun', { execFun: fun, inputFun: ['inp1', 'inp2'], timeExpired: 1500 })
                        .then(function(msg) {
                            console.log('fun 4th', msg)
                            ms.push('fun 4th', msg)
                        })
                }, 1300)
                setTimeout(function() {
                    //第5次呼叫(延遲2700ms), 此時被強制更新之快取值(abc)已失效, 會重新呼叫函數取值, 取得第2次結果(count=2)
                    oc.getProxy('fun', { execFun: fun, inputFun: ['inp1', 'inp2'], timeExpired: 1500 })
                        .then(function(msg) {
                            console.log('fun 5th', msg)
                            ms.push('fun 5th', msg)
                        })
                }, 2700)

                setTimeout(function() {
                    resolve(ms)
                }, 3100)

            })
        }
        console.log('test3')
        let r3 = await test3()
        console.log(JSON.stringify(r3))
        // test3
        // call fun, count=1
        // fun 3rd inp1|inp2, count=1
        // fun 1st inp1|inp2, count=1
        // fun update abc
        // fun 2nd abc
        // fun 4th abc
        // call fun, count=2
        // fun 5th inp1|inp2, count=2
        // ["call fun, count=1","inp1|inp2, count=1","fun 3rd","inp1|inp2, count=1","fun 1st","inp1|inp2, count=1","fun update","abc","fun 2nd","abc","fun 4th","abc","call fun, count=2","inp1|inp2, count=2","fun 5th","inp1|inp2, count=2"]

    }
    topAsync().catch(() => {})

##### Returns:

回傳事件物件，可呼叫事件on、set、get、getProxy、clear、remove。on為監聽事件，需自行監聽message與error事件。set為加入待執行函數，函數結束回傳欲快取的值，set傳入參數依序為key與快取物件，key為唯一識別字串，而快取物件需設定欄位execFun為待執行的非同步函數、inputFun為待執行函數execFun的傳入參數組、timeExpired為過期時間整數，單位ms，預設5000。get為依照key取得目前快取值。getProxy為合併set與get功能，直接set註冊待執行函數與取值，傳入參數同set，回傳同get。update為強制更新key所屬快取值，同時也會更新該快取之時間至當前。clear為清除key所屬快取的是否執行標記，使該快取視為需重新執行函數取值。remove為直接清除key所屬快取，清除後用set重設

Type
  Object

#### (static) cbol(v) → {Boolean}

Source:
  - cbol.mjs, line 56

布林值或字串轉布林值

Unit Test: Github

##### Example

Try in Codepen

    console.log(cbol(true))
    // => true

    console.log(cbol(false))
    // => false

    console.log(cbol(0))
    // => false

    console.log(cbol(1))
    // => true

    console.log(cbol('true'))
    // => true

    console.log(cbol('tRuE'))
    // => true

    console.log(cbol('TRUE'))
    // => true

    console.log(cbol('abc'))
    // => false

    console.log(cbol(''))
    // => false

    console.log(cbol([]))
    // => false

    console.log(cbol({}))
    // => false

    console.log(cbol(null))
    // => false

    console.log(cbol(undefined))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意值

##### Returns:

回傳布林值

Type
  Boolean

#### (static) cdbl(v) → {Number}

Source:
  - cdbl.mjs, line 19

數字或字串轉浮點數 若輸入非數字則回傳0

Unit Test: Github

##### Example

Try in Codepen

    console.log(cdbl('25'))
    // => 25

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | Number | String | 輸入數字或字串

##### Returns:

回傳數字

Type
  Number

#### (static) cfilesize(b) → {String}

Source:
  - cfilesize.mjs, line 33

檔案大小(bytes)自動轉換單位 可調整檔案大小為b,kb,mb,gb，並添加單位 若輸入不是數字或字串時則回傳空字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(cfilesize(0))
    // => '0.0 b'

    console.log(cfilesize(100))
    // => '100.0 b'

    console.log(cfilesize(2048))
    // => '2.0 kb'

    console.log(cfilesize(2000000))
    // => '1.9 mb'

    console.log(cfilesize(2000000000))
    // => '1.9 gb'

##### Parameters:

Name | Type | Description
--- | --- | ---
`b` | Number | String | 輸入單位需為bytes的檔案大小，可為數字或字串

##### Returns:

回傳自動轉換單位後的字串

Type
  String

#### (static) cfinancial(v, idigopt) → {String}

Source:
  - cfinancial.mjs, line 27

數字或字串轉金融格式(百分位添加逗號)表示 若輸入不是數字或字串時則回傳空字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(cfinancial(0.123456789, 3))
    // => '0.123'

    console.log(cfinancial(1234567.89))
    // => '1,234,568'

    console.log(cfinancial(1234567.89, 1))
    // => '1,234,567.9'

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`v` | Number | String |  |  | 輸入數字或字串
`idig` | Integer | <optional> | `0` | 輸入指定小數位整數，預設為0

##### Returns:

回傳金融格式的字串

Type
  String

#### (static) cint(v) → {Integer}

Source:
  - cint.mjs, line 23

數字或字串四捨五入轉整數 若輸入非數字則回傳0

Unit Test: Github

##### Example

Try in Codepen

    console.log(cint('1.5'))
    // => 2

    console.log(cint('-1.5'))
    // => -1

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | Number | String | 輸入數字或字串

##### Returns:

回傳四捨五入後整數

Type
  Integer

#### (static) clearXSS(obj) → {Object|Array|String}

Source:
  - clearXSS.mjs, line 27

清除xss攻擊語法

Depend on: https://jsxss.com/zh/index.html

Unit Test: Github

##### Example

Try in Codepen

    console.log(clearXSS(`><script>alert('XSS')</script>`))
    // => `&gt;&lt;script&gt;alert('XSS')&lt;/script&gt;`

    console.log(clearXSS(`<img src="javascript:alert('XSS')">`))
    // => `<img src>`

##### Parameters:

Name | Type | Description
--- | --- | ---
`obj` | Object | Array | String | 輸入資料

##### Returns:

輸出資料

Type
  Object | Array | String

#### (static) composeTreeObj(items, optopt, bindKeyopt, bindParentopt, bindChildrenopt, saveExtPropsopt) → {Array}

Source:
  - composeTreeObj.mjs, line 93

組合項目物件陣列成為樹狀物件

Unit Test: Github

##### Example

Try in Codepen

    let data = [
        {
            id: 1,
            text: '1-a',
        },
        {
            id: 2,
            text: '2-b',
        },
        {
            id: 3,
            text: '3-c',
            parentId: 2,
        },
        {
            id: 4,
            text: '4-d',
            parentId: 2,
        },
        {
            id: 5,
            text: '5-e',
            parentId: 3,
        },
        {
            id: 6,
            text: 'empty',
        },
    ]
    let r = composeTreeObj(data)
    let cr = JSON.stringify(r)
    console.log(cr)
    // => [
    //   {
    //     "id": 1,
    //     "text": "1-a"
    //   },
    //   {
    //     "id": 2,
    //     "text": "2-b",
    //     "children": [
    //       {
    //         "id": 3,
    //         "text": "3-c",
    //         "parentId": 2,
    //         "children": [
    //           {
    //             "id": 5,
    //             "text": "5-e",
    //             "parentId": 3
    //           }
    //         ]
    //       },
    //       {
    //         "id": 4,
    //         "text": "4-d",
    //         "parentId": 2
    //       }
    //     ]
    //   },
    //   {
    //     "id": 6,
    //     "text": "empty"
    //   }
    // ]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`items` | Array |  |  | 輸入項目物件陣列
`opt` | Object | <optional> | `{}` | 輸入設定物件，預設{}
`bindKey` | String | <optional> | `'id'` | 輸入項目物件識別用欄位字串，預設'id'
`bindParent` | String | <optional> | `'parentId'` | 輸入項目物件內存放父節點欄位字串，預設'parentId'
`bindChildren` | String | <optional> | `'children'` | 輸入產生樹狀物件時，各節點內存放子節點欄位字串，預設'children'
`saveExtProps` | Boolean | <optional> | `false` | 輸入是否儲存項目物件從屬資訊布林值，預設false

##### Returns:

回傳物件陣列

Type
  Array

#### (static) copyStrToClipboard(str, optopt) → {String}

Source:
  - copyStrToClipboard.mjs, line 24

複製字串至剪貼簿

Unit Test: Github

##### Example

Try in Codepen

    copyStrToClipboard('The Woodman(樵夫) set to work at once, and so...')

    let ele = document.querySelector('#id')
    copyStrToClipboard('The Woodman(樵夫) set to work at once, and so...', { eleParent: ele })

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`str` | String |  |  | 輸入欲複製至剪貼簿的字串

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`eleParent` | HTMLElement | <optional> | `document.body` | 輸入臨時插入的父層元素，因例如於鎖定焦點(focus)的區域內要複製字串，會因臨時創建的textarea元素無法聚焦導致無法複製至剪貼簿，故得由外部傳入可聚焦的父層元素供創建textarea之用，預設document.body

##### Returns:

回傳字串，若成功則為空字串，若失敗則回傳錯誤訊息

Type
  String

#### (static) cstr(v) → {String}

Source:
  - cstr.mjs, line 19

輸入轉字串 若輸入不是數字或字串時則回傳空字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(cstr(2.25))
    // => '2.25'

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | Number | String | 輸入資料

##### Returns:

回傳字串

Type
  String

#### (static) day2cht(t, bNoDisplayYearopt) → {String}

Source:
  - day2cht.mjs, line 19

日時間轉中文格式時間字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(day2cht('2019-01-02'))
    // => '民國 108 年 1 月 2 日'

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`t` | String |  |  | 輸入日時間字串
`bNoDisplayYear` | boolean | <optional> | `false` | 輸入是否輸出民國年，預設為false

##### Returns:

回傳中文格式時間字串

Type
  String

#### (static) debounce(msopt)

Source:
  - debounce.mjs, line 121

函數去除抖動

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        function test1() {
            return new Promise((resolve, reject) => {
                let ms = []

                let dbc = debounce(300)

                let i = 0
                function core(name) {
                    i++
                    ms.push({ name, i })
                    console.log({ name, i })
                }

                setTimeout(function() {
                    dbc(() => {
                        core('A')
                    })
                }, 100)
                setTimeout(function() {
                    dbc(() => {
                        core('B')
                    })
                }, 200)
                setTimeout(function() {
                    dbc(() => {
                        core('C')
                    })
                }, 250)
                setTimeout(function() {
                    dbc(() => {
                        core('D')
                    })
                }, 350)
                setTimeout(function() {
                    dbc(() => {
                        core('E')
                    })
                }, 400)
                setTimeout(function() {
                    resolve(ms)
                }, 800)
            })
        }
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // { name: 'E', i: 1 }
        // [{"name":"E","i":1}]

        function test2() {
            return new Promise((resolve, reject) => {
                let ms = []

                let dbc = debounce(300)

                let i = 0
                function core(name) {
                    i++
                    ms.push({ name, i })
                    console.log({ name, i })
                }

                setTimeout(function() {
                    dbc(() => {
                        core('A')
                    })
                }, 50)
                setTimeout(function() {
                    dbc(() => {
                        core('B')
                    })
                }, 100)
                setTimeout(function() {
                    dbc(() => {
                        core('C')
                    })
                }, 150)
                setTimeout(function() {
                    dbc(() => {
                        core('D')
                    })
                }, 500)
                setTimeout(function() {
                    dbc(() => {
                        core('E')
                    })
                }, 550)
                setTimeout(function() {
                    resolve(ms)
                }, 1400)
            })
        }
        console.log('test2')
        let r2 = await test2()
        console.log(JSON.stringify(r2))
        // test2
        // { name: 'C', i: 1 }
        // { name: 'E', i: 2 }
        // [{"name":"C","i":1},{"name":"E","i":2}]

    }
    topAsync().catch(() => {})

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ms` | Integer | <optional> | `300` | 輸入未有調用的時間區間，為正整數，預設300ms

#### (static) delay(msopt) → {Promise}

Source:
  - delay.mjs, line 19

Promise延遲毫秒

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    delay(1000)
    // => 延遲1s才執行

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ms` | Number | <optional> | `1` | 輸入延遲毫秒整數，預設10ms

##### Returns:

} 回傳Promise，resolve代表延遲完畢

Type
  Promise

#### (static) dig(v, idigopt) → {String}

Source:
  - dig.mjs, line 28

數字取指定小數位的字串 為字串故可自動補0 console.log(1.005.toFixed(2)) //1.00 console.log(dig(1.005, 2)) //1.01 若輸入不是數字或字串時則回傳空字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(dig(0.123456789, 3))
    // => '0.123'

    console.log(dig(0.123456789, 4))
    // => '0.1235'

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`v` | Number | String |  |  | 輸入數字或字串
`idig` | Integer | <optional> | `0` | 輸入指定小數位整數，預設為0

##### Returns:

回傳取指定小數位的字串

Type
  String

#### (static) digExp(v, idigopt) → {String}

Source:
  - digExp.mjs, line 22

數字取指定小數位，小於1e-6改指數顯示 若輸入不是數字或字串時則回傳空字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(digExp(0.000000123456789, 2))
    // => '1.23e-7'

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`v` | Number | String |  |  | 輸入數字或字串
`idig` | Integer | <optional> | `0` | 輸入指定小數位整數，預設為0

##### Returns:

回傳取指定小數位的字串

Type
  String

#### (static) domAlert(msg, optopt) → {Promise}

Source:
  - domAlert.mjs, line 221

前端彈出訊息視窗

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    domAlert('提示訊息')

    domAlert('提示訊息', {type:'error'})

    domAlert('提示訊息', {backgroundColor:'rgba(220,220,220,0.3)'})

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`msg` | String |  |  | 輸入彈窗訊息字串，可為html

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`type` | String | <optional> | `'success'` | 輸入訊息種類字串，可使用'success'、'warning'、'error'，預設'success'
`icon` | String | <optional> | `''` | 輸入圖標字串，可為html，預設依照type給予指定圖標，指定圖標詳見程式碼
`position` | String | <optional> | `'top-right'` | 輸入位置字串，可使用'top-right'、'top-left'、'bottom-right'、'bottom-left'，預設'top-right'
`time` | Number | <optional> | `4000` | 輸入顯示時間長度數字，單位ms，預設4000
`paddingStyle` | Object | <optional> | `{top:14,right:26,bottom:14,left:14}` | 輸入內寬設定物件，可輸入top、bottom、left、right，單位為px，預設{top:14,right:26,bottom:14,left:14}
`textColor` | String | <optional> | `'#000'` | 輸入文字顏色字串，預設'#000'
`backgroundColor` | String | <optional> | `'#fff'` | 輸入背景顏色字串，預設'#fff'
`borderWidth` | Number | <optional> | `1` | 輸入邊框寬度數字，單位px，預設1
`borderColor` | String | <optional> | `'#ebeef5'` | 輸入邊框顏色字串，預設'#ebeef5'
`borderRadius` | Number | <optional> | `8` | 輸入邊框圓角數字，單位px，預設8
`shadowStyle` | String | <optional> | `'0 2px 12px 0 rgba(0,0,0,.1)'` | 輸入陰影樣式字串，預設'0 2px 12px 0 rgba(0,0,0,.1)'
`closeIconShift` | Object | <optional> | `{top:10,right:10}` | 輸入關閉按鈕平移距離設定物件，可輸入top、bottom、left、right，單位為px，若需要位於右上角則需設定top與right，預設{top:10,right:10}

##### Returns:

回傳Promise，resolve代表彈窗關閉，無reject

Type
  Promise

#### (static) domAppend(eleParent, itemChild)

Source:
  - domAppend.mjs, line 19

前端於DOM元素內最後處插入元素或Html文字等

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let html = '<div>abc</div>'
    domAppend(document.querySelector('#id'),html)

##### Parameters:

Name | Type | Description
--- | --- | ---
`eleParent` | HTMLElement | 輸入目標DOM元素
`itemChild` | HTMLElement | String | 輸入要插入DOM元素或Html文字等內容

#### (static) domCancelEvent(event)

Source:
  - domCancelEvent.mjs, line 18

前端DOM元素事件停止傳遞事件

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    window.addEventListener('touchstart', (e) => {
        domCancelEvent(e)
    })

##### Parameters:

Name | Type | Description
--- | --- | ---
`event` | HTMLEvent | 輸入event物件

#### (async, static) domConvertToPic(ele, optopt) → {Promise}

Source:
  - domConvertToPic.mjs, line 40

前端DOM元素轉圖片

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    domConvertToPic(ele, { scale: 3 })
        .then((b64)=>{
            // => iVBORw0KGgoAAAANSU...
        })

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ele` | HTMLElement |  |  | 輸入元素

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`scale` | Number | <optional> | `1` | 輸入縮放比例數字，需大於等於1，預設1
`toBase64` | Boolean | <optional> | `true` | 輸入是否輸出為base64圖片，預設true
`picType` | String | <optional> | `'image/png'` | 輸入輸出為base64圖片時的圖片格式，可選'image/jpeg'與'image/png'，使用'image/jpeg'時若無背景預設為黑色，預設'image/png'

##### Returns:

回傳Promise，resolve為成功時的產出圖片，reject為失敗訊息

Type
  Promise

#### (async, static) domConvertToPicDyn(ele, optopt, pathItems) → {Promise}

Source:
  - domConvertToPicDyn.mjs, line 27

前端DOM元素圖片，採用動態加載技術

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    domConvertToPicDyn(ele, { scale: 3 })
        .then((b64)=>{
            // => iVBORw0KGgoAAAANSU...
        })

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ele` | HTMLElement |  |  | 輸入元素

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`scale` | Number | <optional> | `1` | 輸入縮放比例數字，需大於等於1，預設1
`toBase64` | Boolean | <optional> | `true` | 輸入是否輸出為base64圖片，預設true
`picType` | String | <optional> | `'image/png'` | 輸入輸出為base64圖片時的圖片格式，可選'image/jpeg'與'image/png'，使用'image/jpeg'時若無背景預設為黑色，預設'image/png'

`pathItems` | String | Object | Array |  |  | 輸入資源字串、字串陣列、物件、物件陣列

##### Returns:

回傳Promise，resolve回傳使用者瀏覽器資訊物件，reject回傳錯誤訊息

Type
  Promise

#### (static) domDetect(f) → {Object}

Source:
  - domDetect.mjs, line 37

前端監聽DOM元素resize、resizeWithWindow事件，其中resizeWithWindow為dom resize與window resize皆會觸發的事件

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    //監聽dom
    let de = domDetect(() => {
        return document.querySelector('#id')
    })
    de.on('resize', (s) => {
        console.log('resize', s)
    })
    de.on('resizeWithWindow', (s) => {
        console.log('resizeWithWindow', s)
    })
    de.on('display', (s) => {
        console.log('display', s)
    })

    //釋放監聽
    de.clear()

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`f` | function |  |  | 輸入取得dom函數
`opt.timeInterval` | Integer | <optional> | `20` | 輸入定期偵測時間整數，預設20毫秒
`opt.tolerancePixel` | Integer | <optional> | `1` | 輸入容許誤差整數，單位px，預設1

##### Returns:

回傳物件，可使用on與clear函數，on可監聽resize與resizeWithWindow事件，clear為釋放監聽

Type
  Object

#### (static) domDrag(ele, optopt) → {Object}

Source:
  - domDrag.mjs, line 592

前端DOM元素拖曳事件

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    //監聽dom
    let dd = domDrag(document.querySelector('#id'), { group:'group', attIndex: 'dragindex' })

    //change
    dd.on('change', (msg) => {
        console.log('change', msg)
    })
    dd.on('start', (msg) => {
        console.log('start', msg)
    })
    dd.on('move', (msg) => {
        console.log('move', msg)
    })
    dd.on('enter', (msg) => {
        console.log('enter', msg)
    })
    dd.on('leave', (msg) => {
        console.log('leave', msg)
    })
    dd.on('drop', (msg) => {
        console.log('drop', msg)
    })

    //釋放監聽
    dd.clear()

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ele` | HTMLElement |  |  | 輸入元素

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`attIdentify` | String | <optional> | `'dragid'` | 輸入預覽元素唯一識別用之屬性名稱字串，預設'dragid'
`attIndex` | String | <optional> | `'dragindex'` | 輸入預覽元素順序指標之屬性名稱字串，預設'dragindex'
`attGroup` | String | <optional> | `'draggroup'` | 輸入預覽元素群組之屬性名稱字串，預設'draggroup'
`group` | String | <optional> | `'group'` | 輸入預覽元素群組字串，預設'group'
`timeDragStartDelay` | Number | <optional> | `120` | 輸入預覽元素由點擊後延遲出現的時間數字，單位ms，預設120。使用pointerEvents會導致游標樣式失效，故延遲顯示可用來讓點擊事件穿透
`previewOpacity` | Number | <optional> | `0.4` | 輸入預覽元素透明度數字，預設0.4
`previewDisabledOpacity` | Number | <optional> | `0.2` | 輸入無效時(位於非可拖曳元素內)預覽元素透明度數字，預設0.2
`previewBackground` | String | <optional> | `'white'` | 輸入預覽元素背景顏色字串，預設'white'
`previewBorderWidth` | Number | <optional> | `1` | 輸入預覽元素邊框寬度數字，預設1
`previewBorderColor` | String | <optional> | `'#f26'` | 輸入預覽元素邊框顏色字串，預設'#f26'

##### Returns:

回傳物件，可使用on與clear函數，on可監聽change、start、move、enter、leave、drop事件，clear為釋放監聽

Type
  Object

#### (static) domDragBarAndScroll(panel, bar, optopt, getHeighRatioopt, getWidthRatioopt, stopScrollPropagationForPanelopt, stopTouchDragPropagationForPanelopt, useTouchDragForPanelopt) → {Object}

Source:
  - domDragBarAndScroll.mjs, line 39

前端監聽指定panel與bar的DOM元素，可偵測滾輪與拖曳bar事件

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    //監聽dom
    let divPanel = document.querySelector('#id_panel')
    let divBar = document.querySelector('#id_bar')
    let getHeighRatio = () => 0.9
    let das = domDragBarAndScroll(divPanel, divBar, { getHeighRatio, stopScrollPropagationForPanel: true, stopTouchDragPropagationForPanel: true })
    das.on('scrollPanel', () => {})
    das.on('pressBar', () => {})
    das.on('dragBar', () => {})
    das.on('freeBar', () => {})

    //釋放監聽
    das.clear()

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`panel` | HTMLElement |  |  | 輸入panel元素
`bar` | HTMLElement |  |  | 輸入bar元素
`opt` | Object | <optional> | `{}` | 輸入設定物件，預設{}
`getHeighRatio` | function | <optional> | `()=>1` | 輸入取得高度比例函數，因組件本身或內容物可能會調整尺寸, 故需由外部給予函數取得當前heighRatio，預設()=>1
`getWidthRatio` | function | <optional> | `()=>1` | 輸入取得寬度比例函數，因組件本身或內容物可能會調整尺寸, 故需由外部給予函數取得當前widthRatio，預設()=>1
`stopScrollPropagationForPanel` | Boolean | <optional> | `false` | 輸入是否停用滑鼠捲動事件向上傳遞布林值，預設false
`stopTouchDragPropagationForPanel` | Boolean | <optional> | `false` | 輸入是否停用手機拖曳事件向上傳遞布林值，預設false
`useTouchDragForPanel` | Boolean | <optional> | `true` | 輸入是否使用手機拖曳事件布林值，預設true

##### Returns:

回傳物件，可使用on與clear函數，on可監聽pressBar、dragBar、freeBar事件，clear為釋放監聽

Type
  Object

#### (static) domDragPreview(optopt) → {Object}

Source:
  - domDragPreview.mjs, line 39

前端針對DOM元素拖曳時產生其預覽(拷貝)對象

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let pv = domDragPreview({
        attIdentify,
        containerOpacity: previewOpacity,
        containerBackground: previewBackground,
        containerBorderWidth: previewBorderWidth,
        containerBorderColor: previewBorderColor,
    })
    pv.createPreview()
    pv.removeDragPreview()
    pv.clear()

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`attIdentify` | String | <optional> | `'dragprevid'` | 輸入儲存於DOM的識別欄位名稱字串，預設'dragprevid'
`containerOpacity` | Number | <optional> | `0.4` | 輸入預覽元素透明度數字，預設0.4
`containerBackground` | String | <optional> | `'white'` | 輸入預覽元素背景顏色字串，預設'white'
`containerBorderWidth` | Number | <optional> | `1` | 輸入預覽元素邊框寬度數字，預設1
`containerBorderColor` | String | <optional> | `'#f26'` | 輸入預覽元素邊框顏色字串，預設'#f26'

##### Returns:

回傳物件，內含createPreview、updateDragPreview、pauseDragPreview、removeDragPreview、setNodeStyle、setCoverStyle、setSellStyle、setContainerStyle、clear事件

Type
  Object

#### (static) domDropFiles(ele) → {Object}

Source:
  - domDropFiles.mjs, line 170

前端取得拖曳進指定元素的檔案陣列

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    let ev = domDropFiles(ele)
    ev.on('getFiles', ({ files, filesTree, entries, cb }) => {
        console.log(files, filesTree, entries)
        cb()
    })
    ev.on('dropIn', () => {
        console.log('dropIn')
    })
    ev.on('dropOut', () => {
        console.log('dropOut')
    })
    ev.on('error', (err) => {
        console.log('error', err)
    })

##### Parameters:

Name | Type | Description
--- | --- | ---
`ele` | HTMLElement | 輸入dom元素

##### Returns:

回傳物件，包含emit與off事件，emit可監聽dropIn、dropOut、getFiles，通過監聽getFiles即可取得拖曳進指定元素的檔案陣列，並呼叫其內回調函數cb，方能繼續觸發dropOut事件

Type
  Object

#### (static) domFadeIn(ele, optopt)

Source:
  - domFadeIn.mjs, line 26

前端DOM元素fadeIn效果

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    domFadeIn(document.querySelector('#id'))

    domFadeIn(document.querySelector('#id'), { duration: 500, delay: 100, opacityIni: 0.2 })

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ele` | HTMLElement |  |  | 輸入取得dom函數

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`duration` | Number | <optional> | `500` | 輸入動畫持續時間毫秒整數，預設500
`delay` | Number | <optional> | `0` | 輸入動畫延遲啟動時間毫秒整數，預設0
`opacityIni` | Number | <optional> | `0` | 輸入初始透明度浮點數，介於0至1之間，預設0

#### (static) domFadeOut(ele, optopt)

Source:
  - domFadeOut.mjs, line 26

前端DOM元素fadeOut效果

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    domFadeOut(document.querySelector('#id'))

    domFadeOut(document.querySelector('#id'), { duration: 500, delay: 100, opacityIni: 0.8 })

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ele` | HTMLElement |  |  | 輸入取得dom函數

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`duration` | Number | <optional> | `500` | 輸入動畫持續時間毫秒整數，預設500
`delay` | Number | <optional> | `0` | 輸入動畫延遲啟動時間毫秒整數，預設0
`opacityIni` | Number | <optional> | `1` | 輸入初始透明度浮點數，介於0至1之間，預設1

#### (static) domFind(query) → {Element}

Source:
  - domFind.mjs, line 14

前端找尋DOM元素

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = domFind('#id')

##### Parameters:

Name | Type | Description
--- | --- | ---
`query` | String | 輸入查詢字串

##### Returns:

回傳DOM元素

Type
  Element

#### (static) domFinds(query) → {Array}

Source:
  - domFinds.mjs, line 14

前端找尋多DOM元素

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let eles = domFinds('[name="abc"]')

##### Parameters:

Name | Type | Description
--- | --- | ---
`query` | String | 輸入查詢字串

##### Returns:

回傳DOM元素陣列

Type
  Array

#### (static) domGetAttr(ele, attr) → {String}

Source:
  - domGetAttr.mjs, line 22

前端DOM元素取得屬性

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    //<div id="eid" cus_attr="abc"></div>
    let r = domGetAttr(document.querySelector('#eid'), 'cus_attr')
    conssole.log(r)
    // => abc

##### Parameters:

Name | Type | Description
--- | --- | ---
`ele` | HTMLElement | 輸入DOM元素
`attr` | String | 輸入欲取得屬性名稱字串

##### Returns:

回傳屬性值

Type
  String

#### (static) domGetBoudRect(ele) → {Object}

Source:
  - domGetBoudRect.mjs, line 28

前端DOM元素取得getBoundingClientRect

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let r = domGetBoudRect(document.querySelector('#id'))
    console.log(r)
    // => {
      x:...,
      y:...,
      width:...,
      height:...,
      top:...,
      right:...,
      bottom:...,
      left:...,
    }

##### Parameters:

Name | Type | Description
--- | --- | ---
`ele` | HTMLElement | 輸入DOM元素

##### Returns:

回傳getBoundingClientRect結果物件

Type
  Object

#### (static) domGetBoudRectRefSelf(p, ele) → {Object}

Source:
  - domGetBoudRectRefSelf.mjs, line 28

前端由事件clientX與clientY座標，計算於DOM元素內的左上角座標x與y，以及該元素的寬度w與高度h

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let r = domGetBoudRectRefSelf(document.querySelector('#id'))
    console.log(r)
    // => {
      x:...,
      y:...,
      w:...,
      h:...,
    }

##### Parameters:

Name | Type | Description
--- | --- | ---
`p` | Object | 輸入座標點物件，主要需有DOM事件(event)的clientX與clientY，此為相對可視區域左上角的座標，單位皆為px
`ele` | HTMLElement | 輸入DOM元素

##### Returns:

回傳物件，內含x、y、寬度w、高度h，單位皆為px

Type
  Object

#### (static) domGetFileAccept(kindopt) → {String}

Source:
  - domGetFileAccept.mjs, line 25

前端依照檔案類型或種類回傳input file的accept欄位所用字串 kind若需使用種類，可選為'docums', 'compress', 'image', 'data'，或複選以陣列儲存傳入 kind若需使用通用檔案，可使用'common'

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`kind` | String | Array | <optional> | `'*'` | 輸入檔案類型或種類字串或陣列

##### Returns:

回傳input file的accept欄位所用字串

Type
  String

#### (static) domGetFiles(ele, sizelimitopt) → {Array}

Source:
  - domGetFiles.mjs, line 20

前端回傳Input元素所給予的檔案

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    let r = domGetFiles(ele)

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ele` | Element |  |  | 輸入Element Input元素
`sizelimit` | Number | <optional> | `1000` | 輸入檔案大小上線，單位mb，預設為1000mb(約1g)

##### Returns:

回傳檔案陣列

Type
  Array

#### (static) domGetPointFromEvent(e)

Source:
  - domGetPointFromEvent.mjs, line 19

前端DOM元素事件取得使用者滑鼠或第一觸控點座標

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    window.addEventListener('mousemove', (e) => {
      console.log(domGetPointFromEvent(e))
    })

##### Parameters:

Name | Type | Description
--- | --- | ---
`e` | HTEMLEvent | 輸入dom事件物件

#### (static) domGetScrollableParent(ele) → {Element}

Source:
  - domGetScrollableParent.mjs, line 16

前端找尋DOM元素最近的可捲動父層

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let eleScrollableParent = domGetScrollableParent(document.querySelector('#id'))

##### Parameters:

Name | Type | Description
--- | --- | ---
`ele` | HTMLElement | 輸入dom元素

##### Returns:

回傳DOM元素

Type
  Element

#### (static) domIsClientXYIn(clientX, clientY, ele) → {Boolean}

Source:
  - domIsClientXYIn.mjs, line 26

前端計算clientX與clientY是否位於DOM元素內

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let p = {
        clientX: 'from event',
        clientY: 'from event',
    }
    let ele = document.querySelector('#id')
    let b = domIsClientXYIn(p.clientX, p.clientY, ele)
    // => true or false

##### Parameters:

Name | Type | Description
--- | --- | ---
`clientX` | Number | 輸入點的clientX座標
`clientY` | Number | 輸入點的clientY座標
`ele` | HTMLElement | 輸入元素

##### Returns:

回傳是否位於DOM元素內布林值

Type
  Boolean

#### (static) domIsFocused(ele)

Source:
  - domIsFocused.mjs, line 18

前端檢測DOM元素是否為聚焦狀態

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    console.log(domIsFocused(ele))
    // => true or false

##### Parameters:

Name | Type | Description
--- | --- | ---
`ele` | Element | 輸入Element元素

#### (static) domIsVisible(ele)

Source:
  - domIsVisible.mjs, line 71

前端檢測DOM元素是否為顯示(使用者可見)狀態

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    domIsVisible(ele)
        .then(function(visible){
            console.log(visible)
            // => true or false
        })
        .catch(function(err){
            console.log(err)
        })

##### Parameters:

Name | Type | Description
--- | --- | ---
`ele` | Element | 輸入Element元素

#### (static) domPrepend(eleParent, itemChild)

Source:
  - domPrepend.mjs, line 18

前端於DOM元素內最前處插入元素或Html文字等

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    domPrepend(document.querySelector('#id-parent'),document.querySelector('#id-child'))

##### Parameters:

Name | Type | Description
--- | --- | ---
`eleParent` | HTMLElement | 輸入目標DOM元素
`itemChild` | HTMLElement | String | 輸入要插入DOM元素或Html文字等內容

#### (static) domRemove(inp)

Source:
  - domRemove.mjs, line 20

前端找尋DOM元素並刪除

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    domRemove(ele)

##### Parameters:

Name | Type | Description
--- | --- | ---
`inp` | String | HTMLElement | 輸入查詢字串或dom函數

#### (static) domRipple(ele, event)

Source:
  - domRipple.mjs, line 26

前端DOM元素點擊Ripple效果

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    ele.addEventListener('click', (e)=>{
        domRipple(e.currentTarget,e)
    })

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ele` | HTMLElement |  |  | 輸入dom
`event` | Object |  |  | 輸入dom點擊事件
`opt.timeDuration` | Integer | <optional> | `1000` | 輸入Ripple效果持續時間整數，單位ms，預設1000
`opt.color` | String | <optional> | `'rgba(255, 255, 255, 0.5)'` | 輸入Ripple顏色字串，預設'rgba(255, 255, 255, 0.5)'

#### (static) domScrollIntoView(ele, optopt)

Source:
  - domScrollIntoView.mjs, line 21

前端平滑捲動至DOM元素

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    domScrollIntoView(ele, {})

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ele` | Element |  |  | 輸入Element元素
`opt` | Object | <optional> | `{behavior:'smooth'}` | 輸入scrollIntoView的設定物件，預設{behavior:'smooth'}

#### (static) domScrollTo(ele, optopt)

Source:
  - domScrollTo.mjs, line 21

前端DOM元素平滑捲動至指定位置

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    domScrollTo(ele, {})

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ele` | Element |  |  | 輸入Element元素
`opt` | Object | <optional> | `{behavior:'smooth'}` | 輸入scrollTo的設定物件，預設{behavior:'smooth'}

#### (async, static) domShowImages(eleImg, eleGroupopt, optopt)

Source:
  - domShowImages.mjs, line 73

前端彈窗顯示指定元素內圖片或圖片陣列

Unit Test: Github

##### Example

Try in Codepen

    <img src="001.jpg" onclick="domShowImages(this)">
    <img src="002.jpg" onclick="domShowImages(this,this.parentElement)">

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`eleImg` | HTMLElement |  |  | 輸入圖片元素
`eleGroup` | HTMLElement | <optional> | `null` | 輸入元素內含有多圖片元素，預設null
`opt` | Object | <optional> | `{}` | 輸入viewerjs設定物件，預設使用optOne或optMuti，若img僅一個則使用optOne，反之使用optMuti

#### (async, static) domShowImagesDyn(eleImg, eleGroupopt, optopt, pathItems) → {Promise}

Source:
  - domShowImagesDyn.mjs, line 24

前端彈窗顯示指定元素內圖片或圖片陣列，採用動態加載技術

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    <img src="001.jpg" onclick="domShowImagesDyn(this)">

    <img src="002.jpg" onclick="domShowImagesDyn(this,this.parentElement)">

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`eleImg` | HTMLElement |  |  | 輸入圖片元素
`eleGroup` | HTMLElement | <optional> | `null` | 輸入元素內含有多圖片元素，預設null
`opt` | Object | <optional> | `{}` | 輸入viewerjs設定物件，預設使用optOne或optMuti，若img僅一個則使用optOne，反之使用optMuti
`pathItems` | String | Object | Array |  |  | 輸入資源字串、字串陣列、物件、物件陣列

##### Returns:

回傳Promise，resolve回傳為分數或是否，reject回傳錯誤訊息

Type
  Promise

#### (static) domShowInputAndGetFiles(kindopt, multipleopt, sizelimitopt) → {Promise}

Source:
  - domShowInputAndGetFiles.mjs, line 27

前端開啟上傳視窗並回傳檔案

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    domShowInputAndGetFiles()
        .then((files)=>{})

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`kind` | String | Array | <optional> | `'*'` | 輸入檔案類型或種類字串或陣列，可選'docums'、'compress'、'image'、'data'，若給予'common'則代表前述4種，也可給予有限的副檔名(詳見getFileAccept)，預設為全部'*'
`multiple` | Boolean | <optional> | `false` | 輸入是否可選多檔案，預設為false
`sizelimit` | Number | <optional> | `1000` | 輸入檔案大小上線，單位mb，預設為1000mb(約1g)

##### Returns:

回傳Promise，resolve為各檔案陣列，無reject

Type
  Promise

#### (static) domShowInputAndGetFilesU8Arrs(kindopt, multipleopt, sizelimitopt) → {Promise}

Source:
  - domShowInputAndGetFilesU8Arrs.mjs, line 21

前端開啟上傳視窗並讀取各檔案Uint8Array資料陣列

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`kind` | String | Array | <optional> | `'*'` | 輸入檔案類型或種類字串或陣列，預設為全部'*'
`multiple` | Boolean | <optional> | `false` | 輸入是否可選多檔案，預設為false
`sizelimit` | Number | <optional> | `1000` | 輸入檔案大小上線，單位mb，預設為1000mb(約1g)

##### Returns:

回傳Promise，resolve為各檔案的Uint8Array資料陣列，reject為錯誤訊息

Type
  Promise

#### (static) domTooltip(ele, content, optionopt)

Source:
  - domTooltip.mjs, line 25

滑鼠移入元素時彈出提示訊息

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    domTooltip(ele, '<b>Hello</b>World')

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ele` | HTMLElement |  |  | 輸入DOM元素
`content` | String |  |  | 輸入提示html訊息字串，若不給則使用ele.innerHTML
`option` | Object | <optional> | `{}` | 輸入tippy提示設定物件，預設{}，設定物件詳見tippy官網

#### (static) domTriggerEvent(ele, eventName)

Source:
  - domTriggerEvent.mjs, line 63

前端觸發ele的eventName

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    domTriggerEvent(ele, 'click')

##### Parameters:

Name | Type | Description
--- | --- | ---
`ele` | Element | 輸入Element元素
`eventName` | String | 輸入事件名稱字串

#### (async, static) domVirtualCreate(wopt, hopt, fun) → {Promise}

Source:
  - domVirtualCreate.mjs, line 27

前端產生臨時DOM元素為對象並進行客製化處理

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let fun = (ele) => {
        return ele2pic(ele) //use sync or async fun
    }
    let pic = await domVirtualCreate(500, 350, fun)

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`w` | Number | <optional> | `600` | 輸入目標DOM元素寬度數字，單位px，預設600
`h` | Number | <optional> | `400` | 輸入目標DOM元素高度數字，單位px，預設400
`fun` | function |  |  | 輸入處理函數，函數會傳入臨時產生的DOM元素，處理後例如產生base64圖片，並將其回傳，函數可為sync或async函數

##### Returns:

回傳Promise，resolve回傳為fun處理後數據，reject回傳錯誤訊息

Type
  Promise

#### (static) domVirtualCreateQueue() → {function}

Source:
  - domVirtualCreateQueue.mjs, line 33

前端產生臨時DOM元素為對象並進行客製化處理，並通過佇列管控，限定一次處理一個。初始化後將回傳封裝後的domVirtualCreate，輸入與輸出皆與其相同，詳見domVirtualCreate

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let dpq = domVirtualCreateQueue()

    //先給予圖片寬高與產製函數, 內部通過佇列逐次運行產圖與回傳base64
    let fun = async (ele) => {

        //chart
        let highchartsOpt = {...} //給予highcharts設定物件
        window.Highcharts.chart(ele, highchartsOpt)

        //html2picDyn, 預設轉出base64
        let html2canvasOpt = { scale: 3 } //放大3倍, 提高解析度
        b64 = await html2picDyn(ele, html2canvasOpt)

        return b64
    }

    let b64 = await dpq(500, 350, fun)

##### Returns:

回傳domVirtualCreate函數

Type
  function

#### (static) downloadExcelFileFromData(fileName, sheetNameopt, data)

Source:
  - downloadExcelFileFromData.mjs, line 46

下載資料成為Excel(*.xlsx)檔案，前後端都可用

Unit Test: Github

##### Example

Try in Codepen

    let data

    data = [
        ['a', 'b', 'c'],
        [1, 23.45, 'xyz']
    ]
    downloadExcelFileFromData('data(mat).xlsx', 'data', data)

    data = [
        { x: 'a', y: 'b', z: 'c' },
        { x: 1, y: 23.45, zzz: 'xyz' },
    ]
    downloadExcelFileFromData('data(ltdt).xlsx', 'data', data)

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`fileName` | String |  |  | 輸入檔名字串
`sheetName` | String | <optional> | `'data'` | 輸入分頁(sheet)名稱字串，預設為'data'
`data` | Array | Element |  |  | 輸入內容陣列或是DOM的table元素(Element)，內容陣列可為二維陣列(mat)或由物件組成的一維陣列(ltdt)

#### (async, static) downloadExcelFileFromDataDyn(fileName, sheetNameopt, data, pathItems) → {Promise}

Source:
  - downloadExcelFileFromDataDyn.mjs, line 35

前端下載資料成為Excel(*.xlsx)檔案，採用動態加載技術

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let data

    data = [
        ['a', 'b', 'c'],
        [1, 23.45, 'xyz']
    ]
    downloadExcelFileFromDataDyn('data(mat).xlsx', 'data', data)

    data = [
        { x: 'a', y: 'b', z: 'c' },
        { x: 1, y: 23.45, zzz: 'xyz' },
    ]
    downloadExcelFileFromDataDyn('data(ltdt).xlsx', 'data', data)

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`fileName` | String |  |  | 輸入檔名字串
`sheetName` | String | <optional> | `'data'` | 輸入分頁(sheet)名稱字串，預設為'data'
`data` | Array | Element |  |  | 輸入內容陣列或是DOM的table元素(Element)
`pathItems` | String | Object | Array |  |  | 輸入資源字串、字串陣列、物件、物件陣列

##### Returns:

回傳Promise，resolve代表成功，reject回傳錯誤訊息

Type
  Promise

#### (static) downloadFileFromB64(fileName, b64)

Source:
  - downloadFileFromB64.mjs, line 20

前端下載base64資料成為檔案

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    //icon.png to base64
    let b64=' '
    downloadFileFromB64('icon.png',b64)

##### Parameters:

Name | Type | Description
--- | --- | ---
`fileName` | String | 輸入檔名字串
`b64` | String | 輸入base64資料字串

#### (static) downloadFileFromBlob(fileName, blob)

Source:
  - downloadFileFromBlob.mjs, line 65

前端下載Blob資料成為檔案

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    //icon.png to u8a to blob
    let u8a = new Uint8Array([137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,97,0,0,2,26,73,68,65,84,56,79,165,147,205,107,19,65,24,198,103,246,43,18,77,104,161,246,32,130,85,17,10,161,219,209,10,193,116,183,205,65,4,207,106,15,85,235,110,18,163,8,122,20,188,249,23,120,81,168,20,178,155,84,236,37,96,241,224,69,68,73,119,99,90,136,216,77,217,42,138,80,4,47,86,90,48,107,155,54,179,51,178,129,148,198,172,141,224,220,230,253,248,241,242,60,239,11,193,127,62,216,169,127,62,158,58,28,114,55,195,17,227,233,178,95,173,47,192,144,198,187,67,60,127,8,189,201,217,150,148,152,0,0,30,160,20,23,80,49,103,255,9,241,5,88,178,122,15,82,74,72,128,159,133,117,87,30,156,211,50,139,210,53,21,8,244,37,122,61,253,109,55,164,13,176,36,167,174,48,53,252,10,239,103,123,128,75,147,148,226,73,100,78,127,250,56,156,8,213,32,185,142,204,236,131,191,2,150,228,9,209,165,220,113,100,106,179,20,220,103,150,227,223,123,237,131,171,171,99,249,188,235,53,45,142,36,206,49,16,84,197,130,86,106,66,90,38,176,70,149,91,117,71,200,158,126,55,181,225,39,88,121,40,205,11,193,250,13,209,208,31,181,1,172,216,213,94,192,114,23,6,13,125,114,47,103,44,73,189,3,193,214,19,209,156,89,247,234,118,38,120,31,83,16,203,194,35,162,161,63,223,11,80,145,148,75,24,66,251,148,161,55,108,221,1,88,195,138,76,1,67,81,81,51,155,128,249,232,229,112,23,23,160,253,69,173,218,140,85,100,117,148,165,160,22,49,245,133,22,64,229,140,210,239,10,236,192,201,66,38,239,37,202,67,233,32,23,196,73,0,8,192,27,66,166,169,75,69,74,142,67,130,23,6,222,230,190,180,0,188,79,69,86,239,58,216,121,24,43,229,55,45,89,189,72,9,249,192,176,144,33,0,156,64,115,217,103,126,86,182,184,80,142,167,123,120,188,61,182,198,245,105,221,238,138,130,140,236,227,134,125,178,114,115,157,237,203,118,145,175,73,150,212,102,154,2,182,77,224,5,172,145,212,81,72,241,89,66,153,99,144,97,166,32,33,144,66,154,130,12,89,33,219,244,5,42,117,216,68,15,242,249,252,237,176,243,179,26,221,194,245,134,80,129,125,124,84,248,241,171,20,177,243,206,63,221,66,167,11,221,157,255,13,198,21,222,17,48,199,189,166,0,0,0,0,73,69,78,68,174,66,96,130])
    let bb = new Blob([u8a])
    downloadFileFromBlob('icon.png',bb)

##### Parameters:

Name | Type | Description
--- | --- | ---
`fileName` | String | 輸入檔名字串
`blob` | Blob | 輸入資料Blob

#### (static) downloadFileFromText(fileName, ccont, withBOMopt)

Source:
  - downloadFileFromText.mjs, line 26

前端下載text資料成為utf-8(含BOM)檔案

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ctxt = 'abc\r\nde測試'
    downloadFileFromText('data.txt',ctxt,false)

    let ccsv = 'a,b,c\r\nd,e,測試'
    downloadFileFromText('data.csv',ccsv,true)

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`fileName` | String |  |  | 輸入檔名字串
`ccont` | String |  |  | 輸入內容字串
`withBOM` | Boolean | <optional> | `true` | 輸入是否添加BOM，預設true

#### (static) downloadFileFromU8Arr(fileName, u8a)

Source:
  - downloadFileFromU8Arr.mjs, line 23

前端下載binary資料成為檔案

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    //icon.png to u8a
    let u8a = new Uint8Array([137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0,0,31,243,255,97,0,0,2,26,73,68,65,84,56,79,165,147,205,107,19,65,24,198,103,246,43,18,77,104,161,246,32,130,85,17,10,161,219,209,10,193,116,183,205,65,4,207,106,15,85,235,110,18,163,8,122,20,188,249,23,120,81,168,20,178,155,84,236,37,96,241,224,69,68,73,119,99,90,136,216,77,217,42,138,80,4,47,86,90,48,107,155,54,179,51,178,129,148,198,172,141,224,220,230,253,248,241,242,60,239,11,193,127,62,216,169,127,62,158,58,28,114,55,195,17,227,233,178,95,173,47,192,144,198,187,67,60,127,8,189,201,217,150,148,152,0,0,30,160,20,23,80,49,103,255,9,241,5,88,178,122,15,82,74,72,128,159,133,117,87,30,156,211,50,139,210,53,21,8,244,37,122,61,253,109,55,164,13,176,36,167,174,48,53,252,10,239,103,123,128,75,147,148,226,73,100,78,127,250,56,156,8,213,32,185,142,204,236,131,191,2,150,228,9,209,165,220,113,100,106,179,20,220,103,150,227,223,123,237,131,171,171,99,249,188,235,53,45,142,36,206,49,16,84,197,130,86,106,66,90,38,176,70,149,91,117,71,200,158,126,55,181,225,39,88,121,40,205,11,193,250,13,209,208,31,181,1,172,216,213,94,192,114,23,6,13,125,114,47,103,44,73,189,3,193,214,19,209,156,89,247,234,118,38,120,31,83,16,203,194,35,162,161,63,223,11,80,145,148,75,24,66,251,148,161,55,108,221,1,88,195,138,76,1,67,81,81,51,155,128,249,232,229,112,23,23,160,253,69,173,218,140,85,100,117,148,165,160,22,49,245,133,22,64,229,140,210,239,10,236,192,201,66,38,239,37,202,67,233,32,23,196,73,0,8,192,27,66,166,169,75,69,74,142,67,130,23,6,222,230,190,180,0,188,79,69,86,239,58,216,121,24,43,229,55,45,89,189,72,9,249,192,176,144,33,0,156,64,115,217,103,126,86,182,184,80,142,167,123,120,188,61,182,198,245,105,221,238,138,130,140,236,227,134,125,178,114,115,157,237,203,118,145,175,73,150,212,102,154,2,182,77,224,5,172,145,212,81,72,241,89,66,153,99,144,97,166,32,33,144,66,154,130,12,89,33,219,244,5,42,117,216,68,15,242,249,252,237,176,243,179,26,221,194,245,134,80,129,125,124,84,248,241,171,20,177,243,206,63,221,66,167,11,221,157,255,13,198,21,222,17,48,199,189,166,0,0,0,0,73,69,78,68,174,66,96,130])
    downloadFileFromU8Arr('icon.png',u8a)

##### Parameters:

Name | Type | Description
--- | --- | ---
`fileName` | String | 輸入檔名字串
`u8a` | Uint8Array | 輸入Uint8Array資料

#### (static) dtmapping(dt, keys, defopt) → {Object}

Source:
  - dtmapping.mjs, line 25

由dt物件提取指定keys欄位出來成為新物件，若物件不存在keys的欄位時，則會自動填入指定數據def

Unit Test: Github

##### Example

Try in Codepen

    console.log(dtmapping({ a: 'a123', b: 234, c: '345' }, ['a', 'b']))
    // => { a: 'a123', b: 234 }

    console.log(dtmapping({ a: 'a123', b: 234, c: '345' }, ['a', 'b', 'x']))
    // => { a: 'a123', b: 234, x: '' }

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`dt` | Object |  |  | 輸入資料物件
`keys` | Array |  |  | 輸入要提取欄位集合的字串陣列
`def` | * | <optional> | `''` | 輸入若無提取欄位時所給予的預設值，預設為''

##### Returns:

回傳處理後物件

Type
  Object

#### (static) dtpick(dt, keys) → {Object}

Source:
  - dtpick.mjs, line 25

由dt物件提取指定keys欄位出來成為新物件，僅保留有keys的欄位，若不存在欄位就不提取

Unit Test: Github

##### Example

Try in Codepen

    console.log(dtpick({ a: 'a123', b: 234, c: '345' }, ['a', 'b']))
    // => { a: 'a123', b: 234 }

    console.log(dtpick({ a: 'a123', b: 234, c: '345' }, ['a', 'b', 'x']))
    // => { a: 'a123', b: 234 }

##### Parameters:

Name | Type | Description
--- | --- | ---
`dt` | Object | 輸入資料物件
`keys` | Array | 輸入要提取欄位集合的字串陣列

##### Returns:

回傳處理後物件

Type
  Object

#### (static) evem()

Source:
  - evem.mjs, line 22

EventEmitter from eventemitter3

See: eventemitter3

Unit Test: Github

##### Example

Try in Codepen

    let ev = wsemi.evem()
    ev.on('evName',function(msg){
        console.log(msg)
        // => {abc: 12.34}
    })
    let data = {abc:12.34}
    ev.emit('evName',data)

#### (static) execScript(prog, scp) → {*}

Source:
  - execScript.mjs, line 146

呼叫執行檔或程式語言prog執行scp腳本

Unit Test: Github

##### Example

Try in Codepen

    //need test in nodejs

    if(true){
        let prog = 'python'
        let scp = 'fun.py'
        let pa = 'sin'
        let pb = '12'
        let pc = '34.56'
        execScript(prog, [scp, pa, pb, pc])
            .then(function(data) {
                console.log('then', data)
            })
            .catch(function(data) {
                console.log('catch', data)
            })
    }

    if(true){
        let prog = 'prog.exe'
        let arg = 'input'
        execScript(prog, arg)
            .then(function(data) {
                console.log('then', data)
            })
            .catch(function(data) {
                console.log('catch', data)
            })
    }

    if(true){
        let prog = 'C:\\Program Files\\7-Zip\\7z.exe'
        let pw = 'AbcD1234'
        let arg = ['a', 'aaa.7z', 'aaa.txt', '-p' + pw]
        execScript(prog, arg)
            .then(function(data) {
                console.log('then', data)
            })
            .catch(function(data) {
                console.log('catch', data)
            })
    }

##### Parameters:

Name | Type | Description
--- | --- | ---
`prog` | String | 輸入執行檔或程式語言位置字串, 若為註冊系統的全域指令, 例如可直接給'Python', 腳本需自行接收呼叫引數, 並將回傳資料轉json字串後print/log到dos視窗, 即可由nodejs接收
`scp` | String | Array | 輸入腳本檔案位置字串或參數

##### Returns:

回傳任意資料

Type
  *

#### (static) f2c(c) → {String}

Source:
  - f2c.mjs, line 19

函數內註解轉字串

Unit Test: Github

##### Example

Try in Codepen

    let f = function() { ╱**abc*╱ } //jsdoc can't parser multi-line comments here, need convert "╱" to "/"
    console.log(f2c(f))
    // => 'abc'

##### Parameters:

Name | Type | Description
--- | --- | ---
`c` | function | 輸入函數

##### Returns:

回傳字串

Type
  String

#### (static) files2data(files) → {Promise}

Source:
  - files2data.mjs, line 18

前端input檔案物件陣列轉資料物件陣列，各檔案將轉為Base64字串

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

##### Parameters:

Name | Type | Description
--- | --- | ---
`files` | Array | 輸入File陣列

##### Returns:

回傳Promise，resolve回傳File的資料物件陣列，各檔案將轉為Base64字串

Type
  Promise

#### (static) flattenTreeObj(data, optopt, bindKeyopt, bindChildrenopt) → {Array}

Source:
  - flattenTreeObj.mjs, line 75

展平樹狀物件陣列

Unit Test: Github

##### Example

Try in Codepen

    let data1 = { //obj
        id: 1,
        data: '1-abc',
        children: [
            {
                id: 2,
                data: '2-def',
            },
            {
                id: 3,
                data: '3-ghi',
                children: [
                    {
                        id: 4,
                        data: '4-jkl',
                    },
                ],
            },
            {
                id: 5,
                data: '5-mno',
            },
        ],
    }
    let r1 = flattenTreeObj(data1)
    console.log(JSON.stringify(r1))
    // => {"id":1,"data":"1-abc","children":[{"id":2,"data":"2-def"},{"id":3,"data":"3-ghi","children":[{"id":4,"data":"4-jkl"}]},{"id":5,"data":"5-mno"}],"level":0,"nk":[0]}

    let data2 = [ //arr
        {
            id: 1,
            text: '1x',
        },
        {
            id: 2,
            text: '2y',
            children: [
                {
                    id: 3,
                    text: '3z',
                },
            ],
        },
        {
            id: 4,
            text: 'empty',
        },
    ]
    let r2 = flattenTreeObj(data2)
    console.log(JSON.stringify(r2))
    // => [{"id":1,"text":"1x","level":0,"nk":[0]},{"id":2,"text":"2y","children":[{"id":3,"text":"3z"}],"level":0,"nk":[1]},{"id":3,"text":"3z","level":1,"nk":[1,"children",0]},{"id":4,"text":"empty","level":0,"nk":[2]}]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`data` | Array | Object |  |  | 輸入樹狀物件或陣列
`opt` | Object | <optional> | `{}` | 輸入設定物件，預設{}
`bindKey` | String | <optional> | `'id'` | 輸入節點物件識別用欄位字串，預設'id'
`bindChildren` | String | <optional> | `'children'` | 輸入節點物件內存放子節點欄位字串，預設'children'

##### Returns:

回傳節點物件陣列

Type
  Array

#### (static) fsCleanFolder(pah)

Source:
  - fsCleanFolder.mjs, line 17

後端nodejs清空資料夾

Unit Test: Github

##### Example

Try in Codepen

    need test in nodejs. See example in fsCopyFolder.

##### Parameters:

Name | Type | Description
--- | --- | ---
`pah` | String | 輸入欲清空資料夾路徑字串

#### (static) fsCopyFolder(fpSrc, fpTar)

Source:
  - fsCopyFolder.mjs, line 53

後端nodejs複製資料夾

Unit Test: Github

##### Example

Try in Codepen

    need test in nodejs.

    import fs from 'fs'
    import fsCreateFolder from './src/fsCreateFolder.mjs'
    import fsCleanFolder from './src/fsCleanFolder.mjs'
    import fsDeleteFolder from './src/fsDeleteFolder.mjs'
    import fsCopyFolder from './src/fsCopyFolder.mjs'

    console.log('fsCreateFolder', fsCreateFolder('./d/dd/ddd'))

    fs.writeFileSync('./d/a.txt', 'd-a', 'utf8')
    fs.writeFileSync('./d/dd/b.txt', 'd-b', 'utf8')
    fs.writeFileSync('./d/dd/ddd/c.txt', 'd-c', 'utf8')

    console.log('fsCleanFolder', fsCleanFolder('./d'))

    console.log('fsCreateFolder 1', fsCreateFolder('./d/ee/eee'))

    fs.writeFileSync('./d/a.txt', 'e-a', 'utf8')
    fs.writeFileSync('./d/ee/b.txt', 'e-b', 'utf8')
    fs.writeFileSync('./d/ee/eee/c.txt', 'e-c', 'utf8')

    console.log('fsDeleteFolder', fsDeleteFolder('./d'))

    console.log('fsCreateFolder 2', fsCreateFolder('./d/ff/fff'))

    fs.writeFileSync('./d/a.txt', 'f-a', 'utf8')
    fs.writeFileSync('./d/ff/b.txt', 'f-b', 'utf8')
    fs.writeFileSync('./d/ff/fff/c.txt', 'f-c', 'utf8')

    console.log('fsCopyFolder', fsCopyFolder('./d', './e'))

    // fsCreateFolder { success: 'done: ./d/dd/ddd' }
    // fsCleanFolder { success: 'done: ./d' }
    // fsCreateFolder 1 { success: 'done: ./d/ee/eee' }
    // fsDeleteFolder { success: 'done: ./d' }
    // fsCreateFolder 2 { success: 'done: ./d/ff/fff' }
    // fsCopyFolder { success: 'done: ./e' }

##### Parameters:

Name | Type | Description
--- | --- | ---
`fpSrc` | String | 輸入來源資料夾路徑字串
`fpTar` | String | 輸入目的資料夾路徑字串

#### (static) fsCreateFolder(pah)

Source:
  - fsCreateFolder.mjs, line 15

後端nodejs建立資料夾

Unit Test: Github

##### Example

Try in Codepen

    need test in nodejs. See example in fsCopyFolder.

##### Parameters:

Name | Type | Description
--- | --- | ---
`pah` | String | 輸入資料夾路徑字串

#### (static) fsDeleteFolder(pah)

Source:
  - fsDeleteFolder.mjs, line 15

後端nodejs刪除資料夾

Unit Test: Github

##### Example

Try in Codepen

    need test in nodejs. See example in fsCopyFolder.

##### Parameters:

Name | Type | Description
--- | --- | ---
`pah` | String | 輸入欲刪除資料夾路徑字串

#### (static) fsGetFilesInFolder(fd, levelLimitopt) → {Array}

Source:
  - fsGetFilesInFolder.mjs, line 27

列舉指定資料夾下的檔案

Unit Test: Github

##### Example

Try in Codepen

    //need test in nodejs

    let fd = './d'

    fsGetFilesInFolder(fd)
    // => [ './d/a.txt' ]

    fsGetFilesInFolder(fd, null)
    // => [ './d/a.txt', './d/ee/b.txt', './d/ee/eee/c.txt' ]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`fd` | String |  |  | 輸入欲列舉的資料夾字串
`levelLimit` | Integer | <optional> | `1` | 輸入列舉層數限制正整數，設定1為列舉資料夾下第一層的檔案或資料夾，設定null為無窮遍歷所有檔案與資料夾，預設1

##### Returns:

回傳列舉檔案或資料夾陣列

Type
  Array

#### (static) fsGetFoldersInFolder(fd, levelLimitopt) → {Array}

Source:
  - fsGetFoldersInFolder.mjs, line 27

列舉指定資料夾下的資料夾

Unit Test: Github

##### Example

Try in Codepen

    //need test in nodejs

    let fd = './d'

    fsGetFoldersInFolder(fd)
    // => [ './d/ee' ]

    fsGetFoldersInFolder(fd, null)
    // => [ './d/ee', './d/ee/eee' ]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`fd` | String |  |  | 輸入欲列舉的資料夾字串
`levelLimit` | Integer | <optional> | `1` | 輸入列舉層數限制正整數，設定1為列舉資料夾下第一層的檔案或資料夾，設定null為無窮遍歷所有檔案與資料夾，預設1

##### Returns:

回傳列舉檔案或資料夾陣列

Type
  Array

#### (static) fsIsFile(pah)

Source:
  - fsIsFile.mjs, line 22

後端nodejs判斷是否為檔案

Unit Test: Github

##### Example

Try in Codepen

    need test in nodejs.

    let fd = 'folder p'
    fsIsFile(fd)
    // => false

    let fn = 'file q'
    fsIsFile(fn)
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`pah` | String | 輸入路徑字串

#### (static) fsIsFolder(pah)

Source:
  - fsIsFolder.mjs, line 22

後端nodejs判斷是否為資料夾

Unit Test: Github

##### Example

Try in Codepen

    need test in nodejs.

    let fd = 'folder p'
    fsIsFolder(fd)
    // => true

    let fn = 'file q'
    fsIsFolder(fn)
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`pah` | String | 輸入路徑字串

#### (static) fsReadText(fn)

Source:
  - fsReadText.mjs, line 14

後端nodejs由檔案讀取utf-8文字

Unit Test: Github

##### Example

Try in Codepen

    need test in nodejs.

##### Parameters:

Name | Type | Description
--- | --- | ---
`fn` | String | 輸入檔案名稱

#### (static) fsTreeFolder(fd, levelLimitopt) → {Array}

Source:
  - fsTreeFolder.mjs, line 33

列舉指定資料夾下的全部檔案或資料夾

Unit Test: Github

##### Example

Try in Codepen

    //need test in nodejs

    fsTreeFolder(fd)
    // => [
    //   { isFolder: false, level: 1, path: './d/a.txt', name: 'a.txt' },
    //   { isFolder: true, level: 1, path: './d/ee', name: 'ee' }
    // ]

    fsTreeFolder(fd, null)
    // => [
    //   { isFolder: false, level: 1, path: './d/a.txt', name: 'a.txt' },
    //   { isFolder: true, level: 1, path: './d/ee', name: 'ee' },
    //   { isFolder: false, level: 2, path: './d/ee/b.txt', name: 'b.txt' },
    //   { isFolder: true, level: 2, path: './d/ee/eee', name: 'eee' },
    //   { isFolder: false, level: 3, path: './d/ee/eee/c.txt', name: 'c.txt' }
    // ]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`fd` | String |  |  | 輸入欲列舉的資料夾字串
`levelLimit` | Integer | <optional> | `1` | 輸入列舉層數限制正整數，設定1為列舉資料夾下第一層的檔案或資料夾，設定null為無窮遍歷所有檔案與資料夾，預設1

##### Returns:

回傳列舉檔案或資料夾陣列

Type
  Array

#### (static) fsWriteText(fn, c)

Source:
  - fsWriteText.mjs, line 15

寫入utf-8文字至檔案

Unit Test: Github

##### Example

Try in Codepen

    need test in nodejs.

##### Parameters:

Name | Type | Description
--- | --- | ---
`fn` | String | 輸入檔案名稱
`c` | String | 輸入utf-8文字數據

#### (static) genGradientColor(color) → {Object}

Source:
  - genGradientColor.mjs, line 63

產生highchart直條圖用漸變顏色物件

Unit Test: Github

##### Example

Try in Codepen

    console.log(genGradientColor('#000'))
    // => {
    //     linearGradient: { x1: 0, x2: 0, y1: 0, y2: 1 },
    //     stops: [ [ 0, 'rgba(0, 0, 0, 0.4)' ], [ 1, 'rgba(0, 0, 0, 0.9)' ] ]
    //     }

    console.log(genGradientColor('hsl (320, 50%, 40%)'))
    // => {
    //     linearGradient: { x1: 0, x2: 0, y1: 0, y2: 1 },
    //     stops: [
    //         [ 0, 'rgba(153, 51, 119, 0.4)' ],
    //         [ 1, 'rgba(153, 51, 119, 0.9)' ]
    //     ]
    // }

    console.log(genGradientColor('hsva (320, 100%, 50%, 0.1)'))
    // => {
    //     linearGradient: { x1: 0, x2: 0, y1: 0, y2: 1 },
    //     stops: [ [ 0, 'rgba(128, 0, 85, 0.4)' ], [ 1, 'rgba(128, 0, 85, 0.9)' ] ]
    // }

    console.log(genGradientColor('#6a3'))
    // => {
    //     linearGradient: { x1: 0, x2: 0, y1: 0, y2: 1 },
    //     stops: [
    //         [ 0, 'rgba(102, 170, 51, 0.4)' ],
    //         [ 1, 'rgba(102, 170, 51, 0.9)' ]
    //     ]
    // }

    console.log(genGradientColor('#6b8e23'))
    // => {
    //     linearGradient: { x1: 0, x2: 0, y1: 0, y2: 1 },
    //     stops: [
    //         [ 0, 'rgba(107, 142, 35, 0.4)' ],
    //         [ 1, 'rgba(107, 142, 35, 0.9)' ]
    //     ]
    // }

    console.log(genGradientColor('skyblue'))
    // => {
    //     linearGradient: { x1: 0, x2: 0, y1: 0, y2: 1 },
    //     stops: [
    //         [ 0, 'rgba(135, 206, 235, 0.4)' ],
    //         [ 1, 'rgba(135, 206, 235, 0.9)' ]
    //     ]
    // }

##### Parameters:

Name | Type | Description
--- | --- | ---
`color` | * | 輸入color資料

##### Returns:

回傳漸變顏色物件

Type
  Object

#### (static) genID(lenopt) → {String}

Source:
  - genID.mjs, line 23

產生隨機id

Depend on: Math.uuid.js

Unit Test: Github

##### Example

Try in Codepen

    console.log(genID())
    // => Is1NyImU3A9fyqFyYBWuJu4ivXXcGZAb (is random)

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`len` | Integer | <optional> | `32` | 輸入uuid長度，為正整數，預設32

##### Returns:

回傳uuid字串

Type
  String

#### (static) genPm() → {Object}

Source:
  - genPm.mjs, line 86

產生Promise物件，具備鏈式resolve與reject 主要受jQuery Deferred概念啟發

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        function test1() {
            return new Promise((resolve, reject) => {
                let ms = []

                let fn = function(name) {
                    let pm = genPm()
                    setTimeout(function() {
                        ms.push('resolve: ' + name)
                        pm.resolve('resolve: ' + name)
                    }, 1)
                    return pm
                }

                fn('abc')
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + msg)
                    })
                    .finally(() => {
                        resolve(ms)
                    })

            })
        }
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // t1 then resolve: abc
        // ["resolve: abc","t1 then: resolve: abc"]

        function test2() {
            return new Promise((resolve, reject) => {
                let ms = []

                let fn = function(name) {
                    let pm = genPm()
                    setTimeout(function() {
                        ms.push('reject: ' + name)
                        pm.reject('reject: ' + name)
                    }, 1)
                    return pm
                }

                fn('abc')
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + msg)
                    })
                    .finally(() => {
                        resolve(ms)
                    })

            })
        }
        console.log('test2')
        let r2 = await test2()
        console.log(JSON.stringify(r2))
        // test2
        // t1 catch reject: abc
        // ["reject: abc","t1 catch: reject: abc"]

    }
    topAsync().catch(() => {})

##### Returns:

回傳Promise物件

Type
  Object

#### (static) getBufferSize(buf) → {Integer}

Source:
  - getBufferSize.mjs, line 25

計算Uint8Array(Nodejs,Browser)或Buffer(Nodejs)的大小

Unit Test: Github

##### Example

Try in Codepen

    let u8a = new Uint8Array([1, 2, 3, 123])
    console.log(getBufferSize(u8a))
    // => 4

    let buf = Buffer.alloc(8)
    console.log(getBufferSize(buf))
    // => 8

##### Parameters:

Name | Type | Description
--- | --- | ---
`buf` | Unit8Array | Buffer | 傳入Uint8Array(Nodejs,Browser)或Buffer(Nodejs)

##### Returns:

回傳Uint8Array(Nodejs,Browser)或Buffer(Nodejs)的大小

Type
  Integer

#### (static) getClearPathName(str) → {string}

Source:
  - getClearPathName.mjs, line 83

清理檔案或資料夾位置

Unit Test: Github

##### Example

Try in Codepen

    let c

    c = 'C:\\temp\\myfile.html'
    console.log(getClearPathName(c))
    // => { path: 'C:\\temp\\myfile.html', isRoot: false }

    c = 'C:\\temp\\myfile.txt.html'
    console.log(getClearPathName(c))
    // => { path: 'C:\\temp\\myfile.txt.html', isRoot: false }

    c = 'C:\\temp\\\\temp\\\\myfile.txt.html'
    console.log(getClearPathName(c))
    // => { path: 'C:\\temp\\temp\\myfile.txt.html', isRoot: false }

    c = 'C:\\temp\\'
    console.log(getClearPathName(c))
    // => { path: 'C:\\temp', isRoot: false }

    c = 'C:\\temp'
    console.log(getClearPathName(c))
    // => { path: 'C:\\temp', isRoot: false }

    c = 'C:\\'
    console.log(getClearPathName(c))
    // => { path: 'C:\\', isRoot: true }

    c = 'C:'
    console.log(getClearPathName(c))
    // => { path: 'C:\\', isRoot: true }

    c = '/tmp/myfile.html'
    console.log(getClearPathName(c))
    // => { path: '/tmp/myfile.html', isRoot: false }

    c = '/tmp/myfile.txt.html'
    console.log(getClearPathName(c))
    // => { path: '/tmp/myfile.txt.html', isRoot: false }

    c = '//tmp////tmp//myfile.txt.html'
    console.log(getClearPathName(c))
    // => { path: '/tmp/tmp/myfile.txt.html', isRoot: false }

    c = '/tmp/'
    console.log(getClearPathName(c))
    // => { path: '/tmp', isRoot: false }

    c = '/tmp'
    console.log(getClearPathName(c))
    // => { path: '/tmp', isRoot: false }

    c = '/'
    console.log(getClearPathName(c))
    // => { path: '/', isRoot: true }

    c = '/foo/bar/baz/asdf/quux.html'
    console.log(getClearPathName(c))
    // => { path: '/foo/bar/baz/asdf/quux.html', isRoot: false }

    c = '/foo/bar/baz/asdf/quux.txt.html'
    console.log(getClearPathName(c))
    // => { path: '/foo/bar/baz/asdf/quux.txt.html', isRoot: false }

    c = ''
    console.log(getClearPathName(c))
    // => { path: '', isRoot: false }

##### Parameters:

Name | Type | Description
--- | --- | ---
`str` | string | 輸入檔案或資料夾位置字串

##### Returns:

清理後檔案或資料夾位置

Type
  string

#### (static) getCsvStrFromData(data, bomopt)

Source:
  - getCsvStrFromData.mjs, line 58

由陣列數據轉成為Excel(*.csv)的字串數據

Unit Test: Github

##### Example

Try in Codepen

    let data = [
        ['a', '123', 456],
        [null, 'abc123', '', 111.222333],
        [5, '\r\n', true, 'false'],
    ]
    let c = getCsvStrFromData(data)
    console.log(c)
    // => "a","123",456
    //    ,"abc123","",111.222333
    //    5,"",true,"false"
    fs.writeFileSync('temp.csv', c, 'utf8')

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`data` | Array |  |  | 輸入內容陣列
`bom` | Boolean | <optional> | `true` | 輸入是否添加開頭BOM符號，預設true

#### (static) getDataFromExcelFileU8Arr(u8a, optopt) → {Array}

Source:
  - getDataFromExcelFileU8Arr.mjs, line 145

讀取Excel(*.xlsx)檔，前後端都可用，前端由input file的檔案取得Uint8Array，後端由fs.readFileSync讀取Buffer 若數據格式fmt為csv格式，數據分欄符號為逗號，分行符號為[\r\n]，內容開頭無BOM，方便使用者解析

Unit Test: Github

##### Example

Try in Codepen

    // test in browser
    domShowInputAndGetFilesU8Arrs(kind)
        .then(function(d) {
            let file = d[0] //get first file
            let u8a = file.u8a
            let dltdt = getDataFromExcelFileU8Arr(u8a, { fmt: 'ltdt' })
            console.log(dltdt[0].sheetname, dltdt[0].data)
            // => ...
        })

    // test in nodejs
    let u8a = fs.readFileSync('temp.xlsx')
    let r = getDataFromExcelFileU8Arr(u8a, { fmt: 'ltdt' })
    console.log(dltdt[0].sheetname, dltdt[0].data)
    // => ...

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`u8a` | Uint8Array |  |  | 輸入file資料，格式需為Uint8Array

`opt`

Object

<optional>

`{}`

輸入設定物件，預設為{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`fmt` | String | <optional> | `'ltdt'` | 輸入數據格式，可有'ltdt','csv','array'，預設為'ltdt'
`valueToString` | Boolean | <optional> | `true` | 輸入數據是否強制轉字串布林值，預設為true

##### Returns:

回傳數據陣列

Type
  Array

#### (async, static) getDataFromExcelFileU8ArrDyn(u8a, fmtopt, useHeadopt, pathItems) → {Promise}

Source:
  - getDataFromExcelFileU8ArrDyn.mjs, line 22

前端讀取Excel(*.xlsx)檔，前端由input file的檔案取得Uint8Array，並採用動態加載技術 若數據格式fmt為csv格式，數據分欄符號為逗號，分行符號為[\r\n]，內容開頭無BOM，方便使用者解析

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`u8a` | Uint8Array |  |  | 輸入file資料，格式需為Uint8Array
`fmt` | String | <optional> | `'ltdt'` | 輸入數據輸出格式，可有'ltdt','csv','array'，預設為'ltdt'
`useHead` | Boolean | <optional> | `false` | 輸入數據是否讀入首行head，需配合fmt='array'，預設為false
`pathItems` | String | Object | Array |  |  | 輸入資源字串、字串陣列、物件、物件陣列

##### Returns:

回傳Promise，resolve回傳數據陣列，reject回傳錯誤訊息

Type
  Promise

#### (static) getDirName(str) → {string}

Source:
  - getDirName.mjs, line 96

由檔案位置取得檔案所在資料夾名稱

Unit Test: Github

##### Example

Try in Codepen

    let c

    c = 'C:\\temp\\myfile.html'
    console.log(getDirName(c))
    // => C:\\temp

    c = 'C:\\temp\\myfile.txt.html'
    console.log(getDirName(c))
    // => C:\\temp

    c = 'C:\\temp\\myfile'
    console.log(getDirName(c))
    // => C:\\temp

    c = 'C:\\temp\\\\temp\\\\myfile.txt.html'
    console.log(getDirName(c))
    // => C:\\temp\\temp

    c = 'C:\\temp\\'
    console.log(getDirName(c))
    // => C:\\

    c = 'C:\\temp'
    console.log(getDirName(c))
    // => C:\\

    c = 'C:\\'
    console.log(getDirName(c))
    // => C:\\

    c = 'C:'
    console.log(getDirName(c))
    // => C:\\

    c = '/tmp/myfile.html'
    console.log(getDirName(c))
    // => /tmp

    c = '/tmp/myfile.txt.html'
    console.log(getDirName(c))
    // => /tmp

    c = '/tmp/myfile'
    console.log(getDirName(c))
    // => /tmp

    c = '//tmp////tmp//myfile.txt.html'
    console.log(getDirName(c))
    // => /tmp/tmp

    c = '/tmp/'
    console.log(getDirName(c))
    // => /

    c = '/tmp'
    console.log(getDirName(c))
    // => /

    c = '/'
    console.log(getDirName(c))
    // => /

    c = '/foo/bar/baz/asdf/quux.html'
    console.log(getDirName(c))
    // => /foo/bar/baz/asdf

    c = '/foo/bar/baz/asdf/quux.txt.html'
    console.log(getDirName(c))
    // => /foo/bar/baz/asdf

    c = '/foo/bar/baz/asdf/quux'
    console.log(getDirName(c))
    // => /foo/bar/baz/asdf

    c = ''
    console.log(getDirName(c))
    // => [empty string]

##### Parameters:

Name | Type | Description
--- | --- | ---
`str` | string | 輸入檔案位置字串

##### Returns:

檔案名稱

Type
  string

#### (static) getEnv() → {Object}

Source:
  - getEnv.mjs, line 16

取得運行環境

Unit Test: Github

##### Example

Try in Codepen

    console.log(getEnv())
    // => { isWindow: false, isWebWorker: false, isNode: true }

##### Returns:

回傳運行環境物件

Type
  Object

#### (static) getExcelU8ArrFromData(data, sheetNameopt)

Source:
  - getExcelU8ArrFromData.mjs, line 48

由陣列數據轉成為Excel(*.xlsx)的Uint8Array數據

Unit Test: Github

##### Example

Try in Codepen

    import fs from 'fs'

    let data = [
        ['a', '123', 456],
        [null, 'abc123', '', 111.222333],
    ]
    let u8a = getExcelU8ArrFromData(data)
    console.log(u8a)
    // => Uint8Array(14720) [
    //     80,  75,   3,   4,  10,   0,   0,   0,   0,   0, 202,  99,
    //     50,  82, 214, 146, 124,  17,  90,   1,   0,   0,  90,   1,
    //      0,   0,  17,   0,   0,   0, 100, 111,  99,  80, 114, 111,
    //    112, 115,  47,  99, 111, 114, 101,  46, 120, 109, 108,  60,
    //     63, 120, 109, 108,  32, 118, 101, 114, 115, 105, 111, 110,
    //     61,  34,  49,  46,  48,  34,  32, 101, 110,  99, 111, 100,
    //    105, 110, 103,  61,  34,  85,  84,  70,  45,  56,  34,  32,
    //    115, 116,  97, 110, 100,  97, 108, 111, 110, 101,  61,  34,
    //    121, 101, 115,  34,
    //    ... 14620 more items
    //  ]
    fs.writeFileSync('temp.xlsx', u8a)

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`data` | Array |  |  | 輸入內容陣列
`sheetName` | String | <optional> | `'data'` | 輸入輸出為Excel時所在分頁(sheet)名稱字串，預設為'data'

#### (static) getExcelWorkbookFromData(data, sheetNameopt)

Source:
  - getExcelWorkbookFromData.mjs, line 69

由陣列數據轉成為Excel(*.xlsx)的Workbook數據

Unit Test: Github

##### Example

Try in Codepen

    import xlsx from 'xlsx'

    let data = [
        ['a', '123', 456],
        [null, 'abc123', '', 111.222333],
    ]

    let wb1 = getExcelWorkbookFromData(data)
    console.log(wb1)
    // => Workbook {
    //      SheetNames: [ 'data' ],
    //      Sheets: {
    //        data: {
    //          A1: [Object],
    //          B1: [Object],
    //          C1: [Object],
    //          B2: [Object],
    //          C2: [Object],
    //          D2: [Object],
    //          '!ref': 'A1:D2'
    //        }
    //      }
    //    }
    xlsx.writeFile(wb1, 'temp1.xlsx')

    let wb2 = getExcelWorkbookFromData(data, 'tester')
    console.log(wb2)
    // => Workbook {
    //      SheetNames: [ 'tester' ],
    //      Sheets: {
    //        data: {
    //          A1: [Object],
    //          B1: [Object],
    //          C1: [Object],
    //          B2: [Object],
    //          C2: [Object],
    //          D2: [Object],
    //          '!ref': 'A1:D2'
    //        }
    //      }
    //    }
    xlsx.writeFile(wb2, 'temp2.xlsx')

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`data` | Array | Element |  |  | 輸入內容陣列或是DOM的table元素(Element)
`sheetName` | String | <optional> | `'data'` | 輸入輸出為Excel時所在分頁(sheet)名稱字串，預設為'data'

#### (static) getExcelWorkbookFromWorksheet(sheet, sheetNameopt)

Source:
  - getExcelWorkbookFromWorksheet.mjs, line 49

由Worksheet數據轉Workbook數據

Unit Test: Github

##### Example

Try in Codepen

    import xlsx from 'xlsx'

    let data = [
        ['a', '123', 456],
        [null, 'abc123', '', 111.222333],
    ]

    let ws = xlsx.utils.aoa_to_sheet(data)
    console.log('ws', ws)
    // ws {
    //   A1: { v: 'a', t: 's' },
    //   B1: { v: '123', t: 's' },
    //   C1: { v: 456, t: 'n' },
    //   B2: { v: 'abc123', t: 's' },
    //   C2: { v: '', t: 's' },
    //   D2: { v: 111.222333, t: 'n' },
    //   '!ref': 'A1:D2'
    // }

    let wb = getExcelWorkbookFromWorksheet(ws)
    console.log('wb', wb)
    // wb Workbook {
    //   SheetNames: [ 'data' ],
    //   Sheets: {
    //     data: {
    //       A1: [Object],
    //       B1: [Object],
    //       C1: [Object],
    //       B2: [Object],
    //       C2: [Object],
    //       D2: [Object],
    //       '!ref': 'A1:D2'
    //     }
    //   }
    // }

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`sheet` | Object |  |  | 輸入js-xlsx的worksheet物件
`sheetName` | String | <optional> | `'data'` | 輸入輸出為Excel時所在分頁(sheet)名稱字串，預設為'data'

#### (static) getFileAccept(groupByopt) → {Array}

Source:
  - getFileAccept.mjs, line 31

取得檔案關聯性資訊

Unit Test: Github

##### Example

Try in Codepen

    console.log(getFileAccept()[2])
    // => { name: 'pdf',
    //      group: 'docums',
    //      acp: 'application/pdf',
    //      exec: 'acrobat' }

    console.log(getFileAccept('acp')['text/html'])
    // => [ { name: 'htm',
    //        group: 'docums',
    //        acp: 'text/html',
    //        exec: 'browser' },
    //      { name: 'html',
    //        group: 'docums',
    //        acp: 'text/html',
    //        exec: 'browser' } ]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`groupBy` | string | <optional> | `''` | 輸入群組化關鍵字字串，預設''，可選用'name','group','acp','exec'

##### Returns:

回傳檔案關聯性資訊陣列，若有給groupBy則自動群組化

Type
  Array

#### (static) getFileName(str) → {string}

Source:
  - getFileName.mjs, line 93

由檔案位置取得檔案名稱

Unit Test: Github

##### Example

Try in Codepen

    let c

    c = 'C:\\temp\\myfile.html'
    console.log(getFileName(c))
    // => myfile.html

    c = 'C:\\temp\\myfile.txt.html'
    console.log(getFileName(c))
    // => myfile.txt.html

    c = 'C:\\temp\\myfile'
    console.log(getFileName(c))
    // => myfile

    c = 'C:\\temp\\\\temp\\\\myfile.txt.html'
    console.log(getFileName(c))
    // => myfile.txt.html

    c = 'C:\\temp\\'
    console.log(getFileName(c))
    // => temp

    c = 'C:\\temp'
    console.log(getFileName(c))
    // => temp

    c = 'C:\\'
    console.log(getFileName(c))
    // => C:\

    c = 'C:'
    console.log(getFileName(c))
    // => C:\

    c = '/tmp/myfile.html'
    console.log(getFileName(c))
    // => myfile.html

    c = '/tmp/myfile.txt.html'
    console.log(getFileName(c))
    // => myfile.txt.html

    c = '/tmp/myfile'
    console.log(getFileName(c))
    // => myfile

    c = '//tmp////tmp//myfile.txt.html'
    console.log(getFileName(c))
    // => myfile.txt.html

    c = '/tmp/'
    console.log(getFileName(c))
    // => tmp

    c = '/tmp'
    console.log(getFileName(c))
    // => tmp

    c = '/'
    console.log(getFileName(c))
    // => /

    c = '/foo/bar/baz/asdf/quux.html'
    console.log(getFileName(c))
    // => quux.html

    c = '/foo/bar/baz/asdf/quux.txt.html'
    console.log(getFileName(c))
    // => quux.txt.html

    c = '/foo/bar/baz/asdf/quux'
    console.log(getFileName(c))
    // => quux

    c = ''
    console.log(getFileName(c))
    // => [empty string]

##### Parameters:

Name | Type | Description
--- | --- | ---
`str` | string | 輸入檔案位置字串

##### Returns:

檔案名稱

Type
  string

#### (static) getFileTrueName(str) → {string}

Source:
  - getFileTrueName.mjs, line 97

由檔案位置取得檔案的不含副檔名名稱

Unit Test: Github

##### Example

Try in Codepen

    let c

    c = 'C:\\temp\\myfile.html'
    console.log(getFileTrueName(c))
    // => myfile

    c = 'C:\\temp\\myfile.txt.html'
    console.log(getFileTrueName(c))
    // => myfile.txt

    c = 'C:\\temp\\myfile'
    console.log(getFileTrueName(c))
    // => myfile

    c = 'C:\\temp\\\\temp\\\\myfile.txt.html'
    console.log(getFileTrueName(c))
    // => myfile.txt

    c = 'C:\\temp\\'
    console.log(getFileTrueName(c))
    // => temp

    c = 'C:\\temp'
    console.log(getFileTrueName(c))
    // => temp

    c = 'C:\\'
    console.log(getFileTrueName(c))
    // => C:\\

    c = 'C:'
    console.log(getFileTrueName(c))
    // => C:\\

    c = '/tmp/myfile.html'
    console.log(getFileTrueName(c))
    // => myfile

    c = '/tmp/myfile.txt.html'
    console.log(getFileTrueName(c))
    // => myfile.txt

    c = '/tmp/myfile'
    console.log(getFileTrueName(c))
    // => myfile

    c = '//tmp////tmp//myfile.txt.html'
    console.log(getFileTrueName(c))
    // => myfile.txt

    c = '/tmp/'
    console.log(getFileTrueName(c))
    // => tmp

    c = '/tmp'
    console.log(getFileTrueName(c))
    // => tmp

    c = '/'
    console.log(getFileTrueName(c))
    // => /

    c = '/foo/bar/baz/asdf/quux.html'
    console.log(getFileTrueName(c))
    // => quux

    c = '/foo/bar/baz/asdf/quux.txt.html'
    console.log(getFileTrueName(c))
    // => quux.txt

    c = '/foo/bar/baz/asdf/quux'
    console.log(getFileTrueName(c))
    // => quux

    c = ''
    console.log(getFileTrueName(c))
    // => [empty string]

##### Parameters:

Name | Type | Description
--- | --- | ---
`str` | string | 輸入檔案位置字串

##### Returns:

檔案不含副檔名的名稱

Type
  string

#### (static) getGlobal() → {Object}

Source:
  - getGlobal.mjs, line 16

取得運行環境中的頂層物件

Unit Test: Github

##### Example

Try in Codepen

    console.log(getGlobal())
    // => global object in running environment

##### Returns:

回傳頂層物件，若無法取得則回傳null

Type
  Object

#### (static) getltdtkeys(ltdt) → {Array}

Source:
  - getltdtkeys.mjs, line 20

由ltdt提取不重複keys

Unit Test: Github

##### Example

Try in Codepen

    console.log(getltdtkeys([{ a: 123, b: 'xyz', c: '45op', d: null }, { a: 123.456, b: 'xyz', d: '45op', e: '' }]))
    // => ['a', 'b', 'c', 'd', 'e']

##### Parameters:

Name | Type | Description
--- | --- | ---
`ltdt` | Array | 輸入物件陣列

##### Returns:

回傳不重複keys陣列

Type
  Array

#### (static) getObjSize(obj) → {Object}

Source:
  - getObjSize.mjs, line 17

計算物件記憶體大小

Unit Test: Github

##### Example

Try in Codepen

    console.log(getObjSize('abc123'))
    // => 12

    console.log(getObjSize({ a: 123, b: 'xyz', c: '45op', d: null }))
    // => 22

##### Parameters:

Name | Type | Description
--- | --- | ---
`obj` | * | 傳入欲計算大小的任意數據

##### Returns:

回傳記憶體大小物件, int屬性為記憶體所使用的bytes整數, str屬性為自動處理單位後的字串

Type
  Object

#### (static) getTimeBetween(tstart, tend, unitopt) → {Array}

Source:
  - getTimeBetween.mjs, line 28

輸入兩時間，單位皆為unit，由兩時間之間回傳以unit分切的時間點，回傳時間單位一樣為unit

Unit Test: Github

##### Example

Try in Codepen

    console.log(getTimeBetween('2017', '2019', 'years'))
    // => ['2017', '2018', '2019']

    console.log(getTimeBetween('2019-01-01', '2019-01-03', 'days'))
    // => ['2019-01-01', '2019-01-02', '2019-01-03']

    console.log(getTimeBetween('2019-01-01', '2019-01-03'))
    // => ['2019-01-01', '2019-01-02', '2019-01-03']

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`tstart` | String |  |  | 輸入開始時間字串，不含時區
`tend` | String |  |  | 輸入結束時間字串，不含時區
`unit` | String | <optional> | `'days'` | 輸入切分單位字串，預設為'days'

##### Returns:

回傳切分後各時間陣列

Type
  Array

#### (static) getTimeFromUnit(unit) → {String}

Source:
  - getTimeFromUnit.mjs, line 17

輸入時間單位，回傳時間套件所需之解析字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(getTimeFromUnit('years'))
    // => 'YYYY'

    console.log(getTimeFromUnit('seconds'))
    // => 'YYYY-MM-DDTHH:mm:ssZ'

##### Parameters:

Name | Type | Description
--- | --- | ---
`unit` | String | 輸入時間單位字串

##### Returns:

回傳時間套件所需之解析字串，當unit='seconds'時回傳不含時區格式

Type
  String

#### (static) getTimeObject(t, unitopt) → {Object}

Source:
  - getTimeObject.mjs, line 47

輸入時間字串，單位為unit，回傳解析後之時間物件

Unit Test: Github

##### Example

Try in Codepen

    console.log(getTimeObject('2019-01-01', 'days'))
    // => dayjs('2019-01-01', 'YYYY-MM-DD') //use dayjs or moment

    console.log(getTimeObject('2019-01-01T12:34:56', 'seconds'))
    // => dayjs('2019-01-01T12:34:56', 'YYYY-MM-DDTHH:mm:ssZ') //use dayjs or moment

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`t` | String |  |  | 輸入時間字串，不含時區
`unit` | String | <optional> | `'days'` | 輸入時間單位字串，預設為'days'

##### Returns:

回傳時間物件，若非法時間則回傳null

Type
  Object

#### (static) getTimeRange(tstart, tend) → {String}

Source:
  - getTimeRange.mjs, line 32

起訖時間合併顯示，時間單位皆為秒

Unit Test: Github

##### Example

Try in Codepen

    console.log(getTimeRange('2019-01-01T09:00:00'))
    // => '2019-01-01T09:00 至 無'

    console.log(getTimeRange('2019-01-01T09:00:00', '2019-01-01T12:34:56'))
    // => '2019-01-01T09:00 至 12:34'

    console.log(getTimeRange('2019-01-01T09:00:00', '2019-01-03T12:00:00'))
    // => '2019-01-01T09:00 至 2019-01-03T12:00'

    console.log(getTimeRange('2019-01-01T19:00:00', '2019-01-01T12:00:00'))
    // => '2019-01-01T19:00 至 12:00 (起始時間大於結束時間)'

    console.log(getTimeRange('2019-01-03T09:00:00', '2019-01-01T12:00:00'))
    // => '2019-01-03T09:00 至 2019-01-01T12:00 (起始時間大於結束時間)'

##### Parameters:

Name | Type | Description
--- | --- | ---
`tstart` | String | 輸入開始秒時間字串，不含時區
`tend` | String | 輸入結束秒時間字串，不含時區，若不輸入則等同於開始時間字串

##### Returns:

回傳合併顯示時間字串

Type
  String

#### (static) getUserAgent(vopt) → {Object}

Source:
  - getUserAgent.mjs, line 35

取得使用者瀏覽器資訊，後端nodejs環境使用需提供user agent字串

Unit Test: Github

##### Example

Try in Codepen

    let ua = 'Mozilla/5.0 (compatible; Konqueror/4.1; OpenBSD) KHTML/4.1.4 (like Gecko)'
    console.log(getUserAgent(ua))
    // => {
        browsername: 'Konqueror',
        browserversion: '4.1',
        cpuarchitecture: '',
        devicetype: '',
        engineinfor: 'KHTML4.1.4',
        platform: 'OpenBSDundefined'
    }

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`v` | String | <optional> | `null` | 輸入user agent字串，預設null

##### Returns:

回傳使用者瀏覽器資訊物件

Type
  Object

#### (async, static) getUserAgentDyn(vopt, pathItems) → {Promise}

Source:
  - getUserAgentDyn.mjs, line 32

前端取得使用者瀏覽器資訊，於browser中不輸入即可自動偵測，採用動態加載技術

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ua = 'Mozilla/5.0 (compatible; Konqueror/4.1; OpenBSD) KHTML/4.1.4 (like Gecko)'
    getUserAgentDyn(ua)
        .then(function(r) {
            console.log(r)
            // => {
                browsername: 'Konqueror',
                browserversion: '4.1',
                cpuarchitecture: '',
                devicetype: '',
                engineinfor: 'KHTML4.1.4',
                platform: 'OpenBSDundefined'
            }
        })

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`v` | String | <optional> | `null` | 輸入user agent字串，預設null
`pathItems` | String | Object | Array |  |  | 輸入資源字串、字串陣列、物件、物件陣列

##### Returns:

回傳Promise，resolve回傳使用者瀏覽器資訊物件，reject回傳錯誤訊息

Type
  Promise

#### (static) haskey(obj, key) → {Boolean}

Source:
  - haskey.mjs, line 19

判斷物件是否有key屬性

Unit Test: Github

##### Example

Try in Codepen

    console.log(haskey({ a: 123, b: 'xyz', c: '45op', d: null }, 'a'))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`obj` | Object | 輸入物件
`key` | String | 輸入要查找的key字串

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (async, static) html2pic(ele, optopt) → {Promise}

Source:
  - html2pic.mjs, line 108

前端DOM元素轉圖片

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    html2pic(ele, { scale: 3 })
        .then((b64)=>{
            // => iVBORw0KGgoAAAANSU...
        })

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ele` | HTMLElement |  |  | 輸入元素

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`scale` | Number | <optional> | `1` | 輸入縮放比例數字，需大於等於1，預設1
`toBase64` | Boolean | <optional> | `true` | 輸入是否輸出為base64圖片，預設true
`picType` | String | <optional> | `'image/jpeg'` | 輸入輸出為base64圖片時的圖片格式，可選'image/jpeg'與'image/png'，預設'image/jpeg'

##### Returns:

回傳Promise，resolve為成功時的產出圖片，reject為失敗訊息

Type
  Promise

#### (async, static) html2picDyn(ele, optopt, pathItems) → {Promise}

Source:
  - html2picDyn.mjs, line 27

前端DOM元素轉圖片，採用動態加載技術

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    html2picDyn(ele, { scale: 3 })
        .then((b64)=>{
            // => iVBORw0KGgoAAAANSU...
        })

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ele` | HTMLElement |  |  | 輸入元素

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`scale` | Number | <optional> | `1` | 輸入縮放比例數字，需大於等於1，預設1
`toBase64` | Boolean | <optional> | `true` | 輸入是否輸出為base64圖片，預設true
`picType` | String | <optional> | `'image/jpeg'` | 輸入輸出為base64圖片時的圖片格式，可選'image/jpeg'與'image/png'，預設'image/jpeg'

`pathItems` | String | Object | Array |  |  | 輸入資源字串、字串陣列、物件、物件陣列

##### Returns:

回傳Promise，resolve回傳使用者瀏覽器資訊物件，reject回傳錯誤訊息

Type
  Promise

#### (static) html2str(html) → {String}

Source:
  - html2str.mjs, line 55

html轉純文字

Unit Test: Github

##### Example

Try in Codepen

    let h = `
    <!DOCTYPE html>
    <html>

    <body>
        <h1>My First Heading</h1>
        <p>My first paragraph.</p>
    </body>

    </html>
    `

    let c = html2str(h)
    console.log(c)
    // =>
    //
    //
    //
    //
    //     My First Heading
    //     My first paragraph.
    //
    //
    //
    //

##### Parameters:

Name | Type | Description
--- | --- | ---
`html` | String | 輸入html字串

##### Returns:

回傳純文字字串

Type
  String

#### (async, static) html2strDyn(html, pathItems) → {String}

Source:
  - html2strDyn.mjs, line 44

前端html轉純文字，採用動態加載技術

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let h = `
    <!DOCTYPE html>
    <html>

    <body>
        <h1>My First Heading</h1>
        <p>My first paragraph.</p>
    </body>

    </html>
    `

    let c = await html2str(h)
    console.log(c)
    // =>
    //
    //
    //
    //
    //     My First Heading
    //     My first paragraph.
    //
    //
    //
    //

##### Parameters:

Name | Type | Description
--- | --- | ---
`html` | String | 輸入html字串
`pathItems` | String | Object | Array | 輸入資源字串、字串陣列、物件、物件陣列

##### Returns:

回傳純文字字串

Type
  String

#### (static) htmlDecode(str) → {String}

Source:
  - htmlDecode.mjs, line 12

前端html字串反編碼

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

##### Parameters:

Name | Type | Description
--- | --- | ---
`str` | String | 輸入編碼後html字串

##### Returns:

回傳html字串

Type
  String

#### (static) htmlEncode(str) → {String}

Source:
  - htmlEncode.mjs, line 12

前端html字串編碼

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

##### Parameters:

Name | Type | Description
--- | --- | ---
`str` | String | 輸入html字串

##### Returns:

回傳編碼後html字串

Type
  String

#### (static) importResources(pathItems) → {Promise}

Source:
  - importResources.mjs, line 146

前端動態引入資源如Javascript或CSS檔案

Unit Test: Github

##### Example

Try in Codepen

    //need test in browser

    let pathItems

    pathItems = [
        'https://cdn.jsdelivr.net/npm/ag-grid-community@22.0.0/dist/ag-grid-community.noStyle.js',
        'https://cdn.jsdelivr.net/npm/ag-grid-vue@22.0.0/dist/ag-grid-vue.umd.js',
        'https://cdn.jsdelivr.net/npm/w-aggrid-vue@1.0.28/dist/w-aggrid-vue.umd.js',
    ]
    importResources(pathItems)
        .then((res)=>{
            console.log(res)
        })

    pathItems = [
        {
            path: 'https://cdn.jsdelivr.net/npm/ag-grid-community@22.0.0/dist/ag-grid-community.noStyle.js',
            type: 'js',
        },
        {
            path: 'https://cdn.jsdelivr.net/npm/ag-grid-vue@22.0.0/dist/ag-grid-vue.umd.js',
            type: 'js',
        },
        {
            path: 'https://cdn.jsdelivr.net/npm/w-aggrid-vue@1.0.28/dist/w-aggrid-vue.umd.js',
            type: 'js',
        },
    ]
    importResources(pathItems)
        .then((res)=>{
            console.log(res)
        })

##### Parameters:

Name | Type | Description
--- | --- | ---
`pathItems` | String | Object | Array | 輸入資源字串、字串陣列、物件、物件陣列

##### Returns:

回傳Promise，resolve回傳注入成功的HtmlElement，reject回傳錯誤訊息

Type
  Promise

#### (static) interp1(ps, x, optopt) → {Number|Object}

Source:
  - interp1.mjs, line 640

一維數據內插

Unit Test: Github

##### Example

Try in Codepen

    let r
    let x

    let ps = [
        { x: 1, y: 0.2 },
        { x: 3, y: 1.2 },
        { x: 4, y: 2 },
    ]

    let psInv = [
        { x: 4, y: 2 },
        { x: 3, y: 1.2 },
        { x: 1, y: 0.2 },
    ]

    let psErr = [
        { x: 'a', y: 0.2 },
        { x: 'mnop', y: 1.2 },
        { x: 'xyz', y: 2 },
    ]

    let psEmpty = [
    ]

    let psEffOne = [
        { x: 1, y: 0.2 },
        { x: 'mnop', y: 1.2 },
        { x: 'xyz', y: 2 },
    ]

    let psP = [
        { a: 1, b: 0.2 },
        { a: 3, b: 1.2 },
        { a: 4, b: 2 },
    ]

    let opt = {
        mode: 'stairs',
    }

    let optX = {
        mode: 'stairs',
        xMin: 0,
        xMax: 4.5,
    }

    let optP = {
        keyX: 'a',
        keyY: 'b',
    }

    x = 0
    r = interp1(psErr, x)
    console.log(`linear(error data): x=${x}`, 'r=' + JSON.stringify(r))
    // => linear(error data): x=0 r={"err":"ps(length=0) is not effective array","ps":[{"x":"a","y":0.2},{"x":"mnop","y":1.2},{"x":"xyz","y":2}],"psEff":[]}

    x = 0
    r = interp1(psEmpty, x)
    console.log(`linear(empty data): x=${x}`, 'r=' + JSON.stringify(r))
    // => linear(empty data): x=0 r={"err":"ps(length=0) is not effective array","ps":[],"psEff":[]}

    x = 0
    r = interp1(psEffOne, x)
    console.log(`linear(one point): x=${x}`, 'r=' + JSON.stringify(r))
    // => linear(one point): x=0 r={"err":"ps(length=1) is one point only","ps":[{"x":1,"y":0.2},{"x":"mnop","y":1.2},{"x":"xyz","y":2}],"psEff":[{"x":1,"y":0.2}]}

    x = 0
    r = interp1(ps, x)
    console.log(`linear: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear: x=0 r={"err":"x[0] less than lower limit[1]","data":{"ps":[{"x":1,"y":0.2},{"x":3,"y":1.2},{"x":4,"y":2}],"x":0,"trend":"increasing sequence","xmin":1,"xmax":4}}

    x = 1
    r = interp1(ps, x)
    console.log(`linear: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear: x=1 r=0.2

    x = 2
    r = interp1(ps, x)
    console.log(`linear: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear: x=2 r=0.7

    x = 2.6
    r = interp1(ps, x)
    console.log(`linear: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear: x=2.6 r=1

    x = 3
    r = interp1(ps, x)
    console.log(`linear: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear: x=3 r=1.2

    x = 3.5
    r = interp1(ps, x)
    console.log(`linear: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear: x=3.5 r=1.6

    x = 4
    r = interp1(ps, x)
    console.log(`linear: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear: x=4 r=2

    x = 5
    r = interp1(ps, x)
    console.log(`linear: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear: x=5 r={"err":"x[5] greater than upper limit[4]","data":{"ps":[{"x":1,"y":0.2},{"x":3,"y":1.2},{"x":4,"y":2}],"x":5,"trend":"increasing sequence","xmin":1,"xmax":4}}

    x = 0
    r = interp1(psInv, x)
    console.log(`linear(inverse data): x=${x}`, 'r=' + JSON.stringify(r))
    // => linear(inverse data): x=0 r={"err":"x[0] less than lower limit[1]","data":{"ps":[{"x":1,"y":0.2},{"x":3,"y":1.2},{"x":4,"y":2}],"x":0,"trend":"increasing sequence","xmin":1,"xmax":4}}

    x = 1
    r = interp1(psInv, x)
    console.log(`linear(inverse data): x=${x}`, 'r=' + JSON.stringify(r))
    // => linear(inverse data): x=1 r=0.2

    x = 2
    r = interp1(psInv, x)
    console.log(`linear(inverse data): x=${x}`, 'r=' + JSON.stringify(r))
    // => linear(inverse data): x=2 r=0.7

    x = 2.6
    r = interp1(psInv, x)
    console.log(`linear(inverse data): x=${x}`, 'r=' + JSON.stringify(r))
    // => linear(inverse data): x=2.6 r=1

    x = 3
    r = interp1(psInv, x)
    console.log(`linear(inverse data): x=${x}`, 'r=' + JSON.stringify(r))
    // => linear(inverse data): x=3 r=1.2

    x = 3.5
    r = interp1(psInv, x)
    console.log(`linear(inverse data): x=${x}`, 'r=' + JSON.stringify(r))
    // => linear(inverse data): x=3.5 r=1.6

    x = 4
    r = interp1(psInv, x)
    console.log(`linear(inverse data): x=${x}`, 'r=' + JSON.stringify(r))
    // => linear(inverse data): x=4 r=2

    x = 5
    r = interp1(psInv, x)
    console.log(`linear(inverse data): x=${x}`, 'r=' + JSON.stringify(r))
    // => linear: x=5 r={"err":"x[5] greater than upper limit[4]","data":{"ps":[{"x":1,"y":0.2},{"x":3,"y":1.2},{"x":4,"y":2}],"x":5,"trend":"increasing sequence","xmin":1,"xmax":4}}

    x = -1
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=-1 r={"err":"x[-1] less than lower limit[1]","data":{"ps":[{"x":1,"y":0.2},{"x":3,"y":1.2},{"x":4,"y":2}],"x":-1,"trend":"increasing sequence","xmin":1,"xmax":4}}

    x = 0.51
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=0.51 r={"err":"x[0.51] less than lower limit[1]","data":{"ps":[{"x":1,"y":0.2},{"x":3,"y":1.2},{"x":4,"y":2}],"x":0.51,"trend":"increasing sequence","xmin":1,"xmax":4}}

    x = 1
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=1 r=0.2

    x = 1.9
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=1.9 r=0.2

    x = 2
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=2 r=0.2

    x = 2.1
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=2.1 r=1.2

    x = 2.5
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=2.5 r=1.2

    x = 3
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=3 r=1.2

    x = 3.49
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=3.49 r=1.2

    x = 3.5
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=3.5 r=1.2

    x = 3.51
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=3.51 r=2

    x = 4
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=4 r=2

    x = 4.5
    r = interp1(ps, x, opt)
    console.log(`stairs: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs: x=4.5 r={"err":"x[4.5] greater than upper limit[4]","data":{"ps":[{"x":1,"y":0.2},{"x":3,"y":1.2},{"x":4,"y":2}],"x":4.5,"trend":"increasing sequence","xmin":1,"xmax":4}}

    x = -1
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=-1 r={"err":"x[-1] less than lower limit[0]","data":{"ps":[{"x":0,"y":0.2},{"x":1,"y":0.2},{"x":3,"y":1.2},{"x":4,"y":2},{"x":4.5,"y":2}],"x":-1,"trend":"increasing sequence","xmin":0,"xmax":4.5}}

    x = 0
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=0 r=0.2

    x = 0.49
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=0.49 r=0.2

    x = 0.5
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=0.5 r=0.2

    x = 0.51
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=0.51 r=0.2

    x = 1
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=1 r=0.2

    x = 1.9
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=1.9 r=0.2

    x = 2
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=2 r=0.2

    x = 2.1
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=2.1 r=1.2

    x = 2.5
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=2.5 r=1.2

    x = 3
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=3 r=1.2

    x = 3.49
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=3.49 r=1.2

    x = 3.5
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=3.5 r=1.2

    x = 3.51
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=3.51 r=2

    x = 4
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=4 r=2

    x = 4.49
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=4.49 r=2

    x = 4.5
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=4.5 r=2

    x = 4.51
    r = interp1(ps, x, optX)
    console.log(`stairs with x-limit: x=${x}`, 'r=' + JSON.stringify(r))
    // => stairs with x-limit: x=4.51 r={"err":"x[4.51] greater than upper limit[4.5]","data":{"ps":[{"x":0,"y":0.2},{"x":1,"y":0.2},{"x":3,"y":1.2},{"x":4,"y":2},{"x":4.5,"y":2}],"x":4.51,"trend":"increasing sequence","xmin":0,"xmax":4.5}}

    x = 0
    r = interp1(psP, x, optP)
    console.log(`linear by keyX & keyY: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear by keyX & keyY: x=0 r={"err":"x[0] less than lower limit[1]","data":{"ps":[{"x":1,"y":0.2},{"x":3,"y":1.2},{"x":4,"y":2}],"x":0,"trend":"increasing sequence","xmin":1,"xmax":4}}

    x = 1
    r = interp1(psP, x, optP)
    console.log(`linear by keyX & keyY: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear by keyX & keyY: x=1 r=0.2

    x = 2
    r = interp1(psP, x, optP)
    console.log(`linear by keyX & keyY: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear by keyX & keyY: x=2 r=0.7

    x = 2.6
    r = interp1(psP, x, optP)
    console.log(`linear by keyX & keyY: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear by keyX & keyY: x=2.6 r=1

    x = 3
    r = interp1(psP, x, optP)
    console.log(`linear by keyX & keyY: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear by keyX & keyY: x=3 r=1.2

    x = 3.5
    r = interp1(psP, x, optP)
    console.log(`linear by keyX & keyY: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear by keyX & keyY: x=3.5 r=1.6

    x = 4
    r = interp1(psP, x, optP)
    console.log(`linear by keyX & keyY: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear by keyX & keyY: x=4 r=2

    x = 5
    r = interp1(psP, x, optP)
    console.log(`linear by keyX & keyY: x=${x}`, 'r=' + JSON.stringify(r))
    // => linear by keyX & keyY: x=5 r={"err":"x[5] greater than upper limit[4]","data":{"ps":[{"x":1,"y":0.2},{"x":3,"y":1.2},{"x":4,"y":2}],"x":5,"trend":"increasing sequence","xmin":1,"xmax":4}}

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ps` | Array |  |  | 輸入一維數據，格式可支援兩種，第一種各點為陣列[[x1,y1],[x2,y2],...]，例如[[0.1,5],[0.2,12],...]，第二種各點為物件，屬性至少要有x與y，格式為[{x:x1,y:y1},{x:x2,y:y2},...]，例如[{x:0.1,y:5},{x:0.2,y:12},...]，key值x與y可由opt更換
`x` | Number |  |  | 輸入要內插點的x值

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`mode` | String | <optional> | `''` | 輸入內插方法，可選'linear'、'stairs'、'blocks'，預設'linear'
`keyX` | String | <optional> | `'x'` | 輸入若數據為物件陣列，取物件x值時的key字串，預設為'x'
`keyY` | String | <optional> | `'y'` | 輸入若數據為物件陣列，取物件y值時的key字串，預設為'y'
`xMin` | Number | <optional> |  | 輸入若mode='stairs'，更改x範圍下限值，預設為undefined
`xMax` | Number | <optional> |  | 輸入若mode='stairs'，更改x範圍上限值，預設為undefined

##### Returns:

回傳內插結果數值，或是無法內插時之錯誤訊息物件

Type
  Number | Object

#### (static) isab(v) → {Boolean}

Source:
  - isab.mjs, line 14

判斷是否為ArrayBuffer

Unit Test: Github

##### Example

Try in Codepen

    console.log(isab(new ArrayBuffer(1)))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isarr(v) → {Boolean}

Source:
  - isarr.mjs, line 17

判斷是否為陣列

Unit Test: Github

##### Example

Try in Codepen

    console.log(isarr([]))
    // => true

    console.log(isarr([{}]))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isarr0(v) → {Boolean}

Source:
  - isarr0.mjs, line 20

判斷是否為無內容陣列

Unit Test: Github

##### Example

Try in Codepen

    console.log(isarr([]))
    // => true

    console.log(isarr([{}]))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isblob(v) → {Boolean}

Source:
  - isblob.mjs, line 16

前端判斷是否為Blob，NodeJS沒有Blob

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let bb = new Blob([new Uint8Array([66, 97, 115])])
    console.log(isblob(bb))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isbol(v) → {Boolean}

Source:
  - isbol.mjs, line 17

判斷是否為boolean

Unit Test: Github

##### Example

Try in Codepen

    console.log(isbol(false))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isday(v) → {Boolean}

Source:
  - isday.mjs, line 18

判斷是否為日時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(isday('2019-01-01'))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | String | 輸入日時間字串

##### Returns:

回傳是否為日時間布林值

Type
  Boolean

#### (static) isDev() → {Boolean}

Source:
  - isDev.mjs, line 17

前端判斷是否為開發階段 主要判斷location.href內是否含有localhost Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    console.log(isDev())
    // => true or false

##### Returns:

回傳是否為開發階段

Type
  Boolean

#### (static) isearr(v) → {Boolean}

Source:
  - isearr.mjs, line 21

判斷是否為有效陣列，長度至少大於等於1，各元素至少皆為有效

Unit Test: Github

##### Example

Try in Codepen

    console.log(isearr([{}]))
    // => false

    console.log(isearr([{ a: 123 }]))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isEle(ele) → {Boolean}

Source:
  - isEle.mjs, line 19

前端判斷元素是否存在

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let ele = document.querySelector('#id')
    console.log(isEle(ele))
    // => true or false

##### Parameters:

Name | Type | Description
--- | --- | ---
`ele` | Element | 輸入DOM元素

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isEleExistByID(id) → {Boolean}

Source:
  - isEleExistByID.mjs, line 18

前端判斷元素id是否存在

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    console.log(isEleExistByID('#id'))
    // => true or false

##### Parameters:

Name | Type | Description
--- | --- | ---
`id` | String | 輸入id字串

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isEmail(email) → {Boolean}

Source:
  - isEmail.mjs, line 20

判斷是否為廣義無效

Unit Test: Github

##### Example

Try in Codepen

    console.log(isEmail('abc@mail.com'))
    // => true

    console.log(isEmail('abc@a.b'))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`email` | String | 輸入email字串

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) iseobj(v) → {Boolean}

Source:
  - iseobj.mjs, line 20

判斷是否為有效物件

Unit Test: Github

##### Example

Try in Codepen

    console.log(iseobj({}))
    // => false

    console.log(iseobj({ a: 123 }))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) iser(v) → {Boolean}

Source:
  - iser.mjs, line 42

判斷是否為廣義無效

Unit Test: Github

##### Example

Try in Codepen

    console.log(iser('12a5'))
    // => false

    console.log(iser(''))
    // => true

    console.log(iser([]))
    // => true

    console.log(iser([{}]))
    // => false

    console.log(iser(['']))
    // => false

    console.log(iser({}))
    // => true

    console.log(iser(null))
    // => true

    console.log(iser(undefined))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isernot(v) → {Boolean}

Source:
  - isernot.mjs, line 38

判斷是否為廣義有效

Unit Test: Github

##### Example

Try in Codepen

    console.log(isernot('12a5'))
    // => true

    console.log(isernot(''))
    // => false

    console.log(isernot([]))
    // => false

    console.log(isernot([{}]))
    // => true

    console.log(isernot(['']))
    // => true

    console.log(isernot({}))
    // => false

    console.log(isernot(null))
    // => false

    console.log(isernot(undefined))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isestr(v) → {Boolean}

Source:
  - isestr.mjs, line 23

判斷是否為有效字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(isestr('1.25'))
    // => true

    console.log(isestr(125))
    // => false

    console.log(isestr(''))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isfun(v) → {Boolean}

Source:
  - isfun.mjs, line 17

判斷是否為函數

Unit Test: Github

##### Example

Try in Codepen

    console.log(isfun('1.25'))
    // => false

    console.log(isfun(function() {}))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isIE() → {Boolean}

Source:
  - isIE.mjs, line 13

前端判斷瀏覽器是否為IE

Unit Test: Github

##### Example

Try in Codepen

    console.log(isIE())
    // => true

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isint(v) → {Boolean}

Source:
  - isint.mjs, line 28

判斷是否為整數

Unit Test: Github

##### Example

Try in Codepen

    console.log(isint('1.25'))
    // => false

    console.log(isint('125'))
    // => true

    console.log(isint(1.25))
    // => false

    console.log(isint(125))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) ismonth(v) → {Boolean}

Source:
  - ismonth.mjs, line 21

判斷是否為月時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(ismonth('2019-01-01'))
    // => false

    console.log(ismonth('2019-01'))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | String | 輸入月時間字串

##### Returns:

回傳是否為月時間布林值

Type
  Boolean

#### (static) isn0int(v) → {Boolean}

Source:
  - isn0int.mjs, line 25

判斷是否為小於等於0整數(非正整數) 非正整數包含0

Unit Test: Github

##### Example

Try in Codepen

    console.log(isn0int(0))
    // => true

    console.log(isn0int(125))
    // => false

    console.log(isn0int(-125))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isn0num(v) → {Boolean}

Source:
  - isn0num.mjs, line 37

判斷是否為小於等於0浮點數(非正浮點數) 非正浮點數包含0

Unit Test: Github

##### Example

Try in Codepen

    console.log(isn0num(0))
    // => true

    console.log(isn0num(-125))
    // => true

    console.log(isn0num(-1.25))
    // => true

    console.log(isn0num(125))
    // => false

    console.log(isn0num('-125'))
    // => true

    console.log(isn0num('-1.25'))
    // => true

    console.log(isn0num('125'))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isNarrow(eleopt) → {Boolean}

Source:
  - isNarrow.mjs, line 24

前端判斷是否為窄版裝置 主要判斷瀏覽器視窗寬度是否大於0與小於1024，若有傳DOM元素，則再加判斷該元素寬度是否大於0與小於700

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    console.log(isNarrow())
    // => true or false

    let ele = document.querySelector('#id')
    console.log(isNarrow(ele))
    // => true or false

##### Parameters:

Name | Type | Attributes | Description
--- | --- | --- | ---
`ele` | Element | <optional> | 輸入為DOM元素，預設為不使用

##### Returns:

回傳是否為窄版裝置

Type
  Boolean

#### (static) isnbr(v) → {Boolean}

Source:
  - isnbr.mjs, line 17

判斷是否為數字

Unit Test: Github

##### Example

Try in Codepen

    console.log(isnbr(1.25))
    // => true

    console.log(isnbr('1.25'))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isnint(v) → {Boolean}

Source:
  - isnint.mjs, line 25

判斷是否為負整數 負整數不包含0，為小於0的整數

Unit Test: Github

##### Example

Try in Codepen

    console.log(isnint(0))
    // => false

    console.log(isnint(125))
    // => false

    console.log(isnint(-125))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isnull(v) → {Boolean}

Source:
  - isnull.mjs, line 14

判斷是否為null

Unit Test: Github

##### Example

Try in Codepen

    console.log(isnull(null))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isnum(v) → {Boolean}

Source:
  - isnum.mjs, line 24

判斷是否為數字

Unit Test: Github

##### Example

Try in Codepen

    console.log(isnum(0))
    // => true

    console.log(isnum(1.25))
    // => true

    console.log(isnum('-125'))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isobj(v) → {Boolean}

Source:
  - isobj.mjs, line 17

判斷是否為物件

Unit Test: Github

##### Example

Try in Codepen

    console.log(isobj({}))
    // => true

    console.log(isobj({ a: 123 }))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isobj0(v) → {Boolean}

Source:
  - isobj0.mjs, line 20

判斷是否為空物件

Unit Test: Github

##### Example

Try in Codepen

    console.log(isobj0({}))
    // => true

    console.log(isobj0({ a: 123 }))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isp0int(v) → {Boolean}

Source:
  - isp0int.mjs, line 28

判斷是否為大於等於0整數(非負整數) 非負整數包含0

Unit Test: Github

##### Example

Try in Codepen

    console.log(isp0int(0))
    // => true

    console.log(isp0int(125))
    // => true

    console.log(isp0int(1.25))
    // => false

    console.log(isp0int('125'))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isp0num(v) → {Boolean}

Source:
  - isp0num.mjs, line 31

判斷是否為大於等於0浮點數(非負浮點數) 非負浮點數包含0

Unit Test: Github

##### Example

Try in Codepen

    console.log(isp0num(0))
    // => true

    console.log(isp0num(125))
    // => true

    console.log(isp0num(1.25))
    // => true

    console.log(isp0num(-1.25))
    // => false

    console.log(isp0num('1.25'))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) ispint(v) → {Boolean}

Source:
  - ispint.mjs, line 28

判斷是否為正整數 正整數不包含0，為大於0的整數

Unit Test: Github

##### Example

Try in Codepen

    console.log(ispint(0))
    // => false

    console.log(ispint(125))
    // => true

    console.log(ispint('125'))
    // => true

    console.log(ispint(1.25))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) ispm(v) → {Boolean}

Source:
  - ispm.mjs, line 17

判斷是否為Promise

Unit Test: Github

##### Example

Try in Codepen

    console.log(ispm('1.25'))
    // => false

    console.log(ispm(new Promise(function() {})))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isstr(v) → {Boolean}

Source:
  - isstr.mjs, line 20

判斷是否為字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(isstr(0))
    // => false

    console.log(isstr('0'))
    // => true

    console.log(isstr(''))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isstr0(v) → {Boolean}

Source:
  - isstr0.mjs, line 23

判斷是否為空字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(isstr0(''))
    // => true

    console.log(isstr0('0'))
    // => false

    console.log(isstr0('abc125'))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isStrHasCapital(str) → {Boolean}

Source:
  - isStrHasCapital.mjs, line 20

字串是否包含大寫英文字元

Unit Test: Github

##### Example

Try in Codepen

    console.log(isStrHasCapital('abc125'))
    // => false

    console.log(isStrHasCapital('abC125'))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`str` | String | 輸入欲判斷的字串

##### Returns:

回傳是否包含大寫英文字元

Type
  Boolean

#### (static) isStrHasLowerCase(str) → {Boolean}

Source:
  - isStrHasLowerCase.mjs, line 20

字串是否包含小寫英文字元

Unit Test: Github

##### Example

Try in Codepen

    console.log(isStrHasLowerCase('ABC125'))
    // => false

    console.log(isStrHasLowerCase('abC125'))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`str` | String | 輸入欲判斷的字串

##### Returns:

回傳是否包含小寫英文字元

Type
  Boolean

#### (static) isStrHasNumber(str) → {Boolean}

Source:
  - isStrHasNumber.mjs, line 20

字串是否包含數字

Unit Test: Github

##### Example

Try in Codepen

    console.log(isStrHasNumber('abc'))
    // => false

    console.log(isStrHasNumber('abc125'))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`str` | String | 輸入欲判斷的字串

##### Returns:

回傳是否包含數字

Type
  Boolean

#### (static) istime(v) → {Boolean}

Source:
  - istime.mjs, line 24

判斷是否為秒時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(istime('2019-01-01T12:34:56:789'))
    // => false

    console.log(istime('2019-01-01T12:34:56'))
    // => true

    console.log(istime('2019-01-01'))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | String | 輸入秒時間字串，不含時區

##### Returns:

回傳是否為秒時間布林值

Type
  Boolean

#### (static) istimems(v) → {Boolean}

Source:
  - istimems.mjs, line 27

判斷是否為秒時間，不含時區

Unit Test: Github

##### Example

Try in Codepen

    console.log(istimems('2019-01-01T12:34:56:789.321'))
    // => false

    console.log(istimems('2019-01-01T12:34:56.321'))
    // => true

    console.log(istimems('2019-01-01T12:34:56'))
    // => false

    console.log(istimems('2019-01-01'))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | String | 輸入毫秒時間字串，不含時區

##### Returns:

回傳是否為毫秒時間布林值

Type
  Boolean

#### (static) istimemsTZ(v) → {Boolean}

Source:
  - istimemsTZ.mjs, line 31

判斷是否為毫秒時間，含時區

Unit Test: Github

##### Example

Try in Codepen

    console.log(istimemsTZ('2019-01-01T12:34:56.789+08:00'))
    // => true

    console.log(istimemsTZ('2019-01-01T12:34:56.789Z'))
    // => true

    console.log(istimemsTZ('2019-01-01T12:34:56:789+08:00'))
    // => false

    console.log(istimemsTZ('2019-01-01T12:34:56+08:00'))
    // => false

    console.log(istimemsTZ('2019-01-01'))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | String | 輸入毫秒時間字串，含時區

##### Returns:

回傳是否為毫秒時間布林值

Type
  Boolean

#### (static) istimeTZ(v) → {Boolean}

Source:
  - istimeTZ.mjs, line 31

判斷是否為秒時間，含時區

Unit Test: Github

##### Example

Try in Codepen

    console.log(istimeTZ('2019-01-01T12:34:56:789+08:00'))
    // => false

    console.log(istimeTZ('2019-01-01T12:34:56+08:00'))
    // => true

    console.log(istimeTZ('2019-01-01T12:34:56Z'))
    // => true

    console.log(istimeTZ('2019-01-01T12:34:56A'))
    // => false

    console.log(istimeTZ('2019-01-01'))
    // => false

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | String | 輸入秒時間字串，含時區

##### Returns:

回傳是否為秒時間布林值

Type
  Boolean

#### (static) isu8arr(v) → {Boolean}

Source:
  - isu8arr.mjs, line 14

判斷是否為Uint8Array

Unit Test: Github

##### Example

Try in Codepen

    console.log(isu8arr(new Uint8Array(1)))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isu16arr(v) → {Boolean}

Source:
  - isu16arr.mjs, line 14

判斷是否為Uint16Array

Unit Test: Github

##### Example

Try in Codepen

    console.log(isu16arr(new Uint16Array(1)))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isundefined(v) → {Boolean}

Source:
  - isundefined.mjs, line 14

判斷是否為undefined

Unit Test: Github

##### Example

Try in Codepen

    console.log(isundefined(undefined))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) isUserIdentify(v) → {Promise}

Source:
  - isUserIdentify.mjs, line 22

判斷是否為有效中華民國身份證

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    isUserIdentify('A122471399')
        .then(function(){
            console.log('then')
            //code here
        })

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳Promise，resolve為空代表有效，reject為錯誤訊息

Type
  Promise

#### (static) isUserName(v) → {Promise}

Source:
  - isUserName.mjs, line 22

判斷是否為有效使用者名稱

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    isUserName('我的名稱')
        .then(function() {
            console.log('then')
            //code here
        })

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳Promise，resolve為空代表有效，reject為錯誤訊息

Type
  Promise

#### (static) isUserPW(v) → {Promise}

Source:
  - isUserPW.mjs, line 27

判斷是否為有效user password

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    isUserPW('Asdf1234')
        .then(function() {
            console.log('then')
            //code here
        })

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | * | 輸入任意資料

##### Returns:

回傳Promise，resolve為空代表有效，reject為錯誤訊息

Type
  Promise

#### (static) isWindow() → {Boolean}

Source:
  - isWindow.mjs, line 14

判斷是否為瀏覽器環境

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    console.log(isWindow())
    // => true or false

##### Returns:

回傳判斷布林值

Type
  Boolean

#### (static) j2o(v) → {*}

Source:
  - j2o.mjs, line 20

json文字轉任意資料

Unit Test: Github

##### Example

Try in Codepen

    console.log(j2o('[1,"3","abc"]'))
    // => [1, '3', 'abc']

    console.log(j2o('{"a":12.34,"b":"abc"}'))
    // => { a: 12.34, b: 'abc' }

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | String | 輸入json格式字串

##### Returns:

回傳任意資料

Type
  *

#### (static) keysmat2ltdt(keys, mat) → {Array}

Source:
  - keysmat2ltdt.mjs, line 21

由keys與二維陣列mdata轉ltdt

Unit Test: Github

##### Example

Try in Codepen

    console.log(keysmat2ltdt(['a', 'b'], [[12, 34.56], ['123', 'xyz']]))
    // => [{ a: 12, b: 34.56 }, { a: '123', b: 'xyz' }]

##### Parameters:

Name | Type | Description
--- | --- | ---
`keys` | Array | 輸入字串陣列
`mat` | Array | 輸入資料陣列

##### Returns:

回傳物件陣列

Type
  Array

#### (static) log() → {Object}

Source:
  - log.mjs, line 58

log紀錄封裝器

Unit Test: Github

##### Example

Try in Codepen

    let ms = []
    let lg = log()
    lg.init(function(v) {
        console.log(v)
        ms.push({
            from: v.from,
            level: v.level,
            msg: v.msg,
        })
    })

    lg.log('service:web', 'infor', 'abc')
    lg.log('service:web', 'error', 'def')
    lg.log('service:api', 'infor', 'xyz')
    console.log(ms)
    // {
    //   id: '{random-id}',
    //   from: 'service:web',
    //   level: 'infor',
    //   msg: '"abc"',
    //   time: '2021-08-06T14:05:38+08:00'
    // }
    // {
    //   id: '{random-id}',
    //   from: 'service:web',
    //   level: 'error',
    //   msg: '"def"',
    //   time: '2021-08-06T14:05:38+08:00'
    // }
    // {
    //   id: '{random-id}',
    //   from: 'service:api',
    //   level: 'infor',
    //   msg: '"xyz"',
    //   time: '2021-08-06T14:05:38+08:00'
    // }
    // [
    //   { from: 'service:web', level: 'infor', msg: '"abc"' },
    //   { from: 'service:web', level: 'error', msg: '"def"' },
    //   { from: 'service:api', level: 'infor', msg: '"xyz"' }
    // ]

##### Returns:

回傳事件物件，可呼叫事件init與log。init傳入紀錄器函數，可為sync或async，紀錄器會收到一個數據物件，此需由紀錄實做儲存方式。log為外部呼叫的紀錄函數，紀錄函數會收到from(觸發來源)、level(紀錄種類)、msg(紀錄訊息)，回傳係為init取得之紀錄器函數回傳，故可能為sync(一般回傳)或async(Promise)。

Type
  Object

#### (static) ltdt2vrtsable(ltdt, mergerowkeysopt) → {Array}

Source:
  - ltdt2vrtsable.mjs, line 27

由物件陣列ltdt轉陣列vrtable(使用value,style,rowspan儲存)

Unit Test: Github

##### Example

Try in Codepen

    console.log(ltdt2vrtsable([{"a":{"value":"123","style":{}},"b":{"value":34.56,"style":{}}},{"a":{"value":"123","style":{}},"b":{"value":"xyz","style":{}}}], ['a']))
    // => [{"a":{"rowspan":2,"value":"123","style":{}},"b":{"rowspan":1,"value":34.56,"style":{}}},{"a":{"rowspan":null,"value":"123","style":{}},"b":{"rowspan":1,"value":"xyz","style":{}}}]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ltdt` | Array |  |  | 輸入物件陣列
`mergerowkeys` | Array | <optional> | `[]` | 輸入需合併列的關鍵字keys，為字串陣列，預設為空陣列

##### Returns:

回傳物件陣列

Type
  Array

#### (static) ltdtdiff(ltdtOld, ltdtNew, key) → {Object}

Source:
  - ltdtdiff.mjs, line 33

回傳陣列以key為主鍵，vnew對vold中有差異之項目

Unit Test: Github

##### Example

Try in Codepen

    let vOld = [{ id: 'id-1', a: 'a1' }, { id: 'id-2', a: 'a2' }, { id: 'id-3', a: 'a3' }]
    let vNew = [{ id: 'id-1', z: 'z3' }, { id: 'id-3', a: 'a3' }, { id: 'id-4', a: 'a4' }]
    console.log(ltdtdiff(vOld, vNew, 'id'))
    // => {
    //     infor: { 'id-1': 'diff', 'id-2': 'del', 'id-3': 'same', 'id-4': 'add' },
    //     del: [ { id: 'id-2', a: 'a2' } ],
    //     same: [ { id: 'id-3', a: 'a3' } ],
    //     diff: [ { id: 'id-1', z: 'z3' } ],
    //     add: [ { id: 'id-4', a: 'a4' } ]
    // }

##### Parameters:

Name | Type | Description
--- | --- | ---
`ltdtOld` | Array | Object | 輸入舊的物件陣列或物件
`ltdtNew` | Array | Object | 輸入新的物件陣列或物件
`key` | String | 輸入比對的主鍵key值字串

##### Returns:

回傳比對結果物件

Type
  Object

#### (static) ltdtkeys2mat(ltdt, keys) → {Array}

Source:
  - ltdtkeys2mat.mjs, line 27

由物件陣列ltdt並使用keys取值轉二維陣列mat

Unit Test: Github

##### Example

Try in Codepen

    console.log(ltdtkeys2mat([{ a: 12, b: 34.56 }, { a: '123', b: 'xyz' }], ['a', 'b']))
    // => [[12, 34.56], ['123', 'xyz']]

##### Parameters:

Name | Type | Description
--- | --- | ---
`ltdt` | Array | 輸入物件陣列
`keys` | Array | 輸入字串陣列，若不輸入則由ltdt提取

##### Returns:

回傳資料陣列

Type
  Array

#### (static) ltdtkeysheads2mat(ltdt, keysopt, kpheadopt) → {Array}

Source:
  - ltdtkeysheads2mat.mjs, line 26

keys轉heads，物件陣列ltdt使用keys取值，兩者合併轉出二維陣列mat

Unit Test: Github

##### Example

Try in Codepen

    console.log(ltdtkeysheads2mat([{ a: 12, b: 34.56 }, { a: '123', b: 'xyz' }], ['a', 'b'], { a: 'c1', b: 'c2' }))
    // => [['c1', 'c2'], [12, 34.56], ['123', 'xyz']]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ltdt` | Array |  |  | 輸入物件陣列
`keys` | Array | <optional> | `[]` | 輸入字串陣列，若不輸入則由ltdt提取，預設[]
`kphead` | Object | <optional> | `{}` | 輸入字典物件，內含keys對應values之物件，供keys查詢得values，若不輸入則由keys提取，預設{}

##### Returns:

回傳資料陣列

Type
  Array

#### (static) ltdtmapping(ltdt, keys, defopt) → {Array}

Source:
  - ltdtmapping.mjs, line 38

由ltdt陣列各元素物件提取指定keys欄位出來成為新的物件陣列，若物件不存在keys的欄位時，則會自動填入指定數據def

Unit Test: Github

##### Example

Try in Codepen

    let r = [
        { a: 'a123', b: 123, c: 'abc' },
        { a: '1b23', b: 456, c: '123XYZ' },
        { a: '12c3', b: 789.0123, c: null }
    ]

    console.log(ltdtmapping(r, ['a', 'b']))
    // => [
    //     { a: 'a123', b: 123 },
    //     { a: '1b23', b: 456 },
    //     { a: '12c3', b: 789.0123 }
    // ]

    console.log(ltdtmapping(r, ['a', 'c', 'x']))
    // => [
    //     { a: 'a123', c: 'abc', x: '' },
    //     { a: '1b23', c: '123XYZ', x: '' },
    //     { a: '12c3', c: null, x: '' }
    // ]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ltdt` | Array |  |  | 輸入要被提取的任意資料陣列，各元素需為物件，否則提取後為空物件
`keys` | Array |  |  | 輸入要提取欄位集合的字串陣列
`def` | * | <optional> | `''` | 輸入若無提取欄位時所給予的預設值，預設為''

##### Returns:

回傳提取的物件資料陣列

Type
  Array

#### (static) ltdtmerge(ltdt1, ltdt2) → {Array}

Source:
  - ltdtmerge.mjs, line 20

針對物件陣列ltdt1與ltdt2逐一呼叫merge合併

Unit Test: Github

##### Example

Try in Codepen

    console.log(ltdtmerge([{ a: 12, b: 34.56 }, {}], [{ a: '123', c: 'mn' }, { aa: 'a123', bb: 'bmn' }]))
    // => [{ a: '123', b: 34.56, c: 'mn' }, { aa: 'a123', bb: 'bmn' }]

##### Parameters:

Name | Type | Description
--- | --- | ---
`ltdt1` | Array | 輸入資料物件陣列
`ltdt2` | Array | 輸入資料物件陣列，若與ltdt1內物件有重複的欄位值，優先保留ltdt2內物件的欄位值

##### Returns:

回傳處理後物件陣列

Type
  Array

#### (static) ltdtpick(ltdt, keys) → {Array}

Source:
  - ltdtpick.mjs, line 37

由ltdt陣列各元素物件提取指定keys欄位出來成為新的物件陣列，僅保留有keys的欄位，若不存在欄位就不提取

Unit Test: Github

##### Example

Try in Codepen

    let r = [
        { a: 'a123', b: 123, c: 'abc' },
        { a: '1b23', b: 456, c: '123XYZ' },
        { a: '12c3', b: 789.0123, c: null }
    ]

    console.log(ltdtpick(r, ['a', 'b']))
    // => [
    //     { a: 'a123', b: 123 },
    //     { a: '1b23', b: 456 },
    //     { a: '12c3', b: 789.0123 }
    // ]

    console.log(ltdtpick(r, ['a', 'c', 'x']))
    // => [
    //     { a: 'a123', c: 'abc' },
    //     { a: '1b23', c: '123XYZ' },
    //     { a: '12c3', c: null }
    // ]

##### Parameters:

Name | Type | Description
--- | --- | ---
`ltdt` | Array | 輸入要被提取的任意資料陣列，各元素需為物件，否則提取後為空物件
`keys` | Array | 輸入要提取欄位集合的字串陣列

##### Returns:

回傳提取的物件資料陣列

Type
  Array

#### (static) ltdtpull(ltdtAll, ltdtDel, key) → {Array}

Source:
  - ltdtpull.mjs, line 26

由ltdtAll陣列移除ltdtDel陣列，只會針對ltdtDel內各元素的指定key來查找

Unit Test: Github

##### Example

Try in Codepen

    console.log(ltdtpull([{ x: 1, y: 'y1' }, { x: 2, y: 'y2' }], [{ x: 1, y: 'y3' }], 'x'))
    // => [ { x: 2, y: 'y2' } ]

    console.log(ltdtpull([{ id: 1, v: 'v1' }, { id: 2, v: 'v2' }, { id: 3, v: 'v3' }], [{ id: 1, v: '-v1' }, { id: 3, v: '-v3' }], 'id'))
    // => [ { id: 2, v: 'v2' } ]

##### Parameters:

Name | Type | Description
--- | --- | ---
`ltdtAll` | Array | 輸入要被刪除的物件陣列
`ltdtDel` | Array | 輸入要刪除的物件陣列
`key` | String | 輸入要比對物件的key值

##### Returns:

回傳被刪除的物件陣列

Type
  Array

#### (static) mat2ltdt(mat) → {Array}

Source:
  - mat2ltdt.mjs, line 22

由mat第1行當head，其餘當data，轉ltdt mat第1行需為字串陣列，才能當head

Unit Test: Github

##### Example

Try in Codepen

    console.log(mat2ltdt([['a', 'b'], [12, 34.56], ['x', '12.34']]))
    // => [{ a: 12, b: 34.56 }, { a: 'x', b: '12.34' }]

##### Parameters:

Name | Type | Description
--- | --- | ---
`mat` | Array | 輸入資料陣列

##### Returns:

回傳物件陣列

Type
  Array

#### (static) matat(mat, istart, iendopt) → {Array}

Source:
  - matat.mjs, line 26

由二維陣列mat提取資料 若istart與iend有效, 提取istart~iend欄位 若僅istart有效, 提取istart欄位

Unit Test: Github

##### Example

Try in Codepen

    console.log(matat([['a', 'b', '12.34'], [12, 34.56, 'abc']], 1))
    // => [['b'], [34.56]]

    console.log(matat([['a', 'b', '12.34'], [12, 34.56, 'abc']], 1, 2))
    // => [['b', '12.34'], [34.56, 'abc']]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`mat` | Array |  |  | 輸入要被提取的資料陣列
`istart` | Integer |  |  | 輸入起始的欄位指標整數
`iend` | Integer | <optional> | `istart` | 輸入結束的欄位指標整數，若不輸入則等同於istart

##### Returns:

回傳提取的資料陣列

Type
  Array

#### (static) now2str() → {String}

Source:
  - now2str.mjs, line 16

取得目前至秒時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(now2str())
    // => dayjs().format('YYYY-MM-DDTHH:mm:ssZ') //use dayjs or moment

##### Returns:

回傳目前至秒時間字串

Type
  String

#### (static) now2strp() → {String}

Source:
  - now2strp.mjs, line 16

取得目前至秒時間，產生無特殊字串之時間戳

Unit Test: Github

##### Example

Try in Codepen

    console.log(now2strp())
    // => dayjs().format('YYYYMMDDHHmmss') //use dayjs or moment

##### Returns:

回傳目前至秒時間字串

Type
  String

#### (static) nowDay2str() → {String}

Source:
  - nowDay2str.mjs, line 16

取得目前至日時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(nowDay2str())
    // => dayjs().format('YYYY-MM-DD') //use dayjs or moment

##### Returns:

回傳目前至日時間字串

Type
  String

#### (static) nowms2str() → {String}

Source:
  - nowms2str.mjs, line 16

取得目前至毫秒時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(nowms2str())
    // => dayjs().format('YYYY-MM-DDTHH:mm:ss.SSSZ') //use dayjs or moment

##### Returns:

回傳目前至毫秒時間字串

Type
  String

#### (static) nowms2strp() → {String}

Source:
  - nowms2strp.mjs, line 16

取得目前至毫秒時間，產生無特殊字串之時間戳

Unit Test: Github

##### Example

Try in Codepen

    console.log(nowms2strp())
    // => dayjs().format('YYYYMMDDHHmmssSSS') //use dayjs or moment

##### Returns:

回傳目前至毫秒時間字串

Type
  String

#### (static) o2j(v, bFormatopt) → {String}

Source:
  - o2j.mjs, line 27

任意資料轉json文字

Unit Test: Github

##### Example

Try in Codepen

    console.log(o2j([1, '3', 'abc']))
    // => '[1,"3","abc"]'

    console.log(o2j({ a: 12.34, b: 'abc' }))
    // => '{"a":12.34,"b":"abc"}'

    console.log(o2j({ a: 12.34, b: 'abc' }, true))
    // => {
      "a": 12.34,
      "b": "abc"
    }

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`v` | * |  |  | 輸入任意資料
`bFormat` | Boolean | <optional> | `false` | 輸入是否格式化布林值，預設為false

##### Returns:

回傳json格式字串

Type
  String

#### (static) obj2b64(data) → {String}

Source:
  - obj2b64.mjs, line 21

任意資料轉base64字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(obj2b64([1, '3', 'abc']))
    // => 'WzEsIjMiLCJhYmMiXQ=='

    console.log(obj2b64({ a: 12.34, b: 'abc' }))
    // => 'eyJhIjoxMi4zNCwiYiI6ImFiYyJ9'

##### Parameters:

Name | Type | Description
--- | --- | ---
`data` | * | 輸入任意資料

##### Returns:

回傳base64字串

Type
  String

#### (static) obj2pb64(data, key) → {String}

Source:
  - obj2pb64.mjs, line 21

任意資料由key進行AES加密轉為為base64

Unit Test: Github

##### Example

Try in Codepen

    let key = '1234567890abcdef'
    console.log(obj2pb64([1, '3', 'abc'], key))
    // => U2FsdGVkX1+yPgYSW6mKi1VqyslaSKYHKRaw8Pu4QduzHggojRZA6b/T/oB7ltXf (is random)

##### Parameters:

Name | Type | Description
--- | --- | ---
`data` | * | 輸入任意資料
`key` | String | 輸入加密key

##### Returns:

回傳加密base64字串

Type
  String

#### (static) obj2str(data, extopt) → {String}

Source:
  - obj2str.mjs, line 30

任意資料轉字串，可支援內含Uint8Array與Uint16Array數據

Unit Test: Github

##### Example

Try in Codepen

    let o = {
        a: 'abc',
        b: 12.3,
        u8a: new Uint8Array([66, 97, 115]),
        u16a: new Uint16Array([11, 79, 6]),
    }
    console.log(obj2str(o))
    // => '{"a":"abc","b":12.3,"u8a":"[Uint8Array]::QmFz","u16a":{"0":11,"1":79,"2":6}}'

    console.log(obj2str(o, ['Uint8Array', 'Uint16Array']}))
    // => '{"a":"abc","b":12.3,"u8a":"[Uint8Array]::QmFz","u16a":"[Uint16Array]::C08G"}'

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`data` | * |  |  | 輸入任意資料
`ext` | String | Array | <optional> | `'Uint8Array'` | 輸入擴充數據種類字串或陣列，預設'Uint8Array'

##### Returns:

回傳base64字串

Type
  String

#### (static) obj2stru8arr(data) → {Object}

Source:
  - obj2stru8arr.mjs, line 41

物件資料轉字串與Unit8Array，物件內可含Unit8Array數據，適用於大檔。

通過JSON序列化物件內非Unit8Array數據成為字串，另分拆Unit8Array數據出來回傳，兩者間通過指標關聯，主要為避免序列化大型Unit8Array數據造成效能或記憶體不足問題

Unit Test: Github

##### Example

Try in Codepen

    let data = {
        a: 123,
        b: 45.67,
        c: 'l1-測試中文',
        d: {
            da: 123,
            db: 45.67,
            dc: 'l2-測試中文',
            dd: ['a', 'xyz', 321, 76.54],
            de: new Uint8Array([66, 97, 115]),
        },
    }
    let r = obj2stru8arr(data)
    console.log(r)
    // => {
    //     results: '{"a":123,"b":45.67,"c":"l1-測試中文","d":{"da":123,"db":45.67,"dc":"l2-測試中文","dd":["a","xyz",321,76.54],"de":"[Uint8Array]::0"}}',
    //     binarys: [ Uint8Array [ 66, 97, 115 ] ]
    // }

##### Parameters:

Name | Type | Description
--- | --- | ---
`data` | * | 輸入任意資料

##### Returns:

回傳物件，results欄位儲存物件內非序列化文字，binarys欄位儲存各Unit8Array數據

Type
  Object

#### (static) obj2u8arr(data) → {Uint8Array}

Source:
  - obj2u8arr.mjs, line 51

物件或陣列資料轉Uint8Array

Unit Test: Github

##### Example

Try in Codepen

    let data = {
        a: [123, 45.67, 'test中文'],
        b: {
            c: new Uint8Array([66, 97, 115]),
        },
    }
    let u8a = obj2u8arr(data)
    console.log(u8a)
    // => Uint8Array [
    //     64,  24,   0,   0,   0,  0,  0,   0,  91,  53,  56,  44,
    //     51,  93, 123,  34,  97, 34, 58,  91,  49,  50,  51,  44,
    //     52,  53,  46,  54,  55, 44, 34, 116, 101, 115, 116, 228,
    //    184, 173, 230, 150, 135, 34, 93,  44,  34,  98,  34,  58,
    //    123,  34,  99,  34,  58, 34, 91,  85, 105, 110, 116,  56,
    //     65, 114, 114,  97, 121, 93, 58,  58,  48,  34, 125, 125,
    //     66,  97, 115
    // ]

##### Parameters:

Name | Type | Description
--- | --- | ---
`data` | Object | Array | 輸入物件或陣列資料，物件內可支援Uint8Array、Uint16Array、ArrayBuffer，注意因ArrayBuffer無法直接操作(非View，只有TypedArray與DataView可操作)故預設會轉Uint8Array進行處理

##### Returns:

回傳Uint8Array

Type
  Uint8Array

#### (async, static) ocr(img, optopt) → {Object}

Source:
  - ocr.mjs, line 126

基於tesseract.js的文字辨識(OCR)，注意瀏覽器版精度較差

Unit Test: Github

##### Example

Try in Codepen

    function getImg() {
        function getEng() {
            return 'data:image/png;base64,...'
        }
        function getTra() {
            return 'data:image/png;base64,...'
        }
        function getSim() {
            return 'data:image/png;base64,...'
        }

        let resEng = `
    Mild Splendour of the various-vested Night!
    Mother of wildly-working visions! haill
    I watch thy gliding, while with watery light
    Thy weak eye glimmers through a fleecy veil;
    And when thou lovest thy pale orb to shroud
    Behind the gather’'d blackness lost on high;
    And when thou dartest from the wind-rent cloud
    Thy placid lightning o’er the awakend sky.
    `

        let resChiTra = `
    齎 家 王 說 闊 夜 又 山 ‧ 碰 巧 撞 上 了 風 妻 綽 約 的 寨 主 鍾 無 艷 ， 一 人 一 見 鍾 情 。 鍾 情
    於 鍾 無 艷 的 狐 狸 精 被 拒 愛 ， 於 是 向 無 艷 施 『 愛 情 咒 」， 使 其 臉 上 忽 然 多 了 塊 大
    痧 ‧ 把 齊 宣 王 嚇 得 採 腿 而 逃 ‧ 二 人 媒 情 從 此 障 礙 重 重 。
    `

        let resChiSim = `
    狐 狸 精 化 身 为 美 女 夏 迎 春 去 勾 引 齐 王 , 忽 男 忽 女 的 她 竟 同 时 爱 上 齐 王 和 无 艳 ,
    硬 是 周 旋 在 二 人 之 间 。 齐 王 被 狐 狸 精 的 美 色 所 诱 , 但 无 艳 仍 对 齐 王 痴 心 一 片 ,
    甘 为 齐 王 南 征 北 战 , 冲 锋 陷 阵 、 出 生 入 死 。 无 艳 在 迎 春 多 畴 打 击 下 多 次 入 冷
    宫 、 坐 天 牢 仍 无 怨 无 悔 , 对 齐 王 矢 志 不 渝 。
    `

        return {
            eng: getEng(),
            tra: getTra(),
            sim: getSim(),
            resEng,
            resChiTra,
            resChiSim,
        }
    }

    function replace(c, t, r) {
        let o = new RegExp(t, 'g')
        let rr = String(c).replace(o, r)
        return rr
    }

    function p(c) {
        c = replace(c, ' ', '')
        c = replace(c, '\r', '')
        c = replace(c, '\n', '')
        return c
    }

    async function core() {

        //kpImg
        let kpImg = getImg()

        let rEng = await ocr(kpImg.eng)
        console.log(rEng)
        console.log('ocr for eng:', p(rEng) === p(kpImg.resEng))
        // => Mild Splendour of the various-vested Night!
        // Mother of wildly-working visions! haill
        // I watch thy gliding, while with watery light
        // Thy weak eye glimmers through a fleecy veil;
        // And when thou lovest thy pale orb to shroud
        // Behind the gather’'d blackness lost on high;
        // And when thou dartest from the wind-rent cloud
        // Thy placid lightning o’er the awakend sky.
        //
        // => ocr for chi_tra: true

        let rChiTra = await ocr(kpImg.tra, { lang: 'chi_tra' })
        console.log(rChiTra)
        console.log('ocr for chi_tra:', p(rChiTra) === p(kpImg.resChiTra))
        // => 齎 家 王 說 闊 夜 又 山 ‧ 碰 巧 撞 上 了 風 妻 綽 約 的 寨 主 鍾 無 艷 ， 一 人 一 見 鍾 情 。 鍾 情
        // 於 鍾 無 艷 的 狐 狸 精 被 拒 愛 ， 於 是 向 無 艷 施 『 愛 情 咒 」， 使 其 臉 上 忽 然 多 了 塊 大
        // 痧 ‧ 把 齊 宣 王 嚇 得 採 腿 而 逃 ‧ 二 人 媒 情 從 此 障 礙 重 重 。
        //
        // => ocr for chi_tra: true

        let rChiSim = await ocr(kpImg.sim, { lang: 'chi_sim' })
        console.log(rChiSim)
        console.log('ocr for chi_sim:', p(rChiSim) === p(kpImg.resChiSim))
        // => 狐 狸 精 化 身 为 美 女 夏 迎 春 去 勾 引 齐 王 , 忽 男 忽 女 的 她 竟 同 时 爱 上 齐 王 和 无 艳 ,
        // 硬 是 周 旋 在 二 人 之 间 。 齐 王 被 狐 狸 精 的 美 色 所 诱 , 但 无 艳 仍 对 齐 王 痴 心 一 片 ,
        // 甘 为 齐 王 南 征 北 战 , 冲 锋 陷 阵 、 出 生 入 死 。 无 艳 在 迎 春 多 畴 打 击 下 多 次 入 冷
        // 宫 、 坐 天 牢 仍 无 怨 无 悔 , 对 齐 王 矢 志 不 渝 。
        //
        // => ocr for chi_sim: true

    }
    core()

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`img` | String |  |  | 輸入圖片網址或base64格式(以data:開頭)字串

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`lang` | String | <optional> | `'eng'` | 輸入辨識語系字串，可輸入'eng'、'chi_tra'、'chi_sim'等，多語系可用「+」合併，預設'eng+chi_tra+chi_sim'
`whitelist` | String | <optional> |  | 輸入白名單字串，可指定輸入只辨識之字元，預設undefined

##### Returns:

回傳辨識結果物件

Type
  Object

#### (async, static) ocrDyn(img, optopt, pathItems) → {Object}

Source:
  - ocrDyn.mjs, line 80

基於tesseract.js的文字辨識(OCR)，採用動態加載技術，注意瀏覽器版精度較差

Unit Test: Github

##### Example

Try in Codepen

    let resEng = `
    Mild Splendour of the various-vested Night!
    Mother of wildly-working visions! haill
    I watch thy gliding, while with watery light
    Thy weak eye glimmers through a fleecy veil;
    And when thou lovest thy pale orb to shroud
    Behind the gather’d blackness lost on high;
    And when thou dartest from the wind-rent cloud
    Thy placid lightning o’er the awaken’d sky.
    `

    let resChiTra = `
    齊宣王誤闖夜叉山，碰巧撞上了風姿綽約的寨主鍾無艷，二人一見鍾情。鍾情
    於鍾無艷的狐狸精被拒愛，於是向無艷施「愛情咒」，使其臉上忽然多了塊大
    痣，把齊宣王嚇得拔腿而逃，二人感情從此障礙重重。
    `

    let resChiSim = `
    狐狸精化身为美女夏迎春去勾引齐王，忽男忽女的她竟同时爱上齐王和无艳，
    硬是周旋在二人之间。齐王被狐狸精的美色所诱，但无艳仍对齐王痴心一片，
    甘为齐王南征北战，冲锋陷阵、出生入死。无艳在迎春多番打击下多次入冷
    宫、坐天牢仍无怨无悔，对齐王矢志不渝。
    `

    //辨識英文
    let rEng = await ocrDyn('data:image/png;base64,...')
    console.log('ocrDyn for eng:', p(rEng) === p(resEng))
    // => ocrDyn for eng: true

    console.log(resEng)
    // => Mild Splendour of the various-vested Night!
    // Mother of wildly-working visions! haill
    // I watch thy gliding, while with watery light
    // Thy weak eye glimmers through a fleecy veil;
    // And when thou lovest thy pale orb to shroud
    // Behind the gather’d blackness lost on high;
    // And when thou dartest from the wind-rent cloud
    // Thy placid lightning o’er the awaken’d sky.

    //辨識繁體中文
    let rChiTra = await ocrDyn('data:image/png;base64,...', { lang: 'chi_tra' })
    console.log('ocrDyn for chi_tra:', p(rChiTra) === p(resChiTra))
    // => ocrDyn for chi_tra: true

    console.log(resChiTra)
    // => 齊宣王誤闖夜叉山，碰巧撞上了風姿綽約的寨主鍾無艷，二人一見鍾情。鍾情
    // 於鍾無艷的狐狸精被拒愛，於是向無艷施「愛情咒」，使其臉上忽然多了塊大
    // 痣，把齊宣王嚇得拔腿而逃，二人感情從此障礙重重。

    //辨識簡體中文
    let rChiSim = await ocrDyn('data:image/png;base64,...', { lang: 'chi_sim' })
    console.log('ocrDyn for chi_sim:', p(rChiSim) === p(resChiSim))
    // => ocrDyn for chi_sim: true

    console.log(resChiSim)
    // => 狐狸精化身为美女夏迎春去勾引齐王，忽男忽女的她竟同时爱上齐王和无艳，
    // 硬是周旋在二人之间。齐王被狐狸精的美色所诱，但无艳仍对齐王痴心一片，
    // 甘为齐王南征北战，冲锋陷阵、出生入死。无艳在迎春多番打击下多次入冷
    // 宫、坐天牢仍无怨无悔，对齐王矢志不渝。

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`img` | String |  |  | 輸入圖片網址或base64格式(以data:開頭)字串

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`lang` | String | <optional> | `'eng'` | 輸入辨識語系字串，可輸入'eng'、'chi_tra'、'chi_sim'等，多語系可用「+」合併，預設'eng+chi_tra+chi_sim'
`whitelist` | String | <optional> |  | 輸入白名單字串，可指定輸入只辨識之字元，預設undefined

`pathItems` | String | Object | Array |  |  | 輸入資源字串、字串陣列、物件、物件陣列

##### Returns:

回傳辨識結果物件

Type
  Object

#### (static) oo(o) → {*}

Source:
  - oo.mjs, line 27

暴力cloneDeep物件

Unit Test: Github

##### Example

Try in Codepen

    console.log(oo([1, '3', 'abc']))
    // => [1, '3', 'abc']

    console.log(oo([1, '3', 'abc', function(){}]))
    // => [1, '3', 'abc', null]

    console.log(oo({ a: 12.34, b: 'abc' }))
    // => { a: 12.34, b: 'abc' }

    console.log(oo({ a: 12.34, b: 'abc', c: function(){} }))
    // => { a: 12.34, b: 'abc' }

##### Parameters:

Name | Type | Description
--- | --- | ---
`o` | * | 輸入任意資料

##### Returns:

回傳任意資料

Type
  *

#### (static) openLink(url)

Source:
  - openLink.mjs, line 17

前端開啟連結

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let url = 'https://www.google.com/'
    openLink(url)

##### Parameters:

Name | Type | Description
--- | --- | ---
`url` | String |

#### (static) pb642obj(key, b64) → {*}

Source:
  - pb642obj.mjs, line 22

base64解密取得原始資料

Unit Test: Github

##### Example

Try in Codepen

    let key = '1234567890abcdef'
    let str = U2FsdGVkX1+yPgYSW6mKi1VqyslaSKYHKRaw8Pu4QduzHggojRZA6b/T/oB7ltXf //(is random)
    console.log(pb642obj(str, key))
    // => [1, '3', 'abc']

##### Parameters:

Name | Type | Description
--- | --- | ---
`key` | String | 輸入加密key
`b64` | String | 輸入加密base64字串

##### Returns:

回傳任意物件

Type
  *

#### (static) pm2resolve(fn) → {Promise}

Source:
  - pm2resolve.mjs, line 132

將Promise函式的resolve與reject皆轉為resolve

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        async function test1() {
            return new Promise((resolve, reject) => {
                let ms = []

                function fun1(c) {
                    return new Promise((resolve, reject) => {
                        setTimeout(function() {
                            console.log('resolve fun1: ' + c)
                            ms.push('resolve fun1: ' + c)
                            resolve('fun1: ' + c)
                        }, 1)
                    })
                }

                pm2resolve(fun1)('abc')
                    .then((msg) => {
                        console.log('t1 then: ', msg)
                        ms.push({ mode: 't1 then', msg })
                    })
                    .catch((msg) => {
                        console.log('t1 catch: ', msg)
                        ms.push({ mode: 't1 catch', msg })
                    })
                    .finally(() => {
                        resolve(ms)
                    })

            })
        }
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // resolve fun1: abc
        // t1 then:  { state: 'success', msg: 'fun1: abc' }
        // ["resolve fun1: abc",{"mode":"t1 then","msg":{"state":"success","msg":"fun1: abc"}}]

        async function test2() {
            return new Promise((resolve, reject) => {
                let ms = []

                function fun1(c) {
                    return new Promise((resolve, reject) => {
                        setTimeout(function() {
                            console.log('reject fun1: ' + c)
                            ms.push('reject fun1: ' + c)
                            reject('fun1: ' + c)
                        }, 1)
                    })
                }

                pm2resolve(fun1)('abc')
                    .then((msg) => {
                        console.log('t1 then: ', msg)
                        ms.push({ mode: 't1 then', msg })
                    })
                    .catch((msg) => {
                        console.log('t1 catch: ', msg)
                        ms.push({ mode: 't1 catch', msg })
                    })
                    .finally(() => {
                        resolve(ms)
                    })

            })
        }
        console.log('test2')
        let r2 = await test2()
        console.log(JSON.stringify(r2))
        // test2
        // reject fun1: abc
        // { state: 'error', msg: 'fun1: abc' }
        // ["reject fun1: abc",{"mode":"t1 then","msg":{"state":"error","msg":"fun1: abc"}}]

        async function test3() {
            return new Promise((resolve, reject) => {
                let ms = []

                function fun1(p1, p2) {
                    return new Promise((resolve, reject) => {
                        setTimeout(function() {
                            console.log('resolve fun1: ' + p1 + ', ' + p2)
                            ms.push('resolve fun1: ' + p1 + ', ' + p2)
                            resolve('fun1: ' + p1 + ', ' + p2)
                        }, 1)
                    })
                }

                pm2resolve(fun1)('abc', 'def')
                    .then((msg) => {
                        console.log('t1 then: ', msg)
                        ms.push({ mode: 't1 then', msg })
                    })
                    .catch((msg) => {
                        console.log('t1 catch: ', msg)
                        ms.push({ mode: 't1 catch', msg })
                    })
                    .finally(() => {
                        resolve(ms)
                    })

            })
        }
        console.log('test3')
        let r3 = await test3()
        console.log(JSON.stringify(r3))
        // test3
        // resolve fun1: abc, def
        // t1 then:  { state: 'success', msg: 'fun1: abc, def' }
        // ["resolve fun1: abc, def",{"mode":"t1 then","msg":{"state":"success","msg":"fun1: abc, def"}}]

    }
    topAsync().catch(() => {})

##### Parameters:

Name | Type | Description
--- | --- | ---
`fn` | function | 輸入函數，可支援async與sync函數

##### Returns:

回傳Promise，皆使用resolve回傳物件資料，物件欄位有state與msg，state可有success、error與cancelled。cancelled代表reject回傳{ reason: 'cancelled' }

Type
  Promise

#### (static) pmChain(pms, initial) → {Promise}

Source:
  - pmChain.mjs, line 135

傳入initial初始值並循序執行Promise陣列

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        async function test1() {
            return new Promise((resolve, reject) => {
                let ms = []

                let pm1 = function(v) {
                    return new Promise((resolve, reject) => {
                        setTimeout(() => {
                            console.log('resolve pm1' + v)
                            ms.push('resolve pm1' + v)
                            resolve('pm1' + v)
                        }, 100)
                    })
                }
                let pm2 = function(v) {
                    return new Promise((resolve, reject) => {
                        setTimeout(() => {
                            console.log('resolve pm2' + v)
                            ms.push('resolve pm2' + v)
                            resolve('pm2' + v)
                        }, 150)
                    })
                }
                let pm3 = function(v) {
                    return new Promise((resolve, reject) => {
                        setTimeout(() => {
                            console.log('resolve pm3' + v)
                            ms.push('resolve pm3' + v)
                            resolve('pm3' + v)
                        }, 50)
                    })
                }

                pmChain([pm1, pm2, pm3], '*')
                    .then((msg) => {
                        console.log('t1 then: ', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch((msg) => {
                        console.log('t1 catch: ', msg)
                        ms.push('t1 catch: ' + msg)
                    })
                    .finally(() => {
                        resolve(ms)
                    })

            })
        }
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // resolve pm1*
        // resolve pm2pm1*
        // resolve pm3pm2pm1*
        // t1 then:  pm3pm2pm1*
        // ["resolve pm1*","resolve pm2pm1*","resolve pm3pm2pm1*","t1 then: pm3pm2pm1*"]

        async function test2() {
            return new Promise((resolve, reject) => {
                let ms = []

                let pm1 = function(v) {
                    return new Promise((resolve, reject) => {
                        setTimeout(() => {
                            console.log('resolve pm1' + v)
                            ms.push('resolve pm1' + v)
                            resolve('pm1' + v)
                        }, 100)
                    })
                }
                //pm2為reject
                let pm2 = function(v) {
                    return new Promise((resolve, reject) => {
                        setTimeout(() => {
                            console.log('reject pm2' + v)
                            ms.push('reject pm2' + v)
                            reject('pm2' + v)
                        }, 150)
                    })
                }
                let pm3 = function(v) {
                    return new Promise((resolve, reject) => {
                        setTimeout(() => {
                            console.log('resolve pm3' + v)
                            ms.push('resolve pm3' + v)
                            resolve('pm3' + v)
                        }, 50)
                    })
                }

                pmChain([pm1, pm2, pm3], '*')
                    .then((msg) => {
                        console.log('t1 then: ', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch((msg) => {
                        console.log('t1 catch: ', msg)
                        ms.push('t1 catch: ' + msg)
                    })
                    .finally(() => {
                        resolve(ms)
                    })

            })
        }
        console.log('test2')
        let r2 = await test2()
        console.log(JSON.stringify(r2))
        // test2
        // resolve pm1*
        // reject pm2pm1*
        // t1 catch:  pm2pm1*
        // ["resolve pm1*","reject pm2pm1*","t1 catch: pm2pm1*"]

    }
    topAsync().catch(() => {})

##### Parameters:

Name | Type | Default | Description
--- | --- | --- | ---
`pms` | Array |  | 輸入Promise陣列
`initial` | * | `null` | 輸入循序執行Promise陣列的初始值

##### Returns:

回傳Promise，resolve為成功結果，reject為失敗結果

Type
  Promise

#### (static) pmHook(fun, cbopt) → {Promise}

Source:
  - pmHook.mjs, line 258

掛勾非同步(Promise)函數，可監聽或修改Promise的輸出入訊號

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        async function test1() {
            return new Promise((resolve, reject) => {
                let ms = []

                //使用resolve
                let pm = function (v1, v2) {
                    return new Promise(function(resolve, reject) {
                        ms.push(`resolve: v1=${v1}, v2=${v2}`)
                        resolve(`resolve: v1=${v1}, v2=${v2}`)
                    })
                }

                //針對before修改輸入
                let pmr = pmHook(pm, (msg) => {
                    console.log('cb', msg)
                    if (msg.mode === 'before') {
                        //arguments有兩個輸入故得分開改
                        msg.data[0] = '[modify input a]' + msg.data[0]
                        msg.data[1] = '[modify input b]' + msg.data[1]
                        return msg.data
                    }
                })

                pmr('t1', 12.3)
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + msg)
                    })
                    .finally(function() {
                        resolve(ms)
                    })

            })
        }
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // cb { mode: 'before', data: [Arguments] { '0': 't1', '1': 12.3 } }
        // cb {
        //   mode: 'afterThen',
        //   data: 'resolve: v1=[modify input a]t1, v2=[modify input b]12.3'
        // }
        // t1 then resolve: v1=[modify input a]t1, v2=[modify input b]12.3
        // ["resolve: v1=[modify input a]t1, v2=[modify input b]12.3","t1 then: resolve: v1=[modify input a]t1, v2=[modify input b]12.3"]

        async function test2() {
            return new Promise((resolve, reject) => {
                let ms = []

                //使用resolve
                let pm = function (v1, v2) {
                    return new Promise(function(resolve, reject) {
                        ms.push(`resolve: v1=${v1}, v2=${v2}`)
                        resolve(`resolve: v1=${v1}, v2=${v2}`)
                    })
                }

                //針對afterThen修改輸出
                let pmr = pmHook(pm, (msg) => {
                    console.log('cb', msg)
                    if (msg.mode === 'afterThen') {
                        //arguments有兩個輸入故得分開改
                        msg.data = '[modify output]' + msg.data
                        return msg.data
                    }
                })

                pmr('t1', 12.3)
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + msg)
                    })
                    .finally(function() {
                        resolve(ms)
                    })

            })
        }
        console.log('test2')
        let r2 = await test2()
        console.log(JSON.stringify(r2))
        // test2
        // cb { mode: 'before', data: [Arguments] { '0': 't1', '1': 12.3 } }
        // cb { mode: 'afterThen', data: 'resolve: v1=t1, v2=12.3' }
        // t1 then [modify output]resolve: v1=t1, v2=12.3
        // ["resolve: v1=t1, v2=12.3","t1 then: [modify output]resolve: v1=t1, v2=12.3"]

        async function test3() {
            return new Promise((resolve, reject) => {
                let ms = []

                //使用reject
                let pm = function (v1, v2) {
                    return new Promise(function(resolve, reject) {
                        ms.push(`reject: v1=${v1}, v2=${v2}`)
                        reject(`reject: v1=${v1}, v2=${v2}`)
                    })
                }

                //針對afterThen修改輸出, 但因使用reject故改不到
                let pmr = pmHook(pm, (msg) => {
                    console.log('cb', msg)
                    if (msg.mode === 'afterThen') {
                        //arguments有兩個輸入故得分開改
                        msg.data = '[modify output]' + msg.data
                        return msg.data
                    }
                })

                pmr('t1', 12.3)
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + msg)
                    })
                    .finally(function() {
                        resolve(ms)
                    })

            })
        }
        console.log('test3')
        let r3 = await test3()
        console.log(JSON.stringify(r3))
        // test3
        // cb { mode: 'before', data: [Arguments] { '0': 't1', '1': 12.3 } }
        // cb { mode: 'afterCatch', data: 'reject: v1=t1, v2=12.3' }
        // t1 catch reject: v1=t1, v2=12.3
        // ["reject: v1=t1, v2=12.3","t1 catch: reject: v1=t1, v2=12.3"]

        async function test4() {
            return new Promise((resolve, reject) => {
                let ms = []

                //使用reject
                let pm = function (v1, v2) {
                    return new Promise(function(resolve, reject) {
                        ms.push(`reject: v1=${v1}, v2=${v2}`)
                        reject(`reject: v1=${v1}, v2=${v2}`)
                    })
                }

                //針對afterCatch修改輸出
                let pmr = pmHook(pm, (msg) => {
                    console.log('cb', msg)
                    if (msg.mode === 'afterCatch') {
                        //arguments有兩個輸入故得分開改
                        msg.data = '[modify output]' + msg.data
                        return msg.data
                    }
                })

                pmr('t1', 12.3)
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + msg)
                    })
                    .finally(function() {
                        resolve(ms)
                    })

            })
        }
        console.log('test4')
        let r4 = await test4()
        console.log(JSON.stringify(r4))
        // test4
        // cb { mode: 'before', data: [Arguments] { '0': 't1', '1': 12.3 } }
        // cb { mode: 'afterCatch', data: 'reject: v1=t1, v2=12.3' }
        // t1 catch [modify output]reject: v1=t1, v2=12.3
        // ["reject: v1=t1, v2=12.3","t1 catch: [modify output]reject: v1=t1, v2=12.3"]

        async function test5() {
            return new Promise((resolve, reject) => {
                let ms = []

                //使用resolve, 此函數無輸入
                let pm = function () {
                    return new Promise(function(resolve, reject) {
                        ms.push(`resolve`)
                        resolve(`resolve`)
                    })
                }

                //針對afterThen修改輸出
                let pmr = pmHook(pm, (msg) => {
                    console.log('cb', msg)
                    if (msg.mode === 'afterThen') {
                        //arguments有兩個輸入故得分開改
                        msg.data = '[modify output]' + msg.data
                        return msg.data
                    }
                })

                pmr()
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + msg)
                    })
                    .finally(function() {
                        resolve(ms)
                    })

            })
        }
        console.log('test5')
        let r5 = await test5()
        console.log(JSON.stringify(r5))
        // test5
        // cb { mode: 'before', data: [Arguments] {} }
        // cb { mode: 'afterThen', data: 'resolve' }
        // t1 then [modify output]resolve
        // ["resolve","t1 then: [modify output]resolve"]

    }
    topAsync().catch(() => {})

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`fun` | function |  |  | 輸入非同步Promise函數
`cb` | function | <optional> | `() => {}` | 輸入回調函數，預設()={}，cb函數之輸入為監聽到的資訊物件，欄位有mode與data，mode可為'before'、'afterThen'、'afterCatch'字串，而data則代表非同步函數的輸入或輸出資訊。若想於cb函數修改回傳，則由cb函數的輸入修改完回傳即可。例如收到msg={mode:'before',data:'123'}，將msg.data='abc'，再return msg.data

##### Returns:

回傳為Promise，resolve為回傳成功結果，reject為回傳失敗訊息

Type
  Promise

#### (static) pmHookReject(fun, cbopt) → {Promise}

Source:
  - pmHookReject.mjs, line 103

掛勾非同步(Promise)函數，可監聽或修改Promise的reject輸出數據

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        async function test1() {
            return new Promise((resolve, reject) => {
                let ms = []

                let pm = function (v1, v2) {
                    return new Promise(function(resolve, reject) {
                        ms.push(`reject: v1=${v1}, v2=${v2}`)
                        reject(`reject: v1=${v1}, v2=${v2}`)
                    })
                }

                let pmr = pmHookReject(pm, (msg) => {
                    console.log('cb: ' + msg)
                    msg = '[modify catch]' + msg
                    ms.push('cb: ' + msg)
                    return msg
                })

                pmr('t1', 12.3)
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + msg)
                    })
                    .finally(function() {
                        resolve(ms)
                    })

            })
        }
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // cb: reject: v1=t1, v2=12.3
        // t1 catch [modify catch]reject: v1=t1, v2=12.3
        // ["reject: v1=t1, v2=12.3","cb: [modify catch]reject: v1=t1, v2=12.3","t1 catch: [modify catch]reject: v1=t1, v2=12.3"]

        async function test2() {
            return new Promise((resolve, reject) => {
                let ms = []

                let pm = function () {
                    return new Promise(function(resolve, reject) {
                        ms.push(`reject`)
                        reject(`reject`)
                    })
                }

                let pmr = pmHookReject(pm, (msg) => {
                    console.log('cb: ' + msg)
                    msg = '[modify catch]' + msg
                    ms.push('cb: ' + msg)
                    return msg
                })

                pmr() //測試無輸入
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + msg)
                    })
                    .finally(function() {
                        resolve(ms)
                    })

            })
        }
        console.log('test2')
        let r2 = await test2()
        console.log(JSON.stringify(r2))
        // test2
        // cb: reject
        // t1 catch [modify catch]reject
        // ["reject","cb: [modify catch]reject","t1 catch: [modify catch]reject"]

    }
    topAsync().catch(() => {})

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`fun` | function |  |  | 輸入非同步Promise函數
`cb` | function | <optional> | `() => {}` | 輸入回調函數，預設()={}，cb函數之輸入為監聽reject到的資訊數據。若想於cb函數修改reject數據，則由cb函數的輸入修改完回傳即可。例如收到reject的msg為'aaa'，將msg='bbb'再return msg即可

##### Returns:

回傳為Promise，resolve為回傳成功結果，reject為回傳失敗訊息

Type
  Promise

#### (static) pmIni() → {Promise}

Source:
  - pmIni.mjs, line 16

以Promise開啟鏈式

Unit Test: Github

##### Example

Try in Codepen

    pmIni()
        .then(function() {
            console.log('then')
            //code here
        })

##### Returns:

回傳Promise

Type
  Promise

#### (static) pmMap(rs, fun, takeLimitopt) → {Promise}

Source:
  - pmMap.mjs, line 358

Promise的map，可設定同時處理數量

若輸入rs為資料陣列則fn需將數據處理並回傳Promise，若輸入rs為Promise陣列則fn可不給，並循序執行各Promise。 若先行產生promise則takeLimit設定會無效，因promise已先行初始化啟動。 等同於Bluebird的Promise.map，而concurrency為takeLimit。 使用函數執行時，當takeLimit=1，等同於mapSeries，promise依序執行完畢才會調用下一個promise。 使用函數執行時，當takeLimit=0，等同於先行產生promise的情形，各promise直接執行視各自執行時間結束。

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        async function test1() {
            return new Promise((resolve, reject) => {
                let ms = []
                let takeLimit = 2 //通過function調用產生promise, 可受takeLimit控管同時執行數量, takeLimit=2
                pmMap([1, 2, 3, 4, 5], function (v, k) {
                    return new Promise(function(resolve, reject) {
                        let d = 400 - ((v ** 2) * 10 + 50)
                        console.log('call', v)
                        ms.push({ call: v })
                        setTimeout(function() {
                            console.log('resolve', v, 'd', d)
                            ms.push({ resolve: v, d })
                            resolve('#' + v)
                        }, d)
                    })
                }, takeLimit)
                    .then(function(res) {
                        console.log('then', JSON.stringify(res))
                        ms.push({ res })
                        resolve(ms)
                    })
                    .catch(function(err) {
                        console.log('catch', JSON.stringify(err))
                        ms.push({ err })
                        resolve(ms)
                    })
            })
        }
        //cost: (1)340, (2)310, (3)260, (4)190, (5)100
        //1core: call 2(0) -> resolve 2(310) -> call 3(310) -> resolve 3(310+260=570)
        //2core: call 1(0) -> resolve 1(340) -> call 4(340) -> resolve 4(340+190=530) -> call 5(530) -> resolve 5(340+190+100=630)
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // call 1
        // call 2
        // resolve 2 d 310
        // call 3
        // resolve 1 d 340
        // call 4
        // resolve 4 d 190
        // call 5
        // resolve 3 d 260
        // resolve 5 d 100
        // then ["#1","#2","#3","#4","#5"]
        // [{"call":1},{"call":2},{"resolve":2,"d":310},{"call":3},{"resolve":1,"d":340},{"call":4},{"resolve":4,"d":190},{"call":5},{"resolve":3,"d":260},{"resolve":5,"d":100},{"res":["#1","#2","#3","#4","#5"]}]

        async function test2() {
            return new Promise((resolve, reject) => {
                let ms = []
                let takeLimit = 1 //通過function調用產生promise, takeLimit=1, 等同於mapSeries
                pmMap([1, 2, 3, 4, 5], function (v, k) {
                    return new Promise(function(resolve, reject) {
                        let d = 400 - ((v ** 2) * 10 + 50)
                        console.log('call', v)
                        ms.push({ call: v })
                        setTimeout(function() {
                            console.log('resolve', v, 'd', d)
                            ms.push({ resolve: v, d })
                            resolve('#' + v)
                        }, d)
                    })
                }, takeLimit)
                    .then(function(res) {
                        console.log('then', JSON.stringify(res))
                        ms.push({ res })
                        resolve(ms)
                    })
                    .catch(function(err) {
                        console.log('catch', JSON.stringify(err))
                        ms.push({ err })
                        resolve(ms)
                    })
            })
        }
        console.log('test2')
        let r2 = await test2()
        console.log(JSON.stringify(r2))
        // test2
        // call 1
        // resolve 1 d 340
        // call 2
        // resolve 2 d 310
        // call 3
        // resolve 3 d 260
        // call 4
        // resolve 4 d 190
        // call 5
        // resolve 5 d 100
        // then ["#1","#2","#3","#4","#5"]
        // [{"call":1},{"resolve":1,"d":340},{"call":2},{"resolve":2,"d":310},{"call":3},{"resolve":3,"d":260},{"call":4},{"resolve":4,"d":190},{"call":5},{"resolve":5,"d":100},{"res":["#1","#2","#3","#4","#5"]}]

        async function test3() {
            return new Promise((resolve, reject) => {
                let ms = []
                let takeLimit = 0 //通過function調用產生promise, takeLimit=0, 無限制同時執行數量
                pmMap([1, 2, 3, 4, 5], function (v, k) {
                    return new Promise(function(resolve, reject) {
                        let d = 400 - ((v ** 2) * 10 + 50)
                        console.log('call', v)
                        ms.push({ call: v })
                        setTimeout(function() {
                            console.log('resolve', v, 'd', d)
                            ms.push({ resolve: v, d })
                            resolve('#' + v)
                        }, d)
                    })
                }, takeLimit)
                    .then(function(res) {
                        console.log('then', JSON.stringify(res))
                        ms.push({ res })
                        resolve(ms)
                    })
                    .catch(function(err) {
                        console.log('catch', JSON.stringify(err))
                        ms.push({ err })
                        resolve(ms)
                    })
            })
        }
        console.log('test3')
        let r3 = await test3()
        console.log(JSON.stringify(r3))
        // test3
        // call 1
        // call 2
        // call 3
        // call 4
        // call 5
        // resolve 5 d 100
        // resolve 4 d 190
        // resolve 3 d 260
        // resolve 2 d 310
        // resolve 1 d 340
        // then ["#1","#2","#3","#4","#5"]
        // [{"call":1},{"call":2},{"call":3},{"call":4},{"call":5},{"resolve":5,"d":100},{"resolve":4,"d":190},{"resolve":3,"d":260},{"resolve":2,"d":310},{"resolve":1,"d":340},{"res":["#1","#2","#3","#4","#5"]}]

        async function test4() {
            return new Promise((resolve, reject) => {
                let ms = []
                let takeLimit = 2 //同takeLimit=0(無限制同時執行數量), 因rs已事先初始化就執行故無法受takeLimit控管
                let rs = [1, 2, 3, 4, 5].map(function (v, k) {
                    return new Promise(function(resolve, reject) {
                        let d = 400 - ((v ** 2) * 10 + 50)
                        console.log('call', v)
                        ms.push({ call: v })
                        setTimeout(function() {
                            console.log('resolve', v, 'd', d)
                            ms.push({ resolve: v, d })
                            resolve('#' + v)
                        }, d)
                    })
                })
                pmMap(rs, null, takeLimit)
                    .then(function(res) {
                        console.log('then', JSON.stringify(res))
                        ms.push({ res })
                        resolve(ms)
                    })
                    .catch(function(err) {
                        console.log('catch', JSON.stringify(err))
                        ms.push({ err })
                        resolve(ms)
                    })
            })
        }
        console.log('test4')
        let r4 = await test4()
        console.log(JSON.stringify(r4))
        // test4
        // call 1
        // call 2
        // call 3
        // call 4
        // call 5
        // resolve 5 d 100
        // resolve 4 d 190
        // resolve 3 d 260
        // resolve 2 d 310
        // resolve 1 d 340
        // then ["#1","#2","#3","#4","#5"]
        // [{"call":1},{"call":2},{"call":3},{"call":4},{"call":5},{"resolve":5,"d":100},{"resolve":4,"d":190},{"resolve":3,"d":260},{"resolve":2,"d":310},{"resolve":1,"d":340},{"res":["#1","#2","#3","#4","#5"]}]

        async function test5() {
            return new Promise((resolve, reject) => {
                let ms = []
                let takeLimit = 1 //takeLimit=1循序執行, 執行到3先catch而跳出pmMap, 故其他任務4與5不會執行
                pmMap([1, 2, 3, 4, 5], function (v, k) {
                    return new Promise(function(resolve, reject) {
                        let d = 400 - ((v ** 2) * 10 + 50)
                        console.log('call', v)
                        ms.push({ call: v })
                        setTimeout(function() {
                            if (v === 3) {
                                console.log('reject', v, 'd', d)
                                ms.push({ reject: v, d })
                                reject('#' + v)
                            }
                            else {
                                console.log('resolve', v, 'd', d)
                                ms.push({ resolve: v, d })
                                resolve('#' + v)
                            }
                        }, d)
                    })
                }, takeLimit)
                    .then(function(res) {
                        console.log('then', JSON.stringify(res))
                        ms.push({ res })
                        resolve(ms)
                    })
                    .catch(function(err) {
                        console.log('catch', JSON.stringify(err))
                        ms.push({ err })
                        resolve(ms)
                    })
            })
        }
        console.log('test5')
        let r5 = await test5()
        console.log(JSON.stringify(r5))
        // test5
        // call 1
        // resolve 1 d 340
        // call 2
        // resolve 2 d 310
        // call 3
        // reject 3 d 260
        // catch "#3"
        // [{"call":1},{"resolve":1,"d":340},{"call":2},{"resolve":2,"d":310},{"call":3},{"reject":3,"d":260},{"err":"#3"}]

        async function test6() {
            return new Promise((resolve, reject) => {
                let ms = []
                let takeLimit = 0 //無限制同時執行數量, 會於3先catch而跳出pmMap, 但因順發同時執行(1~5都已call), 故3 catch(260m)之後還會有resolve 1(340)與2(310)
                pmMap([1, 2, 3, 4, 5], function (v, k) {
                    return new Promise(function(resolve, reject) {
                        let d = 400 - ((v ** 2) * 10 + 50)
                        console.log('call', v)
                        ms.push({ call: v })
                        setTimeout(function() {
                            if (v === 3) {
                                console.log('reject', v, 'd', d)
                                ms.push({ reject: v, d })
                                reject('#' + v)
                            }
                            else {
                                console.log('resolve', v, 'd', d)
                                ms.push({ resolve: v, d })
                                resolve('#' + v)
                            }
                        }, d)
                    })
                }, takeLimit)
                    .then(function(res) {
                        console.log('then', JSON.stringify(res))
                        ms.push({ res })
                        resolve(ms)
                    })
                    .catch(function(err) {
                        console.log('catch', JSON.stringify(err))
                        ms.push({ err })
                        resolve(ms)
                    })
            })
        }
        console.log('test6')
        let r6 = await test6()
        console.log(JSON.stringify(r6))
        // test6
        // call 1
        // call 2
        // call 3
        // call 4
        // call 5
        // resolve 5 d 100
        // resolve 4 d 190
        // reject 3 d 260
        // catch "#3"
        // [{"call":1},{"call":2},{"call":3},{"call":4},{"call":5},{"resolve":5,"d":100},{"resolve":4,"d":190},{"reject":3,"d":260},{"err":"#3"}]
        // resolve 2 d 310
        // resolve 1 d 340

        let delay = () => {
            return new Promise(function(resolve, reject) {
                setTimeout(function() {
                    resolve()
                }, 700)
            })
        }
        await delay()

        async function test7() {
            return new Promise((resolve, reject) => {
                let ms = []
                pmMap({
                    t1: 1,
                    t2: 2.345,
                    t3: 'abc',
                }, function (v, k) {
                    return new Promise(function(resolve, reject) {
                        resolve(`k=${k},v=${v}`)
                    })
                },)
                    .then(function(res) {
                        console.log('then', JSON.stringify(res))
                        ms.push({ res })
                        resolve(ms)
                    })
                    .catch(function(err) {
                        console.log('catch', JSON.stringify(err))
                        ms.push({ err })
                        resolve(ms)
                    })
            })
        }
        console.log('test7')
        let r7 = await test7()
        console.log(JSON.stringify(r7))
        // test7
        // then ["k=t1,v=1","k=t2,v=2.345","k=t3,v=abc"]
        // [{"res":["k=t1,v=1","k=t2,v=2.345","k=t3,v=abc"]}]

    }
    topAsync().catch(() => {})

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`rs` | Array |  |  | 輸入資料陣列，若不給fn則rs需要為Promise陣列
`fun` | function |  |  | 輸入循序執行值的呼叫函數
`takeLimit` | Integer | <optional> | `0` | 輸入同時處理數量整數，預設0，代表無限制

##### Returns:

回傳Promise，resolve為成功結果，reject為失敗結果

Type
  Promise

#### (static) pmQueue(takeLimitopt, takeLastopt) → {function}

Source:
  - pmQueue.mjs, line 365

通過佇列限制與呼叫非同步(Promise)函數，可推入不同之非同步函數，將一併受限

通過new建構，呼叫時輸入不同之非同步函數，以及其輸入參數，會推入佇列後並循序等待執行

可限制同時運行的非同步函數總數量(takeLimit>0)，可只取最後呼叫的非同步函數進行防抖功能(takeLast=true)，代表前面的呼叫皆自動轉為catch，而其回傳訊息為物件{reason:'cancelled'}

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        async function test1() {
            return new Promise((resolve, reject) => {

                let ms = []
                let pmq = pmQueue(1) //同時處理1個

                function fun1(v) {
                    console.log('call fun1')
                    ms.push('call fun1')
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            ms.push('fun1 resolve: ' + v)
                            resolve('#' + v)
                        }, 300)
                    })
                }

                function fun2(v) {
                    console.log('call fun2')
                    ms.push('call fun2')
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            ms.push('fun2 resolve: ' + v)
                            resolve('#' + v)
                        }, 200)
                    })
                }

                function fun3(v) {
                    console.log('call fun3')
                    ms.push('call fun3')
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            ms.push('fun3 resolve: ' + v)
                            resolve('#' + v)
                        }, 100)
                    })
                }

                pmq(fun1, 'inp1')
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + 'reason ' + msg.reason)
                    })
                pmq(fun2, 'inp2')
                    .then(function(msg) {
                        console.log('t2 then', msg)
                        ms.push('t2 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t2 catch', msg)
                        ms.push('t2 catch: ' + 'reason ' + msg.reason)
                    })
                pmq(fun3, 'inp3')
                    .then(function(msg) {
                        console.log('t3 then', msg)
                        ms.push('t3 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t3 catch', msg)
                        ms.push('t3 catch: ' + 'reason ' + msg.reason)
                    })
                setTimeout(function() {
                    resolve(ms)
                }, 650)
            })
        }
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // call fun1
        // t1 then #inp1
        // call fun2
        // t2 then #inp2
        // call fun3
        // t3 then #inp3
        // ["call fun1","fun1 resolve: inp1","t1 then: #inp1","call fun2","fun2 resolve: inp2","t2 then: #inp2","call fun3","fun3 resolve: inp3","t3 then: #inp3"]

        async function test2() {
            return new Promise((resolve, reject) => {

                let ms = []
                let pmq = pmQueue(2) //同時處理2個

                function fun1(v) {
                    console.log('call fun1')
                    ms.push('call fun1')
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            ms.push('fun1 resolve: ' + v)
                            resolve('#' + v)
                        }, 300)
                    })
                }

                function fun2(v) {
                    console.log('call fun2')
                    ms.push('call fun2')
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            ms.push('fun2 resolve: ' + v)
                            resolve('#' + v)
                        }, 200)
                    })
                }

                function fun3(v) {
                    console.log('call fun3')
                    ms.push('call fun3')
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            ms.push('fun3 resolve: ' + v)
                            resolve('#' + v)
                        }, 100)
                    })
                }

                pmq(fun1, 'inp1')
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + 'reason ' + msg.reason)
                    })
                pmq(fun2, 'inp2')
                    .then(function(msg) {
                        console.log('t2 then', msg)
                        ms.push('t2 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t2 catch', msg)
                        ms.push('t2 catch: ' + 'reason ' + msg.reason)
                    })
                pmq(fun3, 'inp3')
                    .then(function(msg) {
                        console.log('t3 then', msg)
                        ms.push('t3 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t3 catch', msg)
                        ms.push('t3 catch: ' + 'reason ' + msg.reason)
                    })
                setTimeout(function() {
                    resolve(ms)
                }, 650)
            })
        }
        console.log('test2')
        let r2 = await test2()
        console.log(JSON.stringify(r2))
        // test2
        // call fun1
        // call fun2
        // t2 then #inp2
        // call fun3
        // t1 then #inp1
        // t3 then #inp3
        // ["call fun1","call fun2","fun2 resolve: inp2","t2 then: #inp2","call fun3","fun1 resolve: inp1","t1 then: #inp1","fun3 resolve: inp3","t3 then: #inp3"]

        async function test3() {
            return new Promise((resolve, reject) => {

                let ms = []
                let pmq = pmQueue(null) //同時處理全部

                function fun1(v) {
                    console.log('call fun1')
                    ms.push('call fun1')
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            ms.push('fun1 resolve: ' + v)
                            resolve('#' + v)
                        }, 300)
                    })
                }

                function fun2(v) {
                    console.log('call fun2')
                    ms.push('call fun2')
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            ms.push('fun2 resolve: ' + v)
                            resolve('#' + v)
                        }, 200)
                    })
                }

                function fun3(v) {
                    console.log('call fun3')
                    ms.push('call fun3')
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            ms.push('fun3 resolve: ' + v)
                            resolve('#' + v)
                        }, 100)
                    })
                }

                pmq(fun1, 'inp1')
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + 'reason ' + msg.reason)
                    })
                pmq(fun2, 'inp2')
                    .then(function(msg) {
                        console.log('t2 then', msg)
                        ms.push('t2 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t2 catch', msg)
                        ms.push('t2 catch: ' + 'reason ' + msg.reason)
                    })
                pmq(fun3, 'inp3')
                    .then(function(msg) {
                        console.log('t3 then', msg)
                        ms.push('t3 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t3 catch', msg)
                        ms.push('t3 catch: ' + 'reason ' + msg.reason)
                    })
                setTimeout(function() {
                    resolve(ms)
                }, 650)
            })
        }
        console.log('test3')
        let r3 = await test3()
        console.log(JSON.stringify(r3))
        // test3
        // call fun1
        // call fun2
        // call fun3
        // t3 then #inp3
        // t2 then #inp2
        // t1 then #inp1
        // ["call fun1","call fun2","call fun3","fun3 resolve: inp3","t3 then: #inp3","fun2 resolve: inp2","t2 then: #inp2","fun1 resolve: inp1","t1 then: #inp1"]

        async function test4() {
            return new Promise((resolve, reject) => {

                let ms = []
                let pmq = pmQueue(null, true) //同時處理全部, 但只拿最後執行者的結果

                function fun1(v) {
                    console.log('call fun1')
                    ms.push('call fun1')
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            ms.push('fun1 resolve: ' + v)
                            resolve('#' + v)
                        }, 300)
                    })
                }

                function fun2(v) {
                    console.log('call fun2')
                    ms.push('call fun2')
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            ms.push('fun2 resolve: ' + v)
                            resolve('#' + v)
                        }, 200)
                    })
                }

                function fun3(v) {
                    console.log('call fun3')
                    ms.push('call fun3')
                    return new Promise(function(resolve, reject) {
                        setTimeout(function() {
                            ms.push('fun3 resolve: ' + v)
                            resolve('#' + v)
                        }, 100)
                    })
                }

                pmq(fun1, 'inp1')
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + 'reason ' + msg.reason)
                    })
                pmq(fun2, 'inp2')
                    .then(function(msg) {
                        console.log('t2 then', msg)
                        ms.push('t2 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t2 catch', msg)
                        ms.push('t2 catch: ' + 'reason ' + msg.reason)
                    })
                pmq(fun3, 'inp3')
                    .then(function(msg) {
                        console.log('t3 then', msg)
                        ms.push('t3 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t3 catch', msg)
                        ms.push('t3 catch: ' + 'reason ' + msg.reason)
                    })
                setTimeout(function() {
                    resolve(ms)
                }, 650)
            })
        }
        console.log('test4')
        let r4 = await test4()
        console.log(JSON.stringify(r4))
        // test4
        // call fun1
        // call fun2
        // call fun3
        // t3 then #inp3
        // t2 catch { reason: 'cancelled' }
        // t1 catch { reason: 'cancelled' }
        // ["call fun1","call fun2","call fun3","fun3 resolve: inp3","t3 then: #inp3","fun2 resolve: inp2","t2 catch: reason cancelled","fun1 resolve: inp1","t1 catch: reason cancelled"]

    }
    topAsync().catch(() => {})

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`takeLimit` | Integer | <optional> | `0` | 輸入同時處理數量整數，預設0，代表無限制
`takeLast` | Boolean | <optional> | `false` | 輸入多次觸發時是否只取最後呼叫的非同步函數，預設false，搭配takeLimit=0進行非同步函數防抖

##### Returns:

回傳Function，第1參數為非同步函數，第2參數之後為欲輸入非同步函數之參數。回傳為Promise，resolve回傳成功結果而reject回傳失敗訊息

Type
  function

#### (static) pmSeries(rs, fun) → {Promise}

Source:
  - pmSeries.mjs, line 212

Promise的mapSeries，循序執行Promise

若輸入rs為資料陣列則fn需將數據處理並回傳Promise，若輸入rs為Promise陣列則fn可不給，並循序執行各Promise。 使用函數執行時，等同於pmMap使用函數執行且takeLimit=1，promise依序執行完畢才會調用下一個promise。 先行產生promise時，等同於pmMap使用函數執行且takeLimit=0，或是等同於pmMap先行產生promise，各promise直接執行視各自執行時間結束。

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        async function test1() {
            return new Promise((resolve, reject) => {
                let ms = []

                //通過function調用產生promise, 各promise循序調用
                pmSeries([1, 2, 3, 4, 5], function (v, k) {
                    return new Promise(function(resolve, reject) {
                        let d = 400 - ((v ** 2) * 10 + 50)
                        console.log('call', v)
                        ms.push({ call: v })
                        setTimeout(function() {
                            console.log('resolve', v, 'd', d)
                            ms.push({ resolve: v, d })
                            resolve('#' + v)
                        }, d)
                    })
                })
                    .then(function(res) {
                        console.log('then', JSON.stringify(res))
                        ms.push({ res })
                        resolve(ms)
                    })
                    .catch(function(err) {
                        console.log('catch', JSON.stringify(err))
                        ms.push({ err })
                        resolve(ms)
                    })

            })

        }
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // call 1
        // resolve 1 d 340
        // call 2
        // resolve 2 d 310
        // call 3
        // resolve 3 d 260
        // call 4
        // resolve 4 d 190
        // call 5
        // resolve 5 d 100
        // then ["#1","#2","#3","#4","#5"]
        // [{"call":1},{"resolve":1,"d":340},{"call":2},{"resolve":2,"d":310},{"call":3},{"resolve":3,"d":260},{"call":4},{"resolve":4,"d":190},{"call":5},{"resolve":5,"d":100},{"res":["#1","#2","#3","#4","#5"]}]

        async function test2() {
            return new Promise((resolve, reject) => {
                let ms = []

                //通過function調用產生promise, 各promise循序調用, 於3會觸發reject而跳出pmSeries
                pmSeries([1, 2, 3, 4, 5], function (v, k) {
                    return new Promise(function(resolve, reject) {
                        let d = 400 - ((v ** 2) * 10 + 50)
                        console.log('call', v)
                        ms.push({ call: v })
                        setTimeout(function() {
                            if (v === 3) {
                                console.log('reject', v, 'd', d)
                                ms.push({ reject: v, d })
                                reject('#' + v)
                            }
                            else {
                                console.log('resolve', v, 'd', d)
                                ms.push({ resolve: v, d })
                                resolve('#' + v)
                            }
                        }, d)
                    })
                })
                    .then(function(res) {
                        console.log('then', JSON.stringify(res))
                        ms.push({ res })
                        resolve(ms)
                    })
                    .catch(function(err) {
                        console.log('catch', JSON.stringify(err))
                        ms.push({ err })
                        resolve(ms)
                    })

            })

        }
        console.log('test2')
        let r2 = await test2()
        console.log(JSON.stringify(r2))
        // test2
        // call 1
        // resolve 1 d 340
        // call 2
        // resolve 2 d 310
        // call 3
        // reject 3 d 260
        // catch "#3"
        // [{"call":1},{"resolve":1,"d":340},{"call":2},{"resolve":2,"d":310},{"call":3},{"reject":3,"d":260},{"err":"#3"}]

        async function test3() {
            return new Promise((resolve, reject) => {
                let ms = []

                //先產生promise, 因事先初始化故各promise會依照各自執行時間結束
                let rs = [1, 2, 3, 4, 5].map(function (v, k) {
                    return new Promise(function(resolve, reject) {
                        let d = 400 - ((v ** 2) * 10 + 50)
                        console.log('call', v)
                        ms.push({ call: v })
                        setTimeout(function() {
                            console.log('resolve', v, 'd', d)
                            ms.push({ resolve: v, d })
                            resolve('#' + v)
                        }, d)
                    })
                })
                pmSeries(rs, null)
                    .then(function(res) {
                        console.log('then', JSON.stringify(res))
                        ms.push({ res })
                        resolve(ms)
                    })
                    .catch(function(err) {
                        console.log('catch', JSON.stringify(err))
                        ms.push({ err })
                        resolve(ms)
                    })

            })

        }
        console.log('test3')
        let r3 = await test3()
        console.log(JSON.stringify(r3))
        // test3
        // call 1
        // call 2
        // call 3
        // call 4
        // call 5
        // resolve 5 d 100
        // resolve 4 d 190
        // resolve 3 d 260
        // resolve 2 d 310
        // resolve 1 d 340
        // then ["#1","#2","#3","#4","#5"]
        // [{"call":1},{"call":2},{"call":3},{"call":4},{"call":5},{"resolve":5,"d":100},{"resolve":4,"d":190},{"resolve":3,"d":260},{"resolve":2,"d":310},{"resolve":1,"d":340},{"res":["#1","#2","#3","#4","#5"]}]

        async function test4() {
            return new Promise((resolve, reject) => {
                let ms = []

                //通過function調用產生promise, 各promise循序調用
                pmSeries({
                    t1: 1,
                    t2: 2.345,
                    t3: 'abc',
                }, function (v, k) {
                    return new Promise(function(resolve, reject) {
                        resolve(`k=${k},v=${v}`)
                    })
                })
                    .then(function(res) {
                        console.log('then', JSON.stringify(res))
                        ms.push({ res })
                        resolve(ms)
                    })
                    .catch(function(err) {
                        console.log('catch', JSON.stringify(err))
                        ms.push({ err })
                        resolve(ms)
                    })

            })

        }
        console.log('test4')
        let r4 = await test4()
        console.log(JSON.stringify(r4))
        // test4
        // then ["k=t1,v=1","k=t2,v=2.345","k=t3,v=abc"]
        // [{"res":["k=t1,v=1","k=t2,v=2.345","k=t3,v=abc"]}]

    }
    topAsync().catch(() => {})

##### Parameters:

Name | Type | Description
--- | --- | ---
`rs` | Array | 輸入資料陣列，若不給fn則rs需要為Promise陣列
`fun` | function | 輸入循序執行值的呼叫函數

##### Returns:

回傳Promise，resolve為成功結果，reject為失敗結果

Type
  Promise

#### (static) pmThrottle() → {function}

Source:
  - pmThrottle.mjs, line 253

非同步函數進行防抖，通過new建構，呼叫時輸入不同之非同步函數，以及其輸入參數，會推入佇列後並循序等待執行

同時僅會執行一個佇列(非同步函數)，若前一個執行完畢，則直接呼叫最新(末)的佇列，前面的呼叫皆會自動轉為catch，回傳訊息為物件{reason:'cancelled'}

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        async function test1() {
            return new Promise((resolve, reject) => {

                let ms = []
                let pmt = pmThrottle()

                let fun = function (name, t) {
                    return new Promise(function(resolve, reject) {
                        setTimeout(() => {
                            console.log('resolve: ' + name + ', t: ' + t)
                            resolve('resolve: ' + name + ', t: ' + t)
                        }, t)
                    })
                }

                pmt(fun, 't1', 150)
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + 'reason ' + msg.reason)
                    })
                pmt(fun, 't2', 100)
                    .then(function(msg) {
                        console.log('t2 then', msg)
                        ms.push('t2 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t2 catch', msg)
                        ms.push('t2 catch: ' + 'reason ' + msg.reason)
                    })
                pmt(fun, 't3', 50)
                    .then(function(msg) {
                        console.log('t3 then', msg)
                        ms.push('t3 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t3 catch', msg)
                        ms.push('t3 catch: ' + 'reason ' + msg.reason)
                    })

                setTimeout(() => {
                    pmt(fun, 't4', 50)
                        .then((msg) => {
                            console.log('t4 then', msg)
                            ms.push('t4 then: ' + msg)
                        })
                        .catch((msg) => {
                            console.log('t4 catch', msg)
                            ms.push('t4 catch: ' + 'reason ' + msg.reason)
                        })
                        .finally(() => {
                            resolve(ms)
                        })
                }, 200)

            })
        }
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // t1 catch { reason: 'cancelled' }
        // t2 catch { reason: 'cancelled' }
        // resolve: t3, t: 50
        // t3 then resolve: t3, t: 50
        // resolve: t4, t: 50
        // t4 then resolve: t4, t: 50
        // ["t1 catch: reason cancelled","t2 catch: reason cancelled","t3 then: resolve: t3, t: 50","t4 then: resolve: t4, t: 50"]

        async function test2() {
            return new Promise((resolve, reject) => {

                let ms = []
                let pmt = pmThrottle()

                let fun1 = function (name, t) {
                    return new Promise(function(resolve, reject) {
                        setTimeout(() => {
                            console.log('fun1 resolve: ' + name + ', t: ' + t)
                            resolve('fun1 resolve: ' + name + ', t: ' + t)
                        }, t)
                    })
                }

                let fun2 = function (name, t) {
                    return new Promise(function(resolve, reject) {
                        setTimeout(() => {
                            console.log('fun2 resolve: ' + name + ', t: ' + t)
                            resolve('fun2 resolve: ' + name + ', t: ' + t)
                        }, t)
                    })
                }

                //測試不同函數fun1與fun2
                pmt(fun1, 't1', 150)
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + 'reason ' + msg.reason)
                    })
                pmt(fun2, 't2', 100)
                    .then(function(msg) {
                        console.log('t2 then', msg)
                        ms.push('t2 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t2 catch', msg)
                        ms.push('t2 catch: ' + 'reason ' + msg.reason)
                    })
                pmt(fun2, 't3', 50)
                    .then(function(msg) {
                        console.log('t3 then', msg)
                        ms.push('t3 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t3 catch', msg)
                        ms.push('t3 catch: ' + 'reason ' + msg.reason)
                    })

                setTimeout(() => {
                    pmt(fun1, 't4', 50)
                        .then((msg) => {
                            console.log('t4 then', msg)
                            ms.push('t4 then: ' + msg)
                        })
                        .catch((msg) => {
                            console.log('t4 catch', msg)
                            ms.push('t4 catch: ' + 'reason ' + msg.reason)
                        })
                        .finally(() => {
                            resolve(ms)
                        })
                }, 200)

            })
        }
        console.log('test2')
        let r2 = await test2()
        console.log(JSON.stringify(r2))
        // test2
        // t1 catch { reason: 'cancelled' }
        // t2 catch { reason: 'cancelled' }
        // fun2 resolve: t3, t: 50
        // t3 then fun2 resolve: t3, t: 50
        // fun1 resolve: t4, t: 50
        // t4 then fun1 resolve: t4, t: 50
        // ["t1 catch: reason cancelled","t2 catch: reason cancelled","t3 then: fun2 resolve: t3, t: 50","t4 then: fun1 resolve: t4, t: 50"]

        async function test3() {
            return new Promise((resolve, reject) => {

                let ms = []
                let pmt = pmThrottle()

                let i = 0
                let fun = function () {
                    return new Promise(function(resolve, reject) {
                        setTimeout(() => {
                            i++
                            console.log('resolve: ' + i)
                            resolve('resolve: ' + i)
                        }, 100)
                    })
                }

                //測試無輸入參數
                pmt(fun)
                    .then(function(msg) {
                        console.log('t1 then', msg)
                        ms.push('t1 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t1 catch', msg)
                        ms.push('t1 catch: ' + 'reason ' + msg.reason)
                    })
                pmt(fun)
                    .then(function(msg) {
                        console.log('t2 then', msg)
                        ms.push('t2 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t2 catch', msg)
                        ms.push('t2 catch: ' + 'reason ' + msg.reason)
                    })
                pmt(fun)
                    .then(function(msg) {
                        console.log('t3 then', msg)
                        ms.push('t3 then: ' + msg)
                    })
                    .catch(function(msg) {
                        console.log('t3 catch', msg)
                        ms.push('t3 catch: ' + 'reason ' + msg.reason)
                    })

                setTimeout(() => {
                    pmt(fun)
                        .then((msg) => {
                            console.log('t4 then', msg)
                            ms.push('t4 then: ' + msg)
                        })
                        .catch((msg) => {
                            console.log('t4 catch', msg)
                            ms.push('t4 catch: ' + 'reason ' + msg.reason)
                        })
                        .finally(() => {
                            resolve(ms)
                        })
                }, 200)

            })
        }
        console.log('test3')
        let r3 = await test3()
        console.log(JSON.stringify(r3))
        // test3
        // t1 catch { reason: 'cancelled' }
        // t2 catch { reason: 'cancelled' }
        // core: resolve: 1
        // t3 then resolve: 1
        // core: resolve: 2
        // t4 then resolve: 2
        // ["t1 catch: reason cancelled","t2 catch: reason cancelled","t3 then: resolve: 1","t4 then: resolve: 2"]

    }
    topAsync().catch(() => {})

##### Returns:

回傳Function，輸入為非同步函數與其輸入，會推入佇列後並循序等待執行，回傳為Promise，resolve回傳成功結果而reject回傳失敗訊息

Type
  function

#### (static) queue(takeLimitopt) → {Object}

Source:
  - queue.mjs, line 160

佇列處理器，單生產者單消費者模式，核心使用迭代器，具有消息堵塞與可限定同時處理上限數量功能

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        async function test(takeLimit, timeCallBack) {
            return new Promise((resolve, reject) => {

                //queue
                let q = queue(takeLimit)
                let n = 0
                let ms = []

                //message
                q.on('message', function(qs) {
                    console.log('message', JSON.stringify(qs))

                    //ms
                    ms.push(JSON.parse(JSON.stringify(qs)))

                    //get
                    let v = q.get()
                    if (!v) {
                        return
                    }
                    console.log('get', v)

                    setTimeout(function() {
                        console.log('cb', v)

                        //cb
                        q.cb()

                        //resolve
                        if (v === '$10') {
                            resolve(ms)
                        }

                    }, timeCallBack)

                })

                //queues push 1~5
                setTimeout(function() {
                    console.log('queues push 1~5')
                    let t = setInterval(function() {
                        n += 1
                        q.push('$' + n)
                        if (n === 5) {
                            clearInterval(t)
                        }
                    }, 50)
                }, 1)

                //queues push 6~10 by delay 1s
                setTimeout(function() {
                    console.log('queues push 6~10')
                    let t = setInterval(function() {
                        n += 1
                        q.push('$' + n)
                        if (n === 10) {
                            clearInterval(t)
                        }
                    }, 50)
                }, 500)

            })
        }

        console.log('test1')
        let r1 = await test(2, 1000)
        console.log(JSON.stringify(r1))
        // queues push 1~5
        // message ["$1"]
        // get $1
        // message ["$2"]
        // get $2
        // queues push 6~10
        // cb $1
        // message ["$3","$4","$5","$6","$7","$8","$9","$10"]
        // get $3
        // cb $2
        // message ["$4","$5","$6","$7","$8","$9","$10"]
        // get $4
        // cb $3
        // message ["$5","$6","$7","$8","$9","$10"]
        // get $5
        // cb $4
        // message ["$6","$7","$8","$9","$10"]
        // get $6
        // cb $5
        // message ["$7","$8","$9","$10"]
        // get $7
        // cb $6
        // message ["$8","$9","$10"]
        // get $8
        // cb $7
        // message ["$9","$10"]
        // get $9
        // cb $8
        // message ["$10"]
        // get $10
        // cb $9
        // cb $10
        // [["$1"],["$2"],["$3","$4","$5","$6","$7","$8","$9","$10"],["$4","$5","$6","$7","$8","$9","$10"],["$5","$6","$7","$8","$9","$10"],["$6","$7","$8","$9","$10"],["$7","$8","$9","$10"],["$8","$9","$10"],["$9","$10"],["$10"]]

        console.log('test2')
        let r2 = await test(0, 500) //takeLimit=0, timeCallBack=500ms
        console.log(JSON.stringify(r2))
        // test2
        // queues push 1~5
        // message ["$1"]
        // get $1
        // message ["$2"]
        // get $2
        // message ["$3"]
        // get $3
        // message ["$4"]
        // get $4
        // message ["$5"]
        // get $5
        // queues push 6~10
        // message ["$6"]
        // get $6
        // cb $1
        // message ["$7"]
        // get $7
        // cb $2
        // message ["$8"]
        // get $8
        // cb $3
        // message ["$9"]
        // get $9
        // cb $4
        // message ["$10"]
        // get $10
        // cb $5
        // cb $6
        // cb $7
        // cb $8
        // cb $9
        // cb $10
        // [["$1"],["$2"],["$3"],["$4"],["$5"],["$6"],["$7"],["$8"],["$9"],["$10"]]

    }
    topAsync().catch(() => {})

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`takeLimit` | Integer | <optional> | `0` | 輸入同時處理數量整數，預設0，代表無限制

##### Returns:

回傳事件物件，可呼叫事件on、push、get、cb、clear。on為監聽事件，需自行監聽message事件，push為加入最新佇列消息，get為回傳當前最早佇列消息，cb為於message事件內回調使迭代器可取得下一個佇列消息，clear為清空佇列

Type
  Object

#### (static) rep(c, n) → {Array}

Source:
  - rep.mjs, line 20

產生重複n次字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(rep('abc', 2))
    // => 'abcabc'

##### Parameters:

Name | Type | Description
--- | --- | ---
`c` | String | 輸入欲重複的字串
`n` | Integer | 輸入重複次數之含零正整數

##### Returns:

回傳任意資料之陣列

Type
  Array

#### (static) replace(c, t, r) → {String}

Source:
  - replace.mjs, line 22

取代字串 針對c查找是否含有t，並將t全部取代成r 若輸入c,t,r不是字串時則回傳空字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(replace('1.25abc', '5a', '0'))
    // => '1.20bc'

##### Parameters:

Name | Type | Description
--- | --- | ---
`c` | String | 輸入要被取代的字串
`t` | String | 輸入要查找的字串
`r` | String | 輸入要取代的字串

##### Returns:

回傳取代後字串

Type
  String

#### (static) replaceObj(c, o) → {String}

Source:
  - replaceObj.mjs, line 22

取代字串，由c內大括號會標記為被取代的{key}，再由物件o的key所對應value進行取代，而各value皆需要為有效字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(replaceObj('1.25abc中文', { '5a': '0', '中': '英' }))
    // => '1.20bc英文'

##### Parameters:

Name | Type | Description
--- | --- | ---
`c` | String | 輸入要被取代的字串
`o` | Object | 輸入用來取代的key,value物件

##### Returns:

回傳取代後字串

Type
  String

#### (static) replacePlus(c, pre, aft, notopt, r) → {String}

Source:
  - replacePlus.mjs, line 25

取代字串，找尋條件為滿足具字首字尾則被取代

Unit Test: Github

##### Example

Try in Codepen

    console.log(replacePlus('1.25mn1.25abc中文結尾', '1', '文', null, 'xyz'))
    // => 'xyz結尾'

    console.log(replacePlus('1.25mn1.25abc中文結尾', '1', '文', 'm', 'xyz'))
    // => '1.25mnxyz結尾'

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`c` | String |  |  | 輸入要被取代的字串
`pre` | String |  |  | 輸入需為字首的字串
`aft` | String |  |  | 輸入需為字尾的字串
`not` | String | <optional> | `null` | 輸入需不包含的字串，預設為不使用
`r` | String |  |  | 輸入要取代的字串

##### Returns:

回傳取代後字串

Type
  String

#### (static) repObj(o, n) → {Array}

Source:
  - repObj.mjs, line 24

產生重複n次任意資料之陣列

Unit Test: Github

##### Example

Try in Codepen

    console.log(repObj({ a: 12.45, b: 'opqr' }, 2))
    // => [{ a: 12.45, b: 'opqr' }, { a: 12.45, b: 'opqr' }]

    console.log(repObj({ a: 12.45, b: 'opqr' }, 0))
    // => []

##### Parameters:

Name | Type | Description
--- | --- | ---
`o` | * | 輸入任意資料
`n` | Integer | 輸入重複次數之正整數

##### Returns:

回傳任意資料之陣列

Type
  Array

#### (static) round(v) → {Integer}

Source:
  - round.mjs, line 26

數字或字串四捨五入至整數 若輸入不是數字或字串時則回傳空字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(round(1.5))
    // => 2

    console.log(round('1.5'))
    // => 2

    console.log(round('125abc'))
    // => ''

##### Parameters:

Name | Type | Description
--- | --- | ---
`v` | Number | String | 輸入數字或字串

##### Returns:

回傳四捨五入的整數

Type
  Integer

#### (static) sep(c, t) → {Array}

Source:
  - sep.mjs, line 20

切割字串並剔除非有效元素

Unit Test: Github

##### Example

Try in Codepen

    console.log(sep('1.25 abc  中文', ' '))
    // => ['1.25', 'abc', '中文']

##### Parameters:

Name | Type | Description
--- | --- | ---
`c` | String | 輸入要被切割的字串
`t` | String | 輸入用來切割的符號字串

##### Returns:

回傳切割後的字串陣列

Type
  Array

#### (static) sepInt(v, n, breverseopt) → {Array}

Source:
  - sepInt.mjs, line 23

由整數v切分n個正整數，回傳切分後之整數陣列

Unit Test: Github

##### Example

Try in Codepen

    console.log(sepInt(10, 3))
    // => [3, 3, 4]

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`v` | Integer |  |  | 輸入要被切分的整數
`n` | Integer |  |  | 輸入要切分數量的整數
`breverse` | Boolean | <optional> | `true` | 輸入是否要反轉順序，預設true為由小至大，反序則為由大至小

##### Returns:

回傳切分後的整數陣列

Type
  Array

#### (static) split(c, t) → {Array}

Source:
  - split.mjs, line 18

切割字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(split('1.25 abc  中文', ' '))
    // => ['1.25', 'abc', '', '中文']

##### Parameters:

Name | Type | Description
--- | --- | ---
`c` | String | 輸入要被切割的字串
`t` | String | 輸入用來切割的符號字串

##### Returns:

回傳切割後的字串陣列

Type
  Array

#### (static) str2aes(str, key, base64opt) → {String}

Source:
  - str2aes.mjs, line 31

一般字串轉AES字串 使用AES-128-CBC加密，字串採用PKCS#7填充

Unit Test: Github

##### Example

Try in Codepen

    let str = 'test中文abcdefghijklmn'
    let key = '1234567890abcdefghijk'
    console.log(str2aes(str, key))
    // => 53616c7465645f5f9d7366e54b51e9352dbccf6a6ec9b3af0595b19b345ea903b713143f5d66417f4cd968c628863f61 (is random)

    console.log(str2aes(str, key, true))
    // => U2FsdGVkX19c7rKkQ38SfqZLaQEKzLD0PhXzzdYeGbngewsPmzS8PcOwHQIsf2Zo (is random)

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`str` | String |  |  | 輸入一般字串
`key` | String |  |  | 輸入加密key
`base64` | Boolean | <optional> | `false` | 輸入是否轉為base64字串，預設為false

##### Returns:

回傳經AES轉換後字串，採Hex/base64顯示

Type
  String

#### (static) str2b64(str) → {String}

Source:
  - str2b64.mjs, line 19

一般字串轉base64字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(str2b64('test中文'))
    // => 'dGVzdOS4reaWhw=='

##### Parameters:

Name | Type | Description
--- | --- | ---
`str` | String | 輸入一般字串

##### Returns:

回傳base64字串

Type
  String

#### (static) str2md5(str, base64opt) → {String}

Source:
  - str2md5.mjs, line 22

一般字串轉MD5字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(str2md5('test中文'))
    // => '5393554e94bf0eb6436f240a4fd71282'

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`str` | String |  |  | 輸入一般字串
`base64` | Boolean | <optional> | `false` | 輸入是否轉為base64字串，預設為false

##### Returns:

回傳經MD5轉換後字串

Type
  String

#### (static) str2obj(data, extopt) → {String}

Source:
  - str2obj.mjs, line 33

字串轉任意資料，可支援內含Uint8Array與Uint16Array數據

Unit Test: Github

##### Example

Try in Codepen

    console.log(str2obj('{"a":"abc","b":12.3,"u8a":"[Uint8Array]::QmFz","u16a":{"0":11,"1":79,"2":6}}'))
    // => {
    // =>   a: 'abc',
    // =>   b: 12.3,
    // =>   u8a: Uint8Array [ 66, 97, 115 ],
    // =>   u16a: { '0': 11, '1': 79, '2': 6 }
    // => }

    console.log(str2obj('{"a":"abc","b":12.3,"u8a":"[Uint8Array]::QmFz","u16a":"[Uint8Array]::C08G"}', ['Uint8Array', 'Uint16Array']}))
    // => {
    // =>   a: 'abc',
    // =>   b: 12.3,
    // =>   u8a: Uint8Array [ 66, 97, 115 ],
    // =>   u16a: Uint8Array [ 11, 79, 6 ]
    // => }

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`data` | * |  |  | 輸入任意資料
`ext` | String | Array | <optional> | `'Uint8Array'` | 輸入擴充數據種類字串或陣列，預設'Uint8Array'

##### Returns:

回傳base64字串

Type
  String

#### (static) str2sha512(str, base64opt) → {String}

Source:
  - str2sha512.mjs, line 23

一般字串轉SHA512字串 Secure Hash Algorithm 512位

Unit Test: Github

##### Example

Try in Codepen

    console.log(str2sha512('test中文'))
    // => 'ab43333a01571e767a2eb15460c270fa123964c121b88c73e274a211d6e2cf98b10d89220e8d04e2fc573354da93400f3255e94d445dc956e177aa4201a4fc30'

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`str` | String |  |  | 輸入一般字串
`base64` | Boolean | <optional> | `false` | 輸入是否轉為base64字串，預設為false

##### Returns:

回傳經SHA512轉換後字串

Type
  String

#### (static) str2u8arr(str) → {Uint8Array}

Source:
  - str2u8arr.mjs, line 19

字串轉Uint8Array

Unit Test: Github

##### Example

Try in Codepen

    console.log(str2u8arr('test中文'))
    // => Uint8Array [116, 101, 115, 116, 228, 184, 173, 230, 150, 135]

##### Parameters:

Name | Type | Description
--- | --- | ---
`str` | String | 輸入一般字串

##### Returns:

回傳Uint8Array

Type
  Uint8Array

#### (static) strCompare(str1, str2) → {Number}

Source:
  - strCompare.mjs, line 57

計算2字串相似度

Fork: string-similarity

Unit Test: Github

##### Example

Try in Codepen

    console.log(strCompare('The Woodman(樵夫) set to work at once, and so...', 'Wodooman(樵夫)'))
    // => 0.375

##### Parameters:

Name | Type | Description
--- | --- | ---
`str1` | String | 輸入欲比對之一般字串
`str2` | String | 輸入欲比對之一般字串

##### Returns:

回傳字串相似度0~1

Type
  Number

#### (static) strdelleft(c, n) → {String}

Source:
  - strdelleft.mjs, line 20

刪除字串左邊n個字元

Unit Test: Github

##### Example

Try in Codepen

    console.log(strdelleft('test中文', 2))
    // => 'st中文'

##### Parameters:

Name | Type | Description
--- | --- | ---
`c` | String | 輸入要被刪除的字串
`n` | Integer | 輸入刪除左邊n個字元正整數

##### Returns:

回傳處理後字串

Type
  String

#### (static) strdelright(c, n) → {String}

Source:
  - strdelright.mjs, line 20

刪除字串右邊n個字元

Unit Test: Github

##### Example

Try in Codepen

    console.log(strdelright('test中文', 2))
    // => 'test'

##### Parameters:

Name | Type | Description
--- | --- | ---
`c` | String | 輸入要被刪除的字串
`n` | Integer | 輸入刪除右邊n個字元

##### Returns:

回傳處理後字串

Type
  String

#### (static) strFindFuzz(ar, strkey, bscoreopt) → {Boolean|Number}

Source:
  - strFindFuzz.mjs, line 50

以空白分切strkey做為關鍵字，查詢字串陣列ar是否含有相似關鍵字

Unit Test: Github

##### Example

Try in Codepen

    console.log(strFindFuzz('Wodooman(樵夫)', 'The Woodman(樵夫) set to work at once, and so...', true))
    // => 41.333333333333336, 第2參數會被空白切分成多關鍵字

    console.log(strFindFuzz('The Woodman(樵夫) set to work at once, and so...', 'Wodooman(樵夫)', true))
    // => 82

    console.log(strFindFuzz(['abc', 'def123', '中文測試'], 'ef', true))
    // => 100

    console.log(strFindFuzz(['abc', 'def123', '中文測試'], 'efgg', true))
    // => 50

    console.log(strFindFuzz(['abc', 'def123', '中文測試'], 'ef'))
    // => true

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ar` | Array | String |  |  | 輸入資料，若輸入陣列則自動join成字串
`strkey` | String | Number |  |  | 查找ar內是否含有關鍵字，多關鍵字係以空白區分
`bscore` | Boolean | <optional> | `false` | 是否回傳分數，當設定為true時回傳值為分數，設定為false時回傳值為是否(預設)

##### Returns:

輸出資料，回傳值為分數或是否

Type
  Boolean | Number

#### (async, static) strFindFuzzDyn(ar, strkey, bscoreopt, pathItems) → {Promise}

Source:
  - strFindFuzzDyn.mjs, line 50

前端以空白分切strkey做為關鍵字，查詢字串陣列ar是否含有相似關鍵字

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    strFindFuzzDyn('Wodooman(樵夫)', 'The Woodman(樵夫) set to work at once, and so...', true)
        .then(function(r) {
            console.log(r)
            // => 41.333333333333336, 第2參數會被空白切分成多關鍵字
        })

    strFindFuzzDyn('The Woodman(樵夫) set to work at once, and so...', 'Wodooman(樵夫)', true)
        .then(function(r) {
            console.log(r)
            // => 82
        })

    strFindFuzzDyn(['abc', 'def123', '中文測試'], 'ef', true)
        .then(function(r) {
            console.log(r)
            // => 100
        })

    strFindFuzzDyn(['abc', 'def123', '中文測試'], 'efgg', true)
        .then(function(r) {
            console.log(r)
            // => 50
        })

    strFindFuzzDyn(['abc', 'def123', '中文測試'], 'ef')
        .then(function(r) {
            console.log(r)
            // => true
        })

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`ar` | Array | String |  |  | 輸入資料，若輸入陣列則自動join成字串
`strkey` | String | Number |  |  | 查找ar內是否含有關鍵字，多關鍵字係以空白區分
`bscore` | Boolean | <optional> | `false` | 是否回傳分數，當設定為true時回傳值為分數，設定為false時回傳值為是否(預設)
`pathItems` | String | Object | Array |  |  | 輸入資源字串、字串陣列、物件、物件陣列

##### Returns:

回傳Promise，resolve回傳為分數或是否，reject回傳錯誤訊息

Type
  Promise

#### (static) strFindSimilar(ar, strkeys) → {Object}

Source:
  - strFindSimilar.mjs, line 43

計算字串ar與多關鍵字陣列strkeys之相似程度

Unit Test: Github

##### Example

Try in Codepen

    console.log(strFindSimilar('The Woodman(樵夫) set to work at once, and so...', ['Wodooman(樵夫)', 'manWood(樵夫)', 'Wood樵man(夫)', 'Woodman(樵夫)']))
    // => { 'ratings': [{ 'target': 'Wodooman(樵夫)', 'rating': 0.375 }, { 'target': 'manWood(樵夫)', 'rating': 0.3404255319148936 }, { 'target': 'Wood樵man(夫)', 'rating': 0.2978723404255319 }, { 'target': 'Woodman(樵夫)', 'rating': 0.425531914893617 }], 'bestMatch': { 'target': 'Woodman(樵夫)', 'rating': 0.425531914893617 }, 'bestMatchIndex': 3 }

##### Parameters:

Name | Type | Description
--- | --- | ---
`ar` | Array | String | 輸入資料，若輸入陣列則自動join成字串
`strkeys` | String | Number | Array | 查找ar內與多關鍵字strkeys的個別相似度

##### Returns:

輸出比對資料物件，回傳與各關鍵字之相似度以及最相關者

Type
  Object

#### (static) strleft(c, n) → {String}

Source:
  - strleft.mjs, line 19

取字串左邊n個字元

Unit Test: Github

##### Example

Try in Codepen

    console.log(strleft('test中文', 2))
    // => 'te'

##### Parameters:

Name | Type | Description
--- | --- | ---
`c` | String | 輸入要被取的字串
`n` | Integer | 輸入取左邊n個字元

##### Returns:

回傳處理後字串

Type
  String

#### (static) strmid(c, s, nopt) → {String}

Source:
  - strmid.mjs, line 25

取字串中位置s開始後n個字元

Unit Test: Github

##### Example

Try in Codepen

    console.log(strmid('test中文', 2, 1))
    // => 's'

    console.log(strmid('test中文', 2, 3))
    // => 'st中'

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`c` | String |  |  | 輸入要被取的字串
`s` | Integer |  |  | 輸入要由第s個位置開始，為正整數
`n` | Integer | <optional> | `1` | 輸入開始後n個字元，為正整數，預設1

##### Returns:

回傳處理後字串

Type
  String

#### (static) strright(c, n) → {String}

Source:
  - strright.mjs, line 19

取字串右邊n個字元

Unit Test: Github

##### Example

Try in Codepen

    console.log(strright('test中文', 2))
    // => '中文'

##### Parameters:

Name | Type | Description
--- | --- | ---
`c` | String | 輸入要被取的字串
`n` | Integer | 輸入取右邊n個字元

##### Returns:

回傳處理後字串

Type
  String

#### (static) stru8arr2obj() → {*}

Source:
  - stru8arr2obj.mjs, line 37

由字串與Unit8Array陣列轉物件，為對obj2stru8arr序列化之數據進行反序列化

Unit Test: Github

##### Example

Try in Codepen

    let r = {
        results: '{"a":123,"b":45.67,"c":"l1-測試中文","d":{"da":123,"db":45.67,"dc":"l2-測試中文","dd":["a","xyz",321,76.54],"de":"[Uint8Array]::0"}}',
        binarys: [new Uint8Array([66, 97, 115])]
    }
    let data = stru8arr2obj(r)
    console.log(data)
    // => {
    //     a: 123,
    //     b: 45.67,
    //     c: 'l1-測試中文',
    //     d: {
    //         da: 123,
    //         db: 45.67,
    //         dc: 'l2-測試中文',
    //         dd: [ 'a', 'xyz', 321, 76.54 ],
    //         de: Uint8Array [ 66, 97, 115 ]
    //     }
    // }

##### Parameters:

Name | Type | Description
--- | --- | ---
`data.results` | String | 輸入待反序列化字串
`data.binarys` | Array | 輸入Unit8Array陣列

##### Returns:

回傳任意物件

Type
  *

#### (static) time2day(t) → {String}

Source:
  - time2day.mjs, line 18

秒時間取至日時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(time2day('2019-01-01T12:34:56'))
    // => '2019-01-01'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入秒時間字串，不含時區

##### Returns:

回傳日時間字串

Type
  String

#### (static) time2hour(t) → {String}

Source:
  - time2hour.mjs, line 18

秒時間取至時時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(time2hour('2019-01-01T12:34:56'))
    // => '2019-01-01T12'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入秒時間字串，不含時區

##### Returns:

回傳時時間字串

Type
  String

#### (static) time2min(t) → {String}

Source:
  - time2min.mjs, line 18

秒時間取至分時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(time2min('2019-01-01T12:34:56'))
    // => '2019-01-01T12:34'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入秒時間字串，不含時區

##### Returns:

回傳分時間字串

Type
  String

#### (static) timems2day(t) → {String}

Source:
  - timems2day.mjs, line 18

毫秒時間取至日時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(timems2day('2019-01-01T12:34:56.987'))
    // => '2019-01-01'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入毫秒時間字串，不含時區

##### Returns:

回傳日時間字串

Type
  String

#### (static) timems2hour(t) → {String}

Source:
  - timems2hour.mjs, line 18

毫秒時間取至時時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(timems2hour('2019-01-01T12:34:56.987'))
    // => '2019-01-01T12'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入毫秒時間字串，不含時區

##### Returns:

回傳時時間字串

Type
  String

#### (static) timems2min(t) → {String}

Source:
  - timems2min.mjs, line 18

毫秒時間取至分時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(timems2min('2019-01-01T12:34:56.987'))
    // => '2019-01-01T12:34'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入毫秒時間字串，不含時區

##### Returns:

回傳分時間字串

Type
  String

#### (static) timems2time(t) → {String}

Source:
  - timems2time.mjs, line 18

毫秒時間取至秒時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(timems2time('2019-01-01T12:34:56.987'))
    // => '2019-01-01T12:34:56'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入毫秒時間字串，不含時區

##### Returns:

回傳秒時間字串

Type
  String

#### (static) timemsTZ2day(t) → {String}

Source:
  - timemsTZ2day.mjs, line 22

毫秒時間(含時區)取至日時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(timemsTZ2day('2019-01-01T12:34:56.987+08:00'))
    // => '2019-01-01'

    console.log(timemsTZ2day('2019-01-01T12:34:56.987Z'))
    // => '2019-01-01'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入毫秒時間字串，含時區

##### Returns:

回傳日時間字串

Type
  String

#### (static) timemsTZ2expire(t, tNowopt) → {String}

Source:
  - timemsTZ2expire.mjs, line 70

毫秒時間轉到期時間

Unit Test: Github

##### Example

Try in Codepen

    let t
    let tNow = '2020-10-18T12:34:56.987+08:00'
    let r

    t = '2020-10-18T12:34:58.987+08:00'
    r = timemsTZ2expire(t, tNow)
    console.log(r)
    // => { today: true, msg: '2秒後', err: '' }

    t = '2020-10-18T04:34:58.987+00:00'
    r = timemsTZ2expire(t, tNow)
    console.log(r)
    // => { today: true, msg: '2秒後', err: '' }

    t = '2020-10-18T04:34:58.987Z'
    r = timemsTZ2expire(t, tNow)
    console.log(r)
    // => { today: true, msg: '2秒後', err: '' }

    t = '2020-10-18T12:34:58.123+08:00'
    r = timemsTZ2expire(t, tNow)
    console.log(r)
    // => { today: true, msg: '1秒後', err: '' }

    t = '2020-10-18T12:37:58.987+08:00'
    r = timemsTZ2expire(t, tNow)
    console.log(r)
    // => { today: true, msg: '3分鐘後', err: '' }

    t = '2020-10-18T16:37:58.987+08:00'
    r = timemsTZ2expire(t, tNow)
    console.log(r)
    // => { today: true, msg: '4小時後，今天16:37', err: '' }

    t = '2020-10-23T16:37:58.987+08:00'
    r = timemsTZ2expire(t, tNow)
    console.log(r)
    // => { today: false, msg: '5天後', err: '' }

    t = '2021-04-23T16:37:58.987+08:00'
    r = timemsTZ2expire(t, tNow)
    console.log(r)
    // => { today: false, msg: '6個月後', err: '' }

    t = '2028-04-23T16:37:58.987+08:00'
    r = timemsTZ2expire(t, tNow)
    console.log(r)
    // => { today: false, msg: '7年後', err: '' }

    t = '2018-04-23T16:37:58.987+08:00'
    r = timemsTZ2expire(t, tNow)
    console.log(r)
    // => { today: null, msg: '', err: '時間已過' }

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`t` | String |  |  | 輸入毫秒時間字串
`tNow` | String | <optional> | `null` | 輸入現在毫秒時間字串

##### Returns:

回傳到期時間字串

Type
  String

#### (static) timemsTZ2hour(t) → {String}

Source:
  - timemsTZ2hour.mjs, line 22

毫秒時間(含時區)取至時時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(timemsTZ2hour('2019-01-01T12:34:56.987+08:00'))
    // => '2019-01-01T12'

    console.log(timemsTZ2hour('2019-01-01T12:34:56.987Z'))
    // => '2019-01-02T12'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入毫秒時間字串，含時區

##### Returns:

回傳時時間字串

Type
  String

#### (static) timemsTZ2min(t) → {String}

Source:
  - timemsTZ2min.mjs, line 22

毫秒時間(含時區)取至分時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(timemsTZ2min('2019-01-01T12:34:56.987+08:00'))
    // => '2019-01-01T12:34'

    console.log(timemsTZ2min('2019-01-01T12:34:56.987Z'))
    // => '2019-01-01T12:34'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入毫秒時間字串，含時區

##### Returns:

回傳分時間字串

Type
  String

#### (static) timemsTZ2past(t, tNowopt) → {String}

Source:
  - timemsTZ2past.mjs, line 70

毫秒時間轉過去時間

Unit Test: Github

##### Example

Try in Codepen

    let t
    let tNow = '2020-10-18T12:34:56.987+08:00'
    let r

    t = '2020-10-18T12:34:54.987+08:00'
    r = timemsTZ2past(t, tNow)
    console.log(r)
    // => { today: true, msg: '2秒前', err: '' }

    t = '2020-10-18T04:34:54.987+00:00'
    r = timemsTZ2past(t, tNow)
    console.log(r)
    // => { today: true, msg: '2秒前', err: '' }

    t = '2020-10-18T04:34:54.987Z'
    r = timemsTZ2past(t, tNow)
    console.log(r)
    // => { today: true, msg: '2秒前', err: '' }

    t = '2020-10-18T12:34:55.500+08:00'
    r = timemsTZ2past(t, tNow)
    console.log(r)
    // => { today: true, msg: '1秒前', err: '' }

    t = '2020-10-18T12:31:54.987+08:00'
    r = timemsTZ2past(t, tNow)
    console.log(r)
    // => { today: true, msg: '3分鐘前', err: '' }

    t = '2020-10-18T08:31:54.987+08:00'
    r = timemsTZ2past(t, tNow)
    console.log(r)
    // => { today: true, msg: '4小時前', err: '' }

    t = '2020-10-13T08:31:54.987+08:00'
    r = timemsTZ2past(t, tNow)
    console.log(r)
    // => { today: false, msg: '5天前', err: '' }

    t = '2020-04-13T08:31:54.987+08:00'
    r = timemsTZ2past(t, tNow)
    console.log(r)
    // => { today: false, msg: '6個月前', err: '' }

    t = '2013-04-13T08:31:54.987+08:00'
    r = timemsTZ2past(t, tNow)
    console.log(r)
    // => { today: false, msg: '7年前', err: '' }

    t = '2023-04-13T08:31:54.987+08:00'
    r = timemsTZ2past(t, tNow)
    console.log(r)
    // => { today: null, msg: '', err: '時間未到' }

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`t` | String |  |  | 輸入毫秒時間字串
`tNow` | String | <optional> | `null` | 輸入現在毫秒時間字串

##### Returns:

回傳過去時間字串

Type
  String

#### (static) timemsTZ2time(t) → {String}

Source:
  - timemsTZ2time.mjs, line 22

毫秒時間(含時區)取至秒時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(timemsTZ2time('2019-01-01T12:34:56.987+08:00'))
    // => '2019-01-01T12:34:56'

    console.log(timemsTZ2time('2019-01-01T12:34:56.987Z'))
    // => '2019-01-01T12:34:56'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入毫秒時間字串，含時區

##### Returns:

回傳秒時間字串

Type
  String

#### (static) timeTZ2day(t) → {String}

Source:
  - timeTZ2day.mjs, line 19

秒時間取至日時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(timeTZ2day('2019-01-01T12:34:56+08:00'))
    // => '2019-01-01'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入秒時間字串

##### Returns:

回傳日時間字串

Type
  String

#### (static) timeTZ2expire(t, tNowopt) → {String}

Source:
  - timeTZ2expire.mjs, line 73

秒時間轉到期時間

Unit Test: Github

##### Example

Try in Codepen

    let t
    let tNow = '2020-10-18T12:34:56+08:00'
    let r

    t = '2020-10-18T12:34:58+08:00'
    r = timeTZ2expire(t, tNow)
    console.log(r)
    // => { today: true, msg: '2秒後', err: '' }

    t = '2020-10-18T04:34:58+00:00'
    r = timeTZ2expire(t, tNow)
    console.log(r)
    // => { today: true, msg: '2秒後', err: '' }

    t = '2020-10-18T04:34:58Z'
    r = timeTZ2expire(t, tNow)
    console.log(r)
    // => { today: true, msg: '2秒後', err: '' }

    t = '2020-10-18T12:37:58+08:00'
    r = timeTZ2expire(t, tNow)
    console.log(r)
    // => { today: true, msg: '3分鐘後', err: '' }

    t = '2020-10-18T16:37:58+08:00'
    r = timeTZ2expire(t, tNow)
    console.log(r)
    // => { today: true, msg: '4小時後，今天16:37', err: '' }

    t = '2020-10-23T16:37:58+08:00'
    r = timeTZ2expire(t, tNow)
    console.log(r)
    // => { today: false, msg: '5天後', err: '' }

    t = '2021-04-23T16:37:58+08:00'
    r = timeTZ2expire(t, tNow)
    console.log(r)
    // => { today: false, msg: '6個月後', err: '' }

    t = '2028-04-23T16:37:58+08:00'
    r = timeTZ2expire(t, tNow)
    console.log(r)
    // => { today: false, msg: '7年後', err: '' }

    t = '2018-04-23T16:37:58+08:00'
    r = timeTZ2expire(t, tNow)
    console.log(r)
    // => { today: null, msg: '', err: '時間已過' }

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`t` | String |  |  | 輸入秒時間字串
`tNow` | String | <optional> | `null` | 輸入現在秒時間字串

##### Returns:

回傳到期時間字串

Type
  String

#### (static) timeTZ2hour(t) → {String}

Source:
  - timeTZ2hour.mjs, line 19

秒時間取至時時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(timeTZ2hour('2019-01-01T12:34:56+08:00'))
    // => '2019-01-01T12'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入秒時間字串

##### Returns:

回傳時時間字串

Type
  String

#### (static) timeTZ2min(t) → {String}

Source:
  - timeTZ2min.mjs, line 19

秒時間取至分時間

Unit Test: Github

##### Example

Try in Codepen

    console.log(timeTZ2min('2019-01-01T12:34:56+08:00'))
    // => '2019-01-01T12:34'

##### Parameters:

Name | Type | Description
--- | --- | ---
`t` | String | 輸入秒時間字串

##### Returns:

回傳分時間字串

Type
  String

#### (static) timeTZ2past(t, tNowopt) → {String}

Source:
  - timeTZ2past.mjs, line 73

秒時間轉過去時間

Unit Test: Github

##### Example

Try in Codepen

    let t
    let tNow = '2020-10-18T12:34:56+08:00'
    let r

    t = '2020-10-18T12:34:54+08:00'
    r = timeTZ2past(t, tNow)
    console.log(r)
    // => { today: true, msg: '2秒前', err: '' }

    t = '2020-10-18T04:34:54+00:00'
    r = timeTZ2past(t, tNow)
    console.log(r)
    // => { today: true, msg: '2秒前', err: '' }

    t = '2020-10-18T04:34:54Z'
    r = timeTZ2past(t, tNow)
    console.log(r)
    // => { today: true, msg: '2秒前', err: '' }

    t = '2020-10-18T12:31:54+08:00'
    r = timeTZ2past(t, tNow)
    console.log(r)
    // => { today: true, msg: '3分鐘前', err: '' }

    t = '2020-10-18T08:31:54+08:00'
    r = timeTZ2past(t, tNow)
    console.log(r)
    // => { today: true, msg: '4小時前', err: '' }

    t = '2020-10-13T08:31:54+08:00'
    r = timeTZ2past(t, tNow)
    console.log(r)
    // => { today: false, msg: '5天前', err: '' }

    t = '2020-04-13T08:31:54+08:00'
    r = timeTZ2past(t, tNow)
    console.log(r)
    // => { today: false, msg: '6個月前', err: '' }

    t = '2013-04-13T08:31:54+08:00'
    r = timeTZ2past(t, tNow)
    console.log(r)
    // => { today: false, msg: '7年前', err: '' }

    t = '2023-04-13T08:31:54+08:00'
    r = timeTZ2past(t, tNow)
    console.log(r)
    // => { today: null, msg: '', err: '時間未到' }

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`t` | String |  |  | 輸入秒時間字串
`tNow` | String | <optional> | `null` | 輸入現在秒時間字串

##### Returns:

回傳過去時間字串

Type
  String

#### (static) treeObj(data, hookFunopt, optopt) → {*}

Source:
  - treeObj.mjs, line 375

遍歷物件並回傳複製物件，類似JSON.stringify，但不會序列化成為字串

Unit Test: Github

##### Example

Try in Codepen

    let r
    let data = {
        a: 123,
        b: 145.67,
        c: 'test中文1',
        d: true,
        e: function() {},
        f: [11, 'xyz', false, new Uint8Array([166, 197, 215])],
        g: {
            ga: 223,
            gb: 245.67,
            gc: 'test中文2',
            gd: new Uint8Array([66, 97, 115]),
        },
        h: Symbol('foo'),
        [Symbol('i-sym-key')]: 'i-sym-value',
    }

    r = treeObj(data, (value, key, nk) => {
        console.log('=>', value, key, nk)
        return value
    })
    console.log('force: false', r)
    // => 123 a []
    // => 145.67 b []
    // => test中文1 c []
    // => true d []
    // => [Function: e] e []
    // => [ 11, 'xyz', false, Uint8Array(3) [ 166, 197, 215 ] ] f []
    // => 11 0 [ 'f' ]
    // => xyz 1 [ 'f' ]
    // => false 2 [ 'f' ]
    // => Uint8Array(3) [ 166, 197, 215 ] 3 [ 'f' ]
    // => {
    //   ga: 223,
    //   gb: 245.67,
    //   gc: 'test中文2',
    //   gd: Uint8Array(3) [ 66, 97, 115 ]
    // } g []
    // => 223 ga [ 'g' ]
    // => 245.67 gb [ 'g' ]
    // => test中文2 gc [ 'g' ]
    // => Uint8Array(3) [ 66, 97, 115 ] gd [ 'g' ]
    // => Symbol(foo) h []
    // force: false {
    //   a: 123,
    //   b: 145.67,
    //   c: 'test中文1',
    //   d: true,
    //   e: [Function: e],
    //   f: [ 11, 'xyz', false, Uint8Array(3) [ 166, 197, 215 ] ],
    //   g: {
    //     ga: 223,
    //     gb: 245.67,
    //     gc: 'test中文2',
    //     gd: Uint8Array(3) [ 66, 97, 115 ]
    //   },
    //   h: Symbol(foo)
    // }

    r = treeObj(data, (value, key, nk) => {
        console.log('=>', value, key, nk)
        return value
    }, { force: true })
    console.log('force: true', r)
    // => 123 a []
    // => 145.67 b []
    // => test中文1 c []
    // => true d []
    // => [Function: e] e []
    // => [ 11, 'xyz', false, Uint8Array(3) [ 166, 197, 215 ] ] f []
    // => 11 0 [ 'f' ]
    // => xyz 1 [ 'f' ]
    // => false 2 [ 'f' ]
    // => Uint8Array(3) [ 166, 197, 215 ] 3 [ 'f' ]
    // => {
    //   ga: 223,
    //   gb: 245.67,
    //   gc: 'test中文2',
    //   gd: Uint8Array(3) [ 66, 97, 115 ]
    // } g []
    // => 223 ga [ 'g' ]
    // => 245.67 gb [ 'g' ]
    // => test中文2 gc [ 'g' ]
    // => Uint8Array(3) [ 66, 97, 115 ] gd [ 'g' ]
    // => Symbol(foo) h []
    // => i-sym-value Symbol(i-sym-key) []
    // force: true {
    //   a: 123,
    //   b: 145.67,
    //   c: 'test中文1',
    //   d: true,
    //   e: [Function: e],
    //   f: [ 11, 'xyz', false, Uint8Array(3) [ 166, 197, 215 ] ],
    //   g: {
    //     ga: 223,
    //     gb: 245.67,
    //     gc: 'test中文2',
    //     gd: Uint8Array(3) [ 66, 97, 115 ]
    //   },
    //   h: Symbol(foo),
    //   [Symbol(i-sym-key)]: 'i-sym-value'
    // }

##### Parameters:

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`data` | * |  |  | 輸入任意資料
`hookFun` | function | <optional> | `null` | 輸入攔截處理函數，預設null

`opt`

Object

<optional>

`{}`

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`force` | Boolean | <optional> | `false` | 輸入是否允許鍵值為Symbol類型布林值，預設false

##### Returns:

回傳複製後的任意資料

Type
  *

#### (static) trim(c) → {String}

Source:
  - trim.mjs, line 44

字串頭尾去除空白字串，若字串開頭含有BOM亦可清除，若輸入不是字串時則回傳空字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(trim(' abc 中 文 '))
    // => 'abc 中 文'

    let tr = (c) => {
        c = replace(c, '\r\n', '')
        c = replace(c, '\r', '')
        c = replace(c, '\n', '')
        return c
    }

    let b64BOM = '77u/YSxiLCzkuK3mlocNCjEsMjMuNDUsImFiYyIsIjY3LjgiDQo='
    let b64NoBOM = 'YSxiLCzkuK3mlocNCjEsMjMuNDUsImFiYyIsIjY3LjgiDQo='
    let cBOMCor = `
    a,b,,中文
    1,23.45,"abc","67.8"
    `

    let cBOM = b642str(b64BOM)
    console.log(tr(cBOM) === tr(cBOMCor))
    // => false

    let cBOMtrim = trim(cBOM)
    console.log(tr(cBOMtrim) === tr(cBOMCor))
    // => true

    let cNoBOM = b642str(b64NoBOM)
    console.log(tr(cNoBOM) === tr(cBOMCor))
    // => true

##### Parameters:

Name | Type | Description
--- | --- | ---
`c` | String | 輸入字串

##### Returns:

回傳去除空白的字串

Type
  String

#### (static) u8arr2ab(u8a) → {ArrayBuffer}

Source:
  - u8arr2ab.mjs, line 17

Uint8Array轉ArrayBuffer

Unit Test: Github

##### Example

Try in Codepen

    console.log(u8arr2ab(new Uint8Array([66, 97, 115])))
    // (new Uint8Array([66, 97, 115])).buffer

##### Parameters:

Name | Type | Description
--- | --- | ---
`u8a` | Uint8Array | 輸入Uint8Array

##### Returns:

回傳ArrayBuffer

Type
  ArrayBuffer

#### (static) u8arr2b64(u8a) → {String}

Source:
  - u8arr2b64.mjs, line 19

Uint8Array轉base64字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(u8arr2b64(new Uint8Array([1, 2.3, '45', 'abc'])))
    // => 'AQItAA=='

##### Parameters:

Name | Type | Description
--- | --- | ---
`u8a` | Uint8Array | 輸入Uint8Array

##### Returns:

回傳base64字串

Type
  String

#### (static) u8arr2blob(u8a) → {Blob}

Source:
  - u8arr2blob.mjs, line 21

Unit8Array資料轉Blob資料

Unit Test: Github

##### Example

Try in Codepen

    need test in browser

    let u8a = new Uint8Array([1, 2.3, '45', 'abc'])
    let bb = u8arr2blob(u8a)
    console.log(bb)
    // => Blob {size: 4, type: ""}

##### Parameters:

Name | Type | Description
--- | --- | ---
`u8a` | Unit8Array | 輸入Unit8Array資料

##### Returns:

回傳Blob資料

Type
  Blob

#### (static) u8arr2bs(u8a) → {String}

Source:
  - u8arr2bs.mjs, line 17

Unit8Array轉BinaryString，BinaryString為UTF-16編碼

Unit Test: Github

##### Example

Try in Codepen

    console.log(u8arr2bs(new Uint8Array([97, 98, 99])))
    // => 'abc'

##### Parameters:

Name | Type | Description
--- | --- | ---
`u8a` | Unit8Array | 輸入Unit8Array資料

##### Returns:

回傳BinaryString字串

Type
  String

#### (static) u8arr2obj(u8a) → {Object|Array}

Source:
  - u8arr2obj.mjs, line 46

Uint8Array轉物件或陣列資料

Unit Test: Github

##### Example

Try in Codepen

    let u8a = new Uint8Array([
        64, 24, 0, 0, 0, 0, 0, 0, 91, 53, 56, 44,
        51, 93, 123, 34, 97, 34, 58, 91, 49, 50, 51, 44,
        52, 53, 46, 54, 55, 44, 34, 116, 101, 115, 116, 228,
        184, 173, 230, 150, 135, 34, 93, 44, 34, 98, 34, 58,
        123, 34, 99, 34, 58, 34, 91, 85, 105, 110, 116, 56,
        65, 114, 114, 97, 121, 93, 58, 58, 48, 34, 125, 125,
        66, 97, 115
    ])
    let data = u8arr2obj(u8a)
    console.log(data)
    // => { a: [ 123, 45.67, 'test中文' ], b: { c: Uint8Array [ 66, 97, 115 ] } }

##### Parameters:

Name | Type | Description
--- | --- | ---
`u8a` | Uint8Array | 輸入Uint8Array

##### Returns:

回傳物件或陣列資料，物件內可支援Uint8Array、Uint16Array、ArrayBuffer，因obj2u8arr預設會把ArrayBuffer轉Uint8Array進行操作，故物件內原為ArrayBuffer者會以Uint8Array返回

Type
  Object | Array

#### (static) u8arr2str(u8a) → {String}

Source:
  - u8arr2str.mjs, line 19

Uint8Array轉字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(u8arr2str(new Uint8Array([116, 101, 115, 116, 228, 184, 173, 230, 150, 135])))
    // => test中文

##### Parameters:

Name | Type | Description
--- | --- | ---
`u8a` | Uint8Array | 輸入Uint8Array

##### Returns:

回傳一般字串

Type
  String

#### (static) u8arr2u16arr(u8a) → {Uint16Array}

Source:
  - u8arr2u16arr.mjs, line 17

Uint8Array轉Uint16Array

Unit Test: Github

##### Example

Try in Codepen

    console.log(u8arr2u16arr(new Uint8Array([66, 97, 115])))
    // => new Uint16Array([66, 97, 115])

##### Parameters:

Name | Type | Description
--- | --- | ---
`u8a` | Uint8Array | 輸入Uint8Array

##### Returns:

回傳Uint16Array

Type
  Uint16Array

#### (static) u16arr2b64(u16a) → {String}

Source:
  - u16arr2b64.mjs, line 19

Uint16Array轉base64字串

Unit Test: Github

##### Example

Try in Codepen

    console.log(u16arr2b64(new Uint16Array([1, 2.3, '45', 'abc'])))
    // => 'AQItAA=='

##### Parameters:

Name | Type | Description
--- | --- | ---
`u16a` | Uint16Array | 輸入Uint16Array

##### Returns:

回傳base64字串

Type
  String

#### (static) u16arr2u8arr(u16a) → {Uint8Array}

Source:
  - u16arr2u8arr.mjs, line 17

Uint16Array轉Uint8Array

Unit Test: Github

##### Example

Try in Codepen

    console.log(u16arr2u8arr(new Uint16Array([66, 97, 115])))
    // => new Uint8Array([66, 97, 115])

##### Parameters:

Name | Type | Description
--- | --- | ---
`u16a` | Uint16Array | 輸入Uint16Array

##### Returns:

回傳Uint8Array

Type
  Uint8Array

#### (static) urlParse(url) → {Object}

Source:
  - urlParse.mjs, line 21

切分網址取得參數物件

Unit Test: Github

##### Example

Try in Codepen

    console.log(urlParse('http://localhost:3000/index.html?a=12.34&b=xyz&abc=xyz123.456'))
    // => { a: '12.34', abc: 'xyz123.456', b: 'xyz' }

##### Parameters:

Name | Type | Description
--- | --- | ---
`url` | String | 輸入要切分的網址字串

##### Returns:

回傳資訊物件

Type
  Object

#### (static) verifyValue(type, value) → {Object}

Source:
  - verifyValue.mjs, line 51

驗證數值是否為指定類型

Unit Test: Github

##### Example

Try in Codepen

    console.log(verifyValue('12a5', 'isstr'))
    // => r.err=false

    console.log(verifyValue('12', 'isint'))
    // => r.err=false

    console.log(verifyValue('0', 'isp0int'))
    // => r.err=false

    console.log(verifyValue('12', 'isp0int'))
    // => r.err=false

    console.log(verifyValue('0', 'isn0int'))
    // => r.err=false

    console.log(verifyValue('-12', 'isn0int'))
    // => r.err=false

    console.log(verifyValue('12.34', 'isnum'))
    // => r.err=false

    console.log(verifyValue('12.34', 'isp0num'))
    // => r.err=false

    console.log(verifyValue('-12.34', 'isn0num'))
    // => r.err=false

##### Parameters:

Name | Type | Description
--- | --- | ---
`type` | String | function | 輸入判斷資料類型字串或判斷函式，資料類型可選為'isstr','isnum','isp0num','isn0num','isint','ispint','isp0int','isnint','isn0int','isfun'
`value` | * | 輸入任意資料

##### Returns:

回傳判斷結果，屬性value為回傳資料類型的取值，屬性err為是否資料類型有錯，屬性errmsg為類型有錯時之錯誤訊息

Type
  Object

#### (static) waitFun(f, opt) → {Promise}

Source:
  - waitFun.mjs, line 57

等待f函數回傳true 原始名稱為waitFunction，但與nodejs或travis-ci有名稱衝突，故才改為waitFun

Unit Test: Github

##### Example

Try in Codepen

    async function topAsync() {

        function test1() {
            return new Promise((resolve, reject) => {
                let ms = []

                let i = 0
                waitFun(function() {
                    i++
                    console.log('waiting: ' + i)
                    ms.push('waiting: ' + i)
                    return i >= 2
                })
                    .then(function() {
                        console.log('t1 then')
                        ms.push('t1 then')
                    })

                setTimeout(function() {
                    resolve(ms)
                }, 1100)

            })
        }
        console.log('test1')
        let r1 = await test1()
        console.log(JSON.stringify(r1))
        // test1
        // waiting: 1
        // waiting: 2
        // t1 then
        // ["waiting: 1","waiting: 2","t1 then"]

    }
    topAsync().catch(() => {})

##### Parameters:

Name | Type | Description
--- | --- | ---
`f` | function | 輸入判斷用函數

`opt`

Object

輸入設定物件，預設{}

###### Properties

Name | Type | Attributes | Default | Description
--- | --- | --- | --- | ---
`attemptNum` | Integer | <optional> | `200` | 輸入最大嘗試次數，為正整數，預設200
`timeInterval` | Integer | <optional> | `1000` | 輸入嘗試時間週期，為正整數，單位為ms，預設1000

##### Returns:

回傳Promise，resolve為空代表f函數回傳true或超過最大嘗試次數，reject為錯誤訊息

Type
  Promise