1/*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16interface HelpUtil {
17  TextEncoder: Object;
18  TextDecoder: TextDecoder;
19  Base64: Object;
20  Base64Helper: NativeBase64;
21  Types: Object;
22  StringDecoder: Object;
23  dealwithformatstring(formatString: string | Array<string | number | Function>): string;
24  printf(formatString: string | Array<string | number | Function>,
25    ...valueString: Array<Object>): string;
26  format(formatString: Array<string | number | Function>, ...valueString: Array<Object>): string
27  geterrorstring(errnum: number): string;
28  errnoToString(errnum: number): string;
29  randomUUID(entropyCache?: boolean): string;
30  randomBinaryUUID(entropyCache?: boolean): Uint8Array;
31  parseUUID(uuid: string): Uint8Array;
32  getHash(obj: object): number;
33}
34
35type AnyType = Object | null | undefined;
36
37declare function requireInternal(s: string): HelpUtil;
38const helpUtil = requireInternal('util');
39let textEncoder = helpUtil.TextEncoder;
40let base64 = helpUtil.Base64;
41let types = helpUtil.Types;
42let stringdecoder = helpUtil.StringDecoder;
43
44const typeErrorCode = 401;
45const syntaxErrorCode = 10200002;
46class BusinessError extends Error {
47  code: number;
48  constructor(msg: string) {
49    super(msg);
50    this.name = 'BusinessError';
51    this.code = typeErrorCode;
52  }
53}
54
55interface NativeBase64 {
56  new(): NativeBase64;
57  encodeSync(src: Uint8Array, options?: Type): Uint8Array;
58  encodeToStringSync(src: Uint8Array, options?: Type): string;
59  decodeSync(src: Uint8Array | string, options?: Type): Uint8Array;
60  encode(src: Uint8Array, options?: Type): Promise<Uint8Array>;
61  encodeToString(src: Uint8Array, options?: Type): Promise<string>;
62  decode(src: Uint8Array | string, options?: Type): Promise<Uint8Array>;
63}
64
65interface Base64Helper {
66  Base64Helper: NativeBase64;
67}
68
69enum Type {
70  BASIC,
71  MIME,
72  BASIC_URL_SAFE,
73  MIME_URL_SAFE
74}
75
76class Base64Helper {
77  base64: NativeBase64;
78  constructor() {
79    this.base64 = new helpUtil.Base64Helper();
80  }
81
82  encodeSync(src: Uint8Array, options: Type = Type.BASIC): Uint8Array {
83    return this.base64.encodeSync(src, options);
84  }
85
86  private addBreaks(resultString: string): string {
87    const chunkSize = 76; // 76 : MIME format encoding data limitations
88    let i = 0;
89    let newString: string = '';
90    let stringLength = resultString.length;
91    if (stringLength < chunkSize) {
92      throw new Error('The parameter length does not meet this encoding format.');
93    }
94    while (i < stringLength && stringLength > chunkSize) {
95      let index = i + chunkSize;
96      if (i + chunkSize > stringLength) {
97        index = stringLength;
98      }
99      let temp: string = resultString.substring(i, index);
100      newString = newString + temp + '\r\n';
101      i += chunkSize;
102    }
103    return newString;
104  }
105
106  encodeToStringSync(src: Uint8Array, options: Type = Type.BASIC): string {
107    let resultString: string = this.base64.encodeToStringSync(src, options);
108    if (options === Type.MIME || options === Type.MIME_URL_SAFE) {
109      return this.addBreaks(resultString);
110    }
111    return resultString;
112  }
113
114  decodeSync(src: Uint8Array | string, options: Type = Type.BASIC): Uint8Array {
115    if (typeof src === 'string' && (src.indexOf('\r') !== -1 || src.indexOf('\n') !== -1)) {
116      src = src.replace(/[\r\n]/g, '');
117    }
118    return this.base64.decodeSync(src, options);
119  }
120
121  encode(src: Uint8Array, options: Type = Type.BASIC): Promise<Uint8Array> {
122    if (!Object.values(Type).includes(options) || options === Type.MIME || options === Type.MIME_URL_SAFE) {
123      let error = new BusinessError(`Parameter error. The type of ${options} must be BASIC or BASIC_URL_SAFE`);
124      throw error;
125    }
126    return this.base64.encode(src, options);
127  }
128
129  encodeToString(src: Uint8Array, options: Type = Type.BASIC): Promise<string> {
130    if (!Object.values(Type).includes(options)) {
131      let error = new BusinessError(`Parameter error. The type of ${options} must be one of the type enumerations`);
132      throw error;
133    }
134    let base64Result: Promise<string> = this.base64.encodeToString(src, options);
135    if (options === Type.MIME || options === Type.MIME_URL_SAFE) {
136      return base64Result.then((result) => {
137        return this.addBreaks(result);
138      });
139    }
140    return base64Result;
141  }
142
143  decode(src: Uint8Array | string, options: Type = Type.BASIC): Promise<Uint8Array> {
144    if (!Object.values(Type).includes(options)) {
145      let error = new BusinessError(`Parameter error. The type of ${options} must be one of the type enumerations`);
146      throw error;
147    }
148    if (typeof src === 'string') {
149      src = src.replace(/[\r\n]/g, '');
150    }
151    return this.base64.decode(src, options);
152  }
153}
154
155function switchLittleObject(enter: string, obj: Object, count: number): string | Object {
156  let str: string = '';
157  if (obj === null) {
158    str += obj;
159  } else if (obj instanceof Array) {
160    str += '[ ' + arrayToString(enter, obj, count) + '[length]: ' + obj.length + ' ]';
161  } else if (typeof obj === 'function') {
162    str += '{ [Function: ' + obj.name + ']' + enter +
163      '[length]: ' + obj.length + ',' + enter +
164      '[name] :\'' + obj.name + '\',' + enter +
165      '[prototype]: ' + obj.name + ' { [constructor]: [Circular] } }';
166  } else if (typeof obj === 'object') {
167    str += '{ ';
168    let i: string;
169    let flag: boolean = false;
170    for (i in obj) {
171      flag = true;
172      str += switchLittleValue(enter, i, obj, count);
173    }
174    if (!flag) {
175      return obj;
176    }
177    str = str.substr(0, str.length - enter.length - 1);
178    str += ' }';
179  } else if (typeof obj === 'string') {
180    str += '\'' + obj + '\'';
181  } else {
182    str += obj;
183  }
184  return str;
185}
186
187function switchLittleValue(enter: string, protoName: string, obj: Object, count: number): string {
188  let str: string = '';
189  if (obj[protoName] === null) {
190    str += protoName + ': null,' + enter;
191  } else if (obj[protoName] instanceof Array) {
192    str += protoName + ':' + enter +
193      '[ ' + arrayToString(enter + '  ', obj[protoName], count) + '[length]: ' +
194      obj[protoName].length + ' ],' + enter;
195  } else if (typeof obj[protoName] === 'object') {
196    if (obj[protoName] === obj) {
197      str += protoName + ': [Circular]' + enter;
198    } else {
199      str += protoName + ':' + enter;
200      str += switchLittleObject(enter + '  ', obj[protoName], count + 1) + ',' + enter;
201    }
202  } else if (typeof obj[protoName] === 'function') {
203    let space: string = enter;
204    if (obj[protoName].name !== '') {
205      str += obj[protoName].name + ':' + space;
206    }
207    space += '  ';
208    str += '{ [Function: ' + obj[protoName].name + ']' + space +
209      '[length]: ' + obj[protoName].length + ',' + space +
210      '[name] :\'' + obj[protoName].name + '\',' + space +
211      '[prototype]: ' + obj[protoName].name +
212      ' { [constructor]: [Circular] } },' + enter;
213  } else {
214    if (typeof obj[protoName] === 'string') {
215      str += protoName + ': \'' + obj[protoName] + '\',' + enter;
216    } else {
217      str += protoName + ': ' + obj[protoName] + ',' + enter;
218    }
219  }
220  return str;
221}
222
223function arrayToString(enter: string, arr: Array<string | number | Function>, count: number): string {
224  let str: string = '';
225  if (!arr.length) {
226    return '';
227  }
228  let arrayEnter: string = ', ';
229  for (let k in arr) {
230    if (arr[k] !== null && (typeof arr[k] === 'function' || typeof arr[k] === 'object') && count <= 2) {
231      arrayEnter += enter;
232      break;
233    }
234  }
235  for (let i of arr) {
236    if (typeof i === 'string') {
237      str += '\'' + i.toString() + '\'' + arrayEnter;
238    } else if (typeof i === 'object') {
239      str += switchLittleObject(enter + '  ', i, count + 1);
240      str += arrayEnter;
241    } else if (typeof i === 'function') {
242      let space: string = enter;
243      space += '  ';
244      let end: string = '';
245      if (i.name !== '') {
246        str += '{ [Function: ' + i.name + ']' + space;
247        end = i.name + ' { [constructor]: [Circular] } }' + arrayEnter;
248      } else {
249        str += '{ [Function]' + space;
250        end = '{ [constructor]: [Circular] } }' + arrayEnter;
251      }
252      str += '[length]: ' +
253        i.length + ',' + space +
254        '[name] :\'' + i.name + '\',' + space +
255        '[prototype]: ' + end;
256    } else {
257      str += i + arrayEnter;
258    }
259  }
260  return str;
261}
262
263function switchBigObject(enter: string, obj: Object, count: number): string | Object {
264  let str: string = '';
265  if (obj === null) {
266    str += obj;
267  } else if (obj instanceof Array) {
268    str += '[ ' + arrayToBigString(enter, obj, count) + ' ]';
269  } else if (typeof obj === 'function') {
270    str += '{ [Function: ' + obj.name + '] }';
271  } else if (typeof obj === 'object') {
272    str += '{ ';
273    let i: string;
274    let flag: boolean = false;
275    for (i in obj) {
276      flag = true;
277      str += switchBigValue(enter, i, obj, count);
278    }
279    if (!flag) {
280      return obj;
281    }
282    str = str.substr(0, str.length - enter.length - 1);
283    str += ' }';
284  } else if (typeof obj === 'string') {
285    str += '\'' + obj + '\'';
286  } else {
287    str += obj;
288  }
289  return str;
290}
291
292function switchBigValue(enter: string, protoName: string, obj: Object, count: number): string {
293  let str: string = '';
294  if (obj[protoName] === null) {
295    str += protoName + ': null,' + enter;
296  } else if (obj[protoName] instanceof Array) {
297    str += protoName + ':' + enter +
298      '[ ' + arrayToBigString(enter + '  ', obj[protoName], count) + ' ],' + enter;
299  } else if (typeof obj[protoName] === 'object') {
300    if (obj[protoName] === obj) {
301      str += protoName + ': [Circular]' + enter;
302    } else {
303      str += protoName + ':' + enter;
304      str += switchBigObject(enter + '  ', obj[protoName], count + 1) + ',' + enter;
305    }
306  } else if (typeof obj[protoName] === 'function') {
307    if (obj[protoName].name !== '') {
308      str += obj[protoName].name + ': ';
309    }
310    str += '[Function: ' + obj[protoName].name + '],' + enter;
311  } else {
312    if (typeof obj[protoName] === 'string') {
313      str += protoName + ': \'' + obj[protoName] + '\',' + enter;
314    } else {
315      str += protoName + ': ' + obj[protoName] + ',' + enter;
316    }
317  }
318  return str;
319}
320
321function arrayToBigString(enter: string, arr: Array<string | number | Function>, count: number): string {
322  let str: string = '';
323  if (!arr.length) {
324    return '';
325  }
326
327  let arrayEnter = ', ';
328  for (let i of arr) {
329    if (i !== null && (typeof i === 'object') && count <= 2) {
330      arrayEnter += enter;
331      break;
332    }
333  }
334  for (let j of arr) {
335    if (typeof j === 'string') {
336      str += '\'' + j + '\'' + arrayEnter;
337    } else if (typeof j === 'object') {
338      str += switchBigObject(enter + '  ', j, count + 1);
339      str += arrayEnter;
340    } else if (typeof j === 'function') {
341      if (j.name !== '') {
342        str += '[Function: ' + j.name + ']' + arrayEnter;
343      } else {
344        str += '[Function]' + arrayEnter;
345      }
346    } else {
347      str += j + arrayEnter;
348    }
349  }
350  str = str.substr(0, str.length - arrayEnter.length);
351  return str;
352}
353
354function switchIntValue(value: Object | symbol): string {
355  let str: string = '';
356  if (value === '') {
357    str += 'NaN';
358  } else if (typeof value === 'bigint') {
359    str += value + 'n';
360  } else if (typeof value === 'symbol') {
361    str += 'NaN';
362  } else if (typeof value === 'number') {
363    str += parseInt(value.toString(), 10); // 10:The function uses decimal.
364  } else if (value instanceof Array) {
365    if (typeof value[0] === 'number') {
366      str += parseInt(value[0].toString(), 10); // 10:The function uses decimal.
367    } else if (typeof value[0] === 'string') {
368      if (isNaN(Number(value[0]))) {
369        str += 'NaN';
370      } else {
371        str += parseInt(value[0], 10); // 10:The function uses decimal.
372      }
373    }
374  } else if (typeof value === 'string') {
375    if (isNaN(Number(value))) {
376      str += 'NaN';
377    } else {
378      str += parseInt(value, 10); // 10:The function uses decimal.
379    }
380  } else {
381    str += 'NaN';
382  }
383  return str;
384}
385
386function switchFloatValue(value: Object | symbol): string {
387  let str: string = '';
388  if (value === '') {
389    str += 'NaN';
390  } else if (typeof value === 'symbol') {
391    str += 'NaN';
392  } else if (typeof value === 'number') {
393    str += value;
394  } else if (value instanceof Array) {
395    if (typeof value[0] === 'number') {
396      str += parseFloat(value.toString());
397    } else if (typeof value[0] === 'string') {
398      if (isNaN(Number(value[0]))) {
399        str += 'NaN';
400      } else {
401        str += parseFloat(value[0]);
402      }
403    }
404  } else if (typeof value === 'string') {
405    if (isNaN(Number(value))) {
406      str += 'NaN';
407    } else {
408      str += parseFloat(value);
409    }
410  } else if (typeof value === 'bigint') {
411    str += value;
412  } else {
413    str += 'NaN';
414  }
415  return str;
416}
417
418function switchNumberValue(value: Object | symbol): string {
419  let str: string = '';
420  if (value === '') {
421    str += '0';
422  } else if (typeof value === 'symbol') {
423    str += 'NaN';
424  } else if (typeof value === 'number') {
425    str += value;
426  } else if (value instanceof Array) {
427    str += 'NaN';
428  } else if (typeof value === 'string') {
429    if (isNaN(Number(value))) {
430      str += 'NaN';
431    } else {
432      str += Number(value);
433    }
434  } else if (typeof value === 'bigint') {
435    str += value.toString() + 'n';
436  } else {
437    str += 'NaN';
438  }
439  return str;
440}
441
442function switchStringValue(value: Object | symbol): string {
443  let str: string = '';
444  if (typeof value === 'undefined') {
445    str += 'undefined';
446  } else if (typeof value === 'object') {
447    if (value === null) {
448      str += 'null';
449    } else {
450      str += value;
451    }
452  } else if (typeof value === 'symbol') {
453    str += value.toString();
454  } else {
455    str += value;
456  }
457  return str;
458}
459
460function printf(formatString: Array<string | number | Function>, ...valueString: Array<Object>): string {
461  let formats: string = helpUtil.dealwithformatstring(formatString);
462  let arr: Array<Object> = [];
463  arr = formats.split(' ');
464  let switchString: Array<Object> = [];
465  let valueLength: number = valueString.length;
466  let arrLength: number = arr.length;
467  let i: number = 0;
468  for (let sub of valueString) {
469    if (i >= arrLength) {
470      break;
471    }
472    if (arr[i] === 'o') {
473      switchString.push(switchLittleObject('\n  ', sub, 1));
474    } else if (arr[i] === 'O') {
475      switchString.push(switchBigObject('\n  ', sub, 1));
476    } else if (arr[i] === 'i') {
477      switchString.push(switchIntValue(sub));
478    } else if (arr[i] === 'j') {
479      switchString.push(JSON.stringify(sub));
480    } else if (arr[i] === 'd') {
481      switchString.push(switchNumberValue(sub));
482    } else if (arr[i] === 's') {
483      switchString.push(switchStringValue(sub));
484    } else if (arr[i] === 'f') {
485      switchString.push(switchFloatValue(sub));
486    } else if (arr[i] === 'c') {
487      switchString.push(sub.toString());
488    }
489    ++i;
490  }
491  while (i < valueLength) {
492    switchString.push(valueString[i].toString());
493    i++;
494  }
495  let helpUtilString: string = helpUtil.printf(formatString, ...switchString);
496  return helpUtilString;
497}
498
499function format(formatString: Array<string | number | Function>, ...valueString: Array<Object>): string {
500  if (!(formatString instanceof Array) && (typeof formatString !== 'string')) {
501    let error = new BusinessError(`Parameter error. The type of ${formatString} must be string or array`);
502    throw error;
503  }
504  let valueLength: number = valueString.length;
505  if (valueLength !== 0) {
506    for (let val of valueString) {
507      if (typeof val !== 'object' && typeof val !== 'number' &&
508        typeof val !== 'function' && typeof val !== 'string') {
509        let error = new BusinessError('Parameter error. The type of last parameters must be object');
510        throw error;
511      }
512    }
513  }
514  let formats: string = helpUtil.dealwithformatstring(formatString);
515  let arr: Array<Object> = [];
516  arr = formats.split(' ');
517  let switchString: Array<Object> = [];
518  let arrLength: number = arr.length;
519  let i: number = 0;
520  for (let sub of valueString) {
521    if (i >= arrLength) {
522      break;
523    }
524    if (arr[i] === 'o') {
525      switchString.push(switchLittleObject('\n  ', sub, 1));
526    } else if (arr[i] === 'O') {
527      switchString.push(switchBigObject('\n  ', sub, 1));
528    } else if (arr[i] === 'i') {
529      switchString.push(switchIntValue(sub));
530    } else if (arr[i] === 'j') {
531      switchString.push(JSON.stringify(sub));
532    } else if (arr[i] === 'd') {
533      switchString.push(switchNumberValue(sub));
534    } else if (arr[i] === 's') {
535      switchString.push(switchStringValue(sub));
536    } else if (arr[i] === 'f') {
537      switchString.push(switchFloatValue(sub));
538    } else if (arr[i] === 'c') {
539      switchString.push(sub.toString());
540    }
541    ++i;
542  }
543  while (i < valueLength) {
544    switchString.push(valueString[i].toString());
545    i++;
546  }
547  let helpUtilString: string = helpUtil.printf(formatString, ...switchString);
548  return helpUtilString;
549}
550
551function getErrorString(errnum: number): string {
552  let errorString: string = helpUtil.geterrorstring(errnum);
553  return errorString;
554}
555
556function errnoToString(errnum: number): string {
557  if (typeof errnum !== 'number') {
558    let error = new BusinessError(`Parameter error. The type of ${errnum} must be number`);
559    throw error;
560  }
561  let errorString: string = helpUtil.geterrorstring(errnum);
562  return errorString;
563}
564
565function randomUUID(entropyCache?: boolean): string {
566  if (entropyCache === undefined || entropyCache === null) {
567    entropyCache = true;
568  }
569  if (typeof entropyCache !== 'boolean') {
570    let error = new BusinessError(`Parameter error. The type of ${entropyCache} must be boolean`);
571    throw error;
572  }
573  let uuidString: string = helpUtil.randomUUID(entropyCache);
574  return uuidString;
575}
576
577function randomBinaryUUID(entropyCache?: boolean): Uint8Array {
578  if (entropyCache === undefined || entropyCache === null) {
579    entropyCache = true;
580  }
581  if (typeof entropyCache !== 'boolean') {
582    let error = new BusinessError(`Parameter error. The type of ${entropyCache} must be boolean`);
583    throw error;
584  }
585  let uuidArray: Uint8Array = helpUtil.randomBinaryUUID(entropyCache);
586  return uuidArray;
587}
588
589function parseUUID(uuid: string): Uint8Array {
590  let format = /[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}/;
591  if (!format.test(uuid)) {
592    let error = new BusinessError(`Syntax Error.Invalid ${uuid} string`);
593    error.code = syntaxErrorCode;
594    throw error;
595  }
596  let uuidArray: Uint8Array = helpUtil.parseUUID(uuid);
597  return uuidArray;
598}
599
600function getHash(obj: object): number {
601  let result: number = helpUtil.getHash(obj);
602  return result;
603}
604
605function callbackified(original: Function, ...args: Array<string | number | Function>): void {
606  const maybeCb = args.pop();
607  if (typeof maybeCb !== 'function') {
608    throw new Error('maybe is not function');
609  }
610  const cb = (...args: Array<null>) : void => {
611    Reflect.apply(maybeCb, this, args);
612  };
613  Reflect.apply(original, this, args).then((ret: null) => cb(null, ret), (rej: null) => cb(rej));
614}
615
616function getOwnPropertyDescriptors(obj: Function): PropertyDescriptorMap {
617  const result: PropertyDescriptorMap = {};
618  for (let key of Reflect.ownKeys(obj)) {
619    if (typeof key === 'string') {
620      result[key] = Object.getOwnPropertyDescriptor(obj, key);
621    }
622  }
623  return result;
624}
625
626function callbackWrapper(original: Function): Function {
627  if (typeof original !== 'function') {
628    let error = new BusinessError(`Parameter error. The type of ${original} must be function`);
629    throw error;
630  }
631  if (original.constructor.name !== 'AsyncFunction') {
632    console.error('callbackWrapper: The type of Parameter must be AsyncFunction');
633  }
634  const descriptors = getOwnPropertyDescriptors(original);
635  if (typeof descriptors.length.value === 'number') {
636    descriptors.length.value++;
637  }
638  if (typeof descriptors.name.value === 'string') {
639    descriptors.name.value += 'callbackified';
640  }
641  function cb(...args: Array<string | number | Function>): void {
642    callbackified(original, ...args);
643  }
644  Object.defineProperties(cb, descriptors);
645  return cb;
646}
647
648function promiseWrapper(func: Function): Object {
649  return function (...args: Array<Object>) {
650    return new Promise((resolve, reject) => {
651      let callback: Function = function (err: Object | string, ...values: Array<Object>) {
652        if (err) {
653          reject(err);
654        } else {
655          resolve(values);
656        }
657      };
658      func.apply(null, [...args, callback]);
659    });
660  };
661}
662
663function promisify(func: Function): Function {
664  if (typeof func !== 'function') {
665    let error = new BusinessError(`Parameter error. The type of ${func} must be function`);
666    throw error;
667  }
668  return function (...args: Array<Object>) {
669    return new Promise((resolve, reject) => {
670      let callback: Function = function (err: Object | string, ...values: Array<Object>) {
671        if (err) {
672          reject(err);
673        } else {
674          resolve(values);
675        }
676      };
677      func.apply(null, [...args, callback]);
678    });
679  };
680}
681
682interface TextDecoder {
683  new(encoding?: string, options?: { fatal?: boolean; ignoreBOM?: boolean }): TextDecoder;
684}
685
686class TextDecoder {
687  static encodeStr: string = '';
688  textDecoder: TextDecoder;
689  constructor(encoding?: string, options?: { fatal?: boolean; ignoreBOM?: boolean }) {
690    if (arguments.length === 0) {
691      this.textDecoder = new helpUtil.TextDecoder();
692    } else if (arguments.length === 1) {
693      this.textDecoder = new helpUtil.TextDecoder(encoding);
694    } else {
695      this.textDecoder = new helpUtil.TextDecoder(encoding, options);
696    }
697  }
698
699  static create(encoding?: string, options?: { fatal?: boolean; ignoreBOM?: boolean }): TextDecoder {
700    if (arguments.length === 0) {
701      TextDecoder.encodeStr = 'utf-8';
702      return new TextDecoder();
703    } else if (arguments.length === 1) {
704      if (typeof encoding !== 'string' && encoding !== undefined && encoding !== null) {
705        throw new BusinessError(`Parameter error. The type of ${encoding} must be string`);
706      }
707      TextDecoder.encodeStr = encoding;
708      return new TextDecoder(encoding);
709    } else {
710      if (typeof encoding !== 'string' && encoding !== undefined && encoding !== null) {
711        throw new BusinessError(`Parameter error. The type of ${encoding} must be string`);
712      }
713      if (typeof options !== 'object' && options !== undefined && options !== null) {
714        throw new BusinessError(`Parameter error. The type of ${options} must be object`);
715      }
716      TextDecoder.encodeStr = encoding;
717      return new TextDecoder(encoding, options);
718    }
719  }
720
721  public decodeToString(input: Uint8Array, options?: { stream?: boolean }): string {
722    if (input === null) {
723      throw new BusinessError(`Parameter error. The type of Parameter must be Uint8Array.`);
724    }
725    if (arguments.length === 0 || input === undefined || input.length === 0) {
726      return '';
727    }
728    if (arguments.length === 1) {
729      return this.textDecoder.decodeToString(input);
730    }
731    return this.textDecoder.decodeToString(input, options);
732  }
733
734  public decodeWithStream(input: Uint8Array, options?: { stream?: boolean }): string {
735    let uint8: Uint8Array = new Uint8Array(input);
736    if (arguments.length === 1) {
737      return this.textDecoder.decodeWithStream(uint8);
738    }
739    return this.textDecoder.decodeWithStream(uint8, options);
740  }
741
742  public decode(input: Uint8Array, options?: { stream?: boolean }): string {
743    if (arguments.length === 1) {
744      return this.textDecoder.decode(input);
745    }
746    return this.textDecoder.decode(input, options);
747  }
748
749  get encoding(): string {
750    return this.textDecoder.encoding;
751  }
752
753  get fatal(): boolean {
754    return this.textDecoder.fatal;
755  }
756
757  get ignoreBOM(): boolean {
758    return this.textDecoder.ignoreBOM;
759  }
760}
761
762class LruBuffer {
763  private cache: Map<Object | undefined, Object | undefined>;
764  // Default current size
765  private maxSize: number = 64;
766  // Default maximum size
767  private maxNumber: number = 2147483647;
768  private putCount: number = 0;
769  private createCount: number = 0;
770  private evictionCount: number = 0;
771  private hitCount: number = 0;
772  private missCount: number = 0;
773  public length: number = 0;
774
775  public constructor(capacity?: number) {
776    if (capacity !== undefined && capacity !== null) {
777      if (capacity <= 0 || capacity % 1 !== 0 || capacity > this.maxNumber) {
778        throw new Error('data error');
779      }
780      this.maxSize = capacity;
781    }
782    this.cache = new Map();
783  }
784
785  public updateCapacity(newCapacity: number): void {
786    if (newCapacity <= 0 || newCapacity % 1 !== 0 || newCapacity > this.maxNumber) {
787      throw new Error('data error');
788    } else if (this.cache.size > newCapacity) {
789      this.changeCapacity(newCapacity);
790    }
791    this.length = this.cache.size;
792    this.maxSize = newCapacity;
793  }
794
795  public get(key: Object): Object {
796    if (key === null) {
797      throw new Error('key not be null');
798    }
799    let value: Object;
800    if (this.cache.has(key)) {
801      value = this.cache.get(key);
802      this.hitCount++;
803      this.cache.delete(key);
804      this.cache.set(key, value);
805      return value;
806    }
807
808    this.missCount++;
809    let createValue: Object = this.createDefault(key);
810    if (createValue === undefined) {
811      return undefined;
812    } else {
813      value = this.put(key, createValue);
814      this.createCount++;
815      if (value !== undefined) {
816        this.put(key, value);
817        this.afterRemoval(false, key, createValue, value);
818        return value;
819      }
820      return createValue;
821    }
822  }
823
824  public put(key: Object, value: Object): Object {
825    if (key === null || value === null) {
826      throw new Error('key or value not be null');
827    }
828    let former: Object = undefined;
829    this.putCount++;
830    if (this.cache.has(key)) {
831      former = this.cache.get(key);
832      this.cache.delete(key);
833      this.afterRemoval(false, key, former, value);
834    } else if (this.cache.size >= this.maxSize) {
835      this.afterRemoval(true, this.cache.keys().next().value, this.cache.values().next().value, null);
836      this.cache.delete(this.cache.keys().next().value);
837      this.evictionCount++;
838    }
839    this.cache.set(key, value);
840    this.length = this.cache.size;
841    former = this.cache.get(key);
842    return former;
843  }
844
845  public getCreateCount(): number {
846    return this.createCount;
847  }
848
849  public getMissCount(): number {
850    return this.missCount;
851  }
852
853  public getRemovalCount(): number {
854    return this.evictionCount;
855  }
856
857  public getMatchCount(): number {
858    return this.hitCount;
859  }
860
861  public getPutCount(): number {
862    return this.putCount;
863  }
864
865  public getCapacity(): number {
866    return this.maxSize;
867  }
868
869  public clear(): void {
870    this.afterRemoval(false, this.cache.keys(), this.cache.values(), null);
871    this.cache.clear();
872    this.length = this.cache.size;
873  }
874
875  public isEmpty(): boolean {
876    let temp: boolean = false;
877    if (this.cache.size === 0) {
878      temp = true;
879    }
880    return temp;
881  }
882
883  public contains(key: Object): boolean {
884    let flag: boolean = false;
885    if (this.cache.has(key)) {
886      flag = true;
887      let value: Object;
888      this.hitCount++;
889      value = this.cache.get(key);
890      this.cache.delete(key);
891      this.cache.set(key, value);
892      this.length = this.cache.size;
893      return flag;
894    }
895    this.missCount++;
896    return flag;
897  }
898
899  public remove(key: Object): Object {
900    if (key === null) {
901      throw new Error('key not be null');
902    } else if (this.cache.has(key)) {
903      let former: Object;
904      former = this.cache.get(key);
905      this.cache.delete(key);
906      if (former !== null) {
907        this.afterRemoval(false, key, former, null);
908        this.length = this.cache.size;
909        return former;
910      }
911    }
912    this.length = this.cache.size;
913    return undefined;
914  }
915
916  public toString(): string {
917    let peek: number = 0;
918    let hitRate: number = 0;
919    peek = this.hitCount + this.missCount;
920    if (peek !== 0) {
921      // The value is 100 times larger
922      hitRate = 100 * this.hitCount / peek;
923    } else {
924      hitRate = 0;
925    }
926    let str: string = '';
927    str = 'Lrubuffer[ maxSize = ' + this.maxSize + ', hits = ' + this.hitCount +
928      ', misses = ' + this.missCount + ', hitRate = ' + hitRate + '% ]';
929    return str;
930  }
931
932  public values(): Object[] {
933    let arr: Array<Object> = [];
934    for (let value of this.cache.values()) {
935      arr.push(value);
936    }
937    return arr;
938  }
939
940  public keys(): Object[] {
941    let arr: Array<Object> = Array.from(this.cache.keys());
942    return arr;
943  }
944
945  protected afterRemoval(isEvict: boolean, key: Object | undefined | null, value: Object | undefined | null,
946    newValue: Object | undefined | null): void {
947  }
948
949  protected createDefault(key: Object): Object {
950    return undefined;
951  }
952
953  public entries(): IterableIterator<[Object, Object]> {
954    return this.cache.entries();
955  }
956
957  public [Symbol.iterator](): IterableIterator<[Object, Object]> {
958    return this.cache.entries();
959  }
960
961  private changeCapacity(newCapacity: number): void {
962    while (this.cache.size > newCapacity) {
963      this.cache.delete(this.cache.keys().next().value);
964      this.evictionCount++;
965      this.afterRemoval(true, this.cache.keys(), this.cache.values(), null);
966    }
967  }
968}
969
970class LRUCache {
971  private cache: Map<Object | undefined, Object | undefined>;
972  // Default current size
973  private maxSize: number = 64;
974  // Default maximum size
975  private maxNumber: number = 2147483647;
976  private putCount: number = 0;
977  private createCount: number = 0;
978  private evictionCount: number = 0;
979  private hitCount: number = 0;
980  private missCount: number = 0;
981  public length: number = 0;
982
983  public constructor(capacity?: number) {
984    if (capacity !== undefined && capacity !== null) {
985      if (capacity <= 0 || capacity % 1 !== 0 || capacity > this.maxNumber) {
986        let error = new BusinessError(`Parameter error. The type of ${capacity} must be small integer`);
987        throw error;
988      }
989      this.maxSize = capacity;
990    }
991    this.cache = new Map();
992  }
993
994  private changeCapacity(newCapacity: number): void {
995    while (this.cache.size > newCapacity) {
996      this.cache.delete(this.cache.keys().next().value);
997      this.evictionCount++;
998      this.afterRemoval(true, this.cache.keys(), this.cache.values(), null);
999    }
1000  }
1001
1002  protected afterRemoval(isEvict: boolean, key: Object | undefined | null, value: Object | undefined | null,
1003    newValue: Object | undefined | null): void {
1004  }
1005
1006  protected createDefault(key: Object): Object {
1007    if (typeof (key as Object) === 'undefined') {
1008      let error = new BusinessError(`Parameter error. The type of ${key} must be Object`);
1009      throw error;
1010    }
1011    return undefined;
1012  }
1013
1014  public updateCapacity(newCapacity: number): void {
1015    if (typeof newCapacity !== 'number') {
1016      let error = new BusinessError(`Parameter error. The type of ${newCapacity} must be number`);
1017      throw error;
1018    }
1019    if (newCapacity <= 0 || newCapacity % 1 !== 0 || newCapacity > this.maxNumber) {
1020      let error = new BusinessError(`Parameter error. The type of ${newCapacity} must be small integer`);
1021      throw error;
1022    } else if (this.cache.size > newCapacity) {
1023      this.changeCapacity(newCapacity);
1024    }
1025    this.length = this.cache.size;
1026    this.maxSize = newCapacity;
1027  }
1028
1029  public get(key: Object): Object {
1030    if (typeof (key as Object) === 'undefined' || key === null) {
1031      let error = new BusinessError(`Parameter error. The type of ${key} must be Object`);
1032      throw error;
1033    }
1034    let value: Object;
1035    if (this.cache.has(key)) {
1036      value = this.cache.get(key);
1037      this.hitCount++;
1038      this.cache.delete(key);
1039      this.cache.set(key, value);
1040      return value;
1041    }
1042
1043    this.missCount++;
1044    let createValue: Object = this.createDefault(key);
1045    if (createValue === undefined) {
1046      return undefined;
1047    } else {
1048      value = this.put(key, createValue);
1049      this.createCount++;
1050      if (value !== undefined) {
1051        this.put(key, value);
1052        this.afterRemoval(false, key, createValue, value);
1053        return value;
1054      }
1055      return createValue;
1056    }
1057  }
1058
1059  public put(key: Object, value: Object): Object {
1060    if (typeof (key as Object) === 'undefined') {
1061      let error = new BusinessError(`Parameter error. The type of ${key} must be Object`);
1062      throw error;
1063    }
1064    if (typeof (value as Object) === 'undefined') {
1065      let error = new BusinessError(`Parameter error. The type of ${value} must be Object`);
1066      throw error;
1067    }
1068    if (key === null || value === null) {
1069      let error = new BusinessError(`Parameter error. The type of key and value must be Object`);
1070      throw error;
1071    }
1072    let former: Object = undefined;
1073    this.putCount++;
1074    if (this.cache.has(key)) {
1075      former = this.cache.get(key);
1076      this.cache.delete(key);
1077      this.afterRemoval(false, key, former, value);
1078    } else if (this.cache.size >= this.maxSize) {
1079      this.afterRemoval(true, this.cache.keys().next().value, this.cache.values().next().value, null);
1080      this.cache.delete(this.cache.keys().next().value);
1081      this.evictionCount++;
1082    }
1083    this.cache.set(key, value);
1084    this.length = this.cache.size;
1085    former = this.cache.get(key);
1086    return former;
1087  }
1088
1089  public remove(key: Object): Object {
1090    if (typeof (key as Object) === 'undefined' || key === null) {
1091      let error = new BusinessError(`Parameter error. The type of ${key} must be Object`);
1092      throw error;
1093    }
1094    if (this.cache.has(key)) {
1095      let former: Object = this.cache.get(key);
1096      this.cache.delete(key);
1097      if (former !== null) {
1098        this.afterRemoval(false, key, former, null);
1099        this.length = this.cache.size;
1100        return former;
1101      }
1102    }
1103    this.length = this.cache.size;
1104    return undefined;
1105  }
1106
1107  public contains(key: Object): boolean {
1108    if (typeof (key as Object) === 'undefined') {
1109      let error = new BusinessError(`Parameter error. The type of ${key} must be Object`);
1110      throw error;
1111    }
1112    let flag: boolean = false;
1113    if (this.cache.has(key)) {
1114      flag = true;
1115      this.hitCount++;
1116      let value: Object = this.cache.get(key);
1117      this.cache.delete(key);
1118      this.cache.set(key, value);
1119      this.length = this.cache.size;
1120      return flag;
1121    }
1122    this.missCount++;
1123    return flag;
1124  }
1125
1126  public getCreateCount(): number {
1127    return this.createCount;
1128  }
1129
1130  public getMissCount(): number {
1131    return this.missCount;
1132  }
1133
1134  public getRemovalCount(): number {
1135    return this.evictionCount;
1136  }
1137
1138  public getMatchCount(): number {
1139    return this.hitCount;
1140  }
1141
1142  public getPutCount(): number {
1143    return this.putCount;
1144  }
1145
1146  public getCapacity(): number {
1147    return this.maxSize;
1148  }
1149
1150  public clear(): void {
1151    this.afterRemoval(false, this.cache.keys(), this.cache.values(), null);
1152    this.cache.clear();
1153    this.length = this.cache.size;
1154  }
1155
1156  public isEmpty(): boolean {
1157    return this.cache.size === 0;
1158  }
1159
1160  public toString(): string {
1161    let peek: number = 0;
1162    let hitRate: number = 0;
1163    peek = this.hitCount + this.missCount;
1164    if (peek !== 0) {
1165      // The value is 100 times larger
1166      hitRate = 100 * this.hitCount / peek;
1167    }
1168    let str: string = '';
1169    str = 'LRUCache[ maxSize = ' + this.maxSize + ', hits = ' + this.hitCount +
1170      ', misses = ' + this.missCount + ', hitRate = ' + hitRate + '% ]';
1171    return str;
1172  }
1173
1174  public values(): Object[] {
1175    let arr: Array<Object> = [];
1176    for (let value of this.cache.values()) {
1177      arr.push(value);
1178    }
1179    return arr;
1180  }
1181
1182  public keys(): Object[] {
1183    let arr: Array<Object> = [];
1184    for (let key of this.cache.keys()) {
1185      arr.push(key);
1186    }
1187    return arr;
1188  }
1189
1190  public entries(): IterableIterator<[Object, Object]> {
1191    return this.cache.entries();
1192  }
1193
1194  public [Symbol.iterator](): IterableIterator<[Object, Object]> {
1195    return this.cache.entries();
1196  }
1197}
1198
1199class RationalNumber {
1200  private mnum: number = 0;
1201  private mden: number = 0;
1202
1203  public constructor();
1204  public constructor(num: number, den: number);
1205  public constructor(num?: number, den?: number) {
1206    if (num || den) {
1207      num = den < 0 ? num * (-1) : num;
1208      den = den < 0 ? den * (-1) : den;
1209      if (den === 0) {
1210        if (num > 0) {
1211          this.mnum = 1;
1212          this.mden = 0;
1213        } else if (num < 0) {
1214          this.mnum = -1;
1215          this.mden = 0;
1216        } else {
1217          this.mnum = 0;
1218          this.mden = 0;
1219        }
1220      } else if (num === 0) {
1221        this.mnum = 0;
1222        this.mden = 1;
1223      } else {
1224        let gnum: number = 0;
1225        gnum = this.getCommonDivisor(num, den);
1226        if (gnum !== 0) {
1227          this.mnum = num / gnum;
1228          this.mden = den / gnum;
1229        }
1230      }
1231    }
1232  }
1233
1234  static isNumeric(str: string): boolean {
1235    return !isNaN(parseFloat(str)) && isFinite(+str);
1236  }
1237
1238  static parseRationalNumber(num: number, den: number): RationalNumber {
1239    if (typeof num !== 'number') {
1240      let error = new BusinessError(`Parameter error. The type of ${num} must be number`);
1241      throw error;
1242    }
1243    if (typeof den !== 'number') {
1244      let error = new BusinessError(`Parameter error. The type of ${den} must be number`);
1245      throw error;
1246    }
1247    if (!Number.isInteger(num) || !Number.isInteger(den)) {
1248      console.error('parseRationalNumber: The type of Parameter must be integer');
1249    }
1250    num = den < 0 ? num * (-1) : num;
1251    den = den < 0 ? den * (-1) : den;
1252    let ratNum = new RationalNumber();
1253    if (den === 0) {
1254      if (num > 0) {
1255        ratNum.mnum = 1;
1256        ratNum.mden = 0;
1257      } else if (num < 0) {
1258        ratNum.mnum = -1;
1259        ratNum.mden = 0;
1260      } else {
1261        ratNum.mnum = 0;
1262        ratNum.mden = 0;
1263      }
1264    } else if (num === 0) {
1265      ratNum.mnum = 0;
1266      ratNum.mden = 1;
1267    } else {
1268      let gnum: number = 0;
1269      gnum = this.getCommonFactor(num, den);
1270      if (gnum !== 0) {
1271        ratNum.mnum = num / gnum;
1272        ratNum.mden = den / gnum;
1273      }
1274    }
1275    return ratNum;
1276  }
1277
1278  static createRationalFromString(str: string): RationalNumber {
1279    if (typeof str !== 'string' || str === null) {
1280      let error = new BusinessError(`Parameter error. The type of ${str} must be string`);
1281      throw error;
1282    }
1283    let colon: number = str.indexOf(':');
1284    let semicolon: number = str.indexOf('/');
1285    if ((colon < 0 && semicolon < 0) || (colon > 0 && semicolon > 0)) {
1286      let error = new BusinessError(`Parameter error. The type of ${str} must be effective string`);
1287      throw error;
1288    }
1289    let index: number = (colon > 0) ? colon : semicolon;
1290    let str1: string = str.substr(0, index);
1291    let str2: string = str.substr(index + 1, str.length);
1292    if (RationalNumber.isNumeric(str1) && RationalNumber.isNumeric(str2)) {
1293      let num1: number = Number(str1);
1294      let num2: number = Number(str2);
1295      if (!Number.isInteger(num1) || !Number.isInteger(num2)) {
1296        console.error('createRationalFromString: The type of Parameter must be integer string');
1297      }
1298      return RationalNumber.parseRationalNumber(num1, num2);
1299    } else {
1300      let error = new BusinessError(`Parameter error. The type of ${str} must be character string`);
1301      throw error;
1302    }
1303  }
1304
1305  public compareTo(other: RationalNumber): number {
1306    if (this.mnum === other.mnum && this.mden === other.mden) {
1307      return 0;
1308    } else if (this.mnum === 0 && this.mden === 0) {
1309      return 1;
1310    } else if ((other.mnum === 0) && (other.mden === 0)) {
1311      return -1;
1312    } else if ((this.mden === 0 && this.mnum > 0) || (other.mden === 0 && other.mnum < 0)) {
1313      return 1;
1314    } else if ((this.mden === 0 && this.mnum < 0) || (other.mden === 0 && other.mnum > 0)) {
1315      return -1;
1316    }
1317    let thisnum: number = this.mnum * other.mden;
1318    let othernum: number = other.mnum * this.mden;
1319    if (thisnum < othernum) {
1320      return -1;
1321    } else if (thisnum > othernum) {
1322      return 1;
1323    } else {
1324      return 0;
1325    }
1326  }
1327
1328  public compare(other: RationalNumber): number {
1329    if (!(other instanceof RationalNumber)) {
1330      let error = new BusinessError(`Parameter error. The type of ${other} must be RationalNumber`);
1331      throw error;
1332    }
1333    if (this.mnum === other.mnum && this.mden === other.mden) {
1334      return 0;
1335    } else if (this.mnum === 0 && this.mden === 0) {
1336      return 1;
1337    } else if ((other.mnum === 0) && (other.mden === 0)) {
1338      return -1;
1339    } else if ((this.mden === 0 && this.mnum > 0) || (other.mden === 0 && other.mnum < 0)) {
1340      return 1;
1341    } else if ((this.mden === 0 && this.mnum < 0) || (other.mden === 0 && other.mnum > 0)) {
1342      return -1;
1343    }
1344    let thisnum: number = this.mnum * other.mden;
1345    let othernum: number = other.mnum * this.mden;
1346    if (thisnum < othernum) {
1347      return -1;
1348    } else if (thisnum > othernum) {
1349      return 1;
1350    } else {
1351      return 0;
1352    }
1353  }
1354
1355  public equals(obj: object): boolean {
1356    if (!(obj instanceof RationalNumber)) {
1357      return false;
1358    }
1359    let thisnum: number = this.mnum * obj.mden;
1360    let objnum: number = obj.mnum * this.mden;
1361    if (this.mnum === obj.mnum && this.mden === obj.mden) {
1362      return true;
1363    } else if ((thisnum === objnum) && (this.mnum !== 0 && this.mden !== 0) && (obj.mnum !== 0 && obj.mden !== 0)) {
1364      return true;
1365    } else if ((this.mnum === 0 && this.mden !== 0) && (obj.mnum === 0 && obj.mden !== 0)) {
1366      return true;
1367    } else if ((this.mnum > 0 && this.mden === 0) && (obj.mnum > 0 && obj.mden === 0)) {
1368      return true;
1369    } else if ((this.mnum < 0 && this.mden === 0) && (obj.mnum < 0 && obj.mden === 0)) {
1370      return true;
1371    } else {
1372      return false;
1373    }
1374  }
1375
1376  public valueOf(): number {
1377    if (this.mnum > 0 && this.mden === 0) {
1378      return Number.POSITIVE_INFINITY;
1379    } else if (this.mnum < 0 && this.mden === 0) {
1380      return Number.NEGATIVE_INFINITY;
1381    } else if ((this.mnum === 0) && (this.mden === 0)) {
1382      return Number.NaN;
1383    } else {
1384      return this.mnum / this.mden;
1385    }
1386  }
1387
1388  public getCommonDivisor(number1: number, number2: number): number {
1389    if (number1 === 0 || number2 === 0) {
1390      throw new Error('Parameter cannot be zero!');
1391    }
1392    let temp: number = 0;
1393    if (number1 < number2) {
1394      temp = number1;
1395      number1 = number2;
1396      number2 = temp;
1397    }
1398    while (number1 % number2 !== 0) {
1399      temp = number1 % number2;
1400      number1 = number2;
1401      number2 = temp;
1402    }
1403    return number2;
1404  }
1405
1406  static getCommonFactor(firNum: number, SecNum: number): number {
1407    if (typeof firNum !== 'number') {
1408      let error = new BusinessError(`Parameter error. The type of ${firNum} must be number`);
1409      throw error;
1410    }
1411    if (typeof SecNum !== 'number') {
1412      let error = new BusinessError(`Parameter error. The type of ${SecNum} must be number`);
1413      throw error;
1414    }
1415    if (firNum === 0 || SecNum === 0) {
1416      let error = new BusinessError(`Parameter error. The Parameter cannot be zero`);
1417      throw error;
1418    }
1419    if (!Number.isInteger(firNum) || !Number.isInteger(SecNum) ) {
1420      console.error('getCommonFactor: The type of Parameter must be integer');
1421    }
1422
1423    let temp: number = 0;
1424    if (firNum < SecNum) {
1425      temp = firNum;
1426      firNum = SecNum;
1427      SecNum = temp;
1428    }
1429    while (firNum % SecNum !== 0) {
1430      temp = firNum % SecNum;
1431      firNum = SecNum;
1432      SecNum = temp;
1433    }
1434    return SecNum;
1435  }
1436
1437  public getDenominator(): number {
1438    return this.mden;
1439  }
1440
1441  public getNumerator(): number {
1442    return this.mnum;
1443  }
1444
1445  public isFinite(): boolean {
1446    return this.mden !== 0;
1447  }
1448
1449  public isNaN(): boolean {
1450    return this.mnum === 0 && this.mden === 0;
1451  }
1452
1453  public isZero(): boolean {
1454    return this.mnum === 0 && this.mden !== 0;
1455  }
1456
1457  public toString(): string {
1458    let buf: string;
1459    if (this.mnum === 0 && this.mden === 0) {
1460      buf = 'NaN';
1461    } else if (this.mnum > 0 && this.mden === 0) {
1462      buf = 'Infinity';
1463    } else if (this.mnum < 0 && this.mden === 0) {
1464      buf = '-Infinity';
1465    } else {
1466      buf = String(this.mnum) + '/' + String(this.mden);
1467    }
1468    return buf;
1469  }
1470}
1471
1472interface ScopeComparable {
1473  compareTo(other: ScopeComparable): boolean;
1474}
1475
1476type ScopeType = ScopeComparable;
1477
1478class Scope {
1479  private readonly _lowerLimit: ScopeType;
1480  private readonly _upperLimit: ScopeType;
1481
1482  public constructor(readonly lowerObj: ScopeType, readonly upperObj: ScopeType) {
1483    this.checkNull(lowerObj, 'lower limit not be null');
1484    this.checkNull(upperObj, 'upper limit not be null');
1485
1486    if (lowerObj.compareTo(upperObj)) {
1487      throw new Error('lower limit must be less than or equal to upper limit');
1488    }
1489    this._lowerLimit = lowerObj;
1490    this._upperLimit = upperObj;
1491  }
1492
1493  public getLower(): ScopeType {
1494    return this._lowerLimit;
1495  }
1496
1497  public getUpper(): ScopeType {
1498    return this._upperLimit;
1499  }
1500
1501  public compareTo(): boolean {
1502    return false;
1503  }
1504
1505  public contains(value: ScopeType): boolean;
1506  public contains(scope: Scope): boolean;
1507  public contains(x: Scope | ScopeType): boolean {
1508    let resLower: boolean;
1509    let resUpper: boolean;
1510    this.checkNull(x, 'value must not be null');
1511    if (x instanceof Scope) {
1512      resLower = x._lowerLimit.compareTo(this._lowerLimit);
1513      resUpper = this._upperLimit.compareTo(x._upperLimit);
1514    } else {
1515      resLower = x.compareTo(this._lowerLimit);
1516      resUpper = this._upperLimit.compareTo(x);
1517    }
1518    return resLower && resUpper;
1519  }
1520
1521  public clamp(value: ScopeType): ScopeType {
1522    this.checkNull(value, 'value must not be null');
1523    if (!value.compareTo(this._lowerLimit)) {
1524      return this._lowerLimit;
1525    } else if (value.compareTo(this._upperLimit)) {
1526      return this._upperLimit;
1527    } else {
1528      return value;
1529    }
1530  }
1531
1532  public intersect(scope: Scope): Scope;
1533  public intersect(lowerObj: ScopeType, upperObj: ScopeType): Scope;
1534  public intersect(x: Scope, y?: Scope | ScopeType): Scope {
1535    let reLower: boolean;
1536    let reUpper: boolean;
1537    let mLower: ScopeType;
1538    let mUpper: ScopeType;
1539    if (y) {
1540      this.checkNull(x, 'lower limit must not be null');
1541      this.checkNull(y, 'upper limit must not be null');
1542      reLower = this._lowerLimit.compareTo(x);
1543      reUpper = y.compareTo(this._upperLimit);
1544      if (reLower && reUpper) {
1545        return this;
1546      } else {
1547        mLower = reLower ? this._lowerLimit : x;
1548        mUpper = reUpper ? this._upperLimit : y;
1549        return new Scope(mLower, mUpper);
1550      }
1551    } else {
1552      this.checkNull(x, 'scope must not be null');
1553      reLower = this._lowerLimit.compareTo(x._lowerLimit);
1554      reUpper = x._upperLimit.compareTo(this._upperLimit);
1555      if (!reLower && !reUpper) {
1556        return x;
1557      } else if (reLower && reUpper) {
1558        return this;
1559      } else {
1560        mLower = reLower ? this._lowerLimit : x._lowerLimit;
1561        mUpper = reUpper ? this._upperLimit : x._upperLimit;
1562        return new Scope(mLower, mUpper);
1563      }
1564    }
1565  }
1566
1567  public expand(obj: ScopeType): Scope;
1568  public expand(scope: Scope): Scope;
1569  public expand(lowerObj: ScopeType, upperObj: ScopeType): Scope;
1570  public expand(x: ScopeType, y?: ScopeType): Scope {
1571    let reLower: boolean;
1572    let reUpper: boolean;
1573    let mLower: ScopeType;
1574    let mUpper: ScopeType;
1575    if (!y) {
1576      this.checkNull(x, 'value must not be null');
1577      if (!(x instanceof Scope)) {
1578        this.checkNull(x, 'value must not be null');
1579        return this.expand(x, x);
1580      }
1581      reLower = x._lowerLimit.compareTo(this._lowerLimit);
1582      reUpper = this._upperLimit.compareTo(x._upperLimit);
1583      if (reLower && reUpper) {
1584        return this;
1585      } else if (!reLower && !reUpper) {
1586        return x;
1587      } else {
1588        mLower = reLower ? this._lowerLimit : x._lowerLimit;
1589        mUpper = reUpper ? this._upperLimit : x._upperLimit;
1590        return new Scope(mLower, mUpper);
1591      }
1592
1593    } else {
1594      this.checkNull(x, 'lower limit must not be null');
1595      this.checkNull(y, 'upper limit must not be null');
1596      reLower = x.compareTo(this._lowerLimit);
1597      reUpper = this._upperLimit.compareTo(y);
1598      if (reLower && reUpper) {
1599        return this;
1600      }
1601      mLower = reLower ? this._lowerLimit : x;
1602      mUpper = reUpper ? this._upperLimit : y;
1603      return new Scope(mLower, mUpper);
1604    }
1605  }
1606
1607  public toString(): string {
1608    let strLower: string = this._lowerLimit.toString();
1609    let strUpper: string = this._upperLimit.toString();
1610    return `[${strLower}, ${strUpper}]`;
1611  }
1612
1613  public checkNull(o: ScopeType, str: string): void {
1614    if (o === null) {
1615      throw new Error(str);
1616    }
1617  }
1618}
1619
1620class ScopeHelper {
1621  private readonly _lowerLimit: ScopeType;
1622  private readonly _upperLimit: ScopeType;
1623  public constructor(readonly lowerObj: ScopeType, readonly upperObj: ScopeType) {
1624    if (typeof lowerObj !== 'object') {
1625      let error = new BusinessError(`Parameter error. The type of ${lowerObj} must be object`);
1626      throw error;
1627    }
1628    if (typeof upperObj !== 'object') {
1629      let error = new BusinessError(`Parameter error. The type of ${upperObj} must be object`);
1630      throw error;
1631    }
1632
1633    this.checkNull(lowerObj, 'lower limit not be null');
1634    this.checkNull(upperObj, 'upper limit not be null');
1635
1636    if (lowerObj.compareTo(upperObj)) {
1637      throw new Error('lower limit must be less than or equal to upper limit');
1638    }
1639    this._lowerLimit = lowerObj;
1640    this._upperLimit = upperObj;
1641  }
1642
1643  public getLower(): ScopeType {
1644    return this._lowerLimit;
1645  }
1646
1647  public getUpper(): ScopeType {
1648    return this._upperLimit;
1649  }
1650
1651  public compareTo(): boolean {
1652    return false;
1653  }
1654
1655  public contains(value: ScopeType): boolean;
1656  public contains(scope: ScopeHelper): boolean;
1657  public contains(x: ScopeHelper | ScopeType): boolean {
1658    this.checkNull(x, 'value must not be null');
1659    if (typeof x !== 'object') {
1660      let error = new BusinessError(`Parameter error. The type of ${x} must be object or ScopeHelper`);
1661      throw error;
1662    }
1663    let resLower: boolean;
1664    let resUpper: boolean;
1665    if (x instanceof ScopeHelper) {
1666      resLower = x._lowerLimit.compareTo(this._lowerLimit);
1667      resUpper = this._upperLimit.compareTo(x._upperLimit);
1668    } else {
1669      resLower = x.compareTo(this._lowerLimit);
1670      resUpper = this._upperLimit.compareTo(x);
1671    }
1672    return resLower && resUpper;
1673  }
1674
1675  public clamp(value: ScopeType): ScopeType {
1676    this.checkNull(value, 'value must not be null');
1677    if (typeof value !== 'object') {
1678      let error = new BusinessError(`Parameter error. The type of ${value} must be object`);
1679      throw error;
1680    }
1681
1682    if (!value.compareTo(this._lowerLimit)) {
1683      return this._lowerLimit;
1684    } else if (value.compareTo(this._upperLimit)) {
1685      return this._upperLimit;
1686    } else {
1687      return value;
1688    }
1689  }
1690
1691  public intersect(scope: ScopeHelper): ScopeHelper;
1692  public intersect(lowerObj: ScopeType, upperObj: ScopeType): ScopeHelper;
1693  public intersect(x: ScopeHelper, y?: ScopeType): ScopeHelper {
1694    if (typeof x !== 'object') {
1695      let error = new BusinessError(`Parameter error. The type of ${x} must be ScopeHelper or ScopeType`);
1696      throw error;
1697    }
1698    let reLower: boolean;
1699    let reUpper: boolean;
1700    let mLower: ScopeType;
1701    let mUpper: ScopeType;
1702    if (y) {
1703      this.checkNull(x, 'lower limit must not be null');
1704      this.checkNull(y, 'upper limit must not be null');
1705      if (typeof y !== 'object') {
1706        let error = new BusinessError(`Parameter error. The type of ${y} must be ScopeType`);
1707        throw error;
1708      }
1709      reLower = this._lowerLimit.compareTo(x);
1710      reUpper = y.compareTo(this._upperLimit);
1711      if (reLower && reUpper) {
1712        return this;
1713      } else {
1714        mLower = reLower ? this._lowerLimit : x;
1715        mUpper = reUpper ? this._upperLimit : y;
1716        return new ScopeHelper(mLower, mUpper);
1717      }
1718    } else {
1719      this.checkNull(x, 'scope must not be null');
1720      reLower = this._lowerLimit.compareTo(x._lowerLimit);
1721      reUpper = x._upperLimit.compareTo(this._upperLimit);
1722      if (!reLower && !reUpper) {
1723        return x;
1724      } else if (reLower && reUpper) {
1725        return this;
1726      } else {
1727        mLower = reLower ? this._lowerLimit : x._lowerLimit;
1728        mUpper = reUpper ? this._upperLimit : x._upperLimit;
1729        return new ScopeHelper(mLower, mUpper);
1730      }
1731    }
1732  }
1733
1734  public expand(obj: ScopeType): ScopeHelper;
1735  public expand(scope: ScopeHelper): ScopeHelper;
1736  public expand(lowerObj: ScopeType, upperObj: ScopeType): ScopeHelper;
1737  public expand(x: ScopeType, y?: ScopeType): ScopeHelper {
1738    if (typeof x !== 'object') {
1739      let error = new BusinessError(`Parameter error. The type of ${x} must be ScopeHelper or ScopeType`);
1740      throw error;
1741    }
1742    let reLower: boolean;
1743    let reUpper: boolean;
1744    let mLower: ScopeType;
1745    let mUpper: ScopeType;
1746    if (!y) {
1747      this.checkNull(x, 'value must not be null');
1748      if (!(x instanceof ScopeHelper)) {
1749        this.checkNull(x, 'value must not be null');
1750        return this.expand(x, x);
1751      }
1752      reLower = x._lowerLimit.compareTo(this._lowerLimit);
1753      reUpper = this._upperLimit.compareTo(x._upperLimit);
1754      if (reLower && reUpper) {
1755        return this;
1756      } else if (!reLower && !reUpper) {
1757        return x;
1758      } else {
1759        mLower = reLower ? this._lowerLimit : x._lowerLimit;
1760        mUpper = reUpper ? this._upperLimit : x._upperLimit;
1761        return new ScopeHelper(mLower, mUpper);
1762      }
1763
1764    } else {
1765      if (typeof y !== 'object') {
1766        let error = new BusinessError(`Parameter error. The type of ${y} must be ScopeType`);
1767        throw error;
1768      }
1769
1770      this.checkNull(x, 'lower limit must not be null');
1771      this.checkNull(y, 'upper limit must not be null');
1772      reLower = x.compareTo(this._lowerLimit);
1773      reUpper = this._upperLimit.compareTo(y);
1774      if (reLower && reUpper) {
1775        return this;
1776      }
1777      mLower = reLower ? this._lowerLimit : x;
1778      mUpper = reUpper ? this._upperLimit : y;
1779      return new ScopeHelper(mLower, mUpper);
1780    }
1781  }
1782
1783  public toString(): string {
1784    let strLower: string = this._lowerLimit.toString();
1785    let strUpper: string = this._upperLimit.toString();
1786    return `[${strLower}, ${strUpper}]`;
1787  }
1788
1789  public checkNull(o: ScopeType, str: string): void {
1790    if (o === null) {
1791      throw new Error(str);
1792    }
1793  }
1794}
1795
1796class Aspect {
1797  private static checkMethodType(func: Function, methodName: string): boolean {
1798    if (typeof func !== 'function') {
1799      let error = new BusinessError(`Parameter error. The type of ${methodName} must be a method of targetClass`);
1800      throw error;
1801    }
1802    return func.constructor.name === 'AsyncFunction';
1803  }
1804
1805  private static checkParameters(targetClass: Object, methodName: string, isStatic: boolean): void {
1806    if (typeof (targetClass as Object) === 'undefined') {
1807      let error = new BusinessError(`Parameter error. The type of ${targetClass} must be Object`);
1808      throw error;
1809    }
1810    if (typeof methodName !== 'string') {
1811      let error = new BusinessError(`Parameter error. The type of ${methodName} must be string`);
1812      throw error;
1813    }
1814    if (typeof isStatic !== 'boolean') {
1815      let error = new BusinessError(`Parameter error. The type of ${isStatic} must be boolean`);
1816      throw error;
1817    }
1818  }
1819
1820  static addBefore(targetClass: Object, methodName: string, isStatic: boolean, before: Function): void {
1821    Aspect.checkParameters(targetClass, methodName, isStatic);
1822    if (typeof before !== 'function') {
1823      let error = new BusinessError(`Parameter error. The type of ${before} must be function`);
1824      throw error;
1825    }
1826    let obj = isStatic ? targetClass : Reflect.get(targetClass, 'prototype');
1827    if (!obj) {
1828      return;
1829    }
1830    let oldFunc = obj[methodName];
1831    if (!Aspect.checkMethodType(oldFunc, methodName)) {
1832      let newFunc = function(...args : AnyType[]): AnyType {
1833        before(this, ...args);
1834        let ret = oldFunc.bind(this)(...args);
1835        return ret;
1836      };
1837      obj[methodName] = newFunc;
1838    } else {
1839      let newFunc = async function (...args : AnyType[]): Promise<AnyType> {
1840        before(this, ...args);
1841        let ret = oldFunc.bind(this)(...args);
1842        return ret;
1843      };
1844      obj[methodName] = newFunc;
1845    }
1846  }
1847
1848  static addAfter(targetClass: Object, methodName: string, isStatic: boolean, after: Function): void {
1849    Aspect.checkParameters(targetClass, methodName, isStatic);
1850    if (typeof after !== 'function') {
1851      let error = new BusinessError(`Parameter error. The type of ${after} should be function.`);
1852      throw error;
1853    }
1854    let obj = isStatic ? targetClass : Reflect.get(targetClass, 'prototype');
1855    if (!obj) {
1856      return;
1857    }
1858    let oldFunc = obj[methodName];
1859    if (!Aspect.checkMethodType(oldFunc, methodName)) {
1860      let newFunc = function(...args : AnyType[]): AnyType {
1861        let ret1 = oldFunc.bind(this)(...args);
1862        let ret2 = after(this, ret1, ...args);
1863        return ret2;
1864      };
1865      obj[methodName] = newFunc;
1866    } else {
1867      let newFunc = async function (...args : AnyType[]): Promise<AnyType> {
1868        let ret1 = oldFunc.bind(this)(...args);
1869        let ret2 = after(this, ret1, ...args);
1870        return ret2;
1871      };
1872      obj[methodName] = newFunc;
1873    }
1874  }
1875
1876  static replace(targetClass: Object, methodName: string, isStatic: boolean, instead: Function) : void {
1877    Aspect.checkParameters(targetClass, methodName, isStatic);
1878    if (typeof instead !== 'function') {
1879      let error = new BusinessError(`Parameter error. The type of ${instead} should be function.`);
1880      throw error;
1881    }
1882    let obj = isStatic ? targetClass : Reflect.get(targetClass, 'prototype');
1883    if (!obj) {
1884      return;
1885    }
1886    let oldFunc = obj[methodName];
1887    if (!Aspect.checkMethodType(oldFunc, methodName)) {
1888      let func = function(...args : AnyType[]): AnyType {
1889        let ret = instead(this, ...args);
1890        return ret;
1891      };
1892      obj[methodName] = func;
1893    } else {
1894      let func = async function (...args : AnyType[]): Promise<AnyType> {
1895        let ret = instead(this, ...args);
1896        return ret;
1897      };
1898      obj[methodName] = func;
1899    }
1900  }
1901}
1902
1903export default {
1904  printf: printf,
1905  format: format,
1906  getErrorString: getErrorString,
1907  errnoToString: errnoToString,
1908  callbackWrapper: callbackWrapper,
1909  promiseWrapper: promiseWrapper,
1910  promisify: promisify,
1911  randomUUID: randomUUID,
1912  randomBinaryUUID: randomBinaryUUID,
1913  generateRandomUUID: randomUUID,
1914  generateRandomBinaryUUID: randomBinaryUUID,
1915  parseUUID: parseUUID,
1916  getHash: getHash,
1917  TextEncoder: textEncoder,
1918  TextDecoder: TextDecoder,
1919  Base64: base64,
1920  Base64Helper: Base64Helper,
1921  types: types,
1922  LruBuffer: LruBuffer,
1923  LRUCache: LRUCache,
1924  RationalNumber: RationalNumber,
1925  Scope: Scope,
1926  ScopeHelper: ScopeHelper,
1927  Type: Type,
1928  Aspect: Aspect,
1929  StringDecoder: stringdecoder,
1930};
1931