@powfix/core-js 0.9.25 → 0.9.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -1
- package/.yarnrc +0 -1
- package/browser.ts +0 -73
- package/index.ts +0 -5
- package/src/constants/COORDINATE.ts +0 -9
- package/src/constants/DISTANCE.ts +0 -15
- package/src/constants/DURATION.ts +0 -18
- package/src/interfaces/Coordinate.ts +0 -9
- package/src/interfaces/Point2.ts +0 -4
- package/src/interfaces/Point3.ts +0 -5
- package/src/scripts/base64-polyfill.ts +0 -13
- package/src/services/Session.ts +0 -141
- package/src/services/browser.ts +0 -5
- package/src/services/index.ts +0 -4
- package/src/services/redis/RedisClient.ts +0 -79
- package/src/services/redis/RedisPublisher.ts +0 -48
- package/src/services/redis/RedisSubscriber.ts +0 -49
- package/src/services/redis/index.ts +0 -4
- package/src/services/time/TimeService.ts +0 -304
- package/src/services/time/index.ts +0 -1
- package/src/types/IntRage.ts +0 -5
- package/src/utils/ArrayUtils.ts +0 -25
- package/src/utils/BooleanUtils.ts +0 -4
- package/src/utils/CoordinateUtils.ts +0 -50
- package/src/utils/DateUtils.ts +0 -213
- package/src/utils/JuminNumberUtils.ts +0 -47
- package/src/utils/NumberUtils.ts +0 -23
- package/src/utils/Point3Utils.ts +0 -11
- package/src/utils/RandomUtils.ts +0 -62
- package/src/utils/Sequencer.ts +0 -178
- package/src/utils/StringUtils.ts +0 -43
- package/src/utils/UuidUtils.ts +0 -46
- package/src/utils/Validator.ts +0 -162
- package/src/utils/global/between.ts +0 -3
- package/src/utils/global/sleep.ts +0 -6
- package/tsconfig.json +0 -103
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powfix/core-js",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.26",
|
|
4
4
|
"description": "core package",
|
|
5
5
|
"author": "Kwon Kyung-Min <powfix@gmail.com>",
|
|
6
6
|
"private": false,
|
|
@@ -21,6 +21,9 @@
|
|
|
21
21
|
"clean": "rm -rf dist",
|
|
22
22
|
"build": "yarn clean && tsc -p . && git add dist"
|
|
23
23
|
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
24
27
|
"dependencies": {
|
|
25
28
|
"base-64": "^1.0.0",
|
|
26
29
|
"eventemitter3": "^5.0.1",
|
package/.yarnrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
registry https://nexus.vhd.kr/repository/yarn-proxy/
|
package/browser.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
/** @constants */
|
|
2
|
-
import {DURATION} from "./src/constants/DURATION";
|
|
3
|
-
import {DISTANCE} from "./src/constants/DISTANCE";
|
|
4
|
-
export {
|
|
5
|
-
DISTANCE,
|
|
6
|
-
DURATION,
|
|
7
|
-
};
|
|
8
|
-
|
|
9
|
-
/** @model */
|
|
10
|
-
import {Coordinate, CoordinateM} from "./src/interfaces/Coordinate";
|
|
11
|
-
import {Point2} from "./src/interfaces/Point2";
|
|
12
|
-
import {Point3} from "./src/interfaces/Point3";
|
|
13
|
-
export {
|
|
14
|
-
Coordinate,
|
|
15
|
-
CoordinateM,
|
|
16
|
-
Point2,
|
|
17
|
-
Point3,
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
/** @service */
|
|
21
|
-
import {Session, SessionOptions, StorageProvider} from "./src/services/Session";
|
|
22
|
-
export {
|
|
23
|
-
Session,
|
|
24
|
-
SessionOptions,
|
|
25
|
-
StorageProvider,
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/** @types */
|
|
29
|
-
import {IntRange} from "./src/types/IntRage";
|
|
30
|
-
export {
|
|
31
|
-
IntRange,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
/** @utils */
|
|
35
|
-
import {between} from "./src/utils/global/between";
|
|
36
|
-
import {sleep} from "./src/utils/global/sleep";
|
|
37
|
-
import {StringUtils} from "./src/utils/StringUtils";
|
|
38
|
-
import {NumberUtils} from "./src/utils/NumberUtils";
|
|
39
|
-
import {UuidUtils} from "./src/utils/UuidUtils";
|
|
40
|
-
import {ArrayUtils} from "./src/utils/ArrayUtils";
|
|
41
|
-
import {parseBoolean} from "./src/utils/BooleanUtils";
|
|
42
|
-
import {CoordinateUtils} from "./src/utils/CoordinateUtils";
|
|
43
|
-
import {DateUtils} from "./src/utils/DateUtils";
|
|
44
|
-
import {RandomUtils} from "./src/utils/RandomUtils";
|
|
45
|
-
import {Validator} from './src/utils/Validator';
|
|
46
|
-
import {JuminNumberUtils} from "./src/utils/JuminNumberUtils";
|
|
47
|
-
import {Sequence, Sequencer, SequencerEvent, SequencerOption, SequencerStatus} from "./src/utils/Sequencer";
|
|
48
|
-
import {base64Polyfill} from "./src/scripts/base64-polyfill";
|
|
49
|
-
export {
|
|
50
|
-
between,
|
|
51
|
-
sleep,
|
|
52
|
-
|
|
53
|
-
base64Polyfill,
|
|
54
|
-
UuidUtils,
|
|
55
|
-
ArrayUtils,
|
|
56
|
-
RandomUtils,
|
|
57
|
-
DateUtils,
|
|
58
|
-
StringUtils,
|
|
59
|
-
NumberUtils,
|
|
60
|
-
CoordinateUtils,
|
|
61
|
-
parseBoolean,
|
|
62
|
-
Validator,
|
|
63
|
-
JuminNumberUtils,
|
|
64
|
-
Sequence,
|
|
65
|
-
SequencerStatus,
|
|
66
|
-
SequencerOption,
|
|
67
|
-
SequencerEvent,
|
|
68
|
-
Sequencer,
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
// Directories
|
|
73
|
-
export * from './src/services/browser';
|
package/index.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
export class DISTANCE {
|
|
2
|
-
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export namespace DISTANCE {
|
|
6
|
-
export enum UNIT {
|
|
7
|
-
FEET = 'FEET',
|
|
8
|
-
KILOMETERS = 'KILOMETERS',
|
|
9
|
-
MILLIMETERS = 'MILLIMETERS',
|
|
10
|
-
CENTIMETERS = 'CENTIMETERS',
|
|
11
|
-
METERS = 'METERS',
|
|
12
|
-
MILES = 'MILES',
|
|
13
|
-
YARDS = 'YARDS',
|
|
14
|
-
}
|
|
15
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
export class DURATION {
|
|
2
|
-
|
|
3
|
-
}
|
|
4
|
-
|
|
5
|
-
export namespace DURATION {
|
|
6
|
-
export enum UNIT {
|
|
7
|
-
NANOSECONDS = 'NANOSECONDS',
|
|
8
|
-
MICROSECONDS = 'MICROSECONDS',
|
|
9
|
-
MILLISECONDS = 'MILLISECONDS',
|
|
10
|
-
SECONDS = 'SECONDS',
|
|
11
|
-
MINUTES = 'MINUTES',
|
|
12
|
-
HOURS = 'HOURS',
|
|
13
|
-
DAYS = 'DAYS',
|
|
14
|
-
YEARS = 'YEARS',
|
|
15
|
-
DECADES = 'DECADES',
|
|
16
|
-
CENTURIES = 'CENTURIES',
|
|
17
|
-
}
|
|
18
|
-
}
|
package/src/interfaces/Point2.ts
DELETED
package/src/interfaces/Point3.ts
DELETED
package/src/services/Session.ts
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import {jwtDecode, JwtPayload} from "jwt-decode";
|
|
2
|
-
import {AxiosInstance} from "axios";
|
|
3
|
-
import moment from "moment";
|
|
4
|
-
|
|
5
|
-
export interface SessionOptions {
|
|
6
|
-
api: AxiosInstance;
|
|
7
|
-
storageProvider: StorageProvider;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface StorageProvider {
|
|
11
|
-
key?: () => string;
|
|
12
|
-
set: (key: string, value: string) => Promise<void> | void;
|
|
13
|
-
get: (key: string) => Promise<string | null> | (string | null);
|
|
14
|
-
remove: (key: string) => Promise<void> | void;
|
|
15
|
-
clear?: () => Promise<void> | void;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const logWithTs = (...p: any) => {
|
|
19
|
-
console.log(Date.now(), ...p);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export class Session {
|
|
23
|
-
// Service parameters
|
|
24
|
-
protected api: AxiosInstance;
|
|
25
|
-
protected storageProvider: StorageProvider;
|
|
26
|
-
|
|
27
|
-
// Emitter
|
|
28
|
-
// private emitter = new EventEmitter({});
|
|
29
|
-
// public on = this.emitter.on;
|
|
30
|
-
// public off = this.emitter.off;
|
|
31
|
-
// private emit = this.emitter.emit;
|
|
32
|
-
|
|
33
|
-
public constructor(options: SessionOptions) {
|
|
34
|
-
// Init service parameters
|
|
35
|
-
console.log('Session initialized', Date.now(), options.api);
|
|
36
|
-
this.api = options.api;
|
|
37
|
-
this.storageProvider = options.storageProvider;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
private getKey(): string {
|
|
41
|
-
try {
|
|
42
|
-
if (this.storageProvider.key) {
|
|
43
|
-
return this.storageProvider.key();
|
|
44
|
-
}
|
|
45
|
-
} catch (e) {
|
|
46
|
-
console.error(e);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return Session.STORAGE_KEY.SESSION_AUTHORIZATION;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
public async hasAuthorization(): Promise<boolean> {
|
|
53
|
-
return !!(await this.getAuthorization());
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
public async getAuthorization(): Promise<string | null> {
|
|
57
|
-
return this.storageProvider.get(this.getKey());
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
public async setAuthorization(authorization?: string | null): Promise<string | null> {
|
|
61
|
-
if (authorization === null) {
|
|
62
|
-
await this.removeAuthorization();
|
|
63
|
-
return null;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
let nextAuthorization = await (async () => {
|
|
67
|
-
if (authorization === undefined) {
|
|
68
|
-
return await this.getAuthorization();
|
|
69
|
-
}
|
|
70
|
-
return authorization;
|
|
71
|
-
})();
|
|
72
|
-
|
|
73
|
-
if (!nextAuthorization) {
|
|
74
|
-
console.log('nextAuthorization is null or undefined');
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
try {
|
|
79
|
-
// Replace Bearer prefix
|
|
80
|
-
nextAuthorization = nextAuthorization.replace(/^Bearer\s+/, '');
|
|
81
|
-
|
|
82
|
-
const decoded = jwtDecode(nextAuthorization) as JwtPayload & {uuid: string};
|
|
83
|
-
if (!decoded) {
|
|
84
|
-
console.warn('JWT decode failed');
|
|
85
|
-
return null;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
console.log('Session:JWT decoded');
|
|
89
|
-
(() => {
|
|
90
|
-
console.log(' - User', decoded.uuid);
|
|
91
|
-
|
|
92
|
-
console.log(' - IAT', ...(() => {
|
|
93
|
-
if (!decoded.iat) {return [decoded.iat];}
|
|
94
|
-
const iat = moment.unix(decoded.iat);
|
|
95
|
-
if (!iat.isValid()) {return [decoded.iat];}
|
|
96
|
-
return [decoded.iat, iat.format(), iat.diff(Date.now(), 'days'), 'days left'];
|
|
97
|
-
})());
|
|
98
|
-
|
|
99
|
-
console.log(' - NBF', ...(() => {
|
|
100
|
-
if (!decoded.nbf) {return [decoded.nbf];}
|
|
101
|
-
const nbf = moment.unix(decoded.nbf);
|
|
102
|
-
if (!nbf.isValid()) {return [decoded.nbf];}
|
|
103
|
-
return [decoded.nbf, nbf.format(), nbf.diff(Date.now(), 'days'), 'days left'];
|
|
104
|
-
})());
|
|
105
|
-
|
|
106
|
-
console.log(' - EXP', ...(() => {
|
|
107
|
-
if (!decoded.exp) {return [decoded.exp];}
|
|
108
|
-
const exp = moment.unix(decoded.exp);
|
|
109
|
-
if (!exp.isValid()) {return [decoded.exp];}
|
|
110
|
-
return [decoded.exp, exp.format(), exp.diff(Date.now(), 'days'), 'days left'];
|
|
111
|
-
})());
|
|
112
|
-
})();
|
|
113
|
-
|
|
114
|
-
// AsyncStorage 에 토큰 저장
|
|
115
|
-
await this.storageProvider.set(this.getKey(), nextAuthorization);
|
|
116
|
-
|
|
117
|
-
// API Instance header 설정
|
|
118
|
-
this.api.defaults.headers.common.Authorization = `Bearer ${nextAuthorization}`;
|
|
119
|
-
|
|
120
|
-
// Return
|
|
121
|
-
return nextAuthorization;
|
|
122
|
-
} catch (e) {
|
|
123
|
-
console.error(e);
|
|
124
|
-
}
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
public async removeAuthorization() {
|
|
129
|
-
// API Instance header 에서 토큰 제거
|
|
130
|
-
delete this.api.defaults.headers.common.Authorization;
|
|
131
|
-
|
|
132
|
-
// 스토리지에서 authorization 제거
|
|
133
|
-
await this.storageProvider.remove(this.getKey());
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
export namespace Session {
|
|
138
|
-
export enum STORAGE_KEY {
|
|
139
|
-
SESSION_AUTHORIZATION = 'SESSION_AUTHORIZATION',
|
|
140
|
-
}
|
|
141
|
-
}
|
package/src/services/browser.ts
DELETED
package/src/services/index.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import redis, {
|
|
2
|
-
createClient,
|
|
3
|
-
RedisClientType,
|
|
4
|
-
RedisDefaultModules,
|
|
5
|
-
RedisFunctions,
|
|
6
|
-
RedisModules,
|
|
7
|
-
RedisScripts
|
|
8
|
-
} from 'redis';
|
|
9
|
-
|
|
10
|
-
const LOG_PREFIX = 'RedisClient';
|
|
11
|
-
|
|
12
|
-
export class RedisClient {
|
|
13
|
-
private readonly options: RedisClient.RedisClientOptions = {};
|
|
14
|
-
private status: RedisClient.Status = RedisClient.Status.STOPPED;
|
|
15
|
-
public readonly client: RedisClientType<RedisDefaultModules & RedisModules, RedisFunctions, RedisScripts>;
|
|
16
|
-
|
|
17
|
-
public constructor(options?: RedisClient.RedisClientOptions) {
|
|
18
|
-
console.log(Date.now(), LOG_PREFIX, 'initialized');
|
|
19
|
-
|
|
20
|
-
if (options) {
|
|
21
|
-
this.options = options;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (options?.redisOptions) {
|
|
25
|
-
this.client = createClient(options.redisOptions);
|
|
26
|
-
} else {
|
|
27
|
-
this.client = createClient({});
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
public async start(): Promise<RedisClient.Status> {
|
|
32
|
-
console.log(LOG_PREFIX, 'trying to start');
|
|
33
|
-
|
|
34
|
-
// register event callback
|
|
35
|
-
this.client.on('connect', this.handleOnConnect);
|
|
36
|
-
this.client.on('error', this.handleOnError);
|
|
37
|
-
|
|
38
|
-
await this.client.connect();
|
|
39
|
-
|
|
40
|
-
this.status = RedisClient.Status.RUNNING;
|
|
41
|
-
console.log(LOG_PREFIX, 'now started');
|
|
42
|
-
return this.status;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
public async stop(): Promise<RedisClient.Status> {
|
|
46
|
-
console.log(LOG_PREFIX, 'trying to stop');
|
|
47
|
-
|
|
48
|
-
// unregister event callback
|
|
49
|
-
this.client.off('connect', this.handleOnConnect);
|
|
50
|
-
this.client.off('error', this.handleOnError);
|
|
51
|
-
|
|
52
|
-
if (this.client.isOpen) {
|
|
53
|
-
await this.client.disconnect();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
this.status = RedisClient.Status.STOPPED;
|
|
57
|
-
console.log(LOG_PREFIX, 'now stopped');
|
|
58
|
-
return this.status;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private handleOnConnect() {
|
|
62
|
-
console.log(LOG_PREFIX, 'connected');
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
private handleOnError(error: Error) {
|
|
66
|
-
console.error(LOG_PREFIX, error);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export namespace RedisClient {
|
|
71
|
-
export enum Status {
|
|
72
|
-
RUNNING,
|
|
73
|
-
STOPPED,
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface RedisClientOptions {
|
|
77
|
-
redisOptions?: redis.RedisClientOptions;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import {RedisClient} from "./RedisClient";
|
|
2
|
-
|
|
3
|
-
export class RedisPublisher extends RedisClient {
|
|
4
|
-
private logging: RedisPublisher.LOGGING = 'length';
|
|
5
|
-
|
|
6
|
-
public constructor(options?: RedisClient.RedisClientOptions) {
|
|
7
|
-
super(options);
|
|
8
|
-
console.log(Date.now(), "RedisPublisher", 'initialized');
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
public async start(): Promise<RedisClient.Status> {
|
|
12
|
-
return await super.start();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
public async stop(): Promise<RedisClient.Status> {
|
|
16
|
-
return await super.stop();
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
public setLogging(logging: RedisPublisher.LOGGING) {
|
|
20
|
-
this.logging = logging;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
public getLogging(): RedisPublisher.LOGGING {
|
|
24
|
-
return this.logging;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Make public method
|
|
28
|
-
public publish = async (channel: string, data: string | object) => {
|
|
29
|
-
const stringifyData = typeof data !== 'string' ? JSON.stringify(data) : data;
|
|
30
|
-
|
|
31
|
-
switch (this.logging) {
|
|
32
|
-
case "none": {break;}
|
|
33
|
-
case "length": {
|
|
34
|
-
console.log(Date.now(), 'Server ---> Redis', channel, stringifyData.length);
|
|
35
|
-
break;
|
|
36
|
-
}
|
|
37
|
-
case "data": {
|
|
38
|
-
console.log(Date.now(), 'Server ---> Redis', channel, stringifyData);
|
|
39
|
-
break;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
await this.client.publish(channel, stringifyData);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export namespace RedisPublisher {
|
|
47
|
-
export type LOGGING = 'none' | 'length' | 'data';
|
|
48
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import {RedisClient} from "./RedisClient";
|
|
2
|
-
import {PubSubListener} from "@redis/client/dist/lib/client/pub-sub";
|
|
3
|
-
|
|
4
|
-
export class RedisSubscriber extends RedisClient {
|
|
5
|
-
public constructor(options?: RedisClient.RedisClientOptions) {
|
|
6
|
-
super(options);
|
|
7
|
-
console.log(Date.now(), 'Subscriber', 'initialized');
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
public subscribe = async <T extends boolean = false>(channels: string | string[], listener: PubSubListener<T>, bufferMode?: T | undefined) => {
|
|
11
|
-
for (const channel of Array.isArray(channels) ? channels : [channels]) {
|
|
12
|
-
if ((/\*/g).test(channel)) {
|
|
13
|
-
await this.client.pSubscribe(channel, listener, bufferMode);
|
|
14
|
-
} else {
|
|
15
|
-
await this.client.subscribe(channel, listener, bufferMode);
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
public unsubscribe = async <T extends boolean = false>(channels: string | string[], listener?: PubSubListener<T> | undefined, bufferMode?: T | undefined): Promise<void> => {
|
|
21
|
-
for (const channel of Array.isArray(channels) ? channels : [channels]) {
|
|
22
|
-
if ((/\*/g).test(channel)) {
|
|
23
|
-
await this.client.pUnsubscribe(channel, listener, bufferMode);
|
|
24
|
-
} else {
|
|
25
|
-
await this.client.unsubscribe(channel, listener, bufferMode);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
public async start(): Promise<RedisClient.Status> {
|
|
31
|
-
const status = await super.start();
|
|
32
|
-
await this.registerListeners();
|
|
33
|
-
return status;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
public async stop(): Promise<RedisClient.Status> {
|
|
37
|
-
const status = await super.stop();
|
|
38
|
-
await this.unregisterListeners();
|
|
39
|
-
return status;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
protected async registerListeners() {
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
protected async unregisterListeners() {
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
}
|