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