@igo2/utils 1.15.4 → 1.15.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/esm2020/igo2-utils.mjs +4 -4
- package/esm2020/lib/base64.mjs +85 -85
- package/esm2020/lib/change.interface.mjs +7 -7
- package/esm2020/lib/change.mjs +87 -87
- package/esm2020/lib/clipboard.mjs +52 -52
- package/esm2020/lib/file.mjs +28 -28
- package/esm2020/lib/index.mjs +13 -13
- package/esm2020/lib/number-utils.mjs +7 -7
- package/esm2020/lib/object-utils.mjs +248 -248
- package/esm2020/lib/strenum.mjs +8 -8
- package/esm2020/lib/string-utils.mjs +105 -105
- package/esm2020/lib/user-agent.mjs +3 -3
- package/esm2020/lib/uuid.mjs +9 -9
- package/esm2020/lib/watcher.mjs +41 -41
- package/esm2020/public_api.mjs +5 -5
- package/fesm2015/igo2-utils.mjs +654 -654
- package/fesm2015/igo2-utils.mjs.map +1 -1
- package/fesm2020/igo2-utils.mjs +654 -654
- package/fesm2020/igo2-utils.mjs.map +1 -1
- package/index.d.ts +5 -5
- package/lib/base64.d.ts +8 -8
- package/lib/change.d.ts +5 -5
- package/lib/change.interface.d.ts +24 -24
- package/lib/clipboard.d.ts +7 -7
- package/lib/file.d.ts +16 -16
- package/lib/index.d.ts +12 -12
- package/lib/number-utils.d.ts +3 -3
- package/lib/object-utils.d.ts +26 -26
- package/lib/strenum.d.ts +4 -4
- package/lib/string-utils.d.ts +6 -6
- package/lib/user-agent.d.ts +5 -5
- package/lib/uuid.d.ts +2 -2
- package/lib/watcher.d.ts +19 -19
- package/package.json +1 -1
- package/public_api.d.ts +1 -1
package/fesm2020/igo2-utils.mjs
CHANGED
|
@@ -2,686 +2,686 @@ import * as Bowser from 'bowser';
|
|
|
2
2
|
import { Subject } from 'rxjs';
|
|
3
3
|
import { distinctUntilChanged } from 'rxjs/operators';
|
|
4
4
|
|
|
5
|
-
/* eslint-disable */
|
|
6
|
-
const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
7
|
-
class Base64 {
|
|
8
|
-
static getByte(s, i) {
|
|
9
|
-
const x = s.charCodeAt(i);
|
|
10
|
-
return x;
|
|
11
|
-
}
|
|
12
|
-
static getByte64(s, i) {
|
|
13
|
-
const idx = this.ALPHA.indexOf(s.charAt(i));
|
|
14
|
-
return idx;
|
|
15
|
-
}
|
|
16
|
-
static decode(s) {
|
|
17
|
-
let pads = 0, i, b10, imax = s.length, x = [];
|
|
18
|
-
s = String(s);
|
|
19
|
-
if (imax === 0) {
|
|
20
|
-
return s;
|
|
21
|
-
}
|
|
22
|
-
if (s.charAt(imax - 1) === this.PADCHAR) {
|
|
23
|
-
pads = 1;
|
|
24
|
-
if (s.charAt(imax - 2) === this.PADCHAR) {
|
|
25
|
-
pads = 2;
|
|
26
|
-
}
|
|
27
|
-
imax -= 4;
|
|
28
|
-
}
|
|
29
|
-
for (i = 0; i < imax; i += 4) {
|
|
30
|
-
b10 =
|
|
31
|
-
(this.getByte64(s, i) << 18) |
|
|
32
|
-
(this.getByte64(s, i + 1) << 12) |
|
|
33
|
-
(this.getByte64(s, i + 2) << 6) |
|
|
34
|
-
this.getByte64(s, i + 3);
|
|
35
|
-
x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 255, b10 & 255));
|
|
36
|
-
}
|
|
37
|
-
switch (pads) {
|
|
38
|
-
case 1:
|
|
39
|
-
b10 =
|
|
40
|
-
(this.getByte64(s, i) << 18) |
|
|
41
|
-
(this.getByte64(s, i + 1) << 12) |
|
|
42
|
-
(this.getByte64(s, i + 2) << 6);
|
|
43
|
-
x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 255));
|
|
44
|
-
break;
|
|
45
|
-
case 2:
|
|
46
|
-
b10 = (this.getByte64(s, i) << 18) | (this.getByte64(s, i + 1) << 12);
|
|
47
|
-
x.push(String.fromCharCode(b10 >> 16));
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
return x.join('');
|
|
51
|
-
}
|
|
52
|
-
static encode(s) {
|
|
53
|
-
s = String(s);
|
|
54
|
-
let i, b10, x = [], imax = s.length - s.length % 3;
|
|
55
|
-
if (s.length === 0) {
|
|
56
|
-
return s;
|
|
57
|
-
}
|
|
58
|
-
for (i = 0; i < imax; i += 3) {
|
|
59
|
-
b10 =
|
|
60
|
-
(this.getByte(s, i) << 16) |
|
|
61
|
-
(this.getByte(s, i + 1) << 8) |
|
|
62
|
-
this.getByte(s, i + 2);
|
|
63
|
-
x.push(this.ALPHA.charAt(b10 >> 18));
|
|
64
|
-
x.push(this.ALPHA.charAt((b10 >> 12) & 63));
|
|
65
|
-
x.push(this.ALPHA.charAt((b10 >> 6) & 63));
|
|
66
|
-
x.push(this.ALPHA.charAt(b10 & 63));
|
|
67
|
-
}
|
|
68
|
-
switch (s.length - imax) {
|
|
69
|
-
case 1:
|
|
70
|
-
b10 = this.getByte(s, i) << 16;
|
|
71
|
-
x.push(this.ALPHA.charAt(b10 >> 18) +
|
|
72
|
-
this.ALPHA.charAt((b10 >> 12) & 63) +
|
|
73
|
-
this.PADCHAR +
|
|
74
|
-
this.PADCHAR);
|
|
75
|
-
break;
|
|
76
|
-
case 2:
|
|
77
|
-
b10 = (this.getByte(s, i) << 16) | (this.getByte(s, i + 1) << 8);
|
|
78
|
-
x.push(this.ALPHA.charAt(b10 >> 18) +
|
|
79
|
-
this.ALPHA.charAt((b10 >> 12) & 63) +
|
|
80
|
-
this.ALPHA.charAt((b10 >> 6) & 63) +
|
|
81
|
-
this.PADCHAR);
|
|
82
|
-
break;
|
|
83
|
-
}
|
|
84
|
-
return x.join('');
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
Base64.PADCHAR = '=';
|
|
5
|
+
/* eslint-disable */
|
|
6
|
+
const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
7
|
+
class Base64 {
|
|
8
|
+
static getByte(s, i) {
|
|
9
|
+
const x = s.charCodeAt(i);
|
|
10
|
+
return x;
|
|
11
|
+
}
|
|
12
|
+
static getByte64(s, i) {
|
|
13
|
+
const idx = this.ALPHA.indexOf(s.charAt(i));
|
|
14
|
+
return idx;
|
|
15
|
+
}
|
|
16
|
+
static decode(s) {
|
|
17
|
+
let pads = 0, i, b10, imax = s.length, x = [];
|
|
18
|
+
s = String(s);
|
|
19
|
+
if (imax === 0) {
|
|
20
|
+
return s;
|
|
21
|
+
}
|
|
22
|
+
if (s.charAt(imax - 1) === this.PADCHAR) {
|
|
23
|
+
pads = 1;
|
|
24
|
+
if (s.charAt(imax - 2) === this.PADCHAR) {
|
|
25
|
+
pads = 2;
|
|
26
|
+
}
|
|
27
|
+
imax -= 4;
|
|
28
|
+
}
|
|
29
|
+
for (i = 0; i < imax; i += 4) {
|
|
30
|
+
b10 =
|
|
31
|
+
(this.getByte64(s, i) << 18) |
|
|
32
|
+
(this.getByte64(s, i + 1) << 12) |
|
|
33
|
+
(this.getByte64(s, i + 2) << 6) |
|
|
34
|
+
this.getByte64(s, i + 3);
|
|
35
|
+
x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 255, b10 & 255));
|
|
36
|
+
}
|
|
37
|
+
switch (pads) {
|
|
38
|
+
case 1:
|
|
39
|
+
b10 =
|
|
40
|
+
(this.getByte64(s, i) << 18) |
|
|
41
|
+
(this.getByte64(s, i + 1) << 12) |
|
|
42
|
+
(this.getByte64(s, i + 2) << 6);
|
|
43
|
+
x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 255));
|
|
44
|
+
break;
|
|
45
|
+
case 2:
|
|
46
|
+
b10 = (this.getByte64(s, i) << 18) | (this.getByte64(s, i + 1) << 12);
|
|
47
|
+
x.push(String.fromCharCode(b10 >> 16));
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
return x.join('');
|
|
51
|
+
}
|
|
52
|
+
static encode(s) {
|
|
53
|
+
s = String(s);
|
|
54
|
+
let i, b10, x = [], imax = s.length - s.length % 3;
|
|
55
|
+
if (s.length === 0) {
|
|
56
|
+
return s;
|
|
57
|
+
}
|
|
58
|
+
for (i = 0; i < imax; i += 3) {
|
|
59
|
+
b10 =
|
|
60
|
+
(this.getByte(s, i) << 16) |
|
|
61
|
+
(this.getByte(s, i + 1) << 8) |
|
|
62
|
+
this.getByte(s, i + 2);
|
|
63
|
+
x.push(this.ALPHA.charAt(b10 >> 18));
|
|
64
|
+
x.push(this.ALPHA.charAt((b10 >> 12) & 63));
|
|
65
|
+
x.push(this.ALPHA.charAt((b10 >> 6) & 63));
|
|
66
|
+
x.push(this.ALPHA.charAt(b10 & 63));
|
|
67
|
+
}
|
|
68
|
+
switch (s.length - imax) {
|
|
69
|
+
case 1:
|
|
70
|
+
b10 = this.getByte(s, i) << 16;
|
|
71
|
+
x.push(this.ALPHA.charAt(b10 >> 18) +
|
|
72
|
+
this.ALPHA.charAt((b10 >> 12) & 63) +
|
|
73
|
+
this.PADCHAR +
|
|
74
|
+
this.PADCHAR);
|
|
75
|
+
break;
|
|
76
|
+
case 2:
|
|
77
|
+
b10 = (this.getByte(s, i) << 16) | (this.getByte(s, i + 1) << 8);
|
|
78
|
+
x.push(this.ALPHA.charAt(b10 >> 18) +
|
|
79
|
+
this.ALPHA.charAt((b10 >> 12) & 63) +
|
|
80
|
+
this.ALPHA.charAt((b10 >> 6) & 63) +
|
|
81
|
+
this.PADCHAR);
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
return x.join('');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
Base64.PADCHAR = '=';
|
|
88
88
|
Base64.ALPHA = ALPHA;
|
|
89
89
|
|
|
90
90
|
const userAgent = Bowser.getParser(window.navigator.userAgent);
|
|
91
91
|
|
|
92
|
-
class Clipboard {
|
|
93
|
-
static copy(element) {
|
|
94
|
-
let successful = false;
|
|
95
|
-
if (typeof element === 'string') {
|
|
96
|
-
const textArea = Clipboard.createTextArea(element);
|
|
97
|
-
Clipboard.selectText(textArea);
|
|
98
|
-
successful = Clipboard.copyTextToClipboard();
|
|
99
|
-
Clipboard.destroyTextArea(textArea);
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
Clipboard.selectText(element);
|
|
103
|
-
successful = Clipboard.copyTextToClipboard();
|
|
104
|
-
}
|
|
105
|
-
return successful;
|
|
106
|
-
}
|
|
107
|
-
static createTextArea(text) {
|
|
108
|
-
const textArea = document.createElement('textArea');
|
|
109
|
-
textArea.value = text;
|
|
110
|
-
document.body.appendChild(textArea);
|
|
111
|
-
return textArea;
|
|
112
|
-
}
|
|
113
|
-
static destroyTextArea(textArea) {
|
|
114
|
-
document.body.removeChild(textArea);
|
|
115
|
-
}
|
|
116
|
-
static selectText(textArea) {
|
|
117
|
-
if (userAgent.getOSName() === 'iOS') {
|
|
118
|
-
const oldContentEditable = textArea.contentEditable;
|
|
119
|
-
const oldReadOnly = textArea.readOnly;
|
|
120
|
-
const range = document.createRange();
|
|
121
|
-
const selection = window.getSelection();
|
|
122
|
-
textArea.contenteditable = true;
|
|
123
|
-
textArea.readonly = false;
|
|
124
|
-
range.selectNodeContents(textArea);
|
|
125
|
-
selection.removeAllRanges();
|
|
126
|
-
selection.addRange(range);
|
|
127
|
-
textArea.setSelectionRange(0, 999999);
|
|
128
|
-
textArea.contentEditable = oldContentEditable;
|
|
129
|
-
textArea.readOnly = oldReadOnly;
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
textArea.select();
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
static copyTextToClipboard() {
|
|
136
|
-
if (!(userAgent.getOSName() === 'iOS' && userAgent.compareVersion('<10'))) {
|
|
137
|
-
return document.execCommand('copy');
|
|
138
|
-
}
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
92
|
+
class Clipboard {
|
|
93
|
+
static copy(element) {
|
|
94
|
+
let successful = false;
|
|
95
|
+
if (typeof element === 'string') {
|
|
96
|
+
const textArea = Clipboard.createTextArea(element);
|
|
97
|
+
Clipboard.selectText(textArea);
|
|
98
|
+
successful = Clipboard.copyTextToClipboard();
|
|
99
|
+
Clipboard.destroyTextArea(textArea);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
Clipboard.selectText(element);
|
|
103
|
+
successful = Clipboard.copyTextToClipboard();
|
|
104
|
+
}
|
|
105
|
+
return successful;
|
|
106
|
+
}
|
|
107
|
+
static createTextArea(text) {
|
|
108
|
+
const textArea = document.createElement('textArea');
|
|
109
|
+
textArea.value = text;
|
|
110
|
+
document.body.appendChild(textArea);
|
|
111
|
+
return textArea;
|
|
112
|
+
}
|
|
113
|
+
static destroyTextArea(textArea) {
|
|
114
|
+
document.body.removeChild(textArea);
|
|
115
|
+
}
|
|
116
|
+
static selectText(textArea) {
|
|
117
|
+
if (userAgent.getOSName() === 'iOS') {
|
|
118
|
+
const oldContentEditable = textArea.contentEditable;
|
|
119
|
+
const oldReadOnly = textArea.readOnly;
|
|
120
|
+
const range = document.createRange();
|
|
121
|
+
const selection = window.getSelection();
|
|
122
|
+
textArea.contenteditable = true;
|
|
123
|
+
textArea.readonly = false;
|
|
124
|
+
range.selectNodeContents(textArea);
|
|
125
|
+
selection.removeAllRanges();
|
|
126
|
+
selection.addRange(range);
|
|
127
|
+
textArea.setSelectionRange(0, 999999);
|
|
128
|
+
textArea.contentEditable = oldContentEditable;
|
|
129
|
+
textArea.readOnly = oldReadOnly;
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
textArea.select();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
static copyTextToClipboard() {
|
|
136
|
+
if (!(userAgent.getOSName() === 'iOS' && userAgent.compareVersion('<10'))) {
|
|
137
|
+
return document.execCommand('copy');
|
|
138
|
+
}
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
class StringUtils {
|
|
144
|
-
static diff(s1, s2, p = 4) {
|
|
145
|
-
if (!s1 && !s2) {
|
|
146
|
-
return '';
|
|
147
|
-
}
|
|
148
|
-
if (!s1) {
|
|
149
|
-
return '<span class="inserted">' + s2 + '</span>';
|
|
150
|
-
}
|
|
151
|
-
if (!s2) {
|
|
152
|
-
return '<span class="deleted">' + s1 + '</span>';
|
|
153
|
-
}
|
|
154
|
-
s1 = s1.toString();
|
|
155
|
-
s2 = s2.toString();
|
|
156
|
-
const changeData = StringUtils.getChanges(s1, s2, '', p);
|
|
157
|
-
const nextS = s2.slice(changeData.mtc.length + changeData.ins.length + changeData.sbs.length); // remaining part of "s"
|
|
158
|
-
const nextThis = s1.slice(changeData.mtc.length + changeData.del.length + changeData.sbs.length); // remaining part of "this"
|
|
159
|
-
let result = ''; // the glorious result
|
|
160
|
-
if (changeData.del.length > 0) {
|
|
161
|
-
changeData.del = '<span class="deleted">' + changeData.del + '</span>';
|
|
162
|
-
}
|
|
163
|
-
if (changeData.ins.length > 0) {
|
|
164
|
-
changeData.ins = '<span class="inserted">' + changeData.ins + '</span>';
|
|
165
|
-
}
|
|
166
|
-
result = changeData.mtc + changeData.del + changeData.ins + changeData.sbs;
|
|
167
|
-
result +=
|
|
168
|
-
nextThis !== '' || nextS !== ''
|
|
169
|
-
? StringUtils.diff(nextThis, nextS, p)
|
|
170
|
-
: '';
|
|
171
|
-
return result;
|
|
172
|
-
}
|
|
173
|
-
static getMatchingSubstring(s, l, m) {
|
|
174
|
-
// returns the first matching substring in-between the two strings
|
|
175
|
-
let i = 0;
|
|
176
|
-
let match = false;
|
|
177
|
-
const slen = s.length;
|
|
178
|
-
const o = { fis: slen, mtc: m, sbs: '' }; // temporary object used to construct the cd (change data) object
|
|
179
|
-
while (i < slen) {
|
|
180
|
-
l[i] === s[i]
|
|
181
|
-
? match
|
|
182
|
-
? (o.sbs += s[i]) // o.sbs holds the matching substring itsef
|
|
183
|
-
: ((match = true), (o.fis = i), (o.sbs = s[i]))
|
|
184
|
-
: match
|
|
185
|
-
? (i = slen) // stop after the first found substring
|
|
186
|
-
: (i = i);
|
|
187
|
-
++i;
|
|
188
|
-
}
|
|
189
|
-
return o;
|
|
190
|
-
}
|
|
191
|
-
static getChanges(s1, s2, m, p) {
|
|
192
|
-
const isThisLonger = s1.length >= s1.length ? true : false;
|
|
193
|
-
let [longer, shorter] = isThisLonger ? [s1, s2] : [s2, s1]; // assignment of longer and shorter by es6 destructuring
|
|
194
|
-
let bi = 0; // base index designating the index of first mismacthing character in both strings
|
|
195
|
-
while (shorter[bi] === longer[bi] && bi < shorter.length) {
|
|
196
|
-
++bi;
|
|
197
|
-
} // make bi the index of first mismatching character
|
|
198
|
-
longer = longer.split('').slice(bi); // as the longer string will be rotated it is converted into array
|
|
199
|
-
shorter = shorter.slice(bi); // shorter and longer now starts from the first mismatching character
|
|
200
|
-
const len = longer.length; // length of the longer string
|
|
201
|
-
let cd = {
|
|
202
|
-
fis: shorter.length,
|
|
203
|
-
fil: len,
|
|
204
|
-
sbs: '',
|
|
205
|
-
mtc: m + s2.slice(0, bi)
|
|
206
|
-
}; // if exists mtc holds the matching string at the front
|
|
207
|
-
let sub = { sbs: '' }; // returned substring per 1 character rotation of the longer string
|
|
208
|
-
if (shorter !== '') {
|
|
209
|
-
for (let rc = 0; rc < len && sub.sbs.length < p; rc++) {
|
|
210
|
-
// rc -> rotate count, p -> precision factor
|
|
211
|
-
sub = StringUtils.getMatchingSubstring(shorter, StringUtils.rotateArray(longer, rc), cd.mtc); // rotate longer string 1 char and get substring
|
|
212
|
-
sub.fil =
|
|
213
|
-
rc < len - sub.fis
|
|
214
|
-
? sub.fis + rc // mismatch is longer than the mismatch in short
|
|
215
|
-
: sub.fis - len + rc; // mismatch is shorter than the mismatch in short
|
|
216
|
-
if (sub.sbs.length > cd.sbs.length) {
|
|
217
|
-
cd = sub; // only keep the one with the longest substring.
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
// insert the mismatching delete subsrt and insert substr to the cd object and attach the previous substring
|
|
222
|
-
[cd.del, cd.ins] = isThisLonger
|
|
223
|
-
? [longer.slice(0, cd.fil).join(''), shorter.slice(0, cd.fis)]
|
|
224
|
-
: [shorter.slice(0, cd.fis), longer.slice(0, cd.fil).join('')];
|
|
225
|
-
return cd.del.indexOf(' ') === -1 ||
|
|
226
|
-
cd.ins.indexOf(' ') === -1 ||
|
|
227
|
-
cd.del === '' ||
|
|
228
|
-
cd.ins === '' ||
|
|
229
|
-
cd.sbs === ''
|
|
230
|
-
? cd
|
|
231
|
-
: StringUtils.getChanges(cd.del, cd.ins, cd.mtc, p);
|
|
232
|
-
}
|
|
233
|
-
static rotateArray(array, n) {
|
|
234
|
-
const len = array.length;
|
|
235
|
-
const res = new Array(array.length);
|
|
236
|
-
if (n % len === 0) {
|
|
237
|
-
return array.slice();
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
for (let i = 0; i < len; i++) {
|
|
241
|
-
res[i] = array[(i + (len + (n % len))) % len];
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
return res;
|
|
245
|
-
}
|
|
143
|
+
class StringUtils {
|
|
144
|
+
static diff(s1, s2, p = 4) {
|
|
145
|
+
if (!s1 && !s2) {
|
|
146
|
+
return '';
|
|
147
|
+
}
|
|
148
|
+
if (!s1) {
|
|
149
|
+
return '<span class="inserted">' + s2 + '</span>';
|
|
150
|
+
}
|
|
151
|
+
if (!s2) {
|
|
152
|
+
return '<span class="deleted">' + s1 + '</span>';
|
|
153
|
+
}
|
|
154
|
+
s1 = s1.toString();
|
|
155
|
+
s2 = s2.toString();
|
|
156
|
+
const changeData = StringUtils.getChanges(s1, s2, '', p);
|
|
157
|
+
const nextS = s2.slice(changeData.mtc.length + changeData.ins.length + changeData.sbs.length); // remaining part of "s"
|
|
158
|
+
const nextThis = s1.slice(changeData.mtc.length + changeData.del.length + changeData.sbs.length); // remaining part of "this"
|
|
159
|
+
let result = ''; // the glorious result
|
|
160
|
+
if (changeData.del.length > 0) {
|
|
161
|
+
changeData.del = '<span class="deleted">' + changeData.del + '</span>';
|
|
162
|
+
}
|
|
163
|
+
if (changeData.ins.length > 0) {
|
|
164
|
+
changeData.ins = '<span class="inserted">' + changeData.ins + '</span>';
|
|
165
|
+
}
|
|
166
|
+
result = changeData.mtc + changeData.del + changeData.ins + changeData.sbs;
|
|
167
|
+
result +=
|
|
168
|
+
nextThis !== '' || nextS !== ''
|
|
169
|
+
? StringUtils.diff(nextThis, nextS, p)
|
|
170
|
+
: '';
|
|
171
|
+
return result;
|
|
172
|
+
}
|
|
173
|
+
static getMatchingSubstring(s, l, m) {
|
|
174
|
+
// returns the first matching substring in-between the two strings
|
|
175
|
+
let i = 0;
|
|
176
|
+
let match = false;
|
|
177
|
+
const slen = s.length;
|
|
178
|
+
const o = { fis: slen, mtc: m, sbs: '' }; // temporary object used to construct the cd (change data) object
|
|
179
|
+
while (i < slen) {
|
|
180
|
+
l[i] === s[i]
|
|
181
|
+
? match
|
|
182
|
+
? (o.sbs += s[i]) // o.sbs holds the matching substring itsef
|
|
183
|
+
: ((match = true), (o.fis = i), (o.sbs = s[i]))
|
|
184
|
+
: match
|
|
185
|
+
? (i = slen) // stop after the first found substring
|
|
186
|
+
: (i = i);
|
|
187
|
+
++i;
|
|
188
|
+
}
|
|
189
|
+
return o;
|
|
190
|
+
}
|
|
191
|
+
static getChanges(s1, s2, m, p) {
|
|
192
|
+
const isThisLonger = s1.length >= s1.length ? true : false;
|
|
193
|
+
let [longer, shorter] = isThisLonger ? [s1, s2] : [s2, s1]; // assignment of longer and shorter by es6 destructuring
|
|
194
|
+
let bi = 0; // base index designating the index of first mismacthing character in both strings
|
|
195
|
+
while (shorter[bi] === longer[bi] && bi < shorter.length) {
|
|
196
|
+
++bi;
|
|
197
|
+
} // make bi the index of first mismatching character
|
|
198
|
+
longer = longer.split('').slice(bi); // as the longer string will be rotated it is converted into array
|
|
199
|
+
shorter = shorter.slice(bi); // shorter and longer now starts from the first mismatching character
|
|
200
|
+
const len = longer.length; // length of the longer string
|
|
201
|
+
let cd = {
|
|
202
|
+
fis: shorter.length,
|
|
203
|
+
fil: len,
|
|
204
|
+
sbs: '',
|
|
205
|
+
mtc: m + s2.slice(0, bi)
|
|
206
|
+
}; // if exists mtc holds the matching string at the front
|
|
207
|
+
let sub = { sbs: '' }; // returned substring per 1 character rotation of the longer string
|
|
208
|
+
if (shorter !== '') {
|
|
209
|
+
for (let rc = 0; rc < len && sub.sbs.length < p; rc++) {
|
|
210
|
+
// rc -> rotate count, p -> precision factor
|
|
211
|
+
sub = StringUtils.getMatchingSubstring(shorter, StringUtils.rotateArray(longer, rc), cd.mtc); // rotate longer string 1 char and get substring
|
|
212
|
+
sub.fil =
|
|
213
|
+
rc < len - sub.fis
|
|
214
|
+
? sub.fis + rc // mismatch is longer than the mismatch in short
|
|
215
|
+
: sub.fis - len + rc; // mismatch is shorter than the mismatch in short
|
|
216
|
+
if (sub.sbs.length > cd.sbs.length) {
|
|
217
|
+
cd = sub; // only keep the one with the longest substring.
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
// insert the mismatching delete subsrt and insert substr to the cd object and attach the previous substring
|
|
222
|
+
[cd.del, cd.ins] = isThisLonger
|
|
223
|
+
? [longer.slice(0, cd.fil).join(''), shorter.slice(0, cd.fis)]
|
|
224
|
+
: [shorter.slice(0, cd.fis), longer.slice(0, cd.fil).join('')];
|
|
225
|
+
return cd.del.indexOf(' ') === -1 ||
|
|
226
|
+
cd.ins.indexOf(' ') === -1 ||
|
|
227
|
+
cd.del === '' ||
|
|
228
|
+
cd.ins === '' ||
|
|
229
|
+
cd.sbs === ''
|
|
230
|
+
? cd
|
|
231
|
+
: StringUtils.getChanges(cd.del, cd.ins, cd.mtc, p);
|
|
232
|
+
}
|
|
233
|
+
static rotateArray(array, n) {
|
|
234
|
+
const len = array.length;
|
|
235
|
+
const res = new Array(array.length);
|
|
236
|
+
if (n % len === 0) {
|
|
237
|
+
return array.slice();
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
for (let i = 0; i < len; i++) {
|
|
241
|
+
res[i] = array[(i + (len + (n % len))) % len];
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return res;
|
|
245
|
+
}
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
-
var ChangeType;
|
|
249
|
-
(function (ChangeType) {
|
|
250
|
-
ChangeType["ADDED"] = "added";
|
|
251
|
-
ChangeType["DELETED"] = "deleted";
|
|
252
|
-
ChangeType["MODIFIED"] = "modified";
|
|
248
|
+
var ChangeType;
|
|
249
|
+
(function (ChangeType) {
|
|
250
|
+
ChangeType["ADDED"] = "added";
|
|
251
|
+
ChangeType["DELETED"] = "deleted";
|
|
252
|
+
ChangeType["MODIFIED"] = "modified";
|
|
253
253
|
})(ChangeType || (ChangeType = {}));
|
|
254
254
|
|
|
255
|
-
class ChangeUtils {
|
|
256
|
-
static findChanges(obj1, obj2, ignoreKeys = []) {
|
|
257
|
-
const items = {
|
|
258
|
-
added: [],
|
|
259
|
-
deleted: [],
|
|
260
|
-
modified: []
|
|
261
|
-
};
|
|
262
|
-
if (!obj1 || !obj2) {
|
|
263
|
-
return items;
|
|
264
|
-
}
|
|
265
|
-
const obj1Clone = [...obj1];
|
|
266
|
-
const obj2Clone = [...obj2];
|
|
267
|
-
for (const fromItem of obj1Clone) {
|
|
268
|
-
const index = obj2Clone.findIndex(s => s.id === fromItem.id);
|
|
269
|
-
if (index === -1) {
|
|
270
|
-
items.deleted.push({
|
|
271
|
-
change: { type: ChangeType.DELETED },
|
|
272
|
-
value: fromItem
|
|
273
|
-
});
|
|
274
|
-
continue;
|
|
275
|
-
}
|
|
276
|
-
const toItem = obj2Clone.splice(index, 1)[0];
|
|
277
|
-
const fromItemClone = JSON.parse(JSON.stringify(fromItem));
|
|
278
|
-
const toItemClone = JSON.parse(JSON.stringify(toItem));
|
|
279
|
-
const keysChanged = ChangeUtils.compareObject(fromItemClone, toItemClone, undefined, ignoreKeys);
|
|
280
|
-
if (keysChanged.length) {
|
|
281
|
-
items.modified.push({
|
|
282
|
-
change: {
|
|
283
|
-
type: ChangeType.MODIFIED,
|
|
284
|
-
keysChanged
|
|
285
|
-
},
|
|
286
|
-
value: fromItemClone,
|
|
287
|
-
oldValue: fromItem,
|
|
288
|
-
newValue: toItem
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
items.added = obj2Clone.map(itemAdded => {
|
|
293
|
-
return {
|
|
294
|
-
change: { type: ChangeType.ADDED },
|
|
295
|
-
value: itemAdded
|
|
296
|
-
};
|
|
297
|
-
});
|
|
298
|
-
return items;
|
|
299
|
-
}
|
|
300
|
-
static compareObject(fromItem, toItem, baseKey, ignoreKeys = []) {
|
|
301
|
-
const fromItemClone = JSON.parse(JSON.stringify(fromItem));
|
|
302
|
-
const toItemClone = JSON.parse(JSON.stringify(toItem));
|
|
303
|
-
const keys = new Set([
|
|
304
|
-
...Object.keys(fromItem),
|
|
305
|
-
...Object.keys(toItem)
|
|
306
|
-
]);
|
|
307
|
-
let keysChanged = [];
|
|
308
|
-
keys.forEach(key => {
|
|
309
|
-
const keyString = baseKey ? `${baseKey}.${key}` : key;
|
|
310
|
-
if (ignoreKeys.indexOf(keyString) !== -1) {
|
|
311
|
-
return;
|
|
312
|
-
}
|
|
313
|
-
if (Array.isArray(fromItem[key])) {
|
|
314
|
-
fromItem[key] = fromItem[key].join(',<br>');
|
|
315
|
-
}
|
|
316
|
-
if (Array.isArray(toItem[key])) {
|
|
317
|
-
toItem[key] = toItem[key].join(',<br>');
|
|
318
|
-
}
|
|
319
|
-
if (typeof fromItem[key] === 'object' &&
|
|
320
|
-
typeof toItem[key] === 'object' &&
|
|
321
|
-
fromItem[key] !== null &&
|
|
322
|
-
toItem[key] !== null) {
|
|
323
|
-
keysChanged = keysChanged.concat(this.compareObject(fromItem[key], toItem[key], keyString));
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
326
|
-
if (fromItem[key] !== toItem[key]) {
|
|
327
|
-
keysChanged.push({
|
|
328
|
-
key: keyString,
|
|
329
|
-
oldValue: fromItemClone[key],
|
|
330
|
-
newValue: toItemClone[key]
|
|
331
|
-
});
|
|
332
|
-
fromItem[key] = StringUtils.diff(fromItem[key], toItem[key]);
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
return keysChanged;
|
|
337
|
-
}
|
|
255
|
+
class ChangeUtils {
|
|
256
|
+
static findChanges(obj1, obj2, ignoreKeys = []) {
|
|
257
|
+
const items = {
|
|
258
|
+
added: [],
|
|
259
|
+
deleted: [],
|
|
260
|
+
modified: []
|
|
261
|
+
};
|
|
262
|
+
if (!obj1 || !obj2) {
|
|
263
|
+
return items;
|
|
264
|
+
}
|
|
265
|
+
const obj1Clone = [...obj1];
|
|
266
|
+
const obj2Clone = [...obj2];
|
|
267
|
+
for (const fromItem of obj1Clone) {
|
|
268
|
+
const index = obj2Clone.findIndex(s => s.id === fromItem.id);
|
|
269
|
+
if (index === -1) {
|
|
270
|
+
items.deleted.push({
|
|
271
|
+
change: { type: ChangeType.DELETED },
|
|
272
|
+
value: fromItem
|
|
273
|
+
});
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
const toItem = obj2Clone.splice(index, 1)[0];
|
|
277
|
+
const fromItemClone = JSON.parse(JSON.stringify(fromItem));
|
|
278
|
+
const toItemClone = JSON.parse(JSON.stringify(toItem));
|
|
279
|
+
const keysChanged = ChangeUtils.compareObject(fromItemClone, toItemClone, undefined, ignoreKeys);
|
|
280
|
+
if (keysChanged.length) {
|
|
281
|
+
items.modified.push({
|
|
282
|
+
change: {
|
|
283
|
+
type: ChangeType.MODIFIED,
|
|
284
|
+
keysChanged
|
|
285
|
+
},
|
|
286
|
+
value: fromItemClone,
|
|
287
|
+
oldValue: fromItem,
|
|
288
|
+
newValue: toItem
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
items.added = obj2Clone.map(itemAdded => {
|
|
293
|
+
return {
|
|
294
|
+
change: { type: ChangeType.ADDED },
|
|
295
|
+
value: itemAdded
|
|
296
|
+
};
|
|
297
|
+
});
|
|
298
|
+
return items;
|
|
299
|
+
}
|
|
300
|
+
static compareObject(fromItem, toItem, baseKey, ignoreKeys = []) {
|
|
301
|
+
const fromItemClone = JSON.parse(JSON.stringify(fromItem));
|
|
302
|
+
const toItemClone = JSON.parse(JSON.stringify(toItem));
|
|
303
|
+
const keys = new Set([
|
|
304
|
+
...Object.keys(fromItem),
|
|
305
|
+
...Object.keys(toItem)
|
|
306
|
+
]);
|
|
307
|
+
let keysChanged = [];
|
|
308
|
+
keys.forEach(key => {
|
|
309
|
+
const keyString = baseKey ? `${baseKey}.${key}` : key;
|
|
310
|
+
if (ignoreKeys.indexOf(keyString) !== -1) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (Array.isArray(fromItem[key])) {
|
|
314
|
+
fromItem[key] = fromItem[key].join(',<br>');
|
|
315
|
+
}
|
|
316
|
+
if (Array.isArray(toItem[key])) {
|
|
317
|
+
toItem[key] = toItem[key].join(',<br>');
|
|
318
|
+
}
|
|
319
|
+
if (typeof fromItem[key] === 'object' &&
|
|
320
|
+
typeof toItem[key] === 'object' &&
|
|
321
|
+
fromItem[key] !== null &&
|
|
322
|
+
toItem[key] !== null) {
|
|
323
|
+
keysChanged = keysChanged.concat(this.compareObject(fromItem[key], toItem[key], keyString));
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
if (fromItem[key] !== toItem[key]) {
|
|
327
|
+
keysChanged.push({
|
|
328
|
+
key: keyString,
|
|
329
|
+
oldValue: fromItemClone[key],
|
|
330
|
+
newValue: toItemClone[key]
|
|
331
|
+
});
|
|
332
|
+
fromItem[key] = StringUtils.diff(fromItem[key], toItem[key]);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
return keysChanged;
|
|
337
|
+
}
|
|
338
338
|
}
|
|
339
339
|
|
|
340
|
-
/**
|
|
341
|
-
* Trigger download of a file
|
|
342
|
-
*
|
|
343
|
-
* @param content File content
|
|
344
|
-
* @param mimeType File mime type
|
|
345
|
-
* @param fileName File name
|
|
346
|
-
*/
|
|
347
|
-
function downloadContent(content, mimeType, fileName) {
|
|
348
|
-
const uri = `data:${mimeType},${encodeURIComponent(content)}`;
|
|
349
|
-
downloadFromUri(uri, fileName);
|
|
350
|
-
}
|
|
351
|
-
/**
|
|
352
|
-
* Trigger download of a file
|
|
353
|
-
*
|
|
354
|
-
* @param content File content
|
|
355
|
-
* @param mimeType File mime type
|
|
356
|
-
* @param fileName File name
|
|
357
|
-
*/
|
|
358
|
-
function downloadFromUri(uri, fileName) {
|
|
359
|
-
const element = document.createElement('a');
|
|
360
|
-
element.setAttribute('href', uri);
|
|
361
|
-
element.setAttribute('download', fileName);
|
|
362
|
-
element.style.display = 'none';
|
|
363
|
-
document.body.appendChild(element);
|
|
364
|
-
element.click();
|
|
365
|
-
document.body.removeChild(element);
|
|
340
|
+
/**
|
|
341
|
+
* Trigger download of a file
|
|
342
|
+
*
|
|
343
|
+
* @param content File content
|
|
344
|
+
* @param mimeType File mime type
|
|
345
|
+
* @param fileName File name
|
|
346
|
+
*/
|
|
347
|
+
function downloadContent(content, mimeType, fileName) {
|
|
348
|
+
const uri = `data:${mimeType},${encodeURIComponent(content)}`;
|
|
349
|
+
downloadFromUri(uri, fileName);
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Trigger download of a file
|
|
353
|
+
*
|
|
354
|
+
* @param content File content
|
|
355
|
+
* @param mimeType File mime type
|
|
356
|
+
* @param fileName File name
|
|
357
|
+
*/
|
|
358
|
+
function downloadFromUri(uri, fileName) {
|
|
359
|
+
const element = document.createElement('a');
|
|
360
|
+
element.setAttribute('href', uri);
|
|
361
|
+
element.setAttribute('download', fileName);
|
|
362
|
+
element.style.display = 'none';
|
|
363
|
+
document.body.appendChild(element);
|
|
364
|
+
element.click();
|
|
365
|
+
document.body.removeChild(element);
|
|
366
366
|
}
|
|
367
367
|
|
|
368
|
-
class ObjectUtils {
|
|
369
|
-
static resolve(obj, key) {
|
|
370
|
-
const keysArray = key
|
|
371
|
-
.replace(/\[/g, '.')
|
|
372
|
-
.replace(/\]/g, '')
|
|
373
|
-
.split('.');
|
|
374
|
-
let current = obj;
|
|
375
|
-
while (keysArray.length) {
|
|
376
|
-
if (typeof current !== 'object') {
|
|
377
|
-
return undefined;
|
|
378
|
-
}
|
|
379
|
-
current = current[keysArray.shift()];
|
|
380
|
-
}
|
|
381
|
-
return current;
|
|
382
|
-
}
|
|
383
|
-
static isObject(item) {
|
|
384
|
-
return (item &&
|
|
385
|
-
typeof item === 'object' &&
|
|
386
|
-
!Array.isArray(item) &&
|
|
387
|
-
item !== null &&
|
|
388
|
-
!(item instanceof Date));
|
|
389
|
-
}
|
|
390
|
-
static mergeDeep(target, source, ignoreUndefined = false) {
|
|
391
|
-
const output = Object.assign({}, target);
|
|
392
|
-
if (ObjectUtils.isObject(target) && ObjectUtils.isObject(source)) {
|
|
393
|
-
Object.keys(source)
|
|
394
|
-
.filter(key => !ignoreUndefined || source[key] !== undefined)
|
|
395
|
-
.forEach(key => {
|
|
396
|
-
if (ObjectUtils.isObject(source[key])) {
|
|
397
|
-
if (!(key in target)) {
|
|
398
|
-
Object.assign(output, { [key]: source[key] });
|
|
399
|
-
}
|
|
400
|
-
else {
|
|
401
|
-
output[key] = ObjectUtils.mergeDeep(target[key], source[key], ignoreUndefined);
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
else {
|
|
405
|
-
Object.assign(output, { [key]: source[key] });
|
|
406
|
-
}
|
|
407
|
-
});
|
|
408
|
-
}
|
|
409
|
-
return output;
|
|
410
|
-
}
|
|
411
|
-
static copyDeep(src) {
|
|
412
|
-
const target = Array.isArray(src) ? [] : {};
|
|
413
|
-
for (const prop in src) {
|
|
414
|
-
if (src.hasOwnProperty(prop)) {
|
|
415
|
-
const value = src[prop];
|
|
416
|
-
if (value && typeof value === 'object') {
|
|
417
|
-
target[prop] = this.copyDeep(value);
|
|
418
|
-
}
|
|
419
|
-
else {
|
|
420
|
-
target[prop] = value;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
return target;
|
|
425
|
-
}
|
|
426
|
-
static removeDuplicateCaseInsensitive(obj) {
|
|
427
|
-
const summaryCapitalizeObject = {};
|
|
428
|
-
const capitalizeObject = {};
|
|
429
|
-
const upperCaseCount = [];
|
|
430
|
-
for (const property in obj) {
|
|
431
|
-
if (obj.hasOwnProperty(property)) {
|
|
432
|
-
const upperCaseProperty = property.toUpperCase();
|
|
433
|
-
if (!summaryCapitalizeObject.hasOwnProperty(upperCaseProperty)) {
|
|
434
|
-
summaryCapitalizeObject[upperCaseProperty] = [
|
|
435
|
-
{ [property]: obj[property] }
|
|
436
|
-
];
|
|
437
|
-
}
|
|
438
|
-
else {
|
|
439
|
-
summaryCapitalizeObject[upperCaseProperty].push({
|
|
440
|
-
[property]: obj[property]
|
|
441
|
-
});
|
|
442
|
-
}
|
|
443
|
-
// counting the number of uppercase lettersMna
|
|
444
|
-
upperCaseCount.push({
|
|
445
|
-
key: property,
|
|
446
|
-
count: property.replace(/[^A-Z]/g, '').length
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
for (const capitalizedProperty in summaryCapitalizeObject) {
|
|
451
|
-
if (summaryCapitalizeObject.hasOwnProperty(capitalizedProperty)) {
|
|
452
|
-
if (summaryCapitalizeObject.hasOwnProperty(capitalizedProperty)) {
|
|
453
|
-
const capitalizedPropertyObject = summaryCapitalizeObject[capitalizedProperty];
|
|
454
|
-
if (capitalizedPropertyObject.length === 1) {
|
|
455
|
-
// for single params (no duplicates)
|
|
456
|
-
const singlePossibility = capitalizedPropertyObject[0];
|
|
457
|
-
capitalizeObject[capitalizedProperty] =
|
|
458
|
-
singlePossibility[Object.keys(singlePossibility)[0]];
|
|
459
|
-
}
|
|
460
|
-
else if (capitalizedPropertyObject.length > 1) {
|
|
461
|
-
// defining the closest to lowercase property
|
|
462
|
-
const paramClosestToLowercase = upperCaseCount
|
|
463
|
-
.filter(f => f.key.toLowerCase() === capitalizedProperty.toLowerCase())
|
|
464
|
-
.reduce((prev, current) => {
|
|
465
|
-
return prev.y < current.y ? prev : current;
|
|
466
|
-
});
|
|
467
|
-
capitalizeObject[paramClosestToLowercase.key.toUpperCase()] =
|
|
468
|
-
obj[paramClosestToLowercase.key];
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
for (const property in obj) {
|
|
474
|
-
if (obj.hasOwnProperty(property)) {
|
|
475
|
-
delete obj[property];
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
for (const property in capitalizeObject) {
|
|
479
|
-
if (capitalizeObject.hasOwnProperty(property)) {
|
|
480
|
-
obj[property] = capitalizeObject[property];
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
static removeUndefined(obj) {
|
|
485
|
-
const output = {};
|
|
486
|
-
if (ObjectUtils.isObject(obj)) {
|
|
487
|
-
Object.keys(obj)
|
|
488
|
-
.filter(key => obj[key] !== undefined)
|
|
489
|
-
.forEach(key => {
|
|
490
|
-
if (ObjectUtils.isObject(obj[key]) || Array.isArray(obj[key])) {
|
|
491
|
-
output[key] = ObjectUtils.removeUndefined(obj[key]);
|
|
492
|
-
}
|
|
493
|
-
else {
|
|
494
|
-
output[key] = obj[key];
|
|
495
|
-
}
|
|
496
|
-
});
|
|
497
|
-
return output;
|
|
498
|
-
}
|
|
499
|
-
if (Array.isArray(obj)) {
|
|
500
|
-
return obj.map(o => ObjectUtils.removeUndefined(o));
|
|
501
|
-
}
|
|
502
|
-
return obj;
|
|
503
|
-
}
|
|
504
|
-
static removeNull(obj) {
|
|
505
|
-
const output = {};
|
|
506
|
-
if (ObjectUtils.isObject(obj)) {
|
|
507
|
-
Object.keys(obj)
|
|
508
|
-
.filter(key => obj[key] !== null)
|
|
509
|
-
.forEach(key => {
|
|
510
|
-
if (ObjectUtils.isObject(obj[key]) || Array.isArray(obj[key])) {
|
|
511
|
-
output[key] = ObjectUtils.removeNull(obj[key]);
|
|
512
|
-
}
|
|
513
|
-
else {
|
|
514
|
-
output[key] = obj[key];
|
|
515
|
-
}
|
|
516
|
-
});
|
|
517
|
-
return output;
|
|
518
|
-
}
|
|
519
|
-
if (Array.isArray(obj)) {
|
|
520
|
-
return obj.map(o => ObjectUtils.removeNull(o));
|
|
521
|
-
}
|
|
522
|
-
return obj;
|
|
523
|
-
}
|
|
524
|
-
static naturalCompare(a, b, direction = 'asc', nullsFirst) {
|
|
525
|
-
if (direction === 'desc') {
|
|
526
|
-
b = [a, (a = b)][0];
|
|
527
|
-
}
|
|
528
|
-
// nullsFirst = undefined : end if direction = 'asc', first if direction = 'desc'
|
|
529
|
-
// nullsFirst = true : always first
|
|
530
|
-
// nullsFirst = false : always end
|
|
531
|
-
if (a === null ||
|
|
532
|
-
a === '' ||
|
|
533
|
-
a === undefined ||
|
|
534
|
-
b === null ||
|
|
535
|
-
b === '' ||
|
|
536
|
-
b === undefined) {
|
|
537
|
-
const nullScore = a === b
|
|
538
|
-
? 0
|
|
539
|
-
: a === undefined
|
|
540
|
-
? 3
|
|
541
|
-
: b === undefined
|
|
542
|
-
? -3
|
|
543
|
-
: a === null
|
|
544
|
-
? 2
|
|
545
|
-
: b === null
|
|
546
|
-
? -2
|
|
547
|
-
: a === ''
|
|
548
|
-
? 1
|
|
549
|
-
: -1;
|
|
550
|
-
if (direction === 'desc') {
|
|
551
|
-
return nullsFirst !== false ? nullScore : nullScore * -1;
|
|
552
|
-
}
|
|
553
|
-
return nullsFirst === true ? nullScore * -1 : nullScore;
|
|
554
|
-
}
|
|
555
|
-
const ax = [];
|
|
556
|
-
const bx = [];
|
|
557
|
-
a = '' + a;
|
|
558
|
-
b = '' + b;
|
|
559
|
-
a.replace(/(\d+)|(\D+)/g, (_, $1, $2) => {
|
|
560
|
-
ax.push([$1 || Infinity, $2 || '']);
|
|
561
|
-
});
|
|
562
|
-
b.replace(/(\d+)|(\D+)/g, (_, $1, $2) => {
|
|
563
|
-
bx.push([$1 || Infinity, $2 || '']);
|
|
564
|
-
});
|
|
565
|
-
while (ax.length && bx.length) {
|
|
566
|
-
const an = ax.shift();
|
|
567
|
-
const bn = bx.shift();
|
|
568
|
-
const nn = an[0] - bn[0] || an[1].localeCompare(bn[1]);
|
|
569
|
-
if (nn) {
|
|
570
|
-
return nn;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
return ax.length - bx.length;
|
|
574
|
-
}
|
|
575
|
-
/**
|
|
576
|
-
* Return true if two object are equivalent.
|
|
577
|
-
* Objects are considered equivalent if they have the same properties and
|
|
578
|
-
* if all of their properties (first-level only) share the same value.
|
|
579
|
-
* @param obj1 First object
|
|
580
|
-
* @param obj2 Second object
|
|
581
|
-
* @returns Whether two objects arer equivalent
|
|
582
|
-
*/
|
|
583
|
-
static objectsAreEquivalent(obj1, obj2) {
|
|
584
|
-
if (obj1 === obj2) {
|
|
585
|
-
return true;
|
|
586
|
-
}
|
|
587
|
-
const obj1Props = Object.getOwnPropertyNames(obj1);
|
|
588
|
-
const obj2Props = Object.getOwnPropertyNames(obj2);
|
|
589
|
-
if (obj1Props.length !== obj2Props.length) {
|
|
590
|
-
return false;
|
|
591
|
-
}
|
|
592
|
-
for (const prop of obj1Props) {
|
|
593
|
-
if (obj1[prop] !== obj2[prop]) {
|
|
594
|
-
return false;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
return true;
|
|
598
|
-
}
|
|
599
|
-
/**
|
|
600
|
-
* Return a new object with an array of keys removed
|
|
601
|
-
* @param obj Source object
|
|
602
|
-
* @param keys Keys to remove
|
|
603
|
-
* @returns A new object
|
|
604
|
-
*/
|
|
605
|
-
static removeKeys(obj, keys) {
|
|
606
|
-
const newObj = Object.keys(obj)
|
|
607
|
-
.filter(key => keys.indexOf(key) < 0)
|
|
608
|
-
.reduce((_obj, key) => {
|
|
609
|
-
_obj[key] = obj[key];
|
|
610
|
-
return _obj;
|
|
611
|
-
}, {});
|
|
612
|
-
return newObj;
|
|
613
|
-
}
|
|
368
|
+
class ObjectUtils {
|
|
369
|
+
static resolve(obj, key) {
|
|
370
|
+
const keysArray = key
|
|
371
|
+
.replace(/\[/g, '.')
|
|
372
|
+
.replace(/\]/g, '')
|
|
373
|
+
.split('.');
|
|
374
|
+
let current = obj;
|
|
375
|
+
while (keysArray.length) {
|
|
376
|
+
if (typeof current !== 'object') {
|
|
377
|
+
return undefined;
|
|
378
|
+
}
|
|
379
|
+
current = current[keysArray.shift()];
|
|
380
|
+
}
|
|
381
|
+
return current;
|
|
382
|
+
}
|
|
383
|
+
static isObject(item) {
|
|
384
|
+
return (item &&
|
|
385
|
+
typeof item === 'object' &&
|
|
386
|
+
!Array.isArray(item) &&
|
|
387
|
+
item !== null &&
|
|
388
|
+
!(item instanceof Date));
|
|
389
|
+
}
|
|
390
|
+
static mergeDeep(target, source, ignoreUndefined = false) {
|
|
391
|
+
const output = Object.assign({}, target);
|
|
392
|
+
if (ObjectUtils.isObject(target) && ObjectUtils.isObject(source)) {
|
|
393
|
+
Object.keys(source)
|
|
394
|
+
.filter(key => !ignoreUndefined || source[key] !== undefined)
|
|
395
|
+
.forEach(key => {
|
|
396
|
+
if (ObjectUtils.isObject(source[key])) {
|
|
397
|
+
if (!(key in target)) {
|
|
398
|
+
Object.assign(output, { [key]: source[key] });
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
output[key] = ObjectUtils.mergeDeep(target[key], source[key], ignoreUndefined);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
else {
|
|
405
|
+
Object.assign(output, { [key]: source[key] });
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
return output;
|
|
410
|
+
}
|
|
411
|
+
static copyDeep(src) {
|
|
412
|
+
const target = Array.isArray(src) ? [] : {};
|
|
413
|
+
for (const prop in src) {
|
|
414
|
+
if (src.hasOwnProperty(prop)) {
|
|
415
|
+
const value = src[prop];
|
|
416
|
+
if (value && typeof value === 'object') {
|
|
417
|
+
target[prop] = this.copyDeep(value);
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
target[prop] = value;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return target;
|
|
425
|
+
}
|
|
426
|
+
static removeDuplicateCaseInsensitive(obj) {
|
|
427
|
+
const summaryCapitalizeObject = {};
|
|
428
|
+
const capitalizeObject = {};
|
|
429
|
+
const upperCaseCount = [];
|
|
430
|
+
for (const property in obj) {
|
|
431
|
+
if (obj.hasOwnProperty(property)) {
|
|
432
|
+
const upperCaseProperty = property.toUpperCase();
|
|
433
|
+
if (!summaryCapitalizeObject.hasOwnProperty(upperCaseProperty)) {
|
|
434
|
+
summaryCapitalizeObject[upperCaseProperty] = [
|
|
435
|
+
{ [property]: obj[property] }
|
|
436
|
+
];
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
summaryCapitalizeObject[upperCaseProperty].push({
|
|
440
|
+
[property]: obj[property]
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
// counting the number of uppercase lettersMna
|
|
444
|
+
upperCaseCount.push({
|
|
445
|
+
key: property,
|
|
446
|
+
count: property.replace(/[^A-Z]/g, '').length
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
for (const capitalizedProperty in summaryCapitalizeObject) {
|
|
451
|
+
if (summaryCapitalizeObject.hasOwnProperty(capitalizedProperty)) {
|
|
452
|
+
if (summaryCapitalizeObject.hasOwnProperty(capitalizedProperty)) {
|
|
453
|
+
const capitalizedPropertyObject = summaryCapitalizeObject[capitalizedProperty];
|
|
454
|
+
if (capitalizedPropertyObject.length === 1) {
|
|
455
|
+
// for single params (no duplicates)
|
|
456
|
+
const singlePossibility = capitalizedPropertyObject[0];
|
|
457
|
+
capitalizeObject[capitalizedProperty] =
|
|
458
|
+
singlePossibility[Object.keys(singlePossibility)[0]];
|
|
459
|
+
}
|
|
460
|
+
else if (capitalizedPropertyObject.length > 1) {
|
|
461
|
+
// defining the closest to lowercase property
|
|
462
|
+
const paramClosestToLowercase = upperCaseCount
|
|
463
|
+
.filter(f => f.key.toLowerCase() === capitalizedProperty.toLowerCase())
|
|
464
|
+
.reduce((prev, current) => {
|
|
465
|
+
return prev.y < current.y ? prev : current;
|
|
466
|
+
});
|
|
467
|
+
capitalizeObject[paramClosestToLowercase.key.toUpperCase()] =
|
|
468
|
+
obj[paramClosestToLowercase.key];
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
for (const property in obj) {
|
|
474
|
+
if (obj.hasOwnProperty(property)) {
|
|
475
|
+
delete obj[property];
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
for (const property in capitalizeObject) {
|
|
479
|
+
if (capitalizeObject.hasOwnProperty(property)) {
|
|
480
|
+
obj[property] = capitalizeObject[property];
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
static removeUndefined(obj) {
|
|
485
|
+
const output = {};
|
|
486
|
+
if (ObjectUtils.isObject(obj)) {
|
|
487
|
+
Object.keys(obj)
|
|
488
|
+
.filter(key => obj[key] !== undefined)
|
|
489
|
+
.forEach(key => {
|
|
490
|
+
if (ObjectUtils.isObject(obj[key]) || Array.isArray(obj[key])) {
|
|
491
|
+
output[key] = ObjectUtils.removeUndefined(obj[key]);
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
output[key] = obj[key];
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
return output;
|
|
498
|
+
}
|
|
499
|
+
if (Array.isArray(obj)) {
|
|
500
|
+
return obj.map(o => ObjectUtils.removeUndefined(o));
|
|
501
|
+
}
|
|
502
|
+
return obj;
|
|
503
|
+
}
|
|
504
|
+
static removeNull(obj) {
|
|
505
|
+
const output = {};
|
|
506
|
+
if (ObjectUtils.isObject(obj)) {
|
|
507
|
+
Object.keys(obj)
|
|
508
|
+
.filter(key => obj[key] !== null)
|
|
509
|
+
.forEach(key => {
|
|
510
|
+
if (ObjectUtils.isObject(obj[key]) || Array.isArray(obj[key])) {
|
|
511
|
+
output[key] = ObjectUtils.removeNull(obj[key]);
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
output[key] = obj[key];
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
return output;
|
|
518
|
+
}
|
|
519
|
+
if (Array.isArray(obj)) {
|
|
520
|
+
return obj.map(o => ObjectUtils.removeNull(o));
|
|
521
|
+
}
|
|
522
|
+
return obj;
|
|
523
|
+
}
|
|
524
|
+
static naturalCompare(a, b, direction = 'asc', nullsFirst) {
|
|
525
|
+
if (direction === 'desc') {
|
|
526
|
+
b = [a, (a = b)][0];
|
|
527
|
+
}
|
|
528
|
+
// nullsFirst = undefined : end if direction = 'asc', first if direction = 'desc'
|
|
529
|
+
// nullsFirst = true : always first
|
|
530
|
+
// nullsFirst = false : always end
|
|
531
|
+
if (a === null ||
|
|
532
|
+
a === '' ||
|
|
533
|
+
a === undefined ||
|
|
534
|
+
b === null ||
|
|
535
|
+
b === '' ||
|
|
536
|
+
b === undefined) {
|
|
537
|
+
const nullScore = a === b
|
|
538
|
+
? 0
|
|
539
|
+
: a === undefined
|
|
540
|
+
? 3
|
|
541
|
+
: b === undefined
|
|
542
|
+
? -3
|
|
543
|
+
: a === null
|
|
544
|
+
? 2
|
|
545
|
+
: b === null
|
|
546
|
+
? -2
|
|
547
|
+
: a === ''
|
|
548
|
+
? 1
|
|
549
|
+
: -1;
|
|
550
|
+
if (direction === 'desc') {
|
|
551
|
+
return nullsFirst !== false ? nullScore : nullScore * -1;
|
|
552
|
+
}
|
|
553
|
+
return nullsFirst === true ? nullScore * -1 : nullScore;
|
|
554
|
+
}
|
|
555
|
+
const ax = [];
|
|
556
|
+
const bx = [];
|
|
557
|
+
a = '' + a;
|
|
558
|
+
b = '' + b;
|
|
559
|
+
a.replace(/(\d+)|(\D+)/g, (_, $1, $2) => {
|
|
560
|
+
ax.push([$1 || Infinity, $2 || '']);
|
|
561
|
+
});
|
|
562
|
+
b.replace(/(\d+)|(\D+)/g, (_, $1, $2) => {
|
|
563
|
+
bx.push([$1 || Infinity, $2 || '']);
|
|
564
|
+
});
|
|
565
|
+
while (ax.length && bx.length) {
|
|
566
|
+
const an = ax.shift();
|
|
567
|
+
const bn = bx.shift();
|
|
568
|
+
const nn = an[0] - bn[0] || an[1].localeCompare(bn[1]);
|
|
569
|
+
if (nn) {
|
|
570
|
+
return nn;
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
return ax.length - bx.length;
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* Return true if two object are equivalent.
|
|
577
|
+
* Objects are considered equivalent if they have the same properties and
|
|
578
|
+
* if all of their properties (first-level only) share the same value.
|
|
579
|
+
* @param obj1 First object
|
|
580
|
+
* @param obj2 Second object
|
|
581
|
+
* @returns Whether two objects arer equivalent
|
|
582
|
+
*/
|
|
583
|
+
static objectsAreEquivalent(obj1, obj2) {
|
|
584
|
+
if (obj1 === obj2) {
|
|
585
|
+
return true;
|
|
586
|
+
}
|
|
587
|
+
const obj1Props = Object.getOwnPropertyNames(obj1);
|
|
588
|
+
const obj2Props = Object.getOwnPropertyNames(obj2);
|
|
589
|
+
if (obj1Props.length !== obj2Props.length) {
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
for (const prop of obj1Props) {
|
|
593
|
+
if (obj1[prop] !== obj2[prop]) {
|
|
594
|
+
return false;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
return true;
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Return a new object with an array of keys removed
|
|
601
|
+
* @param obj Source object
|
|
602
|
+
* @param keys Keys to remove
|
|
603
|
+
* @returns A new object
|
|
604
|
+
*/
|
|
605
|
+
static removeKeys(obj, keys) {
|
|
606
|
+
const newObj = Object.keys(obj)
|
|
607
|
+
.filter(key => keys.indexOf(key) < 0)
|
|
608
|
+
.reduce((_obj, key) => {
|
|
609
|
+
_obj[key] = obj[key];
|
|
610
|
+
return _obj;
|
|
611
|
+
}, {});
|
|
612
|
+
return newObj;
|
|
613
|
+
}
|
|
614
614
|
}
|
|
615
615
|
|
|
616
|
-
class NumberUtils {
|
|
617
|
-
static roundToNDecimal(num, decimal = 3) {
|
|
618
|
-
const roundFactor = Math.pow(10, decimal);
|
|
619
|
-
return Math.round((num) * roundFactor) / roundFactor;
|
|
620
|
-
}
|
|
616
|
+
class NumberUtils {
|
|
617
|
+
static roundToNDecimal(num, decimal = 3) {
|
|
618
|
+
const roundFactor = Math.pow(10, decimal);
|
|
619
|
+
return Math.round((num) * roundFactor) / roundFactor;
|
|
620
|
+
}
|
|
621
621
|
}
|
|
622
622
|
|
|
623
|
-
/** Utility function to create a K:V from a list of strings */
|
|
624
|
-
function strEnum(o) {
|
|
625
|
-
return o.reduce((res, key) => {
|
|
626
|
-
res[key] = key;
|
|
627
|
-
return res;
|
|
628
|
-
}, Object.create(null));
|
|
623
|
+
/** Utility function to create a K:V from a list of strings */
|
|
624
|
+
function strEnum(o) {
|
|
625
|
+
return o.reduce((res, key) => {
|
|
626
|
+
res[key] = key;
|
|
627
|
+
return res;
|
|
628
|
+
}, Object.create(null));
|
|
629
629
|
}
|
|
630
630
|
|
|
631
|
-
function S4() {
|
|
632
|
-
// eslint-disable-next-line no-bitwise
|
|
633
|
-
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
|
634
|
-
}
|
|
635
|
-
function uuid() {
|
|
636
|
-
const id = `${S4()}${S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`;
|
|
637
|
-
return id.toLowerCase();
|
|
631
|
+
function S4() {
|
|
632
|
+
// eslint-disable-next-line no-bitwise
|
|
633
|
+
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
|
|
634
|
+
}
|
|
635
|
+
function uuid() {
|
|
636
|
+
const id = `${S4()}${S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`;
|
|
637
|
+
return id.toLowerCase();
|
|
638
638
|
}
|
|
639
639
|
|
|
640
|
-
var SubjectStatus;
|
|
641
|
-
(function (SubjectStatus) {
|
|
642
|
-
SubjectStatus[SubjectStatus["Error"] = 0] = "Error";
|
|
643
|
-
SubjectStatus[SubjectStatus["Done"] = 1] = "Done";
|
|
644
|
-
SubjectStatus[SubjectStatus["Working"] = 2] = "Working";
|
|
645
|
-
SubjectStatus[SubjectStatus["Waiting"] = 3] = "Waiting";
|
|
646
|
-
})(SubjectStatus || (SubjectStatus = {}));
|
|
647
|
-
class Watcher {
|
|
648
|
-
constructor() {
|
|
649
|
-
this.status$ = new Subject();
|
|
650
|
-
}
|
|
651
|
-
get status() {
|
|
652
|
-
return this._status;
|
|
653
|
-
}
|
|
654
|
-
set status(value) {
|
|
655
|
-
this._status = value;
|
|
656
|
-
this.status$.next(value);
|
|
657
|
-
}
|
|
658
|
-
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
659
|
-
subscribe(callback, scope) {
|
|
660
|
-
this.watch();
|
|
661
|
-
this.status$$ = this.status$
|
|
662
|
-
.pipe(distinctUntilChanged())
|
|
663
|
-
.subscribe((status) => {
|
|
664
|
-
this.handleStatusChange(status);
|
|
665
|
-
callback.call(scope, this);
|
|
666
|
-
});
|
|
667
|
-
}
|
|
668
|
-
unsubscribe() {
|
|
669
|
-
this.unwatch();
|
|
670
|
-
if (this.status$$ !== undefined) {
|
|
671
|
-
this.status$$.unsubscribe();
|
|
672
|
-
this.status$$ = undefined;
|
|
673
|
-
}
|
|
674
|
-
this.status = SubjectStatus.Waiting;
|
|
675
|
-
}
|
|
676
|
-
handleStatusChange(status) { }
|
|
640
|
+
var SubjectStatus;
|
|
641
|
+
(function (SubjectStatus) {
|
|
642
|
+
SubjectStatus[SubjectStatus["Error"] = 0] = "Error";
|
|
643
|
+
SubjectStatus[SubjectStatus["Done"] = 1] = "Done";
|
|
644
|
+
SubjectStatus[SubjectStatus["Working"] = 2] = "Working";
|
|
645
|
+
SubjectStatus[SubjectStatus["Waiting"] = 3] = "Waiting";
|
|
646
|
+
})(SubjectStatus || (SubjectStatus = {}));
|
|
647
|
+
class Watcher {
|
|
648
|
+
constructor() {
|
|
649
|
+
this.status$ = new Subject();
|
|
650
|
+
}
|
|
651
|
+
get status() {
|
|
652
|
+
return this._status;
|
|
653
|
+
}
|
|
654
|
+
set status(value) {
|
|
655
|
+
this._status = value;
|
|
656
|
+
this.status$.next(value);
|
|
657
|
+
}
|
|
658
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
659
|
+
subscribe(callback, scope) {
|
|
660
|
+
this.watch();
|
|
661
|
+
this.status$$ = this.status$
|
|
662
|
+
.pipe(distinctUntilChanged())
|
|
663
|
+
.subscribe((status) => {
|
|
664
|
+
this.handleStatusChange(status);
|
|
665
|
+
callback.call(scope, this);
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
unsubscribe() {
|
|
669
|
+
this.unwatch();
|
|
670
|
+
if (this.status$$ !== undefined) {
|
|
671
|
+
this.status$$.unsubscribe();
|
|
672
|
+
this.status$$ = undefined;
|
|
673
|
+
}
|
|
674
|
+
this.status = SubjectStatus.Waiting;
|
|
675
|
+
}
|
|
676
|
+
handleStatusChange(status) { }
|
|
677
677
|
}
|
|
678
678
|
|
|
679
|
-
/*
|
|
680
|
-
* Public API Surface of utils
|
|
679
|
+
/*
|
|
680
|
+
* Public API Surface of utils
|
|
681
681
|
*/
|
|
682
682
|
|
|
683
|
-
/**
|
|
684
|
-
* Generated bundle index. Do not edit.
|
|
683
|
+
/**
|
|
684
|
+
* Generated bundle index. Do not edit.
|
|
685
685
|
*/
|
|
686
686
|
|
|
687
687
|
export { Base64, ChangeType, ChangeUtils, Clipboard, NumberUtils, ObjectUtils, S4, StringUtils, SubjectStatus, Watcher, downloadContent, downloadFromUri, strEnum, userAgent, uuid };
|