homebridge-tydom 0.23.14 → 0.24.0
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/lib/accessories/garageDoorOpener.js +2 -2
- package/lib/accessories/smokeDetector.d.ts +5 -0
- package/lib/accessories/smokeDetector.js +72 -0
- package/lib/accessories/triggerSwitch.d.ts +1 -1
- package/lib/accessories/triggerSwitch.js +1 -1
- package/lib/controller.js +2 -2
- package/lib/helpers/accessory.d.ts +3 -15
- package/lib/helpers/accessory.js +9 -5
- package/lib/helpers/tydom.js +2 -1
- package/lib/typings/tydom.d.ts +4 -0
- package/lib/utils/error.d.ts +1 -0
- package/lib/utils/error.js +15 -0
- package/package.json +20 -20
|
@@ -242,7 +242,7 @@ const setupGarageDoorOpener = (accessory, controller) => {
|
|
|
242
242
|
};
|
|
243
243
|
exports.setupGarageDoorOpener = setupGarageDoorOpener;
|
|
244
244
|
const updateGarageDoorOpener = (accessory, _controller, updates, type) => {
|
|
245
|
-
const { context } = accessory;
|
|
245
|
+
const { context: _context } = accessory;
|
|
246
246
|
// const {state} = context as TydomAccessoryContext<State>;
|
|
247
247
|
// Process command updates
|
|
248
248
|
if (type === 'cdata') {
|
|
@@ -254,7 +254,7 @@ const updateGarageDoorOpener = (accessory, _controller, updates, type) => {
|
|
|
254
254
|
return;
|
|
255
255
|
}
|
|
256
256
|
updates.forEach((update) => {
|
|
257
|
-
const { name, value } = update;
|
|
257
|
+
const { name, value: _value } = update;
|
|
258
258
|
switch (name) {
|
|
259
259
|
default:
|
|
260
260
|
return;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { PlatformAccessory } from 'homebridge';
|
|
2
|
+
import TydomController from '../controller';
|
|
3
|
+
import type { TydomAccessoryContext } from '../typings/tydom';
|
|
4
|
+
export declare const setupSmokeDetector: (accessory: PlatformAccessory<TydomAccessoryContext>, controller: TydomController) => void;
|
|
5
|
+
export declare const updateSmokeDetector: (accessory: PlatformAccessory<TydomAccessoryContext>, _controller: TydomController, updates: Record<string, unknown>[]) => void;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.updateSmokeDetector = exports.setupSmokeDetector = void 0;
|
|
4
|
+
const hap_1 = require("../config/hap");
|
|
5
|
+
const accessory_1 = require("../helpers/accessory");
|
|
6
|
+
const tydom_1 = require("../helpers/tydom");
|
|
7
|
+
const debug_1 = require("../utils/debug");
|
|
8
|
+
const setupSmokeDetector = (accessory, controller) => {
|
|
9
|
+
const { context } = accessory;
|
|
10
|
+
const { client } = controller;
|
|
11
|
+
const { SmokeDetected, StatusLowBattery } = hap_1.Characteristic;
|
|
12
|
+
const { deviceId, endpointId } = context;
|
|
13
|
+
(0, accessory_1.setupAccessoryInformationService)(accessory, controller);
|
|
14
|
+
(0, accessory_1.setupAccessoryIdentifyHandler)(accessory, controller);
|
|
15
|
+
// Add the actual accessory Service
|
|
16
|
+
const service = (0, accessory_1.addAccessoryService)(accessory, hap_1.Service.SmokeSensor, `${accessory.displayName}`, true);
|
|
17
|
+
service
|
|
18
|
+
.getCharacteristic(SmokeDetected)
|
|
19
|
+
.setProps({
|
|
20
|
+
format: "bool" /* Formats.BOOL */
|
|
21
|
+
})
|
|
22
|
+
.on("get" /* CharacteristicEventTypes.GET */, async (callback) => {
|
|
23
|
+
(0, debug_1.debugGet)(SmokeDetected, service);
|
|
24
|
+
try {
|
|
25
|
+
const data = await (0, tydom_1.getTydomDeviceData)(client, { deviceId, endpointId });
|
|
26
|
+
const smokeDefect = (0, tydom_1.getTydomDataPropValue)(data, 'techSmokeDefect');
|
|
27
|
+
(0, debug_1.debugGetResult)(SmokeDetected, service, smokeDefect);
|
|
28
|
+
callback(null, smokeDefect);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
callback(err);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
service
|
|
35
|
+
.getCharacteristic(StatusLowBattery)
|
|
36
|
+
.on("get" /* CharacteristicEventTypes.GET */, async (callback) => {
|
|
37
|
+
(0, debug_1.debugGet)(StatusLowBattery, service);
|
|
38
|
+
try {
|
|
39
|
+
const data = await (0, tydom_1.getTydomDeviceData)(client, { deviceId, endpointId });
|
|
40
|
+
const battDefect = (0, tydom_1.getTydomDataPropValue)(data, 'battDefect');
|
|
41
|
+
(0, debug_1.debugGetResult)(StatusLowBattery, service, battDefect);
|
|
42
|
+
callback(null, battDefect ? StatusLowBattery.BATTERY_LEVEL_LOW : StatusLowBattery.BATTERY_LEVEL_NORMAL);
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
callback(err);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
exports.setupSmokeDetector = setupSmokeDetector;
|
|
50
|
+
const updateSmokeDetector = (accessory, _controller, updates) => {
|
|
51
|
+
updates.forEach((update) => {
|
|
52
|
+
const { name, value } = update;
|
|
53
|
+
const { SmokeDetected, StatusLowBattery } = hap_1.Characteristic;
|
|
54
|
+
switch (name) {
|
|
55
|
+
case 'techSmokeDefect': {
|
|
56
|
+
const service = (0, accessory_1.getAccessoryService)(accessory, hap_1.Service.SmokeSensor);
|
|
57
|
+
(0, debug_1.debugSetUpdate)(SmokeDetected, service, value);
|
|
58
|
+
service.updateCharacteristic(SmokeDetected, value);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
case 'battDefect': {
|
|
62
|
+
const service = (0, accessory_1.getAccessoryService)(accessory, hap_1.Service.SmokeSensor);
|
|
63
|
+
(0, debug_1.debugSetUpdate)(StatusLowBattery, service, value);
|
|
64
|
+
service.updateCharacteristic(StatusLowBattery, value);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
default:
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
exports.updateSmokeDetector = updateSmokeDetector;
|
|
@@ -6,5 +6,5 @@ type TriggerSwitchSettings = {
|
|
|
6
6
|
};
|
|
7
7
|
type TriggerSwitchContext = TydomAccessoryContext<TriggerSwitchSettings>;
|
|
8
8
|
export declare const setupTriggerSwitch: (accessory: PlatformAccessory<TriggerSwitchContext>, controller: TydomController) => void;
|
|
9
|
-
export declare const updateTriggerSwitch: (
|
|
9
|
+
export declare const updateTriggerSwitch: (_accessory: PlatformAccessory<TriggerSwitchContext>, _controller: TydomController, _updates: Record<string, unknown>[]) => void;
|
|
10
10
|
export {};
|
|
@@ -42,7 +42,7 @@ const setupTriggerSwitch = (accessory, controller) => {
|
|
|
42
42
|
.updateValue(false);
|
|
43
43
|
};
|
|
44
44
|
exports.setupTriggerSwitch = setupTriggerSwitch;
|
|
45
|
-
const updateTriggerSwitch = (
|
|
45
|
+
const updateTriggerSwitch = (_accessory, _controller, _updates) => {
|
|
46
46
|
// no-op
|
|
47
47
|
};
|
|
48
48
|
exports.updateTriggerSwitch = updateTriggerSwitch;
|
package/lib/controller.js
CHANGED
|
@@ -10,6 +10,7 @@ const tydom_client_1 = require("tydom-client");
|
|
|
10
10
|
const env_1 = require("./config/env");
|
|
11
11
|
const tydom_1 = require("./helpers/tydom");
|
|
12
12
|
const utils_1 = require("./utils");
|
|
13
|
+
const error_1 = require("./utils/error");
|
|
13
14
|
const DEFAULT_REFRESH_INTERVAL_SEC = 4 * 60 * 60; // 4 hours
|
|
14
15
|
class TydomController extends events_1.EventEmitter {
|
|
15
16
|
constructor(log, config) {
|
|
@@ -30,8 +31,7 @@ class TydomController extends events_1.EventEmitter {
|
|
|
30
31
|
this.handleMessage(message);
|
|
31
32
|
}
|
|
32
33
|
catch (err) {
|
|
33
|
-
this.log.error(`Encountered an uncaught error while processing message=${(0, utils_1.chalkJson)(message)}"`);
|
|
34
|
-
this.log.debug(`${err instanceof Error ? err.stack : err}`);
|
|
34
|
+
this.log.error(`Encountered an uncaught error=${(0, error_1.stringifyError)(err)} while processing message=${(0, utils_1.chalkJson)(message)}"`);
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
37
|
this.client.on('connect', () => {
|
|
@@ -8,23 +8,11 @@ export declare const getAccessoryServiceWithSubtype: (accessory: PlatformAccesso
|
|
|
8
8
|
export declare const addAccessoryService: (accessory: PlatformAccessory, service: ServiceClass, name: string, removeExisting?: boolean) => Service;
|
|
9
9
|
export declare const addAccessoryServiceWithSubtype: (accessory: PlatformAccessory, service: ServiceClass, name: string, subtype: string, removeExisting?: boolean) => Service;
|
|
10
10
|
type TydomAccessorySetup<T extends TydomAccessoryContext> = (accessory: PlatformAccessory<T>, controller: TydomController) => void | Promise<void>;
|
|
11
|
-
export declare const getTydomAccessorySetup: <T extends TydomAccessoryContext<any, any> = TydomAccessoryContext<
|
|
12
|
-
[x: string]: unknown;
|
|
13
|
-
}, {
|
|
14
|
-
[x: string]: unknown;
|
|
15
|
-
}>>(accessory: PlatformAccessory<T>, context: T) => TydomAccessorySetup<T>;
|
|
11
|
+
export declare const getTydomAccessorySetup: <T extends TydomAccessoryContext<any, any> = TydomAccessoryContext>(accessory: PlatformAccessory<T>, context: T) => TydomAccessorySetup<T>;
|
|
16
12
|
export type TydomAccessoryUpdateType = 'data' | 'cdata';
|
|
17
13
|
type TydomAccessoryUpdate<T extends TydomAccessoryContext> = (accessory: PlatformAccessory<T>, controller: TydomController, updates: Record<string, unknown>[], type: TydomAccessoryUpdateType) => void | Promise<void>;
|
|
18
|
-
export declare const getTydomAccessoryDataUpdate: <T extends TydomAccessoryContext<any, any> = TydomAccessoryContext<
|
|
19
|
-
[x: string]: unknown;
|
|
20
|
-
}, {
|
|
21
|
-
[x: string]: unknown;
|
|
22
|
-
}>>(accessory: PlatformAccessory<T>, context: T) => TydomAccessoryUpdate<T>;
|
|
14
|
+
export declare const getTydomAccessoryDataUpdate: <T extends TydomAccessoryContext<any, any> = TydomAccessoryContext>(accessory: PlatformAccessory<T>, context: T) => TydomAccessoryUpdate<T>;
|
|
23
15
|
export declare const setupAccessoryInformationService: (accessory: PlatformAccessory, _controller: TydomController) => void;
|
|
24
16
|
export declare const setupAccessoryIdentifyHandler: (accessory: PlatformAccessory, _controller: TydomController) => void;
|
|
25
|
-
export declare const assignTydomContext: (prev: PlatformAccessory['context'], next: TydomAccessoryContext) => prev is TydomAccessoryContext
|
|
26
|
-
[x: string]: unknown;
|
|
27
|
-
}, {
|
|
28
|
-
[x: string]: unknown;
|
|
29
|
-
}>;
|
|
17
|
+
export declare const assignTydomContext: (prev: PlatformAccessory['context'], next: TydomAccessoryContext) => prev is TydomAccessoryContext;
|
|
30
18
|
export {};
|
package/lib/helpers/accessory.js
CHANGED
|
@@ -15,6 +15,7 @@ const thermostat_1 = require("../accessories/thermostat");
|
|
|
15
15
|
const windowCovering_1 = require("../accessories/windowCovering");
|
|
16
16
|
const hap_1 = require("../config/hap");
|
|
17
17
|
const utils_1 = require("../utils");
|
|
18
|
+
const smokeDetector_1 = require("../accessories/smokeDetector");
|
|
18
19
|
exports.SECURITY_SYSTEM_SENSORS = parseInt(`${11 /* Categories.SECURITY_SYSTEM */}0`);
|
|
19
20
|
const getAccessoryService = (accessory, ServiceClass) => {
|
|
20
21
|
const service = accessory.getService(ServiceClass);
|
|
@@ -23,7 +24,7 @@ const getAccessoryService = (accessory, ServiceClass) => {
|
|
|
23
24
|
};
|
|
24
25
|
exports.getAccessoryService = getAccessoryService;
|
|
25
26
|
const getAccessoryServiceWithSubtype = (accessory, ServiceClass, subtype) => {
|
|
26
|
-
const service = accessory.
|
|
27
|
+
const service = accessory.getServiceById(ServiceClass, subtype);
|
|
27
28
|
(0, utils_1.assert)(service, `Unexpected missing service "${ServiceClass.name}" with subtype="${subtype}" in accessory`);
|
|
28
29
|
return service;
|
|
29
30
|
};
|
|
@@ -36,6 +37,7 @@ const addAccessoryService = (accessory, service, name, removeExisting = false) =
|
|
|
36
37
|
}
|
|
37
38
|
accessory.removeService(existingService);
|
|
38
39
|
}
|
|
40
|
+
// @ts-expect-error legacy HAP API
|
|
39
41
|
return accessory.addService(service, name);
|
|
40
42
|
};
|
|
41
43
|
exports.addAccessoryService = addAccessoryService;
|
|
@@ -50,8 +52,9 @@ const addAccessoryServiceWithSubtype = (accessory, service, name, subtype, remov
|
|
|
50
52
|
return accessory.addService(service, name, subtype);
|
|
51
53
|
};
|
|
52
54
|
exports.addAccessoryServiceWithSubtype = addAccessoryServiceWithSubtype;
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
53
56
|
const getTydomAccessorySetup = (accessory, context) => {
|
|
54
|
-
var _a;
|
|
57
|
+
var _a, _b;
|
|
55
58
|
const { category } = accessory;
|
|
56
59
|
switch (category) {
|
|
57
60
|
case 5 /* Categories.LIGHTBULB */:
|
|
@@ -71,7 +74,7 @@ const getTydomAccessorySetup = (accessory, context) => {
|
|
|
71
74
|
case 11 /* Categories.SECURITY_SYSTEM */:
|
|
72
75
|
return securitySystem_1.setupSecuritySystem;
|
|
73
76
|
case 10 /* Categories.SENSOR */:
|
|
74
|
-
return temperatureSensor_1.setupTemperatureSensor;
|
|
77
|
+
return ((_b = context.settings) === null || _b === void 0 ? void 0 : _b.smokeDetector) ? smokeDetector_1.setupSmokeDetector : temperatureSensor_1.setupTemperatureSensor;
|
|
75
78
|
case 13 /* Categories.WINDOW */:
|
|
76
79
|
case 12 /* Categories.DOOR */:
|
|
77
80
|
return contactSensor_1.setupContactSensor;
|
|
@@ -82,8 +85,9 @@ const getTydomAccessorySetup = (accessory, context) => {
|
|
|
82
85
|
}
|
|
83
86
|
};
|
|
84
87
|
exports.getTydomAccessorySetup = getTydomAccessorySetup;
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
85
89
|
const getTydomAccessoryDataUpdate = (accessory, context) => {
|
|
86
|
-
var _a;
|
|
90
|
+
var _a, _b;
|
|
87
91
|
const { category } = accessory;
|
|
88
92
|
switch (category) {
|
|
89
93
|
case 5 /* Categories.LIGHTBULB */:
|
|
@@ -103,7 +107,7 @@ const getTydomAccessoryDataUpdate = (accessory, context) => {
|
|
|
103
107
|
case 11 /* Categories.SECURITY_SYSTEM */:
|
|
104
108
|
return securitySystem_1.updateSecuritySystem;
|
|
105
109
|
case 10 /* Categories.SENSOR */:
|
|
106
|
-
return temperatureSensor_1.updateTemperatureSensor;
|
|
110
|
+
return ((_b = context.settings) === null || _b === void 0 ? void 0 : _b.smokeDetector) ? smokeDetector_1.updateSmokeDetector : temperatureSensor_1.updateTemperatureSensor;
|
|
107
111
|
case 13 /* Categories.WINDOW */:
|
|
108
112
|
case 12 /* Categories.DOOR */:
|
|
109
113
|
return contactSensor_1.updateContactSensor;
|
package/lib/helpers/tydom.js
CHANGED
|
@@ -104,7 +104,8 @@ const ENDPOINTS_SIGNATURES_CATEGORIES = {
|
|
|
104
104
|
'others:449e2a60377094cde10224cee91d378fb0ae373ae6ceea0ac2cbc1ed011bffa7': 5 /* Categories.LIGHTBULB */,
|
|
105
105
|
'plug:2534c497ff8fb013a88da28d341adff5bc0ba77e1fc8ea8dcb8b8f1c9d62ce19': 7 /* Categories.OUTLET */,
|
|
106
106
|
'shutter:c3fe8e2afa864e1a7a5c6676b4287a7b2f2a886a466baec3df8a1ec4f898ad6c': 14 /* Categories.WINDOW_COVERING */,
|
|
107
|
-
'window:fb935867933d89b3058f09384f76fd63f3defb18cfb3172f60fa9f4f237f748b': 13 /* Categories.WINDOW
|
|
107
|
+
'window:fb935867933d89b3058f09384f76fd63f3defb18cfb3172f60fa9f4f237f748b': 13 /* Categories.WINDOW */,
|
|
108
|
+
'sensor:556f8aaf51e3807397b7e326d0aad4b61cceb8279166b50204f8a2e95464c9ba': [10 /* Categories.SENSOR */, { smokeDetector: true }] // DFR TYXAL+
|
|
108
109
|
};
|
|
109
110
|
const resolveEndpointCategory = ({ firstUsage, metadata, settings }) => {
|
|
110
111
|
// Compute device signature
|
package/lib/typings/tydom.d.ts
CHANGED
|
@@ -145,6 +145,10 @@ export type TydomDeviceSecuritySystemData = [
|
|
|
145
145
|
TydomDataElement<'irv3State', 'AVAILABLE' | 'UNAVAILABLE' | 'LOCKED'>,
|
|
146
146
|
TydomDataElement<'irv4State', 'AVAILABLE' | 'UNAVAILABLE' | 'LOCKED'>
|
|
147
147
|
];
|
|
148
|
+
export type TydomDeviceSmokeDetectorData = [
|
|
149
|
+
TydomDataElement<'techSmokeDefect', boolean>,
|
|
150
|
+
TydomDataElement<'battDefect', boolean>
|
|
151
|
+
];
|
|
148
152
|
export type TydomDeviceDataUpdateBody = {
|
|
149
153
|
id: number;
|
|
150
154
|
endpoints: {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const stringifyError: (err: Error | unknown) => string;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stringifyError = void 0;
|
|
4
|
+
const errorReplacer = (key, value) => {
|
|
5
|
+
if (value instanceof Error) {
|
|
6
|
+
return {
|
|
7
|
+
name: value.name,
|
|
8
|
+
message: value.message,
|
|
9
|
+
stack: value.stack
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
return `${value}`;
|
|
13
|
+
};
|
|
14
|
+
const stringifyError = (err) => JSON.stringify(err, errorReplacer);
|
|
15
|
+
exports.stringifyError = stringifyError;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-tydom",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Homebridge plugin to manage Tydom devices by Delta Dore",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -31,32 +31,32 @@
|
|
|
31
31
|
"prepublishOnly": "npm run build"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"chalk": "^4
|
|
34
|
+
"chalk": "^4",
|
|
35
35
|
"debug": "^4.3.4",
|
|
36
|
-
"fakegato-history": "^0.6.
|
|
36
|
+
"fakegato-history": "^0.6.4",
|
|
37
37
|
"lodash": "^4.17.21",
|
|
38
38
|
"source-map-support": "^0.5.21",
|
|
39
39
|
"tydom-client": "^0.13.4"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@tsconfig/node10": "^1.0.9",
|
|
43
|
-
"@types/debug": "^4.1.
|
|
44
|
-
"@types/jest": "^29.
|
|
45
|
-
"@types/lodash": "^4.14.
|
|
46
|
-
"@types/node": "^18.
|
|
47
|
-
"@types/node-persist": "^3.1.
|
|
48
|
-
"@types/ws": "^8.5.
|
|
49
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
50
|
-
"@typescript-eslint/parser": "^
|
|
51
|
-
"eslint": "^8.
|
|
52
|
-
"eslint-config-prettier": "^
|
|
53
|
-
"eslint-plugin-prettier": "^
|
|
54
|
-
"homebridge": "^1.
|
|
55
|
-
"jest": "^29.3
|
|
56
|
-
"nock": "^13.
|
|
57
|
-
"prettier": "^
|
|
43
|
+
"@types/debug": "^4.1.8",
|
|
44
|
+
"@types/jest": "^29.5.4",
|
|
45
|
+
"@types/lodash": "^4.14.197",
|
|
46
|
+
"@types/node": "^18.17.8",
|
|
47
|
+
"@types/node-persist": "^3.1.4",
|
|
48
|
+
"@types/ws": "^8.5.5",
|
|
49
|
+
"@typescript-eslint/eslint-plugin": "^6.4.1",
|
|
50
|
+
"@typescript-eslint/parser": "^6.4.1",
|
|
51
|
+
"eslint": "^8.47.0",
|
|
52
|
+
"eslint-config-prettier": "^9.0.0",
|
|
53
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
54
|
+
"homebridge": "^1.6.1",
|
|
55
|
+
"jest": "^29.6.3",
|
|
56
|
+
"nock": "^13.3.3",
|
|
57
|
+
"prettier": "^3.0.2",
|
|
58
58
|
"ts-node": "^10.9.1",
|
|
59
|
-
"tsc-alias": "^1.7
|
|
60
|
-
"typescript": "^
|
|
59
|
+
"tsc-alias": "^1.8.7",
|
|
60
|
+
"typescript": "^5.1.6"
|
|
61
61
|
}
|
|
62
62
|
}
|