@rapidmx/mapi-plugin 1.0.0-beta.10
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/LICENSE +382 -0
- package/README.md +60 -0
- package/dist/lib/BaseMapiEmsmdbRoute.js +489 -0
- package/dist/lib/BaseMapiEmsmdbRoute.js.map +1 -0
- package/dist/lib/BaseMapiNspiRoute.js +114 -0
- package/dist/lib/BaseMapiNspiRoute.js.map +1 -0
- package/dist/lib/MapiSessionManager.js +475 -0
- package/dist/lib/MapiSessionManager.js.map +1 -0
- package/dist/lib/RegexPatternUtils.js +30 -0
- package/dist/lib/RegexPatternUtils.js.map +1 -0
- package/dist/lib/RopDispatcher.js +145 -0
- package/dist/lib/RopDispatcher.js.map +1 -0
- package/dist/lib/codec/AppointmentRecurrence.js +315 -0
- package/dist/lib/codec/AppointmentRecurrence.js.map +1 -0
- package/dist/lib/codec/BufferCursor.js +242 -0
- package/dist/lib/codec/BufferCursor.js.map +1 -0
- package/dist/lib/codec/GlobalObjectId.js +98 -0
- package/dist/lib/codec/GlobalObjectId.js.map +1 -0
- package/dist/lib/codec/MapiGuid.js +41 -0
- package/dist/lib/codec/MapiGuid.js.map +1 -0
- package/dist/lib/codec/MapiTimeZone.js +126 -0
- package/dist/lib/codec/MapiTimeZone.js.map +1 -0
- package/dist/lib/codec/PropertyValue.js +240 -0
- package/dist/lib/codec/PropertyValue.js.map +1 -0
- package/dist/lib/codec/RopBuffer.js +38 -0
- package/dist/lib/codec/RopBuffer.js.map +1 -0
- package/dist/lib/codec/TypedString.js +54 -0
- package/dist/lib/codec/TypedString.js.map +1 -0
- package/dist/lib/index.js +99 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/mongo/MapiEmsmdbRouteMongo.js +85 -0
- package/dist/lib/mongo/MapiEmsmdbRouteMongo.js.map +1 -0
- package/dist/lib/mongo/MapiNspiRouteMongo.js +33 -0
- package/dist/lib/mongo/MapiNspiRouteMongo.js.map +1 -0
- package/dist/lib/mongo/index.js +7 -0
- package/dist/lib/mongo/index.js.map +1 -0
- package/dist/lib/mongo.js +6 -0
- package/dist/lib/mongo.js.map +1 -0
- package/dist/lib/nspi/NspiBindHandler.js +54 -0
- package/dist/lib/nspi/NspiBindHandler.js.map +1 -0
- package/dist/lib/nspi/NspiCodec.js +106 -0
- package/dist/lib/nspi/NspiCodec.js.map +1 -0
- package/dist/lib/nspi/NspiGetMatchesHandler.js +142 -0
- package/dist/lib/nspi/NspiGetMatchesHandler.js.map +1 -0
- package/dist/lib/rop/AddressList.js +114 -0
- package/dist/lib/rop/AddressList.js.map +1 -0
- package/dist/lib/rop/CalendarEventTarget.js +30 -0
- package/dist/lib/rop/CalendarEventTarget.js.map +1 -0
- package/dist/lib/rop/CalendarNamedProperties.js +57 -0
- package/dist/lib/rop/CalendarNamedProperties.js.map +1 -0
- package/dist/lib/rop/ContactTarget.js +19 -0
- package/dist/lib/rop/ContactTarget.js.map +1 -0
- package/dist/lib/rop/ContentsTable.js +60 -0
- package/dist/lib/rop/ContentsTable.js.map +1 -0
- package/dist/lib/rop/ExecuteBudget.js +82 -0
- package/dist/lib/rop/ExecuteBudget.js.map +1 -0
- package/dist/lib/rop/FastTransferStream.js +195 -0
- package/dist/lib/rop/FastTransferStream.js.map +1 -0
- package/dist/lib/rop/FolderTarget.js +118 -0
- package/dist/lib/rop/FolderTarget.js.map +1 -0
- package/dist/lib/rop/HandleDataCache.js +412 -0
- package/dist/lib/rop/HandleDataCache.js.map +1 -0
- package/dist/lib/rop/MeetingMessageClassHandler.js +241 -0
- package/dist/lib/rop/MeetingMessageClassHandler.js.map +1 -0
- package/dist/lib/rop/MessageBodyStream.js +68 -0
- package/dist/lib/rop/MessageBodyStream.js.map +1 -0
- package/dist/lib/rop/MessageTarget.js +57 -0
- package/dist/lib/rop/MessageTarget.js.map +1 -0
- package/dist/lib/rop/NamedPropertyRegistry.js +69 -0
- package/dist/lib/rop/NamedPropertyRegistry.js.map +1 -0
- package/dist/lib/rop/PropertyResolvers.js +353 -0
- package/dist/lib/rop/PropertyResolvers.js.map +1 -0
- package/dist/lib/rop/RepoPaging.js +54 -0
- package/dist/lib/rop/RepoPaging.js.map +1 -0
- package/dist/lib/rop/RestapiRules.js +52 -0
- package/dist/lib/rop/RestapiRules.js.map +1 -0
- package/dist/lib/rop/RopCreateMessageHandler.js +55 -0
- package/dist/lib/rop/RopCreateMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopDeleteFolderHandler.js +174 -0
- package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -0
- package/dist/lib/rop/RopDeleteMessagesHandler.js +110 -0
- package/dist/lib/rop/RopDeleteMessagesHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js +61 -0
- package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js +60 -0
- package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js +76 -0
- package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js.map +1 -0
- package/dist/lib/rop/RopGetContentsTableHandler.js +55 -0
- package/dist/lib/rop/RopGetContentsTableHandler.js.map +1 -0
- package/dist/lib/rop/RopGetHierarchyTableHandler.js +42 -0
- package/dist/lib/rop/RopGetHierarchyTableHandler.js.map +1 -0
- package/dist/lib/rop/RopGetPropertiesSpecificHandler.js +56 -0
- package/dist/lib/rop/RopGetPropertiesSpecificHandler.js.map +1 -0
- package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js +92 -0
- package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js.map +1 -0
- package/dist/lib/rop/RopHandler.js +6 -0
- package/dist/lib/rop/RopHandler.js.map +1 -0
- package/dist/lib/rop/RopLogonHandler.js +135 -0
- package/dist/lib/rop/RopLogonHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenFolderHandler.js +48 -0
- package/dist/lib/rop/RopOpenFolderHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenMessageHandler.js +83 -0
- package/dist/lib/rop/RopOpenMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenStreamHandler.js +84 -0
- package/dist/lib/rop/RopOpenStreamHandler.js.map +1 -0
- package/dist/lib/rop/RopQueryRowsHandler.js +120 -0
- package/dist/lib/rop/RopQueryRowsHandler.js.map +1 -0
- package/dist/lib/rop/RopReadStreamHandler.js +73 -0
- package/dist/lib/rop/RopReadStreamHandler.js.map +1 -0
- package/dist/lib/rop/RopReleaseHandler.js +23 -0
- package/dist/lib/rop/RopReleaseHandler.js.map +1 -0
- package/dist/lib/rop/RopSaveChangesMessageHandler.js +269 -0
- package/dist/lib/rop/RopSaveChangesMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopSetColumnsHandler.js +50 -0
- package/dist/lib/rop/RopSetColumnsHandler.js.map +1 -0
- package/dist/lib/rop/RopSetPropertiesHandler.js +173 -0
- package/dist/lib/rop/RopSetPropertiesHandler.js.map +1 -0
- package/dist/lib/rop/RopSubmitMessageHandler.js +342 -0
- package/dist/lib/rop/RopSubmitMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopWriteStreamHandler.js +72 -0
- package/dist/lib/rop/RopWriteStreamHandler.js.map +1 -0
- package/dist/lib/rop/TaskNamedProperties.js +29 -0
- package/dist/lib/rop/TaskNamedProperties.js.map +1 -0
- package/dist/lib/rop/TaskTarget.js +15 -0
- package/dist/lib/rop/TaskTarget.js.map +1 -0
- package/dist/lib/rop/TransportSend.js +16 -0
- package/dist/lib/rop/TransportSend.js.map +1 -0
- package/dist/lib/sql/MapiEmsmdbRouteSQL.js +85 -0
- package/dist/lib/sql/MapiEmsmdbRouteSQL.js.map +1 -0
- package/dist/lib/sql/MapiNspiRouteSQL.js +33 -0
- package/dist/lib/sql/MapiNspiRouteSQL.js.map +1 -0
- package/dist/lib/sql/index.js +7 -0
- package/dist/lib/sql/index.js.map +1 -0
- package/dist/lib/sql.js +6 -0
- package/dist/lib/sql.js.map +1 -0
- package/dist/types/BaseMapiEmsmdbRoute.d.ts +139 -0
- package/dist/types/BaseMapiNspiRoute.d.ts +38 -0
- package/dist/types/MapiSessionManager.d.ts +285 -0
- package/dist/types/RegexPatternUtils.d.ts +14 -0
- package/dist/types/RopDispatcher.d.ts +53 -0
- package/dist/types/codec/AppointmentRecurrence.d.ts +14 -0
- package/dist/types/codec/BufferCursor.d.ts +92 -0
- package/dist/types/codec/GlobalObjectId.d.ts +15 -0
- package/dist/types/codec/MapiGuid.d.ts +6 -0
- package/dist/types/codec/MapiTimeZone.d.ts +7 -0
- package/dist/types/codec/PropertyValue.d.ts +87 -0
- package/dist/types/codec/RopBuffer.d.ts +32 -0
- package/dist/types/codec/TypedString.d.ts +17 -0
- package/dist/types/index.d.ts +94 -0
- package/dist/types/mongo/MapiEmsmdbRouteMongo.d.ts +20 -0
- package/dist/types/mongo/MapiNspiRouteMongo.d.ts +13 -0
- package/dist/types/mongo/index.d.ts +2 -0
- package/dist/types/mongo.d.ts +1 -0
- package/dist/types/nspi/NspiBindHandler.d.ts +22 -0
- package/dist/types/nspi/NspiCodec.d.ts +59 -0
- package/dist/types/nspi/NspiGetMatchesHandler.d.ts +26 -0
- package/dist/types/rop/AddressList.d.ts +48 -0
- package/dist/types/rop/CalendarEventTarget.d.ts +33 -0
- package/dist/types/rop/CalendarNamedProperties.d.ts +37 -0
- package/dist/types/rop/ContactTarget.d.ts +29 -0
- package/dist/types/rop/ContentsTable.d.ts +16 -0
- package/dist/types/rop/ExecuteBudget.d.ts +48 -0
- package/dist/types/rop/FastTransferStream.d.ts +57 -0
- package/dist/types/rop/FolderTarget.d.ts +64 -0
- package/dist/types/rop/HandleDataCache.d.ts +145 -0
- package/dist/types/rop/MeetingMessageClassHandler.d.ts +30 -0
- package/dist/types/rop/MessageBodyStream.d.ts +35 -0
- package/dist/types/rop/MessageTarget.d.ts +45 -0
- package/dist/types/rop/NamedPropertyRegistry.d.ts +50 -0
- package/dist/types/rop/PropertyResolvers.d.ts +86 -0
- package/dist/types/rop/RepoPaging.d.ts +30 -0
- package/dist/types/rop/RestapiRules.d.ts +32 -0
- package/dist/types/rop/RopCreateMessageHandler.d.ts +24 -0
- package/dist/types/rop/RopDeleteFolderHandler.d.ts +53 -0
- package/dist/types/rop/RopDeleteMessagesHandler.d.ts +43 -0
- package/dist/types/rop/RopFastTransferSourceCopyPropertiesHandler.d.ts +25 -0
- package/dist/types/rop/RopFastTransferSourceCopyToHandler.d.ts +25 -0
- package/dist/types/rop/RopFastTransferSourceGetBufferHandler.d.ts +22 -0
- package/dist/types/rop/RopGetContentsTableHandler.d.ts +25 -0
- package/dist/types/rop/RopGetHierarchyTableHandler.d.ts +18 -0
- package/dist/types/rop/RopGetPropertiesSpecificHandler.d.ts +26 -0
- package/dist/types/rop/RopGetPropertyIdsFromNamesHandler.d.ts +23 -0
- package/dist/types/rop/RopHandler.d.ts +106 -0
- package/dist/types/rop/RopLogonHandler.d.ts +31 -0
- package/dist/types/rop/RopOpenFolderHandler.d.ts +20 -0
- package/dist/types/rop/RopOpenMessageHandler.d.ts +28 -0
- package/dist/types/rop/RopOpenStreamHandler.d.ts +28 -0
- package/dist/types/rop/RopQueryRowsHandler.d.ts +43 -0
- package/dist/types/rop/RopReadStreamHandler.d.ts +20 -0
- package/dist/types/rop/RopReleaseHandler.d.ts +15 -0
- package/dist/types/rop/RopSaveChangesMessageHandler.d.ts +59 -0
- package/dist/types/rop/RopSetColumnsHandler.d.ts +21 -0
- package/dist/types/rop/RopSetPropertiesHandler.d.ts +38 -0
- package/dist/types/rop/RopSubmitMessageHandler.d.ts +80 -0
- package/dist/types/rop/RopWriteStreamHandler.d.ts +31 -0
- package/dist/types/rop/TaskNamedProperties.d.ts +24 -0
- package/dist/types/rop/TaskTarget.d.ts +24 -0
- package/dist/types/rop/TransportSend.d.ts +10 -0
- package/dist/types/sql/MapiEmsmdbRouteSQL.d.ts +20 -0
- package/dist/types/sql/MapiNspiRouteSQL.d.ts +13 -0
- package/dist/types/sql/index.d.ts +2 -0
- package/dist/types/sql.d.ts +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import { BufferReader, BufferWriter, DecodeError } from "./codec/BufferCursor.js";
|
|
6
|
+
import { ExecuteBudget, WorkBudgetExceededError } from "./rop/ExecuteBudget.js";
|
|
7
|
+
/** The most ROPs processed from one `Execute` request. A real client batches far fewer; anything past this is
|
|
8
|
+
* left unprocessed. */
|
|
9
|
+
export const MAX_ROPS_PER_EXECUTE = 1024;
|
|
10
|
+
/** The largest `RopsList` a response can carry: `RopSize` is a 16-bit count that includes its own 2 bytes. */
|
|
11
|
+
export const MAX_ROPS_LIST_BYTES = 0xffff - 2;
|
|
12
|
+
/** `RopBufferTooSmall`'s `RopId` (`[MS-OXCROPS]` §2.2.15.1). */
|
|
13
|
+
export const ROP_ID_BUFFER_TOO_SMALL = 0xff;
|
|
14
|
+
/** `MAPI_E_CALL_FAILED`: a ROP failed while running (a database error, undecodable stored data, ...). */
|
|
15
|
+
export const ERROR_CALL_FAILED = 0x80004005;
|
|
16
|
+
/** `MAPI_E_TOO_COMPLEX`: the ROP would have gone past this request's `ExecuteBudget`. */
|
|
17
|
+
export const ERROR_TOO_COMPLEX = 0x80040117;
|
|
18
|
+
/** `RopBufferTooSmall`'s fixed fields: `RopId` and `SizeNeeded`. */
|
|
19
|
+
const BUFFER_TOO_SMALL_HEADER_BYTES = 3;
|
|
20
|
+
/** Thrown by `dispatchRops`, before any ROP runs, when the room for responses can't even hold a `RopBufferTooSmall`
|
|
21
|
+
* carrying the whole request. The route answers the `Execute` with `ecBufferTooSmall` ([MS-OXCRPC]). No ROP has run. */
|
|
22
|
+
export class ExecuteBufferTooSmallError extends Error {
|
|
23
|
+
constructor() {
|
|
24
|
+
super("Execute: MaxRopOut is too small for even a RopBufferTooSmall response.");
|
|
25
|
+
this.name = "ExecuteBufferTooSmallError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Wraps `reader` so that running out of request bytes raises a `DecodeError` (a malformed request) rather than a
|
|
29
|
+
* plain `RangeError`, which a handler may also raise while working on data it read from somewhere else. */
|
|
30
|
+
function decodingReader(reader) {
|
|
31
|
+
return new Proxy(reader, {
|
|
32
|
+
get(target, property) {
|
|
33
|
+
const value = Reflect.get(target, property, target);
|
|
34
|
+
if (typeof value !== "function") {
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
return (...args) => {
|
|
38
|
+
try {
|
|
39
|
+
return value.apply(target, args);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
throw err instanceof RangeError && !(err instanceof DecodeError) ? new DecodeError(err.message) : err;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Walks a decoded `RopBuffer`'s `ropsList` blob, dispatching each contained ROP - identified by its own leading
|
|
50
|
+
* `RopId` byte - to the matching registered handler in turn, collecting every response into one output buffer.
|
|
51
|
+
* Deliberately ROP-agnostic: it knows nothing about any specific ROP's own fields, only how to find the *next* one,
|
|
52
|
+
* via the handler's own advanced `reader` position once `handle()` returns - see `RopBuffer.ts`'s doc comment for
|
|
53
|
+
* why a fully generic split isn't possible for this wire format.
|
|
54
|
+
*
|
|
55
|
+
* - **Malformed requests.** An unrecognized `RopId`, or a ROP whose bytes run out or can't be sized (a
|
|
56
|
+
* `DecodeError`), throws a `DecodeError`: nothing after it can be located, so the route answers 400.
|
|
57
|
+
* - **A failing ROP.** Any other error thrown by a handler fails just that ROP: its partial output is dropped, a
|
|
58
|
+
* failure response (`RopId`, the handle index it echoes, `ReturnValue` `MAPI_E_CALL_FAILED` or, past the
|
|
59
|
+
* `ExecuteBudget`, `MAPI_E_TOO_COMPLEX`) takes its place, and the following ROPs still run. The handler has
|
|
60
|
+
* already read its whole request by the time it does work that can fail, so the next ROP is still where the
|
|
61
|
+
* reader points.
|
|
62
|
+
* - **Output space.** Room for a `RopBufferTooSmall` covering the next ROP and everything after it (3 bytes plus
|
|
63
|
+
* those request bytes) is always kept free. `context.ropOutputRemaining` tells each handler the room left *after*
|
|
64
|
+
* that reserve (computed from where the reader stands, so once a handler has read its request it excludes the
|
|
65
|
+
* handler's own bytes). A response that doesn't leave the reserve is replaced by `RopBufferTooSmall` (`SizeNeeded`
|
|
66
|
+
* plus the unprocessed request bytes, from this ROP on, for the client to resend) and processing stops; that always
|
|
67
|
+
* fits, because the reserve for this ROP was kept by the one before it. Handlers that change state by how much they
|
|
68
|
+
* return (`RopQueryRows`, `RopReadStream`, `RopFastTransferSourceGetBuffer`) size their response to the room, so they
|
|
69
|
+
* are never replaced after moving a cursor. Only when the request as a whole can't be covered by a
|
|
70
|
+
* `RopBufferTooSmall` is `ExecuteBufferTooSmallError` thrown, before anything runs, and the route answers the
|
|
71
|
+
* `Execute` with `ecBufferTooSmall` ([MS-OXCRPC]). So a failed `Execute` never follows state already changed and
|
|
72
|
+
* saved, which a retry would skip past.
|
|
73
|
+
*
|
|
74
|
+
* @author Jean-Philippe Steinmetz
|
|
75
|
+
*/
|
|
76
|
+
export async function dispatchRops(ropsList, handlers, context, options = {}) {
|
|
77
|
+
const maxRops = options.maxRops ?? MAX_ROPS_PER_EXECUTE;
|
|
78
|
+
const maxOutputBytes = Math.min(options.maxOutputBytes ?? MAX_ROPS_LIST_BYTES, MAX_ROPS_LIST_BYTES);
|
|
79
|
+
const reader = decodingReader(new BufferReader(ropsList));
|
|
80
|
+
const writer = new BufferWriter();
|
|
81
|
+
context.budget ?? (context.budget = new ExecuteBudget());
|
|
82
|
+
/** Room for a RopBufferTooSmall resending the request from `offset` on (nothing when there is nothing left). */
|
|
83
|
+
const reserveFrom = (offset) => (offset < ropsList.length ? BUFFER_TOO_SMALL_HEADER_BYTES + ropsList.length - offset : 0);
|
|
84
|
+
if (reserveFrom(0) > maxOutputBytes) {
|
|
85
|
+
throw new ExecuteBufferTooSmallError();
|
|
86
|
+
}
|
|
87
|
+
let remaining = maxOutputBytes;
|
|
88
|
+
Object.defineProperty(context, "ropOutputRemaining", {
|
|
89
|
+
configurable: true,
|
|
90
|
+
enumerable: true,
|
|
91
|
+
get: () => Math.max(0, remaining - reserveFrom(reader.position)),
|
|
92
|
+
});
|
|
93
|
+
let processed = 0;
|
|
94
|
+
try {
|
|
95
|
+
// Stops after `maxRops`, so one Execute can't queue unbounded work.
|
|
96
|
+
while (reader.hasMore() && processed++ < maxRops) {
|
|
97
|
+
const start = reader.position;
|
|
98
|
+
const ropId = reader.readUInt8();
|
|
99
|
+
const handler = handlers.get(ropId);
|
|
100
|
+
if (!handler) {
|
|
101
|
+
throw new DecodeError(`RopDispatcher: unsupported RopId 0x${ropId.toString(16)}.`);
|
|
102
|
+
}
|
|
103
|
+
remaining = maxOutputBytes - writer.length;
|
|
104
|
+
let response;
|
|
105
|
+
try {
|
|
106
|
+
const ropWriter = new BufferWriter();
|
|
107
|
+
await handler.handle(reader, ropWriter, context);
|
|
108
|
+
response = ropWriter.toBuffer();
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
if (err instanceof DecodeError) {
|
|
112
|
+
throw err;
|
|
113
|
+
}
|
|
114
|
+
response = failureResponse(handler, ropsList, start, err instanceof WorkBudgetExceededError ? ERROR_TOO_COMPLEX : ERROR_CALL_FAILED);
|
|
115
|
+
}
|
|
116
|
+
if (response.length + reserveFrom(reader.position) > remaining) {
|
|
117
|
+
// The reserve kept for this ROP guarantees this fits.
|
|
118
|
+
writer
|
|
119
|
+
.writeUInt8(ROP_ID_BUFFER_TOO_SMALL)
|
|
120
|
+
.writeUInt16LE(Math.min(response.length, 0xffff)) // SizeNeeded
|
|
121
|
+
.writeBytes(ropsList.subarray(start)); // RequestBuffers
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
writer.writeBytes(response);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
delete context.ropOutputRemaining;
|
|
129
|
+
}
|
|
130
|
+
return writer.toBuffer();
|
|
131
|
+
}
|
|
132
|
+
/** The response a ROP gets when its handler throws: `RopId`, the handle index its responses echo, `ReturnValue`,
|
|
133
|
+
* then any always-present fields zeroed. Nothing at all for a ROP that never responds. */
|
|
134
|
+
function failureResponse(handler, ropsList, start, returnValue) {
|
|
135
|
+
if (handler.hasNoResponse) {
|
|
136
|
+
return Buffer.alloc(0);
|
|
137
|
+
}
|
|
138
|
+
return new BufferWriter()
|
|
139
|
+
.writeUInt8(handler.ropId)
|
|
140
|
+
.writeUInt8(ropsList[start + (handler.responseHandleIndexOffset ?? 2)] ?? 0)
|
|
141
|
+
.writeUInt32LE(returnValue)
|
|
142
|
+
.writeBytes(Buffer.alloc(handler.failureTailBytes ?? 0))
|
|
143
|
+
.toBuffer();
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=RopDispatcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RopDispatcher.js","sourceRoot":"","sources":["../../src/RopDispatcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import { BufferWriter } from "./BufferCursor.js";
|
|
6
|
+
import { RecurrenceFrequency } from "@rapidmx/restapi";
|
|
7
|
+
/**
|
|
8
|
+
* Encodes/decodes `CalendarEvent.recurrenceRule` to/from the binary blob carried by `PidLidAppointmentRecur`
|
|
9
|
+
* (`[MS-OXOCAL]` §2.2.1.44: the outer `AppointmentRecurrencePattern` structure, §2.2.1.44.5, wrapping an inner
|
|
10
|
+
* `RecurrencePattern`, §2.2.1.44.1). Every field layout/size below was confirmed against those spec pages
|
|
11
|
+
* directly, not assumed.
|
|
12
|
+
*
|
|
13
|
+
* **Pragmatic scope, matching the same limits `CalendarSyncAdapter` (EAS) already carries**:
|
|
14
|
+
* - Only `RecurFrequency` Daily/Weekly/Monthly/Yearly and `PatternType` Day/Week/Month are produced or
|
|
15
|
+
* accepted - `MonthNth`/`MonthEnd`/Hijri patterns have no representation in `RecurrenceRule` (no ordinal-
|
|
16
|
+
* weekday field) and decoding one throws a clear, documented error rather than silently guessing.
|
|
17
|
+
* - `DeletedInstanceCount`/`ModifiedInstanceCount` (recurrence exceptions) and the outer structure's
|
|
18
|
+
* `ExceptionCount` are always written as `0`. Decoding reads the deleted occurrences into `RecurrenceRule.exceptions`
|
|
19
|
+
* and ignores the details of modified ones (`ExceptionInfo`), which `RecurrenceRule` can't hold, instead of failing
|
|
20
|
+
* the whole save.
|
|
21
|
+
* - A `YEARLY` rule with `interval > 1` ("every N years", N>1) is encoded as `RecurFrequency=Monthly` with
|
|
22
|
+
* `Period=12*N`, per the spec's own stated rule that "a yearly recurrence pattern is just a monthly pattern
|
|
23
|
+
* that occurs every 12 months" (a plain `RecurFrequency=Yearly` value's `Period` MUST be exactly 12).
|
|
24
|
+
* **This is a one-way, documented round-trip asymmetry**: decoding that same blob back yields
|
|
25
|
+
* `{freq: MONTHLY, interval: 12*N}`, not the original `{freq: YEARLY, interval: N}` - the two are
|
|
26
|
+
* indistinguishable on the wire once encoded, the same ambiguity a real Exchange server itself has no way
|
|
27
|
+
* around either.
|
|
28
|
+
* - `StartTimeOffset`/`EndTimeOffset` (the outer structure) are derived from `startDate`/`endDate`'s own
|
|
29
|
+
* time-of-day only (`hours*60+minutes`), not carried through decode - the real start/end instant of any
|
|
30
|
+
* given occurrence comes from `PidLidAppointmentStartWhole`/`EndWhole`, not from this blob.
|
|
31
|
+
*
|
|
32
|
+
* @author Jean-Philippe Steinmetz
|
|
33
|
+
*/
|
|
34
|
+
/** `RecurFrequency` (`[MS-OXOCAL]` §2.2.1.44.1). */
|
|
35
|
+
var RecurFrequencyWire;
|
|
36
|
+
(function (RecurFrequencyWire) {
|
|
37
|
+
RecurFrequencyWire[RecurFrequencyWire["Daily"] = 8202] = "Daily";
|
|
38
|
+
RecurFrequencyWire[RecurFrequencyWire["Weekly"] = 8203] = "Weekly";
|
|
39
|
+
RecurFrequencyWire[RecurFrequencyWire["Monthly"] = 8204] = "Monthly";
|
|
40
|
+
RecurFrequencyWire[RecurFrequencyWire["Yearly"] = 8205] = "Yearly";
|
|
41
|
+
})(RecurFrequencyWire || (RecurFrequencyWire = {}));
|
|
42
|
+
/** `PatternType` (`[MS-OXOCAL]` §2.2.1.44.1) - only the 3 values this codec produces/accepts. */
|
|
43
|
+
var PatternTypeWire;
|
|
44
|
+
(function (PatternTypeWire) {
|
|
45
|
+
PatternTypeWire[PatternTypeWire["Day"] = 0] = "Day";
|
|
46
|
+
PatternTypeWire[PatternTypeWire["Week"] = 1] = "Week";
|
|
47
|
+
PatternTypeWire[PatternTypeWire["Month"] = 2] = "Month";
|
|
48
|
+
})(PatternTypeWire || (PatternTypeWire = {}));
|
|
49
|
+
/** `EndType` (`[MS-OXOCAL]` §2.2.1.44.1). */
|
|
50
|
+
var EndTypeWire;
|
|
51
|
+
(function (EndTypeWire) {
|
|
52
|
+
EndTypeWire[EndTypeWire["AfterDate"] = 8225] = "AfterDate";
|
|
53
|
+
EndTypeWire[EndTypeWire["AfterN"] = 8226] = "AfterN";
|
|
54
|
+
EndTypeWire[EndTypeWire["Never"] = 8227] = "Never";
|
|
55
|
+
})(EndTypeWire || (EndTypeWire = {}));
|
|
56
|
+
/** Sentinel `EndDate` value (`[MS-OXOCAL]` §2.2.1.44.1) meaning "never-ending". */
|
|
57
|
+
const NEVER_END_DATE = 0x5ae980df;
|
|
58
|
+
const MINUTES_PER_DAY = 1440;
|
|
59
|
+
const MINUTES_PER_WEEK = 10080;
|
|
60
|
+
/** `RecurrencePattern.CalendarType` `Default` value (Gregorian) - the only calendar type this codec supports. */
|
|
61
|
+
const CALENDAR_TYPE_DEFAULT = 0x0000;
|
|
62
|
+
/** `RecurrencePattern.FirstDOW` `Sunday` value - this codec always encodes with a Sunday week start, since
|
|
63
|
+
* `RecurrenceRule` has no field of its own to source a different one from. */
|
|
64
|
+
const FIRST_DOW_SUNDAY = 0x00000000;
|
|
65
|
+
/** `RecurrencePattern`'s `DayOfWeekMask` bits (`[MS-OXOCAL]` §2.2.1.44.1) - confirmed identical to
|
|
66
|
+
* `CalendarSyncAdapter`'s own `DAY_OF_WEEK_BITS` table for MS-ASCAL's `DayOfWeek` field, reused here under the
|
|
67
|
+
* same RFC 5545 two-letter day codes `RecurrenceRule.byDay` uses. */
|
|
68
|
+
const DAY_OF_WEEK_BITS = { SU: 1, MO: 2, TU: 4, WE: 8, TH: 16, FR: 32, SA: 64 };
|
|
69
|
+
const DAY_OF_WEEK_CODE_BY_BIT = [
|
|
70
|
+
["SU", 1],
|
|
71
|
+
["MO", 2],
|
|
72
|
+
["TU", 4],
|
|
73
|
+
["WE", 8],
|
|
74
|
+
["TH", 16],
|
|
75
|
+
["FR", 32],
|
|
76
|
+
["SA", 64],
|
|
77
|
+
];
|
|
78
|
+
/** Minutes-since-1601-01-01T00:00:00Z epoch, as a JS `Date`-compatible millisecond timestamp - every date field
|
|
79
|
+
* in `RecurrencePattern` uses this epoch/unit, distinct from `PropertyValue.ts`'s `FILETIME` epoch (which is
|
|
80
|
+
* also 1601-based, but in 100-ns units, not minutes). */
|
|
81
|
+
const EPOCH_1601_MS = Date.UTC(1601, 0, 1);
|
|
82
|
+
function dateToMinutesSince1601(date) {
|
|
83
|
+
return Math.round((date.getTime() - EPOCH_1601_MS) / 60000);
|
|
84
|
+
}
|
|
85
|
+
function minutesSince1601ToDate(minutes) {
|
|
86
|
+
return new Date(EPOCH_1601_MS + minutes * 60000);
|
|
87
|
+
}
|
|
88
|
+
function utcMidnight(date) {
|
|
89
|
+
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
|
|
90
|
+
}
|
|
91
|
+
/** Calendar months elapsed between 1601-01-01 and the first day of the month containing `date`. */
|
|
92
|
+
function monthsElapsedSince1601(date) {
|
|
93
|
+
return (date.getUTCFullYear() - 1601) * 12 + date.getUTCMonth();
|
|
94
|
+
}
|
|
95
|
+
function dayOfWeekMaskFromByDay(byDay, fallbackDate) {
|
|
96
|
+
if (byDay && byDay.length > 0) {
|
|
97
|
+
return byDay.reduce((mask, day) => mask | (DAY_OF_WEEK_BITS[day] ?? 0), 0);
|
|
98
|
+
}
|
|
99
|
+
return DAY_OF_WEEK_CODE_BY_BIT[fallbackDate.getUTCDay()][1];
|
|
100
|
+
}
|
|
101
|
+
function byDayFromMask(mask) {
|
|
102
|
+
return DAY_OF_WEEK_CODE_BY_BIT.filter(([, bit]) => (mask & bit) !== 0).map(([code]) => code);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Encodes `rule` (plus the occurrence's own `startDate`/`endDate`, needed for phase/time-of-day derivation)
|
|
106
|
+
* into an `AppointmentRecurrencePattern` blob, ready to be written as the raw content of a `PtypBinary`
|
|
107
|
+
* `PidLidAppointmentRecur` property value.
|
|
108
|
+
*/
|
|
109
|
+
export function encodeAppointmentRecurrence(rule, startDate, endDate) {
|
|
110
|
+
let recurFrequency;
|
|
111
|
+
let patternType;
|
|
112
|
+
let period;
|
|
113
|
+
let patternSpecific;
|
|
114
|
+
let firstDateTime;
|
|
115
|
+
switch (rule.freq) {
|
|
116
|
+
case RecurrenceFrequency.DAILY: {
|
|
117
|
+
recurFrequency = RecurFrequencyWire.Daily;
|
|
118
|
+
patternType = PatternTypeWire.Day;
|
|
119
|
+
period = rule.interval * MINUTES_PER_DAY;
|
|
120
|
+
patternSpecific = Buffer.alloc(0);
|
|
121
|
+
firstDateTime = dateToMinutesSince1601(utcMidnight(startDate)) % period;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
case RecurrenceFrequency.WEEKLY: {
|
|
125
|
+
recurFrequency = RecurFrequencyWire.Weekly;
|
|
126
|
+
patternType = PatternTypeWire.Week;
|
|
127
|
+
period = rule.interval;
|
|
128
|
+
const mask = dayOfWeekMaskFromByDay(rule.byDay, startDate);
|
|
129
|
+
patternSpecific = new BufferWriter().writeUInt32LE(mask).toBuffer();
|
|
130
|
+
const midnight = utcMidnight(startDate);
|
|
131
|
+
const weekStart = new Date(midnight.getTime() - midnight.getUTCDay() * MINUTES_PER_DAY * 60000);
|
|
132
|
+
firstDateTime = dateToMinutesSince1601(weekStart) % (period * MINUTES_PER_WEEK);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case RecurrenceFrequency.MONTHLY: {
|
|
136
|
+
recurFrequency = RecurFrequencyWire.Monthly;
|
|
137
|
+
patternType = PatternTypeWire.Month;
|
|
138
|
+
period = rule.interval;
|
|
139
|
+
const day = rule.byMonthDay?.[0] ?? startDate.getUTCDate();
|
|
140
|
+
patternSpecific = new BufferWriter().writeUInt32LE(day).toBuffer();
|
|
141
|
+
const monthsElapsed = monthsElapsedSince1601(startDate);
|
|
142
|
+
const refMonthIndex = monthsElapsed % period;
|
|
143
|
+
firstDateTime = dateToMinutesSince1601(new Date(Date.UTC(1601, refMonthIndex, 1)));
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
case RecurrenceFrequency.YEARLY: {
|
|
147
|
+
patternType = PatternTypeWire.Month;
|
|
148
|
+
if (rule.interval <= 1) {
|
|
149
|
+
recurFrequency = RecurFrequencyWire.Yearly;
|
|
150
|
+
period = 12;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
recurFrequency = RecurFrequencyWire.Monthly;
|
|
154
|
+
period = 12 * rule.interval;
|
|
155
|
+
}
|
|
156
|
+
const day = rule.byMonthDay?.[0] ?? startDate.getUTCDate();
|
|
157
|
+
patternSpecific = new BufferWriter().writeUInt32LE(day).toBuffer();
|
|
158
|
+
const monthsElapsed = monthsElapsedSince1601(startDate);
|
|
159
|
+
const refMonthIndex = monthsElapsed % period;
|
|
160
|
+
firstDateTime = dateToMinutesSince1601(new Date(Date.UTC(1601, refMonthIndex, 1)));
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
default:
|
|
164
|
+
throw new Error(`AppointmentRecurrence: unsupported RecurrenceFrequency ${rule.freq}`);
|
|
165
|
+
}
|
|
166
|
+
let endType;
|
|
167
|
+
let occurrenceCount = 0;
|
|
168
|
+
let endDateMinutes;
|
|
169
|
+
if (rule.until) {
|
|
170
|
+
endType = EndTypeWire.AfterDate;
|
|
171
|
+
endDateMinutes = dateToMinutesSince1601(utcMidnight(rule.until));
|
|
172
|
+
}
|
|
173
|
+
else if (rule.count != null) {
|
|
174
|
+
endType = EndTypeWire.AfterN;
|
|
175
|
+
occurrenceCount = rule.count;
|
|
176
|
+
endDateMinutes = NEVER_END_DATE;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
endType = EndTypeWire.Never;
|
|
180
|
+
endDateMinutes = NEVER_END_DATE;
|
|
181
|
+
}
|
|
182
|
+
const writer = new BufferWriter();
|
|
183
|
+
// RecurrencePattern (MS-OXOCAL §2.2.1.44.1)
|
|
184
|
+
writer.writeUInt16LE(0x3004); // ReaderVersion
|
|
185
|
+
writer.writeUInt16LE(0x3004); // WriterVersion
|
|
186
|
+
writer.writeUInt16LE(recurFrequency);
|
|
187
|
+
writer.writeUInt16LE(patternType);
|
|
188
|
+
writer.writeUInt16LE(CALENDAR_TYPE_DEFAULT);
|
|
189
|
+
writer.writeUInt32LE(firstDateTime);
|
|
190
|
+
writer.writeUInt32LE(period);
|
|
191
|
+
writer.writeUInt32LE(0); // SlidingFlag
|
|
192
|
+
writer.writeBytes(patternSpecific);
|
|
193
|
+
writer.writeUInt32LE(endType);
|
|
194
|
+
writer.writeUInt32LE(occurrenceCount);
|
|
195
|
+
writer.writeUInt32LE(FIRST_DOW_SUNDAY);
|
|
196
|
+
writer.writeUInt32LE(0); // DeletedInstanceCount
|
|
197
|
+
writer.writeUInt32LE(0); // ModifiedInstanceCount
|
|
198
|
+
writer.writeUInt32LE(dateToMinutesSince1601(utcMidnight(startDate))); // StartDate
|
|
199
|
+
writer.writeUInt32LE(endDateMinutes); // EndDate
|
|
200
|
+
// AppointmentRecurrencePattern's own wrapper fields (MS-OXOCAL §2.2.1.44.5)
|
|
201
|
+
writer.writeUInt32LE(0x00003006); // ReaderVersion2
|
|
202
|
+
writer.writeUInt32LE(0x00003009); // WriterVersion2
|
|
203
|
+
writer.writeUInt32LE(startDate.getUTCHours() * 60 + startDate.getUTCMinutes()); // StartTimeOffset
|
|
204
|
+
writer.writeUInt32LE(endDate.getUTCHours() * 60 + endDate.getUTCMinutes()); // EndTimeOffset
|
|
205
|
+
writer.writeUInt16LE(0); // ExceptionCount
|
|
206
|
+
writer.writeUInt32LE(0); // ReservedBlock1Size
|
|
207
|
+
writer.writeUInt32LE(0); // ReservedBlock2Size
|
|
208
|
+
return writer.toBuffer();
|
|
209
|
+
}
|
|
210
|
+
/** Reads a `DeletedInstanceCount`/`ModifiedInstanceCount`-style count followed by that many 4-byte dates. */
|
|
211
|
+
function readDateList(reader) {
|
|
212
|
+
const count = reader.readUInt32LE();
|
|
213
|
+
if (count * 4 > reader.remaining) {
|
|
214
|
+
throw new RangeError(`AppointmentRecurrence: an instance date count of ${count} is larger than the pattern.`);
|
|
215
|
+
}
|
|
216
|
+
return Array.from({ length: count }, () => reader.readUInt32LE());
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Decodes an `AppointmentRecurrencePattern` blob (read from `reader`'s current position) back into a
|
|
220
|
+
* `RecurrenceRule`. Throws a clear error for any pattern this pragmatic subset can't represent (see this
|
|
221
|
+
* file's own doc comment) rather than silently dropping data.
|
|
222
|
+
*/
|
|
223
|
+
export function decodeAppointmentRecurrence(reader) {
|
|
224
|
+
reader.readUInt16LE(); // ReaderVersion
|
|
225
|
+
reader.readUInt16LE(); // WriterVersion
|
|
226
|
+
const recurFrequency = reader.readUInt16LE();
|
|
227
|
+
const patternType = reader.readUInt16LE();
|
|
228
|
+
reader.readUInt16LE(); // CalendarType
|
|
229
|
+
const firstDateTime = reader.readUInt32LE();
|
|
230
|
+
const period = reader.readUInt32LE();
|
|
231
|
+
reader.readUInt32LE(); // SlidingFlag
|
|
232
|
+
let freq;
|
|
233
|
+
let interval;
|
|
234
|
+
let byDay;
|
|
235
|
+
let byMonthDay;
|
|
236
|
+
let byMonth;
|
|
237
|
+
switch (recurFrequency) {
|
|
238
|
+
case RecurFrequencyWire.Daily:
|
|
239
|
+
if (patternType !== PatternTypeWire.Day) {
|
|
240
|
+
throw new Error(`AppointmentRecurrence: unsupported PatternType 0x${patternType.toString(16)} for Daily`);
|
|
241
|
+
}
|
|
242
|
+
freq = RecurrenceFrequency.DAILY;
|
|
243
|
+
interval = period / MINUTES_PER_DAY;
|
|
244
|
+
break;
|
|
245
|
+
case RecurFrequencyWire.Weekly: {
|
|
246
|
+
if (patternType !== PatternTypeWire.Week) {
|
|
247
|
+
throw new Error(`AppointmentRecurrence: unsupported PatternType 0x${patternType.toString(16)} for Weekly`);
|
|
248
|
+
}
|
|
249
|
+
const mask = reader.readUInt32LE();
|
|
250
|
+
freq = RecurrenceFrequency.WEEKLY;
|
|
251
|
+
interval = period;
|
|
252
|
+
byDay = byDayFromMask(mask);
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
case RecurFrequencyWire.Monthly: {
|
|
256
|
+
if (patternType !== PatternTypeWire.Month) {
|
|
257
|
+
throw new Error(`AppointmentRecurrence: unsupported PatternType 0x${patternType.toString(16)} for Monthly`);
|
|
258
|
+
}
|
|
259
|
+
const day = reader.readUInt32LE();
|
|
260
|
+
freq = RecurrenceFrequency.MONTHLY;
|
|
261
|
+
interval = period;
|
|
262
|
+
byMonthDay = [day];
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
case RecurFrequencyWire.Yearly: {
|
|
266
|
+
if (patternType !== PatternTypeWire.Month) {
|
|
267
|
+
throw new Error(`AppointmentRecurrence: unsupported PatternType 0x${patternType.toString(16)} for Yearly`);
|
|
268
|
+
}
|
|
269
|
+
const day = reader.readUInt32LE();
|
|
270
|
+
freq = RecurrenceFrequency.YEARLY;
|
|
271
|
+
interval = 1;
|
|
272
|
+
byMonthDay = [day];
|
|
273
|
+
byMonth = [minutesSince1601ToDate(firstDateTime).getUTCMonth() + 1];
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
default:
|
|
277
|
+
throw new Error(`AppointmentRecurrence: unsupported RecurFrequency 0x${recurFrequency.toString(16)}`);
|
|
278
|
+
}
|
|
279
|
+
const endType = reader.readUInt32LE();
|
|
280
|
+
const occurrenceCount = reader.readUInt32LE();
|
|
281
|
+
reader.readUInt32LE(); // FirstDOW
|
|
282
|
+
// DeletedInstanceDates holds the original dates of every deleted *or* modified occurrence; ModifiedInstanceDates
|
|
283
|
+
// the (new) dates of the modified ones. An occurrence deleted outright is in the first list only.
|
|
284
|
+
const deletedDates = readDateList(reader);
|
|
285
|
+
const modifiedDates = new Set(readDateList(reader));
|
|
286
|
+
reader.readUInt32LE(); // StartDate
|
|
287
|
+
const endDateMinutes = reader.readUInt32LE();
|
|
288
|
+
let until;
|
|
289
|
+
let count;
|
|
290
|
+
if (endType === EndTypeWire.AfterDate) {
|
|
291
|
+
until = minutesSince1601ToDate(endDateMinutes);
|
|
292
|
+
}
|
|
293
|
+
else if (endType === EndTypeWire.AfterN) {
|
|
294
|
+
count = occurrenceCount;
|
|
295
|
+
}
|
|
296
|
+
reader.readUInt32LE(); // ReaderVersion2
|
|
297
|
+
reader.readUInt32LE(); // WriterVersion2
|
|
298
|
+
const startTimeOffset = reader.readUInt32LE();
|
|
299
|
+
// Everything after this (ExceptionCount, the variable-length ExceptionInfo/ExtendedException blocks for modified
|
|
300
|
+
// occurrences, and the reserved blocks) describes per-occurrence changes RecurrenceRule has no field for, so it is
|
|
301
|
+
// not read. A modified occurrence that stayed on its day remains an ordinary occurrence; one moved to another day
|
|
302
|
+
// only drops out of its original day, since its new time has nowhere to go.
|
|
303
|
+
return {
|
|
304
|
+
freq,
|
|
305
|
+
interval,
|
|
306
|
+
...(byDay ? { byDay } : {}),
|
|
307
|
+
...(byMonthDay ? { byMonthDay } : {}),
|
|
308
|
+
...(byMonth ? { byMonth } : {}),
|
|
309
|
+
...(until ? { until } : {}),
|
|
310
|
+
...(count != null ? { count } : {}),
|
|
311
|
+
// A deleted occurrence's date is midnight (minutes since 1601); its start is that plus the series' start time.
|
|
312
|
+
exceptions: deletedDates.filter((minutes) => !modifiedDates.has(minutes)).map((minutes) => minutesSince1601ToDate(minutes + startTimeOffset)),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=AppointmentRecurrence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AppointmentRecurrence.js","sourceRoot":"","sources":["../../../src/codec/AppointmentRecurrence.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAgB,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAuB,MAAM,kBAAkB,CAAC;AAE5E;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,oDAAoD;AACpD,IAAK,kBAKJ;AALD,WAAK,kBAAkB;IACnB,gEAAc,CAAA;IACd,kEAAe,CAAA;IACf,oEAAgB,CAAA;IAChB,kEAAe,CAAA;AACnB,CAAC,EALI,kBAAkB,KAAlB,kBAAkB,QAKtB;AAED,iGAAiG;AACjG,IAAK,eAIJ;AAJD,WAAK,eAAe;IAChB,mDAAY,CAAA;IACZ,qDAAa,CAAA;IACb,uDAAc,CAAA;AAClB,CAAC,EAJI,eAAe,KAAf,eAAe,QAInB;AAED,6CAA6C;AAC7C,IAAK,WAIJ;AAJD,WAAK,WAAW;IACZ,0DAAsB,CAAA;IACtB,oDAAmB,CAAA;IACnB,kDAAkB,CAAA;AACtB,CAAC,EAJI,WAAW,KAAX,WAAW,QAIf;AAED,mFAAmF;AACnF,MAAM,cAAc,GAAG,UAAU,CAAC;AAElC,MAAM,eAAe,GAAG,IAAI,CAAC;AAC7B,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAE/B,iHAAiH;AACjH,MAAM,qBAAqB,GAAG,MAAM,CAAC;AAErC;8EAC8E;AAC9E,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAEpC;;qEAEqE;AACrE,MAAM,gBAAgB,GAA2B,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AACxG,MAAM,uBAAuB,GAAuB;IAChD,CAAC,IAAI,EAAE,CAAC,CAAC;IACT,CAAC,IAAI,EAAE,CAAC,CAAC;IACT,CAAC,IAAI,EAAE,CAAC,CAAC;IACT,CAAC,IAAI,EAAE,CAAC,CAAC;IACT,CAAC,IAAI,EAAE,EAAE,CAAC;IACV,CAAC,IAAI,EAAE,EAAE,CAAC;IACV,CAAC,IAAI,EAAE,EAAE,CAAC;CACb,CAAC;AAEF;;yDAEyD;AACzD,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAE3C,SAAS,sBAAsB,CAAC,IAAU;IACtC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,aAAa,CAAC,GAAG,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,sBAAsB,CAAC,OAAe;IAC3C,OAAO,IAAI,IAAI,CAAC,aAAa,GAAG,OAAO,GAAG,KAAK,CAAC,CAAC;AACrD,CAAC;AAED,SAAS,WAAW,CAAC,IAAU;IAC3B,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;AAC5F,CAAC;AAED,mGAAmG;AACnG,SAAS,sBAAsB,CAAC,IAAU;IACtC,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;AACpE,CAAC;AAED,SAAS,sBAAsB,CAAC,KAA2B,EAAE,YAAkB;IAC3E,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,uBAAuB,CAAC,YAAY,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,aAAa,CAAC,IAAY;IAC/B,OAAO,uBAAuB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;AACjG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CAAC,IAAoB,EAAE,SAAe,EAAE,OAAa;IAC5F,IAAI,cAAkC,CAAC;IACvC,IAAI,WAA4B,CAAC;IACjC,IAAI,MAAc,CAAC;IACnB,IAAI,eAAuB,CAAC;IAC5B,IAAI,aAAqB,CAAC;IAE1B,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAChB,KAAK,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;YAC7B,cAAc,GAAG,kBAAkB,CAAC,KAAK,CAAC;YAC1C,WAAW,GAAG,eAAe,CAAC,GAAG,CAAC;YAClC,MAAM,GAAG,IAAI,CAAC,QAAQ,GAAG,eAAe,CAAC;YACzC,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAClC,aAAa,GAAG,sBAAsB,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC;YACxE,MAAM;QACV,CAAC;QACD,KAAK,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9B,cAAc,GAAG,kBAAkB,CAAC,MAAM,CAAC;YAC3C,WAAW,GAAG,eAAe,CAAC,IAAI,CAAC;YACnC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC;YACvB,MAAM,IAAI,GAAG,sBAAsB,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YAC3D,eAAe,GAAG,IAAI,YAAY,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;YACpE,MAAM,QAAQ,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;YACxC,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,SAAS,EAAE,GAAG,eAAe,GAAG,KAAK,CAAC,CAAC;YAChG,aAAa,GAAG,sBAAsB,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,GAAG,gBAAgB,CAAC,CAAC;YAChF,MAAM;QACV,CAAC;QACD,KAAK,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;YAC/B,cAAc,GAAG,kBAAkB,CAAC,OAAO,CAAC;YAC5C,WAAW,GAAG,eAAe,CAAC,KAAK,CAAC;YACpC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC;YACvB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;YAC3D,eAAe,GAAG,IAAI,YAAY,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;YACnE,MAAM,aAAa,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;YACxD,MAAM,aAAa,GAAG,aAAa,GAAG,MAAM,CAAC;YAC7C,aAAa,GAAG,sBAAsB,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACnF,MAAM;QACV,CAAC;QACD,KAAK,mBAAmB,CAAC,MAAM,CAAC,CAAC,CAAC;YAC9B,WAAW,GAAG,eAAe,CAAC,KAAK,CAAC;YACpC,IAAI,IAAI,CAAC,QAAQ,IAAI,CAAC,EAAE,CAAC;gBACrB,cAAc,GAAG,kBAAkB,CAAC,MAAM,CAAC;gBAC3C,MAAM,GAAG,EAAE,CAAC;YAChB,CAAC;iBAAM,CAAC;gBACJ,cAAc,GAAG,kBAAkB,CAAC,OAAO,CAAC;gBAC5C,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC;YAChC,CAAC;YACD,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,UAAU,EAAE,CAAC;YAC3D,eAAe,GAAG,IAAI,YAAY,EAAE,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;YACnE,MAAM,aAAa,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC;YACxD,MAAM,aAAa,GAAG,aAAa,GAAG,MAAM,CAAC;YAC7C,aAAa,GAAG,sBAAsB,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACnF,MAAM;QACV,CAAC;QACD;YACI,MAAM,IAAI,KAAK,CAAC,0DAA0D,IAAI,CAAC,IAAc,EAAE,CAAC,CAAC;IACzG,CAAC;IAED,IAAI,OAAoB,CAAC;IACzB,IAAI,eAAe,GAAG,CAAC,CAAC;IACxB,IAAI,cAAsB,CAAC;IAC3B,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC;QAChC,cAAc,GAAG,sBAAsB,CAAC,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACrE,CAAC;SAAM,IAAI,IAAI,CAAC,KAAK,IAAI,IAAI,EAAE,CAAC;QAC5B,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC;QAC7B,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC;QAC7B,cAAc,GAAG,cAAc,CAAC;IACpC,CAAC;SAAM,CAAC;QACJ,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC;QAC5B,cAAc,GAAG,cAAc,CAAC;IACpC,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,4CAA4C;IAC5C,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB;IAC9C,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB;IAC9C,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC;IACrC,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC;IAClC,MAAM,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;IAC5C,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;IACpC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IAC7B,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc;IACvC,MAAM,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;IACnC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9B,MAAM,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;IACtC,MAAM,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;IACvC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,uBAAuB;IAChD,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;IACjD,MAAM,CAAC,aAAa,CAAC,sBAAsB,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY;IAClF,MAAM,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,UAAU;IAEhD,4EAA4E;IAC5E,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,iBAAiB;IACnD,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,iBAAiB;IACnD,MAAM,CAAC,aAAa,CAAC,SAAS,CAAC,WAAW,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,kBAAkB;IAClG,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,gBAAgB;IAC5F,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB;IAC1C,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB;IAC9C,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,qBAAqB;IAE9C,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED,6GAA6G;AAC7G,SAAS,YAAY,CAAC,MAAoB;IACtC,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IACpC,IAAI,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAC/B,MAAM,IAAI,UAAU,CAAC,oDAAoD,KAAK,8BAA8B,CAAC,CAAC;IAClH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;AACtE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,2BAA2B,CAAC,MAAoB;IAC5D,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,gBAAgB;IACvC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,gBAAgB;IACvC,MAAM,cAAc,GAAuB,MAAM,CAAC,YAAY,EAAE,CAAC;IACjE,MAAM,WAAW,GAAoB,MAAM,CAAC,YAAY,EAAE,CAAC;IAC3D,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,eAAe;IACtC,MAAM,aAAa,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IACrC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,cAAc;IAErC,IAAI,IAAyB,CAAC;IAC9B,IAAI,QAAgB,CAAC;IACrB,IAAI,KAA2B,CAAC;IAChC,IAAI,UAAgC,CAAC;IACrC,IAAI,OAA6B,CAAC;IAElC,QAAQ,cAAc,EAAE,CAAC;QACrB,KAAK,kBAAkB,CAAC,KAAK;YACzB,IAAI,WAAW,KAAK,eAAe,CAAC,GAAG,EAAE,CAAC;gBACtC,MAAM,IAAI,KAAK,CAAC,oDAAoD,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC;YAC9G,CAAC;YACD,IAAI,GAAG,mBAAmB,CAAC,KAAK,CAAC;YACjC,QAAQ,GAAG,MAAM,GAAG,eAAe,CAAC;YACpC,MAAM;QACV,KAAK,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;YAC7B,IAAI,WAAW,KAAK,eAAe,CAAC,IAAI,EAAE,CAAC;gBACvC,MAAM,IAAI,KAAK,CAAC,oDAAoD,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;YAC/G,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;YACnC,IAAI,GAAG,mBAAmB,CAAC,MAAM,CAAC;YAClC,QAAQ,GAAG,MAAM,CAAC;YAClB,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;YAC5B,MAAM;QACV,CAAC;QACD,KAAK,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;YAC9B,IAAI,WAAW,KAAK,eAAe,CAAC,KAAK,EAAE,CAAC;gBACxC,MAAM,IAAI,KAAK,CAAC,oDAAoD,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC;YAChH,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;YAClC,IAAI,GAAG,mBAAmB,CAAC,OAAO,CAAC;YACnC,QAAQ,GAAG,MAAM,CAAC;YAClB,UAAU,GAAG,CAAC,GAAG,CAAC,CAAC;YACnB,MAAM;QACV,CAAC;QACD,KAAK,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;YAC7B,IAAI,WAAW,KAAK,eAAe,CAAC,KAAK,EAAE,CAAC;gBACxC,MAAM,IAAI,KAAK,CAAC,oDAAoD,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;YAC/G,CAAC;YACD,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;YAClC,IAAI,GAAG,mBAAmB,CAAC,MAAM,CAAC;YAClC,QAAQ,GAAG,CAAC,CAAC;YACb,UAAU,GAAG,CAAC,GAAG,CAAC,CAAC;YACnB,OAAO,GAAG,CAAC,sBAAsB,CAAC,aAAa,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC;YACpE,MAAM;QACV,CAAC;QACD;YACI,MAAM,IAAI,KAAK,CAAC,uDAAwD,cAAyB,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC1H,CAAC;IAED,MAAM,OAAO,GAAgB,MAAM,CAAC,YAAY,EAAE,CAAC;IACnD,MAAM,eAAe,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IAC9C,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,WAAW;IAClC,iHAAiH;IACjH,kGAAkG;IAClG,MAAM,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IACpD,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,YAAY;IACnC,MAAM,cAAc,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IAE7C,IAAI,KAAuB,CAAC;IAC5B,IAAI,KAAyB,CAAC;IAC9B,IAAI,OAAO,KAAK,WAAW,CAAC,SAAS,EAAE,CAAC;QACpC,KAAK,GAAG,sBAAsB,CAAC,cAAc,CAAC,CAAC;IACnD,CAAC;SAAM,IAAI,OAAO,KAAK,WAAW,CAAC,MAAM,EAAE,CAAC;QACxC,KAAK,GAAG,eAAe,CAAC;IAC5B,CAAC;IAED,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,iBAAiB;IACxC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,iBAAiB;IACxC,MAAM,eAAe,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IAC9C,iHAAiH;IACjH,mHAAmH;IACnH,kHAAkH;IAClH,4EAA4E;IAE5E,OAAO;QACH,IAAI;QACJ,QAAQ;QACR,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3B,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3B,GAAG,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC,+GAA+G;QAC/G,UAAU,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,sBAAsB,CAAC,OAAO,GAAG,eAAe,CAAC,CAAC;KAChJ,CAAC;AACN,CAAC"}
|