@vulog/aima-unavailability 1.2.7 → 1.2.9
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/dist/index.d.mts +48 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +251 -0
- package/dist/index.mjs +218 -0
- package/package.json +3 -3
- package/src/createUnavailability.test.ts +1 -1
- package/src/deleteUnavailabilitiesByVehicle.test.ts +71 -0
- package/src/deleteUnavailabilitiesByVehicle.ts +28 -0
- package/src/deleteUnavailability.test.ts +4 -4
- package/src/deleteUnavailability.ts +2 -2
- package/src/getUnavailabilities.test.ts +2 -2
- package/src/getUnavailabilitiesByVehicle.test.ts +1 -1
- package/src/index.ts +1 -0
- package/src/types.ts +1 -1
- package/src/updateUnavailability.test.ts +3 -3
- package/src/updateUnavailability.ts +2 -2
- package/API_SUMMARY.md +0 -36
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
|
|
3
|
+
type Unavailability = {
|
|
4
|
+
id: number;
|
|
5
|
+
cronExpression: string;
|
|
6
|
+
duration: number;
|
|
7
|
+
maintenanceTitle: string;
|
|
8
|
+
vehicleId: string;
|
|
9
|
+
};
|
|
10
|
+
type CreateUnavailabilityBody = {
|
|
11
|
+
cronExpression: string;
|
|
12
|
+
duration: number;
|
|
13
|
+
maintenanceTitle: string;
|
|
14
|
+
vehicleId: string;
|
|
15
|
+
};
|
|
16
|
+
type UpdateUnavailabilityBody = CreateUnavailabilityBody;
|
|
17
|
+
type UnavailabilityOptions = {
|
|
18
|
+
from: string;
|
|
19
|
+
to: string;
|
|
20
|
+
page?: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
declare const getUnavailabilitiesByVehicle: (client: Client, vehicleId: string) => Promise<Unavailability[]>;
|
|
24
|
+
|
|
25
|
+
declare const getUnavailabilities: (client: Client, options: UnavailabilityOptions) => Promise<Unavailability[]>;
|
|
26
|
+
|
|
27
|
+
declare const createUnavailability: (client: Client, body: CreateUnavailabilityBody) => Promise<Unavailability>;
|
|
28
|
+
|
|
29
|
+
declare const updateUnavailability: (client: Client, id: number, body: UpdateUnavailabilityBody) => Promise<Unavailability>;
|
|
30
|
+
|
|
31
|
+
declare const deleteUnavailability: (client: Client, id: number) => Promise<void>;
|
|
32
|
+
|
|
33
|
+
declare const deleteUnavailabilitiesByVehicle: (client: Client, vehicleId: string) => Promise<void>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Generates a Quartz cron expression from a date.
|
|
37
|
+
* Format: second minute hour day month dayOfWeek year
|
|
38
|
+
* Example: "0 0 23 14 8 ? 2018"
|
|
39
|
+
*
|
|
40
|
+
* @param date - The date to convert to cron expression (Date object or ISO string)
|
|
41
|
+
* @param timezone - Optional timezone string (e.g., "Europe/Paris", "America/New_York")
|
|
42
|
+
* If provided, the date will be converted to the specified timezone.
|
|
43
|
+
* If not provided, the date will be used as-is.
|
|
44
|
+
* @returns A cron expression string in Quartz format
|
|
45
|
+
*/
|
|
46
|
+
declare const generateCronExpression: (date: Date | string, timezone?: string) => string;
|
|
47
|
+
|
|
48
|
+
export { type CreateUnavailabilityBody, type Unavailability, type UnavailabilityOptions, type UpdateUnavailabilityBody, createUnavailability, deleteUnavailabilitiesByVehicle, deleteUnavailability, generateCronExpression, getUnavailabilities, getUnavailabilitiesByVehicle, updateUnavailability };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
|
|
3
|
+
type Unavailability = {
|
|
4
|
+
id: number;
|
|
5
|
+
cronExpression: string;
|
|
6
|
+
duration: number;
|
|
7
|
+
maintenanceTitle: string;
|
|
8
|
+
vehicleId: string;
|
|
9
|
+
};
|
|
10
|
+
type CreateUnavailabilityBody = {
|
|
11
|
+
cronExpression: string;
|
|
12
|
+
duration: number;
|
|
13
|
+
maintenanceTitle: string;
|
|
14
|
+
vehicleId: string;
|
|
15
|
+
};
|
|
16
|
+
type UpdateUnavailabilityBody = CreateUnavailabilityBody;
|
|
17
|
+
type UnavailabilityOptions = {
|
|
18
|
+
from: string;
|
|
19
|
+
to: string;
|
|
20
|
+
page?: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
declare const getUnavailabilitiesByVehicle: (client: Client, vehicleId: string) => Promise<Unavailability[]>;
|
|
24
|
+
|
|
25
|
+
declare const getUnavailabilities: (client: Client, options: UnavailabilityOptions) => Promise<Unavailability[]>;
|
|
26
|
+
|
|
27
|
+
declare const createUnavailability: (client: Client, body: CreateUnavailabilityBody) => Promise<Unavailability>;
|
|
28
|
+
|
|
29
|
+
declare const updateUnavailability: (client: Client, id: number, body: UpdateUnavailabilityBody) => Promise<Unavailability>;
|
|
30
|
+
|
|
31
|
+
declare const deleteUnavailability: (client: Client, id: number) => Promise<void>;
|
|
32
|
+
|
|
33
|
+
declare const deleteUnavailabilitiesByVehicle: (client: Client, vehicleId: string) => Promise<void>;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Generates a Quartz cron expression from a date.
|
|
37
|
+
* Format: second minute hour day month dayOfWeek year
|
|
38
|
+
* Example: "0 0 23 14 8 ? 2018"
|
|
39
|
+
*
|
|
40
|
+
* @param date - The date to convert to cron expression (Date object or ISO string)
|
|
41
|
+
* @param timezone - Optional timezone string (e.g., "Europe/Paris", "America/New_York")
|
|
42
|
+
* If provided, the date will be converted to the specified timezone.
|
|
43
|
+
* If not provided, the date will be used as-is.
|
|
44
|
+
* @returns A cron expression string in Quartz format
|
|
45
|
+
*/
|
|
46
|
+
declare const generateCronExpression: (date: Date | string, timezone?: string) => string;
|
|
47
|
+
|
|
48
|
+
export { type CreateUnavailabilityBody, type Unavailability, type UnavailabilityOptions, type UpdateUnavailabilityBody, createUnavailability, deleteUnavailabilitiesByVehicle, deleteUnavailability, generateCronExpression, getUnavailabilities, getUnavailabilitiesByVehicle, updateUnavailability };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
createUnavailability: () => createUnavailability,
|
|
24
|
+
deleteUnavailabilitiesByVehicle: () => deleteUnavailabilitiesByVehicle,
|
|
25
|
+
deleteUnavailability: () => deleteUnavailability,
|
|
26
|
+
generateCronExpression: () => generateCronExpression,
|
|
27
|
+
getUnavailabilities: () => getUnavailabilities,
|
|
28
|
+
getUnavailabilitiesByVehicle: () => getUnavailabilitiesByVehicle,
|
|
29
|
+
updateUnavailability: () => updateUnavailability
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(index_exports);
|
|
32
|
+
|
|
33
|
+
// src/getUnavailabilitiesByVehicle.ts
|
|
34
|
+
var import_zod = require("zod");
|
|
35
|
+
var schema = import_zod.z.object({
|
|
36
|
+
vehicleId: import_zod.z.string().trim().min(1).uuid()
|
|
37
|
+
});
|
|
38
|
+
var getUnavailabilitiesByVehicle = async (client, vehicleId) => {
|
|
39
|
+
const result = schema.safeParse({ vehicleId });
|
|
40
|
+
if (!result.success) {
|
|
41
|
+
throw new TypeError("Invalid args", {
|
|
42
|
+
cause: result.error.issues
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return client.get(
|
|
46
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability/vehicles/${result.data.vehicleId}`
|
|
47
|
+
).then(({ data }) => data).catch((error) => {
|
|
48
|
+
if (error.formattedError?.status === 404) {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
throw error;
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// src/getUnavailabilities.ts
|
|
56
|
+
var import_zod2 = require("zod");
|
|
57
|
+
var schema2 = import_zod2.z.object({
|
|
58
|
+
from: import_zod2.z.string().datetime({ offset: false, precision: 0 }),
|
|
59
|
+
to: import_zod2.z.string().datetime({ offset: false, precision: 0 }),
|
|
60
|
+
page: import_zod2.z.number().int().nonnegative().default(0)
|
|
61
|
+
});
|
|
62
|
+
var getUnavailabilities = async (client, options) => {
|
|
63
|
+
const result = schema2.safeParse({
|
|
64
|
+
from: options.from,
|
|
65
|
+
to: options.to,
|
|
66
|
+
page: options.page ?? 0
|
|
67
|
+
});
|
|
68
|
+
if (!result.success) {
|
|
69
|
+
throw new TypeError("Invalid args", {
|
|
70
|
+
cause: result.error.issues
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
const allUnavailabilities = [];
|
|
74
|
+
let currentPage = result.data.page;
|
|
75
|
+
let hasMorePages = true;
|
|
76
|
+
const MAX_PAGES = 50;
|
|
77
|
+
while (hasMorePages) {
|
|
78
|
+
if (currentPage >= MAX_PAGES) {
|
|
79
|
+
throw new Error(
|
|
80
|
+
`Maximum page limit (${MAX_PAGES}) reached. This might indicate an issue with the pagination or a very large dataset.`
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
const queryParams = new URLSearchParams({
|
|
84
|
+
from: result.data.from,
|
|
85
|
+
to: result.data.to,
|
|
86
|
+
page: currentPage.toString()
|
|
87
|
+
});
|
|
88
|
+
const unavailabilities = await client.get(
|
|
89
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability/vehicles?${queryParams.toString()}`
|
|
90
|
+
).then(({ data }) => data).catch((error) => {
|
|
91
|
+
if (error.formattedError?.status === 404) {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
throw error;
|
|
95
|
+
});
|
|
96
|
+
allUnavailabilities.push(...unavailabilities);
|
|
97
|
+
hasMorePages = unavailabilities.length > 0;
|
|
98
|
+
currentPage += 1;
|
|
99
|
+
}
|
|
100
|
+
return allUnavailabilities;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// src/createUnavailability.ts
|
|
104
|
+
var import_zod3 = require("zod");
|
|
105
|
+
var schema3 = import_zod3.z.object({
|
|
106
|
+
cronExpression: import_zod3.z.string().min(1),
|
|
107
|
+
duration: import_zod3.z.number().int().positive(),
|
|
108
|
+
maintenanceTitle: import_zod3.z.string().min(1),
|
|
109
|
+
vehicleId: import_zod3.z.string().uuid()
|
|
110
|
+
});
|
|
111
|
+
var createUnavailability = async (client, body) => {
|
|
112
|
+
const result = schema3.safeParse(body);
|
|
113
|
+
if (!result.success) {
|
|
114
|
+
throw new TypeError("Invalid args", {
|
|
115
|
+
cause: result.error.issues
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return client.post(
|
|
119
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability`,
|
|
120
|
+
{
|
|
121
|
+
cronExpression: result.data.cronExpression,
|
|
122
|
+
duration: result.data.duration,
|
|
123
|
+
maintenanceTitle: result.data.maintenanceTitle,
|
|
124
|
+
vehicleId: result.data.vehicleId
|
|
125
|
+
}
|
|
126
|
+
).then(({ data }) => data);
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
// src/updateUnavailability.ts
|
|
130
|
+
var import_zod4 = require("zod");
|
|
131
|
+
var schema4 = import_zod4.z.object({
|
|
132
|
+
id: import_zod4.z.number().int().positive(),
|
|
133
|
+
cronExpression: import_zod4.z.string().min(1),
|
|
134
|
+
duration: import_zod4.z.number().int().positive(),
|
|
135
|
+
maintenanceTitle: import_zod4.z.string().min(1),
|
|
136
|
+
vehicleId: import_zod4.z.string().uuid()
|
|
137
|
+
});
|
|
138
|
+
var updateUnavailability = async (client, id, body) => {
|
|
139
|
+
const result = schema4.safeParse({
|
|
140
|
+
id,
|
|
141
|
+
...body
|
|
142
|
+
});
|
|
143
|
+
if (!result.success) {
|
|
144
|
+
throw new TypeError("Invalid args", {
|
|
145
|
+
cause: result.error.issues
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return client.put(
|
|
149
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability/${result.data.id}`,
|
|
150
|
+
{
|
|
151
|
+
cronExpression: result.data.cronExpression,
|
|
152
|
+
duration: result.data.duration,
|
|
153
|
+
maintenanceTitle: result.data.maintenanceTitle,
|
|
154
|
+
vehicleId: result.data.vehicleId
|
|
155
|
+
}
|
|
156
|
+
).then(({ data }) => data);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// src/deleteUnavailability.ts
|
|
160
|
+
var import_zod5 = require("zod");
|
|
161
|
+
var schema5 = import_zod5.z.object({
|
|
162
|
+
id: import_zod5.z.number().int().positive()
|
|
163
|
+
});
|
|
164
|
+
var deleteUnavailability = async (client, id) => {
|
|
165
|
+
const result = schema5.safeParse({ id });
|
|
166
|
+
if (!result.success) {
|
|
167
|
+
throw new TypeError("Invalid args", {
|
|
168
|
+
cause: result.error.issues
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return client.delete(
|
|
172
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability/${result.data.id}`
|
|
173
|
+
).then(() => void 0).catch((error) => {
|
|
174
|
+
if (error.formattedError?.status === 404) {
|
|
175
|
+
return void 0;
|
|
176
|
+
}
|
|
177
|
+
throw error;
|
|
178
|
+
});
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// src/deleteUnavailabilitiesByVehicle.ts
|
|
182
|
+
var import_zod6 = require("zod");
|
|
183
|
+
var schema6 = import_zod6.z.object({
|
|
184
|
+
vehicleId: import_zod6.z.string().trim().min(1).uuid()
|
|
185
|
+
});
|
|
186
|
+
var deleteUnavailabilitiesByVehicle = async (client, vehicleId) => {
|
|
187
|
+
const result = schema6.safeParse({ vehicleId });
|
|
188
|
+
if (!result.success) {
|
|
189
|
+
throw new TypeError("Invalid args", {
|
|
190
|
+
cause: result.error.issues
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
return client.delete(
|
|
194
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability/vehicles/${result.data.vehicleId}`
|
|
195
|
+
).then(() => void 0).catch((error) => {
|
|
196
|
+
if (error.formattedError?.status === 404) {
|
|
197
|
+
return void 0;
|
|
198
|
+
}
|
|
199
|
+
throw error;
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
// src/generateCronExpression.ts
|
|
204
|
+
var generateCronExpression = (date, timezone) => {
|
|
205
|
+
let dateObj;
|
|
206
|
+
if (typeof date === "string") {
|
|
207
|
+
dateObj = new Date(date);
|
|
208
|
+
} else {
|
|
209
|
+
dateObj = new Date(date);
|
|
210
|
+
}
|
|
211
|
+
if (Number.isNaN(dateObj.getTime())) {
|
|
212
|
+
throw new TypeError("Invalid date provided");
|
|
213
|
+
}
|
|
214
|
+
if (timezone) {
|
|
215
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
216
|
+
timeZone: timezone,
|
|
217
|
+
year: "numeric",
|
|
218
|
+
month: "2-digit",
|
|
219
|
+
day: "2-digit",
|
|
220
|
+
hour: "2-digit",
|
|
221
|
+
minute: "2-digit",
|
|
222
|
+
second: "2-digit",
|
|
223
|
+
hour12: false
|
|
224
|
+
});
|
|
225
|
+
const parts = formatter.formatToParts(dateObj);
|
|
226
|
+
const year2 = parseInt(parts.find((p) => p.type === "year")?.value || "0", 10);
|
|
227
|
+
const month2 = parseInt(parts.find((p) => p.type === "month")?.value || "0", 10);
|
|
228
|
+
const day2 = parseInt(parts.find((p) => p.type === "day")?.value || "0", 10);
|
|
229
|
+
const hour2 = parseInt(parts.find((p) => p.type === "hour")?.value || "0", 10);
|
|
230
|
+
const minute2 = parseInt(parts.find((p) => p.type === "minute")?.value || "0", 10);
|
|
231
|
+
const second2 = parseInt(parts.find((p) => p.type === "second")?.value || "0", 10);
|
|
232
|
+
return `${second2} ${minute2} ${hour2} ${day2} ${month2} ? ${year2}`;
|
|
233
|
+
}
|
|
234
|
+
const year = dateObj.getFullYear();
|
|
235
|
+
const month = dateObj.getMonth() + 1;
|
|
236
|
+
const day = dateObj.getDate();
|
|
237
|
+
const hour = dateObj.getHours();
|
|
238
|
+
const minute = dateObj.getMinutes();
|
|
239
|
+
const second = dateObj.getSeconds();
|
|
240
|
+
return `${second} ${minute} ${hour} ${day} ${month} ? ${year}`;
|
|
241
|
+
};
|
|
242
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
243
|
+
0 && (module.exports = {
|
|
244
|
+
createUnavailability,
|
|
245
|
+
deleteUnavailabilitiesByVehicle,
|
|
246
|
+
deleteUnavailability,
|
|
247
|
+
generateCronExpression,
|
|
248
|
+
getUnavailabilities,
|
|
249
|
+
getUnavailabilitiesByVehicle,
|
|
250
|
+
updateUnavailability
|
|
251
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// src/getUnavailabilitiesByVehicle.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var schema = z.object({
|
|
4
|
+
vehicleId: z.string().trim().min(1).uuid()
|
|
5
|
+
});
|
|
6
|
+
var getUnavailabilitiesByVehicle = async (client, vehicleId) => {
|
|
7
|
+
const result = schema.safeParse({ vehicleId });
|
|
8
|
+
if (!result.success) {
|
|
9
|
+
throw new TypeError("Invalid args", {
|
|
10
|
+
cause: result.error.issues
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
return client.get(
|
|
14
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability/vehicles/${result.data.vehicleId}`
|
|
15
|
+
).then(({ data }) => data).catch((error) => {
|
|
16
|
+
if (error.formattedError?.status === 404) {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
throw error;
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
// src/getUnavailabilities.ts
|
|
24
|
+
import { z as z2 } from "zod";
|
|
25
|
+
var schema2 = z2.object({
|
|
26
|
+
from: z2.string().datetime({ offset: false, precision: 0 }),
|
|
27
|
+
to: z2.string().datetime({ offset: false, precision: 0 }),
|
|
28
|
+
page: z2.number().int().nonnegative().default(0)
|
|
29
|
+
});
|
|
30
|
+
var getUnavailabilities = async (client, options) => {
|
|
31
|
+
const result = schema2.safeParse({
|
|
32
|
+
from: options.from,
|
|
33
|
+
to: options.to,
|
|
34
|
+
page: options.page ?? 0
|
|
35
|
+
});
|
|
36
|
+
if (!result.success) {
|
|
37
|
+
throw new TypeError("Invalid args", {
|
|
38
|
+
cause: result.error.issues
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const allUnavailabilities = [];
|
|
42
|
+
let currentPage = result.data.page;
|
|
43
|
+
let hasMorePages = true;
|
|
44
|
+
const MAX_PAGES = 50;
|
|
45
|
+
while (hasMorePages) {
|
|
46
|
+
if (currentPage >= MAX_PAGES) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Maximum page limit (${MAX_PAGES}) reached. This might indicate an issue with the pagination or a very large dataset.`
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
const queryParams = new URLSearchParams({
|
|
52
|
+
from: result.data.from,
|
|
53
|
+
to: result.data.to,
|
|
54
|
+
page: currentPage.toString()
|
|
55
|
+
});
|
|
56
|
+
const unavailabilities = await client.get(
|
|
57
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability/vehicles?${queryParams.toString()}`
|
|
58
|
+
).then(({ data }) => data).catch((error) => {
|
|
59
|
+
if (error.formattedError?.status === 404) {
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
});
|
|
64
|
+
allUnavailabilities.push(...unavailabilities);
|
|
65
|
+
hasMorePages = unavailabilities.length > 0;
|
|
66
|
+
currentPage += 1;
|
|
67
|
+
}
|
|
68
|
+
return allUnavailabilities;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// src/createUnavailability.ts
|
|
72
|
+
import { z as z3 } from "zod";
|
|
73
|
+
var schema3 = z3.object({
|
|
74
|
+
cronExpression: z3.string().min(1),
|
|
75
|
+
duration: z3.number().int().positive(),
|
|
76
|
+
maintenanceTitle: z3.string().min(1),
|
|
77
|
+
vehicleId: z3.string().uuid()
|
|
78
|
+
});
|
|
79
|
+
var createUnavailability = async (client, body) => {
|
|
80
|
+
const result = schema3.safeParse(body);
|
|
81
|
+
if (!result.success) {
|
|
82
|
+
throw new TypeError("Invalid args", {
|
|
83
|
+
cause: result.error.issues
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return client.post(
|
|
87
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability`,
|
|
88
|
+
{
|
|
89
|
+
cronExpression: result.data.cronExpression,
|
|
90
|
+
duration: result.data.duration,
|
|
91
|
+
maintenanceTitle: result.data.maintenanceTitle,
|
|
92
|
+
vehicleId: result.data.vehicleId
|
|
93
|
+
}
|
|
94
|
+
).then(({ data }) => data);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// src/updateUnavailability.ts
|
|
98
|
+
import { z as z4 } from "zod";
|
|
99
|
+
var schema4 = z4.object({
|
|
100
|
+
id: z4.number().int().positive(),
|
|
101
|
+
cronExpression: z4.string().min(1),
|
|
102
|
+
duration: z4.number().int().positive(),
|
|
103
|
+
maintenanceTitle: z4.string().min(1),
|
|
104
|
+
vehicleId: z4.string().uuid()
|
|
105
|
+
});
|
|
106
|
+
var updateUnavailability = async (client, id, body) => {
|
|
107
|
+
const result = schema4.safeParse({
|
|
108
|
+
id,
|
|
109
|
+
...body
|
|
110
|
+
});
|
|
111
|
+
if (!result.success) {
|
|
112
|
+
throw new TypeError("Invalid args", {
|
|
113
|
+
cause: result.error.issues
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return client.put(
|
|
117
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability/${result.data.id}`,
|
|
118
|
+
{
|
|
119
|
+
cronExpression: result.data.cronExpression,
|
|
120
|
+
duration: result.data.duration,
|
|
121
|
+
maintenanceTitle: result.data.maintenanceTitle,
|
|
122
|
+
vehicleId: result.data.vehicleId
|
|
123
|
+
}
|
|
124
|
+
).then(({ data }) => data);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// src/deleteUnavailability.ts
|
|
128
|
+
import { z as z5 } from "zod";
|
|
129
|
+
var schema5 = z5.object({
|
|
130
|
+
id: z5.number().int().positive()
|
|
131
|
+
});
|
|
132
|
+
var deleteUnavailability = async (client, id) => {
|
|
133
|
+
const result = schema5.safeParse({ id });
|
|
134
|
+
if (!result.success) {
|
|
135
|
+
throw new TypeError("Invalid args", {
|
|
136
|
+
cause: result.error.issues
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return client.delete(
|
|
140
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability/${result.data.id}`
|
|
141
|
+
).then(() => void 0).catch((error) => {
|
|
142
|
+
if (error.formattedError?.status === 404) {
|
|
143
|
+
return void 0;
|
|
144
|
+
}
|
|
145
|
+
throw error;
|
|
146
|
+
});
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// src/deleteUnavailabilitiesByVehicle.ts
|
|
150
|
+
import { z as z6 } from "zod";
|
|
151
|
+
var schema6 = z6.object({
|
|
152
|
+
vehicleId: z6.string().trim().min(1).uuid()
|
|
153
|
+
});
|
|
154
|
+
var deleteUnavailabilitiesByVehicle = async (client, vehicleId) => {
|
|
155
|
+
const result = schema6.safeParse({ vehicleId });
|
|
156
|
+
if (!result.success) {
|
|
157
|
+
throw new TypeError("Invalid args", {
|
|
158
|
+
cause: result.error.issues
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
return client.delete(
|
|
162
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability/vehicles/${result.data.vehicleId}`
|
|
163
|
+
).then(() => void 0).catch((error) => {
|
|
164
|
+
if (error.formattedError?.status === 404) {
|
|
165
|
+
return void 0;
|
|
166
|
+
}
|
|
167
|
+
throw error;
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// src/generateCronExpression.ts
|
|
172
|
+
var generateCronExpression = (date, timezone) => {
|
|
173
|
+
let dateObj;
|
|
174
|
+
if (typeof date === "string") {
|
|
175
|
+
dateObj = new Date(date);
|
|
176
|
+
} else {
|
|
177
|
+
dateObj = new Date(date);
|
|
178
|
+
}
|
|
179
|
+
if (Number.isNaN(dateObj.getTime())) {
|
|
180
|
+
throw new TypeError("Invalid date provided");
|
|
181
|
+
}
|
|
182
|
+
if (timezone) {
|
|
183
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
184
|
+
timeZone: timezone,
|
|
185
|
+
year: "numeric",
|
|
186
|
+
month: "2-digit",
|
|
187
|
+
day: "2-digit",
|
|
188
|
+
hour: "2-digit",
|
|
189
|
+
minute: "2-digit",
|
|
190
|
+
second: "2-digit",
|
|
191
|
+
hour12: false
|
|
192
|
+
});
|
|
193
|
+
const parts = formatter.formatToParts(dateObj);
|
|
194
|
+
const year2 = parseInt(parts.find((p) => p.type === "year")?.value || "0", 10);
|
|
195
|
+
const month2 = parseInt(parts.find((p) => p.type === "month")?.value || "0", 10);
|
|
196
|
+
const day2 = parseInt(parts.find((p) => p.type === "day")?.value || "0", 10);
|
|
197
|
+
const hour2 = parseInt(parts.find((p) => p.type === "hour")?.value || "0", 10);
|
|
198
|
+
const minute2 = parseInt(parts.find((p) => p.type === "minute")?.value || "0", 10);
|
|
199
|
+
const second2 = parseInt(parts.find((p) => p.type === "second")?.value || "0", 10);
|
|
200
|
+
return `${second2} ${minute2} ${hour2} ${day2} ${month2} ? ${year2}`;
|
|
201
|
+
}
|
|
202
|
+
const year = dateObj.getFullYear();
|
|
203
|
+
const month = dateObj.getMonth() + 1;
|
|
204
|
+
const day = dateObj.getDate();
|
|
205
|
+
const hour = dateObj.getHours();
|
|
206
|
+
const minute = dateObj.getMinutes();
|
|
207
|
+
const second = dateObj.getSeconds();
|
|
208
|
+
return `${second} ${minute} ${hour} ${day} ${month} ? ${year}`;
|
|
209
|
+
};
|
|
210
|
+
export {
|
|
211
|
+
createUnavailability,
|
|
212
|
+
deleteUnavailabilitiesByVehicle,
|
|
213
|
+
deleteUnavailability,
|
|
214
|
+
generateCronExpression,
|
|
215
|
+
getUnavailabilities,
|
|
216
|
+
getUnavailabilitiesByVehicle,
|
|
217
|
+
updateUnavailability
|
|
218
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vulog/aima-unavailability",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.9",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/index.mjs",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
"author": "Vulog",
|
|
20
20
|
"license": "MIT",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@vulog/aima-client": "1.2.
|
|
23
|
-
"@vulog/aima-core": "1.2.
|
|
22
|
+
"@vulog/aima-client": "1.2.9",
|
|
23
|
+
"@vulog/aima-core": "1.2.9"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"zod": "^3.25.76"
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { describe, test, vi, expect, beforeEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { Client } from '@vulog/aima-client';
|
|
4
|
+
import { deleteUnavailabilitiesByVehicle } from './deleteUnavailabilitiesByVehicle';
|
|
5
|
+
|
|
6
|
+
describe('deleteUnavailabilitiesByVehicle', () => {
|
|
7
|
+
const deleteMock = vi.fn();
|
|
8
|
+
const client = {
|
|
9
|
+
delete: deleteMock,
|
|
10
|
+
clientOptions: {
|
|
11
|
+
fleetId: 'FLEET_ID',
|
|
12
|
+
},
|
|
13
|
+
} as unknown as Client;
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
vi.clearAllMocks();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('should return invalid args for invalid vehicleId', async () => {
|
|
20
|
+
const vehicleId = 'INVALID_VEHICLE_ID';
|
|
21
|
+
|
|
22
|
+
await expect(deleteUnavailabilitiesByVehicle(client, vehicleId)).rejects.toThrow('Invalid args');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('should handle 404 gracefully (idempotent)', async () => {
|
|
26
|
+
const vehicleId = '550e8400-e29b-41d4-a716-446655440000';
|
|
27
|
+
|
|
28
|
+
deleteMock.mockRejectedValueOnce({
|
|
29
|
+
formattedError: {
|
|
30
|
+
status: 404,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const result = await deleteUnavailabilitiesByVehicle(client, vehicleId);
|
|
35
|
+
expect(result).toBeUndefined();
|
|
36
|
+
expect(deleteMock).toBeCalledWith(
|
|
37
|
+
`/boapi/proxy/user/fleets/FLEET_ID/scheduledRules/unavailability/vehicles/${vehicleId}`
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test('should delete unavailabilities by vehicle successfully', async () => {
|
|
42
|
+
const vehicleId = '550e8400-e29b-41d4-a716-446655440000';
|
|
43
|
+
|
|
44
|
+
deleteMock.mockResolvedValueOnce({
|
|
45
|
+
data: undefined,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const result = await deleteUnavailabilitiesByVehicle(client, vehicleId);
|
|
49
|
+
expect(result).toBeUndefined();
|
|
50
|
+
expect(deleteMock).toBeCalledWith(
|
|
51
|
+
`/boapi/proxy/user/fleets/FLEET_ID/scheduledRules/unavailability/vehicles/${vehicleId}`
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('should throw error on non-404 errors', async () => {
|
|
56
|
+
const vehicleId = '550e8400-e29b-41d4-a716-446655440000';
|
|
57
|
+
|
|
58
|
+
deleteMock.mockRejectedValueOnce({
|
|
59
|
+
formattedError: {
|
|
60
|
+
status: 500,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
await expect(deleteUnavailabilitiesByVehicle(client, vehicleId)).rejects.toEqual({
|
|
65
|
+
formattedError: {
|
|
66
|
+
status: 500,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Client } from '@vulog/aima-client';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
|
|
4
|
+
const schema = z.object({
|
|
5
|
+
vehicleId: z.string().trim().min(1).uuid(),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const deleteUnavailabilitiesByVehicle = async (client: Client, vehicleId: string): Promise<void> => {
|
|
9
|
+
const result = schema.safeParse({ vehicleId });
|
|
10
|
+
if (!result.success) {
|
|
11
|
+
throw new TypeError('Invalid args', {
|
|
12
|
+
cause: result.error.issues,
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
return client
|
|
16
|
+
.delete(
|
|
17
|
+
`/boapi/proxy/user/fleets/${client.clientOptions.fleetId}/scheduledRules/unavailability/vehicles/${result.data.vehicleId}`
|
|
18
|
+
)
|
|
19
|
+
.then(() => undefined)
|
|
20
|
+
.catch((error) => {
|
|
21
|
+
// Handle 404 gracefully (idempotent - if vehicle has no unavailabilities, that's fine)
|
|
22
|
+
if (error.formattedError?.status === 404) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
@@ -17,13 +17,13 @@ describe('deleteUnavailability', () => {
|
|
|
17
17
|
});
|
|
18
18
|
|
|
19
19
|
test('should return invalid args for invalid id', async () => {
|
|
20
|
-
const id =
|
|
20
|
+
const id = -1;
|
|
21
21
|
|
|
22
22
|
await expect(deleteUnavailability(client, id)).rejects.toThrow('Invalid args');
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
test('should handle 404 gracefully (idempotent)', async () => {
|
|
26
|
-
const id =
|
|
26
|
+
const id = 123;
|
|
27
27
|
|
|
28
28
|
deleteMock.mockRejectedValueOnce({
|
|
29
29
|
formattedError: {
|
|
@@ -39,7 +39,7 @@ describe('deleteUnavailability', () => {
|
|
|
39
39
|
});
|
|
40
40
|
|
|
41
41
|
test('should delete unavailability successfully', async () => {
|
|
42
|
-
const id =
|
|
42
|
+
const id = 123;
|
|
43
43
|
|
|
44
44
|
deleteMock.mockResolvedValueOnce({
|
|
45
45
|
data: undefined,
|
|
@@ -53,7 +53,7 @@ describe('deleteUnavailability', () => {
|
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
test('should throw error on non-404 errors', async () => {
|
|
56
|
-
const id =
|
|
56
|
+
const id = 123;
|
|
57
57
|
|
|
58
58
|
deleteMock.mockRejectedValueOnce({
|
|
59
59
|
formattedError: {
|
|
@@ -2,10 +2,10 @@ import { Client } from '@vulog/aima-client';
|
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
4
|
const schema = z.object({
|
|
5
|
-
id: z.
|
|
5
|
+
id: z.number().int().positive(),
|
|
6
6
|
});
|
|
7
7
|
|
|
8
|
-
export const deleteUnavailability = async (client: Client, id:
|
|
8
|
+
export const deleteUnavailability = async (client: Client, id: number): Promise<void> => {
|
|
9
9
|
const result = schema.safeParse({ id });
|
|
10
10
|
if (!result.success) {
|
|
11
11
|
throw new TypeError('Invalid args', {
|
|
@@ -51,7 +51,7 @@ describe('getUnavailabilities', () => {
|
|
|
51
51
|
|
|
52
52
|
const mockResponsePage1: Unavailability[] = [
|
|
53
53
|
{
|
|
54
|
-
id:
|
|
54
|
+
id: 123,
|
|
55
55
|
cronExpression: '0 0 23 * * ? *',
|
|
56
56
|
duration: 60,
|
|
57
57
|
maintenanceTitle: 'GetAround booking 234535',
|
|
@@ -83,7 +83,7 @@ describe('getUnavailabilities', () => {
|
|
|
83
83
|
|
|
84
84
|
const mockResponse: Unavailability[] = [
|
|
85
85
|
{
|
|
86
|
-
id:
|
|
86
|
+
id: 123,
|
|
87
87
|
cronExpression: '0 0 23 * * ? *',
|
|
88
88
|
duration: 60,
|
|
89
89
|
maintenanceTitle: 'GetAround booking 234535',
|
|
@@ -41,7 +41,7 @@ describe('getUnavailabilitiesByVehicle', () => {
|
|
|
41
41
|
|
|
42
42
|
const mockResponse: Unavailability[] = [
|
|
43
43
|
{
|
|
44
|
-
id:
|
|
44
|
+
id: 123,
|
|
45
45
|
cronExpression: '0 0 23 * * ? *',
|
|
46
46
|
duration: 60,
|
|
47
47
|
maintenanceTitle: 'GetAround booking 234535',
|
package/src/index.ts
CHANGED
|
@@ -3,5 +3,6 @@ export { getUnavailabilities } from './getUnavailabilities';
|
|
|
3
3
|
export { createUnavailability } from './createUnavailability';
|
|
4
4
|
export { updateUnavailability } from './updateUnavailability';
|
|
5
5
|
export { deleteUnavailability } from './deleteUnavailability';
|
|
6
|
+
export { deleteUnavailabilitiesByVehicle } from './deleteUnavailabilitiesByVehicle';
|
|
6
7
|
export { generateCronExpression } from './generateCronExpression';
|
|
7
8
|
export * from './types';
|
package/src/types.ts
CHANGED
|
@@ -18,7 +18,7 @@ describe('updateUnavailability', () => {
|
|
|
18
18
|
});
|
|
19
19
|
|
|
20
20
|
test('should return invalid args for invalid id', async () => {
|
|
21
|
-
const id =
|
|
21
|
+
const id = -1;
|
|
22
22
|
const body = {
|
|
23
23
|
cronExpression: '0 0 23 * * ? *',
|
|
24
24
|
duration: 60,
|
|
@@ -30,7 +30,7 @@ describe('updateUnavailability', () => {
|
|
|
30
30
|
});
|
|
31
31
|
|
|
32
32
|
test('should return invalid args for invalid body', async () => {
|
|
33
|
-
const id =
|
|
33
|
+
const id = 123;
|
|
34
34
|
const body = {
|
|
35
35
|
cronExpression: '',
|
|
36
36
|
duration: -1,
|
|
@@ -42,7 +42,7 @@ describe('updateUnavailability', () => {
|
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
test('should update unavailability successfully', async () => {
|
|
45
|
-
const id =
|
|
45
|
+
const id = 123;
|
|
46
46
|
const body = {
|
|
47
47
|
cronExpression: '0 0 24 * * ? *',
|
|
48
48
|
duration: 120,
|
|
@@ -4,7 +4,7 @@ import { z } from 'zod';
|
|
|
4
4
|
import { UpdateUnavailabilityBody, Unavailability } from './types';
|
|
5
5
|
|
|
6
6
|
const schema = z.object({
|
|
7
|
-
id: z.
|
|
7
|
+
id: z.number().int().positive(),
|
|
8
8
|
cronExpression: z.string().min(1),
|
|
9
9
|
duration: z.number().int().positive(),
|
|
10
10
|
maintenanceTitle: z.string().min(1),
|
|
@@ -13,7 +13,7 @@ const schema = z.object({
|
|
|
13
13
|
|
|
14
14
|
export const updateUnavailability = async (
|
|
15
15
|
client: Client,
|
|
16
|
-
id:
|
|
16
|
+
id: number,
|
|
17
17
|
body: UpdateUnavailabilityBody
|
|
18
18
|
): Promise<Unavailability> => {
|
|
19
19
|
const result = schema.safeParse({
|
package/API_SUMMARY.md
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# Vulog Unavailability API Calls - Summary
|
|
2
|
-
|
|
3
|
-
## Implemented API Endpoints
|
|
4
|
-
|
|
5
|
-
### 1. GET `/boapi/proxy/user/fleets/{fleetId}/scheduledRules/unavailability/vehicles/{vehicleId}`
|
|
6
|
-
Lists all unavailability rules for a specific vehicle. Returns array of `Unavailability` objects. Returns empty array on 404.
|
|
7
|
-
|
|
8
|
-
### 2. GET `/boapi/proxy/user/fleets/{fleetId}/scheduledRules/unavailability/vehicles`
|
|
9
|
-
Lists unavailability rules with date range filtering and pagination. Query parameters: `from` (ISO date), `to` (ISO date), `page` (number). Automatically iterates through pages until no more results.
|
|
10
|
-
|
|
11
|
-
### 3. POST `/boapi/proxy/user/fleets/{fleetId}/scheduledRules/unavailability`
|
|
12
|
-
Creates a new unavailability rule. Request body: `{ cronExpression, duration, maintenanceTitle, vehicleId }`. Returns created `Unavailability` object.
|
|
13
|
-
|
|
14
|
-
### 4. PUT `/boapi/proxy/user/fleets/{fleetId}/scheduledRules/unavailability/{id}`
|
|
15
|
-
Updates an existing unavailability rule. Request body same as POST. Returns updated `Unavailability` object.
|
|
16
|
-
|
|
17
|
-
### 5. DELETE `/boapi/proxy/user/fleets/{fleetId}/scheduledRules/unavailability/{id}`
|
|
18
|
-
Deletes an unavailability rule by ID. Idempotent - returns successfully if already deleted (404).
|
|
19
|
-
|
|
20
|
-
## Utility Function
|
|
21
|
-
|
|
22
|
-
### `generateCronExpression(date: Date | string, timezone?: string): string`
|
|
23
|
-
Generates Quartz cron expression from a date. Supports timezone conversion. Format: `second minute hour day month ? year`.
|
|
24
|
-
|
|
25
|
-
## Type Definitions
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
type Unavailability = {
|
|
29
|
-
id: string;
|
|
30
|
-
cronExpression: string;
|
|
31
|
-
duration: number;
|
|
32
|
-
maintenanceTitle: string;
|
|
33
|
-
vehicleId: string;
|
|
34
|
-
};
|
|
35
|
-
```
|
|
36
|
-
|