1 | ;
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | var fp_1 = require("lodash/fp");
|
4 | var gpml_utilities_1 = require("../gpml-utilities");
|
5 | var geom_utils_1 = require("../geom-utils");
|
6 | var calculateAllPoints_1 = require("./calculateAllPoints");
|
7 | var VError = require("verror");
|
8 | var MarkerMappings = require("./MarkerMappings.json");
|
9 | // a stub is a short path segment that is used for the first and/or last segment(s) of a path
|
10 | exports.DEFAULT_STUB_LENGTH = 20;
|
11 | /**
|
12 | * getOffsetAndOrientationScalarsAlongAxis
|
13 | *
|
14 | * @param relValue {number}
|
15 | * @param axis {string}
|
16 | * @param referencedEntity
|
17 | * @return {OffsetOrientationAndPositionScalarsAlongAxis}
|
18 | */
|
19 | function getOffsetAndOrientationScalarsAlongAxis(positionScalar, relativeOffsetScalar, axis,
|
20 | // TODO are we correctly handling the case of a group as the referenced
|
21 | // entity? Do we have the group width and height yet to properly calculate
|
22 | // this?
|
23 | referencedEntity) {
|
24 | var offsetScalar = relativeOffsetScalar *
|
25 | (axis === "x" ? referencedEntity.width : referencedEntity.height);
|
26 | // TODO WP536 has a referenced entity that lacks width/height. Why?
|
27 | // The referenced entity was a group.
|
28 | // Is the problem that the group was nested?
|
29 | // Or is it a problem with the order of evaluation of entities (trying to
|
30 | // parse a dependent entity before its dependencies were parsed)?
|
31 | if (!fp_1.isFinite(offsetScalar)) {
|
32 | throw new Error("\n\t\t\tGot non-finite value " + offsetScalar + " for offsetScalar\n\t\t\talong " + axis + " axis for\n\t\t\tgetOffsetAndOrientationScalarsAlongAxis(\n\t\t\t\tpositionScalar=" + positionScalar + ",\n\t\t\t\trelativeOffsetScalar=" + relativeOffsetScalar + ",\n\t\t\t\treferencedEntity=\n\t\t\t\t" + JSON.stringify(referencedEntity, null, " ") + "\n\t\t\t)\n\t\t");
|
33 | }
|
34 | // orientationScalar here refers to the initial direction the edge takes as
|
35 | // it moves away from the entity to which it is attached.
|
36 | var orientationScalar;
|
37 | if (positionScalar === 0) {
|
38 | orientationScalar = -1;
|
39 | }
|
40 | else if (positionScalar === 1) {
|
41 | orientationScalar = 1;
|
42 | }
|
43 | else {
|
44 | orientationScalar = 0;
|
45 | }
|
46 | return { offsetScalar: offsetScalar, orientationScalar: orientationScalar, positionScalar: positionScalar };
|
47 | }
|
48 | /**
|
49 | * preprocessGPML
|
50 | *
|
51 | * @param edge {GPMLEdge}
|
52 | * @return {GPMLEdge}
|
53 | */
|
54 | function preprocessGPML(Edge) {
|
55 | var isAttachedToOrVia = Edge.Graphics.Point
|
56 | .filter(function (p) { return p.GraphRef && gpml_utilities_1.isDefinedCXML(p.GraphRef); })
|
57 | .map(function (p) { return p.GraphRef; });
|
58 | if (isAttachedToOrVia.length > 0) {
|
59 | // In pvjson, an edge attaches directly to another entity (Node, Edge, Group),
|
60 | // not to an anchor.
|
61 | // If the edge attaches to another edge, it does so VIA an anchor.
|
62 | Edge["isAttachedToOrVia"] = isAttachedToOrVia;
|
63 | }
|
64 | return Edge;
|
65 | }
|
66 | exports.preprocessGPML = preprocessGPML;
|
67 | /**
|
68 | * postprocessPVJSON
|
69 | *
|
70 | * @param referencedEntities
|
71 | * @param pvjsonEdge {pvjsonEdge}
|
72 | * @return {pvjsonEdge}
|
73 | */
|
74 | function postprocessPVJSON(referencedEntities, pvjsonEdge) {
|
75 | var points = pvjsonEdge.points, drawAs = pvjsonEdge.drawAs;
|
76 | var pointCount = points.length;
|
77 | var index = 0;
|
78 | var pvjsonEdgeIsAttachedTo = [];
|
79 | var providedPvjsonPoints = fp_1.map(function (point) {
|
80 | var marker = point.marker, x = point.x, y = point.y;
|
81 | if (!!marker) {
|
82 | // NOTE: side effects below
|
83 | if (index === 0) {
|
84 | pvjsonEdge.markerStart = marker;
|
85 | }
|
86 | else if (index === pointCount - 1) {
|
87 | pvjsonEdge.markerEnd = marker;
|
88 | }
|
89 | if (MarkerMappings.hasOwnProperty(marker)) {
|
90 | pvjsonEdge.type = fp_1.toPairs(MarkerMappings[marker]).reduce(function (acc, _a) {
|
91 | var namespace = _a[0], moreTypes = _a[1];
|
92 | return gpml_utilities_1.unionLSV(acc, moreTypes);
|
93 | }, pvjsonEdge.type);
|
94 | }
|
95 | }
|
96 | if (gpml_utilities_1.isAttachablePoint(point)) {
|
97 | // NOTE: pvjson allows for expressing one edge attached to another edge.
|
98 | // When we do this, we say that the POINT attaches to an ANCHOR on the other edge,
|
99 | // but the EDGE attaches to the other EDGE, never the anchor.
|
100 | var isAttachedTo = point.isAttachedTo, attachmentDisplay = point.attachmentDisplay;
|
101 | if (!attachmentDisplay.offset) {
|
102 | throw new Error("attachmentDisplay for a Point has no offset property.\n\t\t\t\t\tpostprocessPVJSON(\n\t\t\t\t\t\treferencedEntities=" + JSON.stringify(referencedEntities, null, " ") + ",\n\t\t\t\t\t\tpvjsonEdge=" + JSON.stringify(pvjsonEdge, null, " ") + "\n\t\t\t\t\t)");
|
103 | }
|
104 | // entityReferencedByPoint can be a regular node (DataNode, Shape, Label)
|
105 | // or an Anchor. If connected to an Anchor, the biological meaning is
|
106 | // that the edge is connected to another edge, but in this code, we
|
107 | // implement this by treating the Anchor as a node, as if it were
|
108 | // a "burr" that is always stuck (isAttachedTo) the other edge.
|
109 | var entityReferencedByPoint = referencedEntities &&
|
110 | !!isAttachedTo &&
|
111 | referencedEntities[isAttachedTo];
|
112 | var entityIdReferencedByEdge = gpml_utilities_1.isGPMLAnchor(entityReferencedByPoint)
|
113 | ? entityReferencedByPoint.isAttachedTo
|
114 | : entityReferencedByPoint.id;
|
115 | // WARNING: side effect
|
116 | pvjsonEdgeIsAttachedTo.push(entityIdReferencedByEdge);
|
117 | var entityReferencedByEdge = referencedEntities[entityIdReferencedByEdge];
|
118 | var orientation_1 = (point.orientation =
|
119 | point.orientation || []);
|
120 | // attachmentDisplay: { position: [x: number, y: number], offset: [xOffset: number, yOffset: number], orientation: [dx: number, dy: number] }
|
121 | //
|
122 | // x = xDistance / width (relative: [0,1])
|
123 | // y = yDistance / height (relative: [0,1])
|
124 | // xOffset = distance offset in x direction (absolute)
|
125 | // yOffset = distance offset in y direction (absolute)
|
126 | // dx = x component of edge emanation angle (unit: [0,1])
|
127 | // dy = y component of edge emanation angle (unit: [0,1])
|
128 | //
|
129 | // 0 ----------------- x ------------------->
|
130 | // | ========================================
|
131 | // | || ||
|
132 | // | || ||
|
133 | // | || ||
|
134 | // y || ||
|
135 | // | || ||
|
136 | // | || ||
|
137 | // | || ||
|
138 | // | || ||
|
139 | // v ===================*====================
|
140 | // |
|
141 | // yOffset |
|
142 | // | |
|
143 | // v |
|
144 | // ----------*
|
145 | // xOffset> \
|
146 | // \
|
147 | // \ dx>
|
148 | // dy \
|
149 | // | \
|
150 | // v \
|
151 | // \
|
152 | //
|
153 | // example above is an attachmentDisplay specifying an edge that emanates down and to the right
|
154 | // at a 45 deg. angle (1, 1), offset right 5 x units and down 11 y units from the center (0.5)
|
155 | // of the bottom side (1) of the node: {position: [0.75, 1], offset: [5, 11], orientation: [1, 1]}
|
156 | //
|
157 | //
|
158 | // where x is distance from left side along width axis as a percentage of the total width
|
159 | // y is distance from top side along height axis as a percentage of the total height
|
160 | // offsetX, offsetY are obvious from the name. Notice they are absolute, unlike x,y.
|
161 | // dx, dy are unit vector coordinates of a point that specifies how the edge emanates from the node
|
162 | if (gpml_utilities_1.isPvjsonSingleFreeNode(entityReferencedByEdge) ||
|
163 | gpml_utilities_1.isPvjsonGroup(entityReferencedByEdge) ||
|
164 | gpml_utilities_1.isPvjsonBurr(entityReferencedByEdge)) {
|
165 | var position = attachmentDisplay.position, relativeOffset = attachmentDisplay.relativeOffset;
|
166 | // edge connected to a SingleFreeNode, a Group or a Burr, but NOT another edge or an anchor
|
167 | try {
|
168 | var _a = getOffsetAndOrientationScalarsAlongAxis(position[0], relativeOffset[0], "x", entityReferencedByEdge), offsetScalarX = _a.offsetScalar, orientationScalarX = _a.orientationScalar;
|
169 | var _b = getOffsetAndOrientationScalarsAlongAxis(position[1], relativeOffset[1], "y", entityReferencedByEdge), offsetScalarY = _b.offsetScalar, orientationScalarY = _b.orientationScalar;
|
170 | if (index === 0) {
|
171 | orientation_1[0] = orientationScalarX;
|
172 | orientation_1[1] = orientationScalarY;
|
173 | }
|
174 | else {
|
175 | orientation_1[0] = -1 * orientationScalarX;
|
176 | orientation_1[1] = -1 * orientationScalarY;
|
177 | }
|
178 | // TODO is there a case where we would ever use offset for edges?
|
179 | attachmentDisplay.offset[0] = offsetScalarX;
|
180 | attachmentDisplay.offset[1] = offsetScalarY;
|
181 | point.attachmentDisplay = fp_1.omit(["relativeOffset"], attachmentDisplay);
|
182 | }
|
183 | catch (err) {
|
184 | throw new VError(err, "\n\t\t\t\t\t\tError for:\n\t\t\t\t\t\tpostprocessPVJSON(\n\t\t\t\t\t\t\treferencedEntities=" + JSON.stringify(referencedEntities, null, " ") + ",\n\t\t\t\t\t\t\tpvjsonEdge=" + JSON.stringify(pvjsonEdge, null, " ") + "\n\t\t\t\t\t\t)\n\t\t\t\t\t");
|
185 | /* TODO should we use this?
|
186 | console.warn(`Setting offsetScalar equal to 0.`);
|
187 | offsetScalar = 0;
|
188 | //*/
|
189 | }
|
190 | }
|
191 | else if (gpml_utilities_1.isGPMLAnchor(entityReferencedByPoint)) {
|
192 | // edge is connected to another edge via an anchor
|
193 | point.attachmentDisplay.position =
|
194 | entityReferencedByPoint.attachmentDisplay.position;
|
195 | }
|
196 | else {
|
197 | throw new Error("\n\t\t\t\t\tEdge or Point attached to unexpected entity.\n\t\t\t\t\tPoint is attached to:\n\t\t\t\t\t" + JSON.stringify(entityReferencedByPoint, null, " ") + "\n\t\t\t\t\tPoint is attached to:\n\t\t\t\t\t" + JSON.stringify(entityReferencedByEdge, null, " ") + "\n\t\t\t\t\tfor:\n\t\t\t\t\tpostprocessPVJSON(\n\t\t\t\t\treferencedEntities=" + JSON.stringify(referencedEntities, null, " ") + ",\n\t\t\t\t\tpvjsonEdge=" + JSON.stringify(pvjsonEdge, null, " ") + "\n\t\t\t\t\t)\n\t\t\t\t");
|
198 | }
|
199 | }
|
200 | // NOTE: side effect
|
201 | index += 1;
|
202 | return fp_1.omit(["marker"], point);
|
203 | }, points);
|
204 | var pvjsonEdgeAttachedToCount = pvjsonEdgeIsAttachedTo.length;
|
205 | if (pvjsonEdgeAttachedToCount > 0) {
|
206 | pvjsonEdge.isAttachedTo = pvjsonEdgeIsAttachedTo;
|
207 | }
|
208 | var allPvjsonPoints;
|
209 | if (["StraightLine", "SegmentedLine"].indexOf(drawAs) > -1) {
|
210 | allPvjsonPoints = providedPvjsonPoints;
|
211 | }
|
212 | else if (["ElbowLine", "CurvedLine"].indexOf(drawAs) > -1) {
|
213 | // pvjsonEdge.isAttachedTo refers to what the EDGE is fundamentally attached to.
|
214 | // pvjsonEdge.points[0].isAttachedTo refers to what the POINT is attached to.
|
215 | //
|
216 | // From the perspective of the biological meaning, the edge is always attached to
|
217 | // a regular node like a DataNode or Shape (maybe Label?) but never to an Anchor.
|
218 | //
|
219 | // From the perspective of the implementation of the graphics, we say the edge
|
220 | // has points, one or more of which can be connected to an Anchor.
|
221 | var sourceEntity = void 0;
|
222 | var targetEntity = void 0;
|
223 | if (pvjsonEdgeAttachedToCount === 2) {
|
224 | sourceEntity = referencedEntities[pvjsonEdgeIsAttachedTo[0]];
|
225 | targetEntity = referencedEntities[pvjsonEdgeIsAttachedTo[1]];
|
226 | }
|
227 | else if (pvjsonEdgeAttachedToCount === 1) {
|
228 | var firstPoint = providedPvjsonPoints[0];
|
229 | var lastPoint = providedPvjsonPoints[providedPvjsonPoints.length - 1];
|
230 | if (firstPoint.hasOwnProperty("isAttachedTo")) {
|
231 | sourceEntity = referencedEntities[pvjsonEdgeIsAttachedTo[0]];
|
232 | }
|
233 | else if (lastPoint.hasOwnProperty("isAttachedTo")) {
|
234 | targetEntity = referencedEntities[pvjsonEdgeIsAttachedTo[0]];
|
235 | }
|
236 | else {
|
237 | throw new Error("edge \"" + pvjsonEdge.id + "\" is said to be attached to \"" + pvjsonEdge.isAttachedTo.join() + "\",\n\t\t\t\t\tbut neither first nor last points have \"isAttachedTo\" property");
|
238 | }
|
239 | }
|
240 | allPvjsonPoints = calculateAllPoints_1.calculateAllPoints(providedPvjsonPoints.map(function (point) { return new geom_utils_1.SmartPoint(point); }), sourceEntity, targetEntity);
|
241 | }
|
242 | else {
|
243 | throw new Error("\n\t\t\tUnknown edge drawer \"" + drawAs + "\" for:\n\t\t\tpostprocessPVJSON(\n\t\t\treferencedEntities=" + JSON.stringify(referencedEntities, null, " ") + ",\n\t\t\tpvjsonEdge=" + JSON.stringify(pvjsonEdge, null, " ") + "\n\t\t\t)\n\t\t");
|
244 | // TODO should we use this?
|
245 | // allPvjsonPoints = providedPvjsonPoints;
|
246 | }
|
247 | // TODO how do we distinguish between intermediate (not first or last) points that a user
|
248 | // has explicitly specified vs. intermediate points that are only implied?
|
249 | // Do we need to? I think once a user specifies any implicit points, they may all be
|
250 | // made explicit.
|
251 | // GPML currently does not specify implicit intermediate points, but
|
252 | // pvjson does.
|
253 | pvjsonEdge.points = allPvjsonPoints;
|
254 | // TODO can I get rid of isAttachedToOrVia earlier?
|
255 | return fp_1.omit(["isAttachedToOrVia"], pvjsonEdge);
|
256 | }
|
257 | exports.postprocessPVJSON = postprocessPVJSON;
|
258 | //function recursivelyGetReferencedElements(acc, gpmlElement: GPMLElement) {
|
259 | // const { Graphics } = gpmlElement;
|
260 | // const graphRefIds: string[] = !!Graphics.Point &&
|
261 | // Graphics.Point[0]._exists !== false
|
262 | // ? Graphics.Point.filter(P => isString(P.GraphRef)).map(P => P.GraphRef)
|
263 | // : gpmlElement.hasOwnProperty("GraphRef")
|
264 | // ? arrayify(gpmlElement.GraphRef)
|
265 | // : [];
|
266 | //
|
267 | // const referencedElementIds = arrayify(graphRefIds);
|
268 | // //const referencedElementIds = unionLSV(graphRefIds, gpmlElement.GroupRef);
|
269 | // return referencedElementIds.length === 0
|
270 | // ? acc
|
271 | // : hl([
|
272 | // acc,
|
273 | // hl(referencedElementIds)
|
274 | // .flatMap(referencedElementId =>
|
275 | // hl(getGPMLElementByGraphId(referencedElementId))
|
276 | // )
|
277 | // .flatMap(function(referencedElement: GPMLElement) {
|
278 | // return recursivelyGetReferencedElements(
|
279 | // hl([referencedElement]),
|
280 | // referencedElement
|
281 | // );
|
282 | // })
|
283 | // ]).merge();
|
284 | //}
|
285 | //
|
286 | //export function postprocessPVJSON(
|
287 | // pvjsonEdge: PvjsonEdge
|
288 | //): Highland.Stream<PvjsonEdge> {
|
289 | // return hl([
|
290 | // hl([pvjsonEdge])
|
291 | // .reduce(hl([]), recursivelyGetReferencedElements)
|
292 | // .merge()
|
293 | // .flatMap(function(referencedGPMLElement: GPMLElement) {
|
294 | // return hl(
|
295 | // getPvjsonEntityLatestByGraphId(
|
296 | // referencedGPMLElement.GraphId
|
297 | // )
|
298 | // );
|
299 | // })
|
300 | // ])
|
301 | // .merge()
|
302 | // .reduce({}, function(
|
303 | // acc: {
|
304 | // [key: string]: (PvjsonNode | PvjsonEdge);
|
305 | // },
|
306 | // referencedEntity: (PvjsonNode | PvjsonEdge)
|
307 | // ) {
|
308 | // acc[referencedEntity.id] = referencedEntity;
|
309 | // return acc;
|
310 | // })
|
311 | // .map(function(referencedEntities) {
|
312 | // return process(pvjsonEdge, referencedEntities);
|
313 | // });
|
314 | // .merge();
|
315 | //}
|
316 | //
|
317 | //export function createEdgeTransformStream(
|
318 | // processor,
|
319 | // edgeType: "Interaction" | "GraphicalLine"
|
320 | //): (
|
321 | // s: Highland.Stream<GPML2013a.InteractionType | GPML2013a.GraphicalLineType>
|
322 | //) => Highland.Stream<(PvjsonNode | PvjsonEdge)> {
|
323 | // const {
|
324 | // fillInGPMLPropertiesFromParent,
|
325 | // getGPMLElementByGraphId,
|
326 | // getPvjsonEntityLatestByGraphId,
|
327 | // ensureGraphIdExists,
|
328 | // preprocessGPMLElement,
|
329 | // processPropertiesAndType
|
330 | // } = processor;
|
331 | //
|
332 | // function recursivelyGetReferencedElements(acc, gpmlElement: GPMLElement) {
|
333 | // const { Graphics } = gpmlElement;
|
334 | // const graphRefIds: string[] = !!Graphics.Point &&
|
335 | // Graphics.Point[0]._exists !== false
|
336 | // ? Graphics.Point.filter(P => isString(P.GraphRef)).map(P => P.GraphRef)
|
337 | // : gpmlElement.hasOwnProperty("GraphRef")
|
338 | // ? arrayify(gpmlElement.GraphRef)
|
339 | // : [];
|
340 | //
|
341 | // const referencedElementIds = arrayify(graphRefIds);
|
342 | // //const referencedElementIds = unionLSV(graphRefIds, gpmlElement.GroupRef);
|
343 | // return referencedElementIds.length === 0
|
344 | // ? acc
|
345 | // : hl([
|
346 | // acc,
|
347 | // hl(referencedElementIds)
|
348 | // .flatMap(referencedElementId =>
|
349 | // hl(getGPMLElementByGraphId(referencedElementId))
|
350 | // )
|
351 | // .flatMap(function(referencedElement: GPMLElement) {
|
352 | // return recursivelyGetReferencedElements(
|
353 | // hl([referencedElement]),
|
354 | // referencedElement
|
355 | // );
|
356 | // })
|
357 | // ]).merge();
|
358 | // }
|
359 | //
|
360 | // return function(s) {
|
361 | // return s
|
362 | // .map(preprocessGPMLElement)
|
363 | // .flatMap(function(
|
364 | // gpmlEdge: GPMLElement
|
365 | // ): Highland.Stream<Highland.Stream<PvjsonNode | PvjsonEdge>> {
|
366 | // const { Graphics } = gpmlEdge;
|
367 | //
|
368 | // const gpmlAnchors = Graphics.hasOwnProperty("Anchor") &&
|
369 | // Graphics.Anchor &&
|
370 | // Graphics.Anchor[0] &&
|
371 | // Graphics.Anchor[0]._exists !== false
|
372 | // ? Graphics.Anchor.filter(a => a.hasOwnProperty("GraphId"))
|
373 | // : [];
|
374 | //
|
375 | // const fillInGPMLPropertiesFromEdge = fillInGPMLPropertiesFromParent(
|
376 | // gpmlEdge
|
377 | // );
|
378 | //
|
379 | // return hl([
|
380 | // hl([gpmlEdge])
|
381 | // .map(processPropertiesAndType(edgeType))
|
382 | // .flatMap(function(pvjsonEdge: PvjsonEdge) {
|
383 | // return hl([
|
384 | // hl([gpmlEdge])
|
385 | // .reduce(hl([]), recursivelyGetReferencedElements)
|
386 | // .merge()
|
387 | // .flatMap(function(referencedGPMLElement: GPMLElement) {
|
388 | // return hl(
|
389 | // getPvjsonEntityLatestByGraphId(
|
390 | // referencedGPMLElement.GraphId
|
391 | // )
|
392 | // );
|
393 | // })
|
394 | // ])
|
395 | // .merge()
|
396 | // .reduce({}, function(
|
397 | // acc: {
|
398 | // [key: string]: (PvjsonNode | PvjsonEdge);
|
399 | // },
|
400 | // referencedEntity: (PvjsonNode | PvjsonEdge)
|
401 | // ) {
|
402 | // acc[referencedEntity.id] = referencedEntity;
|
403 | // return acc;
|
404 | // })
|
405 | // .map(function(referencedEntities) {
|
406 | // return process(pvjsonEdge, referencedEntities);
|
407 | // });
|
408 | // }),
|
409 | // hl(gpmlAnchors)
|
410 | // .map(preprocessGPMLElement)
|
411 | // .map(function(gpmlAnchor: GPMLElement) {
|
412 | // const filledInAnchor = fillInGPMLPropertiesFromEdge(gpmlAnchor);
|
413 | // filledInAnchor.GraphRef = gpmlEdge.GraphId;
|
414 | // return filledInAnchor;
|
415 | // })
|
416 | // .map(processPropertiesAndType("Anchor"))
|
417 | // .map(function(pvjsonAnchor: PvjsonNode): PvjsonNode {
|
418 | // const drawAnchorAs = pvjsonAnchor.drawAs;
|
419 | // if (drawAnchorAs === "None") {
|
420 | // defaultsDeep(pvjsonAnchor, {
|
421 | // Height: 4,
|
422 | // Width: 4
|
423 | // });
|
424 | // } else if (drawAnchorAs === "Circle") {
|
425 | // defaultsDeep(pvjsonAnchor, {
|
426 | // Height: 8,
|
427 | // Width: 8
|
428 | // });
|
429 | // }
|
430 | // return pvjsonAnchor;
|
431 | // })
|
432 | // ]);
|
433 | // })
|
434 | // .merge();
|
435 | // };
|
436 | //}
|
437 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWRnZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9lZGdlL2VkZ2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSxnQ0FBZ0U7QUFDaEUsb0RBUTJCO0FBQzNCLDRDQUEyQztBQWMzQywyREFBMEQ7QUFDMUQsK0JBQWlDO0FBQ2pDLHNEQUF3RDtBQUV4RCw2RkFBNkY7QUFDaEYsUUFBQSxtQkFBbUIsR0FBRyxFQUFFLENBQUM7QUFFdEM7Ozs7Ozs7R0FPRztBQUNILGlEQUNFLGNBQXNCLEVBQ3RCLG9CQUE0QixFQUM1QixJQUFlO0FBQ2YsdUVBQXVFO0FBQ3ZFLDBFQUEwRTtBQUMxRSxRQUFRO0FBQ1IsZ0JBQTRCO0lBRTVCLElBQUksWUFBWSxHQUNkLG9CQUFvQjtRQUNwQixDQUFDLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDcEUsbUVBQW1FO0lBQ25FLHFDQUFxQztJQUNyQyw0Q0FBNEM7SUFDNUMseUVBQXlFO0lBQ3pFLG1FQUFtRTtJQUNuRSxFQUFFLENBQUMsQ0FBQyxDQUFDLGFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDNUIsTUFBTSxJQUFJLEtBQUssQ0FDYixrQ0FDb0IsWUFBWSx1Q0FDM0IsSUFBSSwwRkFFTSxjQUFjLHdDQUNSLG9CQUFvQiw4Q0FFekMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxnQkFBZ0IsRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLG9CQUUvQyxDQUNFLENBQUM7SUFDSixDQUFDO0lBRUQsMkVBQTJFO0lBQzNFLHlEQUF5RDtJQUN6RCxJQUFJLGlCQUFpQixDQUFDO0lBQ3RCLEVBQUUsQ0FBQyxDQUFDLGNBQWMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3pCLGlCQUFpQixHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQ3pCLENBQUM7SUFBQyxJ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 |
\ | No newline at end of file |