UNPKG

33 kBJavaScriptView Raw
1import "source-map-support/register";
2// TODO should I get rid of the lib above for production browser build?
3import { defaultsDeep as defaultsDeepM } from "lodash";
4import { camelCase, concat, curry, fromPairs, isArray, isObject, isString, toPairsIn } from "lodash/fp";
5import * as hl from "highland";
6import * as VError from "verror";
7import * as iassign from "immutable-assign";
8iassign.setOption({
9 // Deep freeze both input and output. Used in development to make sure they don't change.
10 // TODO watch issue and re-enable when addressed: https://github.com/engineforce/ImassignM/issues/11
11 //freeze: true,
12 ignoreIfNoChange: true
13});
14import { isDefinedCXML, unionLSV } from "./gpml-utilities";
15import { GraphIdManager } from "./GraphIdManager";
16const GPML_ELEMENT_NAME_TO_KAAVIO_TYPE = {
17 Anchor: "Burr",
18 BiopaxRef: "Citation",
19 DataNode: "SingleFreeNode",
20 GraphicalLine: "Edge",
21 Group: "Group",
22 Interaction: "Edge",
23 Label: "SingleFreeNode",
24 //openControlledVocabulary: "Skip",
25 //PublicationXref: "Skip",
26 Shape: "SingleFreeNode",
27 State: "Burr"
28};
29const VALUES_TO_SKIP = ["", null, undefined];
30// TODO update lodash/fp TS defs to use "x is ..."
31function isStringTS(x) {
32 return isString(x);
33}
34function isArrayTS(x) {
35 return isArray(x);
36}
37// NOTE: isPlainObject does not return true for an instance of a class
38function isRecord(x) {
39 return !isArray(x) && isObject(x);
40}
41export class Processor {
42 constructor(KeyMappings, KeyValueConverters, ValueMappings, ValueConverters) {
43 this.output = {
44 pathway: {
45 // NOTE: GPML does not contain a way to express fill (background color).
46 // It's always just white.
47 fill: "white",
48 strokeWidth: 0,
49 stroke: "black",
50 contains: [],
51 drawAs: "rect",
52 gpmlElementName: "Pathway",
53 height: 0,
54 // it appears type = {id: string} & type = {id?: string} makes id required.
55 // TODO can we override that just for PathwayStarter?
56 id: undefined,
57 kaavioType: "Group",
58 name: "New Pathway",
59 // TODO what should the padding be?
60 padding: 5,
61 type: ["Pathway"],
62 width: 0,
63 x: 0,
64 y: 0,
65 zIndex: 0,
66 // NOTE: these properties only apply contents of current element. They do not affect children.
67 fontSize: 12,
68 fontWeight: "bold",
69 textAlign: "left",
70 verticalAlign: "top"
71 },
72 entitiesById: {}
73 };
74 this.graphIdManager = new GraphIdManager();
75 this.graphIdsByGraphRef = {};
76 this.containedGraphIdsByGroupGraphId = {};
77 this.containedGraphIdsByGroupGroupId = {};
78 this.promisedGraphIdByGroupId = {};
79 this.groupIdToGraphIdStream = hl();
80 this.promisedGPMLElementByGraphId = {};
81 this.gpmlElementStream = hl();
82 this.promisedPvjsonEntityLatestByGraphId = {};
83 this.pvjsonEntityLatestStream = hl();
84 this.graphIdToZIndex = {};
85 this.ensureGraphIdExists = (gpmlElement) => {
86 const { containedGraphIdsByGroupGroupId, graphIdManager, groupIdToGraphIdStream } = this;
87 const { GroupId, GroupRef } = gpmlElement;
88 let { GraphId } = gpmlElement;
89 // TODO does this work for all elements? Are there any that we give an id that don't have one in GPML?
90 // Does the schema allow the element to have a GraphId?
91 if (!!GraphId) {
92 // Does it actually have one?
93 if (!isDefinedCXML(GraphId)) {
94 // NOTE: we are making sure that elements that CAN have a GraphId
95 // always DO have a GraphId. GraphIds are optional in GPML for Groups,
96 // so we will add one if it's not already specified. But Pathway
97 // elements never have GraphIds, so we don't add one for them.
98 GraphId = gpmlElement.GraphId = graphIdManager.generateAndRecord();
99 }
100 else {
101 graphIdManager.recordExisting(GraphId);
102 }
103 if (isDefinedCXML(GroupRef)) {
104 containedGraphIdsByGroupGroupId[GroupRef] =
105 containedGraphIdsByGroupGroupId[GroupRef] || [];
106 containedGraphIdsByGroupGroupId[GroupRef].push(GraphId);
107 }
108 if (isDefinedCXML(GroupId)) {
109 groupIdToGraphIdStream.write([GroupId, GraphId]);
110 }
111 }
112 else {
113 throw new Error("GraphId missing.");
114 }
115 return gpmlElement;
116 };
117 this.fillInGPMLPropertiesFromParent = curry((gpmlParentElement, gpmlChildElement) => {
118 const { Graphics } = gpmlParentElement;
119 // NOTE: this makes some assumptions about the distribution of ZOrder values in GPML
120 // TODO This is what we used to do. Do we still need to do this? Or can we just sort them
121 // based on whether they are burrs of each other?
122 //element.zIndex = element.hasOwnProperty('zIndex') ? element.zIndex : referencedElement.zIndex + 1 / elementCount;
123 const propertiesToFillIn = {
124 Graphics: {
125 ZOrder: Graphics.ZOrder
126 }
127 };
128 /* TODO can we delete this?
129 if (isDefinedCXML(gpmlParentElement.GroupRef)) {
130 propertiesToFillIn.GroupRef = gpmlParentElement.GroupRef;
131 }
132 //*/
133 return defaultsDeepM(gpmlChildElement, propertiesToFillIn);
134 });
135 this.getPvjsonEntityLatestByGraphId = graphId => {
136 let promisedPvjsonEntity = this.promisedPvjsonEntityLatestByGraphId[graphId];
137 if (promisedPvjsonEntity) {
138 return promisedPvjsonEntity;
139 }
140 else {
141 const { pvjsonEntityLatestStream } = this;
142 // NOTE: we don't need to set the cache here, because the cache is
143 // set for every item that flows through pvjsonEntityLatestStream
144 promisedPvjsonEntity = new Promise(function (resolve, reject) {
145 pvjsonEntityLatestStream
146 .observe()
147 .find(pvjsonEntity => pvjsonEntity.id === graphId)
148 .errors(reject)
149 .each(resolve);
150 });
151 return promisedPvjsonEntity;
152 }
153 };
154 this.getGPMLElementByGraphId = GraphId => {
155 let promisedGPMLElement = this.promisedGPMLElementByGraphId[GraphId];
156 if (promisedGPMLElement) {
157 return promisedGPMLElement;
158 }
159 else {
160 const { gpmlElementStream } = this;
161 // NOTE: we don't need to set the cache here, because the cache is
162 // set for every item that flows through gpmlElementStream
163 promisedGPMLElement = new Promise(function (resolve, reject) {
164 gpmlElementStream
165 .observe()
166 .find(gpmlElement => gpmlElement.GraphId === GraphId)
167 .errors(reject)
168 .each(resolve);
169 });
170 return promisedGPMLElement;
171 }
172 };
173 this.preprocessGPMLElement = (gpmlElement) => {
174 const { ensureGraphIdExists, gpmlElementStream } = this;
175 const processedGPMLElement = ensureGraphIdExists(gpmlElement);
176 // NOTE: side effect
177 gpmlElementStream.write(processedGPMLElement);
178 return processedGPMLElement;
179 };
180 this.processGPMLAndPropertiesAndType = curry((gpmlElementName, gpmlElement) => {
181 const { preprocessGPMLElement, processPropertiesAndType, pvjsonEntityLatestStream } = this;
182 return processPropertiesAndType(gpmlElementName, preprocessGPMLElement(gpmlElement));
183 });
184 this.processProperties = curry((gpmlElement) => {
185 const { processKV } = this;
186 const entity = fromPairs(toPairsIn(gpmlElement).reduce((acc, x) => concat(acc, processKV(gpmlElement, x)), []));
187 if (!!entity.rotation) {
188 entity.textRotation = -1 * entity.rotation;
189 }
190 return entity;
191 });
192 this.processPropertiesAndType = curry((gpmlElementName, gpmlElement) => {
193 const pvjsonEntity = this.processType(gpmlElementName, this.processProperties(gpmlElement));
194 this.pvjsonEntityLatestStream.write(pvjsonEntity);
195 return pvjsonEntity;
196 });
197 this.processType = curry((gpmlElementName, processed) => {
198 const kaavioType = GPML_ELEMENT_NAME_TO_KAAVIO_TYPE[gpmlElementName];
199 processed.type = unionLSV(processed.type, gpmlElementName, kaavioType);
200 if (!!kaavioType) {
201 processed.kaavioType = kaavioType;
202 }
203 processed.gpmlElementName = gpmlElementName;
204 return processed;
205 });
206 this.setPvjsonEntity = pvjsonEntity => {
207 const { graphIdToZIndex, promisedPvjsonEntityLatestByGraphId } = this;
208 const { id, zIndex } = pvjsonEntity;
209 graphIdToZIndex[id] = zIndex;
210 promisedPvjsonEntityLatestByGraphId[id] = Promise.resolve(pvjsonEntity);
211 this.output = iassign(this.output, function (o) {
212 return o.entitiesById;
213 }, function (entitiesById) {
214 entitiesById[pvjsonEntity.id] = pvjsonEntity;
215 return entitiesById;
216 });
217 };
218 this.getGPMLKeyAsJSFunctionName = (gpmlKey) => {
219 // NOTE: gpmlKeyAsJSFunctionName is for attributes like "Data-Source", because
220 // the following would be invalid JS:
221 // export function Data-Source() {};
222 // TODO what about things like spaces, etc.?
223 return gpmlKey.replace("-", "");
224 };
225 this.getPvjsonValue = (gpmlElement, gpmlKey, gpmlValue) => {
226 const { getGPMLKeyAsJSFunctionName, getPvjsonValue, processKV, ValueConverters, ValueMappings } = this;
227 const gpmlKeyAsJSFunctionName = getGPMLKeyAsJSFunctionName(gpmlKey);
228 let pvjsonValue;
229 try {
230 if (ValueConverters.hasOwnProperty(gpmlKeyAsJSFunctionName)) {
231 return ValueConverters[gpmlKeyAsJSFunctionName](gpmlElement);
232 }
233 else if (isStringTS(gpmlValue)) {
234 if (ValueMappings.hasOwnProperty(gpmlValue)) {
235 return ValueMappings[gpmlValue];
236 }
237 else {
238 return gpmlValue;
239 }
240 }
241 else if (isArrayTS(gpmlValue)) {
242 return gpmlValue.map(valueItem => {
243 return getPvjsonValue(valueItem, gpmlKey, valueItem);
244 });
245 }
246 else if (isRecord(gpmlValue)) {
247 return fromPairs(toPairsIn(gpmlValue).reduce((acc, [key, value]) => {
248 processKV(gpmlValue, [key, value]).forEach(function (x) {
249 acc.push(x);
250 });
251 return acc;
252 }, []));
253 }
254 else {
255 return gpmlValue;
256 }
257 }
258 catch (err) {
259 throw new VError(err, ` when calling
260 getPvjsonValue(
261 ${JSON.stringify(gpmlElement, null, "")},
262 ${JSON.stringify(gpmlKey, null, "")},
263 ${JSON.stringify(gpmlValue, null, "")}
264 )
265 `);
266 }
267 };
268 this.processKV = curry((gpmlElement, [gpmlKey, gpmlValue]) => {
269 try {
270 const { getGPMLKeyAsJSFunctionName, getPvjsonValue, KeyMappings, KeyValueConverters, processKV, ValueMappings } = this;
271 const gpmlKeyAsJSFunctionName = getGPMLKeyAsJSFunctionName(gpmlKey);
272 if (VALUES_TO_SKIP.indexOf(gpmlValue) > -1) {
273 return [];
274 }
275 if (KeyValueConverters.hasOwnProperty(gpmlKeyAsJSFunctionName)) {
276 return KeyValueConverters[gpmlKeyAsJSFunctionName](gpmlElement, KeyMappings, ValueMappings);
277 }
278 const pvjsonKey = KeyMappings[gpmlKey];
279 // NOTE "pvjson:merge" is for elements like "Graphics", where they
280 // are nested in GPML but are merged into the parent in pvjson.
281 if (gpmlKey[0] === "_" ||
282 pvjsonKey === "pvjson:delete" ||
283 (isObject(gpmlValue) && !isDefinedCXML(gpmlValue))) {
284 // NOTE: we don't want to include "private" keys, such as
285 // "_exists" or "_namespace".
286 return [];
287 }
288 else if (pvjsonKey === "pvjson:merge") {
289 return toPairsIn(gpmlValue).reduce((acc, pair) => concat(acc, processKV(gpmlElement, pair)), []);
290 }
291 else if (pvjsonKey === "pvjson:each") {
292 // NOTE: Example of what uses this is GPML Attribute.
293 // (in GPML, 'Attribute' is an XML *ELEMENT* named "Attribute")
294 return toPairsIn(gpmlValue
295 .filter(({ Key, Value }) => VALUES_TO_SKIP.indexOf(Value) === -1)
296 .map(({ Key, Value }) => {
297 return processKV(gpmlElement, [Key, Value]);
298 })
299 .reduce((acc, [[processedKey, processedValue]]) => {
300 // NOTE: this looks more complicated than it needs to be,
301 // but it's to handle the case where there are two or more
302 // sibling Attribute elements that share the same Key.
303 // I don't know of any cases of this in our actual GPML,
304 // but the XSD does not require unique Keys for sibling
305 // Attributes.
306 if (acc.hasOwnProperty(processedKey)) {
307 acc[processedKey] = unionLSV(acc[processedKey], processedValue);
308 }
309 else {
310 acc[processedKey] = processedValue;
311 }
312 return acc;
313 }, {}));
314 }
315 else {
316 const pvjsonValue = getPvjsonValue(gpmlElement, gpmlKey, gpmlValue);
317 // NOTE: we don't include key/value pairs when the value is missing
318 if (VALUES_TO_SKIP.indexOf(pvjsonValue) === -1) {
319 return [[pvjsonKey || camelCase(gpmlKey), pvjsonValue]];
320 }
321 else {
322 return [];
323 }
324 }
325 }
326 catch (err) {
327 throw new VError(err, ` when calling processor.processKV(
328 gpmlElement: ${JSON.stringify(gpmlElement, null, " ")},
329 [
330 gpmlKey: ${gpmlKey},
331 gpmlValue: ${JSON.stringify(gpmlValue, null, " ")}
332 ]
333 )
334 `);
335 }
336 });
337 const { graphIdToZIndex, graphIdsByGraphRef, promisedGPMLElementByGraphId, gpmlElementStream, promisedGraphIdByGroupId, groupIdToGraphIdStream, promisedPvjsonEntityLatestByGraphId, pvjsonEntityLatestStream } = this;
338 this.KeyMappings = KeyMappings;
339 this.KeyValueConverters = KeyValueConverters;
340 this.ValueMappings = ValueMappings;
341 this.ValueConverters = ValueConverters;
342 groupIdToGraphIdStream.each(function ([groupId, graphId]) {
343 promisedGraphIdByGroupId[groupId] = Promise.resolve(graphId);
344 });
345 gpmlElementStream.each(function (gpmlElement) {
346 promisedGPMLElementByGraphId[gpmlElement.GraphId] = Promise.resolve(gpmlElement);
347 });
348 pvjsonEntityLatestStream
349 .doto(function (pvjsonEntity) {
350 const { id, zIndex } = pvjsonEntity;
351 graphIdToZIndex[id] = zIndex;
352 promisedPvjsonEntityLatestByGraphId[id] = Promise.resolve(pvjsonEntity);
353 })
354 .errors(function (err, push) {
355 push(new VError(err, ` observed in pvjsonEntityLatestStream
356 `));
357 })
358 .each(function (pvjsonEntity) { });
359 /*
360 TODO do we need this?
361 endStream.each(function(x) {
362 groupIdToGraphIdStream.end();
363 gpmlElementStream.end();
364 pvjsonEntityLatestStream.end();
365 });
366 //*/
367 }
368}
369//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUHJvY2Vzc29yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1Byb2Nlc3Nvci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLDZCQUE2QixDQUFDO0FBQ3JDLHVFQUF1RTtBQUV2RSxPQUFPLEVBQUUsWUFBWSxJQUFJLGFBQWEsRUFBRSxNQUFNLFFBQVEsQ0FBQztBQUN2RCxPQUFPLEVBRUwsU0FBUyxFQUNULE1BQU0sRUFDTixLQUFLLEVBR0wsU0FBUyxFQUVULE9BQU8sRUFDUCxRQUFRLEVBQ1IsUUFBUSxFQUlSLFNBQVMsRUFDVixNQUFNLFdBQVcsQ0FBQztBQUNuQixPQUFPLEtBQUssRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMvQixPQUFPLEtBQUssTUFBTSxNQUFNLFFBQVEsQ0FBQztBQUNqQyxPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBQzVDLE9BQU8sQ0FBQyxTQUFTLENBQUM7SUFDaEIseUZBQXlGO0lBQ3pGLG9HQUFvRztJQUNwRyxlQUFlO0lBQ2YsZ0JBQWdCLEVBQUUsSUFBSTtDQUN2QixDQUFDLENBQUM7QUFhSCxPQUFPLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQzNELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUVsRCxNQUFNLGdDQUFnQyxHQUFHO0lBQ3ZDLE1BQU0sRUFBRSxNQUFNO0lBQ2QsU0FBUyxFQUFFLFVBQVU7SUFDckIsUUFBUSxFQUFFLGdCQUFnQjtJQUMxQixhQUFhLEVBQUUsTUFBTTtJQUNyQixLQUFLLEVBQUUsT0FBTztJQUNkLFdBQVcsRUFBRSxNQUFNO0lBQ25CLEtBQUssRUFBRSxnQkFBZ0I7SUFDdkIsbUNBQW1DO0lBQ25DLDBCQUEwQjtJQUMxQixLQUFLLEVBQUUsZ0JBQWdCO0lBQ3ZCLEtBQUssRUFBRSxNQUFNO0NBQ2QsQ0FBQztBQUVGLE1BQU0sY0FBYyxHQUFHLENBQUMsRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQztBQWE3QyxrREFBa0Q7QUFDbEQsb0JBQW9CLENBQU07SUFDeEIsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNyQixDQUFDO0FBRUQsbUJBQW1CLENBQU07SUFDdkIsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNwQixDQUFDO0FBRUQsc0VBQXNFO0FBQ3RFLGtCQUFrQixDQUFNO0lBQ3RCLE1BQU0sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDcEMsQ0FBQztBQUVELE1BQU07SUE2REosWUFBWSxXQUFXLEVBQUUsa0JBQWtCLEVBQUUsYUFBYSxFQUFFLGVBQWU7UUE1RDNFLFdBQU0sR0FHRjtZQUNGLE9BQU8sRUFBRTtnQkFDUCx3RUFBd0U7Z0JBQ3hFLDBCQUEwQjtnQkFDMUIsSUFBSSxFQUFFLE9BQU87Z0JBQ2IsV0FBVyxFQUFFLENBQUM7Z0JBQ2QsTUFBTSxFQUFFLE9BQU87Z0JBQ2YsUUFBUSxFQUFFLEVBQUU7Z0JBQ1osTUFBTSxFQUFFLE1BQU07Z0JBQ2QsZUFBZSxFQUFFLFNBQVM7Z0JBQzFCLE1BQU0sRUFBRSxDQUFDO2dCQUNULDJFQUEyRTtnQkFDM0UscURBQXFEO2dCQUNyRCxFQUFFLEVBQUUsU0FBUztnQkFDYixVQUFVLEVBQUUsT0FBTztnQkFDbkIsSUFBSSxFQUFFLGFBQWE7Z0JBQ25CLG1DQUFtQztnQkFDbkMsT0FBTyxFQUFFLENBQUM7Z0JBQ1YsSUFBSSxFQUFFLENBQUMsU0FBUyxDQUFDO2dCQUNqQixLQUFLLEVBQUUsQ0FBQztnQkFDUixDQUFDLEVBQUUsQ0FBQztnQkFDSixDQUFDLEVBQUUsQ0FBQztnQkFDSixNQUFNLEVBQUUsQ0FBQztnQkFDVCw4RkFBOEY7Z0JBQzlGLFFBQVEsRUFBRSxFQUFFO2dCQUNaLFVBQVUsRUFBRSxNQUFNO2dCQUNsQixTQUFTLEVBQUUsTUFBTTtnQkFDakIsYUFBYSxFQUFFLEtBQUs7YUFDckI7WUFDRCxZQUFZLEVBQUUsRUFBRTtTQUNqQixDQUFDO1FBRUYsbUJBQWMsR0FBbUIsSUFBSSxjQUFjLEVBQUUsQ0FBQztRQUV0RCx1QkFBa0IsR0FBNkIsRUFBRSxDQUFDO1FBQ2xELG9DQUErQixHQUE2QixFQUFFLENBQUM7UUFDL0Qsb0NBQStCLEdBQTZCLEVBQUUsQ0FBQztRQUUvRCw2QkFBd0IsR0FBb0MsRUFBRSxDQUFDO1FBQy9ELDJCQUFzQixHQUFzQyxFQUFFLEVBQUUsQ0FBQztRQUVqRSxpQ0FBNEIsR0FBeUMsRUFBRSxDQUFDO1FBQ3hFLHNCQUFpQixHQUFpQyxFQUFFLEVBQUUsQ0FBQztRQUV2RCx3Q0FBbUMsR0FHL0IsRUFBRSxDQUFDO1FBQ1AsNkJBQXdCLEdBQWtDLEVBQUUsRUFBRSxDQUFDO1FBRS9ELG9CQUFlLEdBQTJCLEVBQUUsQ0FBQztRQXVFckMsd0JBQW1CLEdBQUcsQ0FBQyxXQUF3QixFQUFlLEVBQUU7WUFDdEUsTUFBTSxFQUNKLCtCQUErQixFQUMvQixjQUFjLEVBQ2Qsc0JBQXNCLEVBQ3ZCLEdBQUcsSUFBSSxDQUFDO1lBQ1QsTUFBTSxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsR0FBRyxXQUFXLENBQUM7WUFDMUMsSUFBSSxFQUFFLE9BQU8sRUFBRSxHQUFHLFdBQVcsQ0FBQztZQUU5QixzR0FBc0c7WUFDdEcsdURBQXVEO1lBQ3ZELEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO2dCQUNkLDZCQUE2QjtnQkFDN0IsRUFBRSxDQUFDLENBQUMsQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUM1QixpRUFBaUU7b0JBQ2pFLHNFQUFzRTtvQkFDdEUsZ0VBQWdFO29CQUNoRSw4REFBOEQ7b0JBQzlELE9BQU8sR0FBRyxXQUFXLENBQUMsT0FBTyxHQUFHLGNBQWMsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO2dCQUNyRSxDQUFDO2dCQUFDLElBQUksQ0FBQyxDQUFDO29CQUNOLGNBQWMsQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3pDLENBQUM7Z0JBRUQsRUFBRSxDQUFDLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDNUIsK0JBQStCLENBQUMsUUFBUSxDQUFDO3dCQUN2QywrQkFBK0IsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7b0JBQ2xELCtCQUErQixDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDMUQsQ0FBQztnQkFFRCxFQUFFLENBQUMsQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUMzQixzQkFBc0IsQ0FBQyxLQUFLLENBQUMsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQztnQkFDbkQsQ0FBQztZQUNILENBQUM7WUFBQyxJQUFJLENBQUMsQ0FBQztnQkFDTixNQUFNLElBQUksS0FBSyxDQUFDLGtCQUFrQixDQUFDLENBQUM7WUFDdEMsQ0FBQztZQUVELE1BQU0sQ0FBQyxXQUFXLENBQUM7UUFDckIsQ0FBQyxDQUFDO1FBRUYsbUNBQThCLEdBQUcsS0FBSyxDQUNwQyxDQUNFLGlCQUE4QixFQUM5QixnQkFBNkIsRUFDaEIsRUFBRTtZQUNmLE1BQU0sRUFBRSxRQUFRLEVBQUUsR0FBRyxpQkFBaUIsQ0FBQztZQUV2QyxvRkFBb0Y7WUFDcEYseUZBQXlGO1lBQ3pGLGlEQUFpRDtZQUNqRCxtSEFBbUg7WUFDbkgsTUFBTSxrQkFBa0IsR0FBd0I7Z0JBQzlDLFFBQVEsRUFBRTtvQkFDUixNQUFNLEVBQUUsUUFBUSxDQUFDLE1BQU07aUJBQ3hCO2FBQ0YsQ0FBQztZQUVGOzs7O3NCQUlDO1lBRUQsTUFBTSxDQUFDLGFBQWEsQ0FBQyxnQkFBZ0IsRUFBRSxrQkFBa0IsQ0FBQyxDQUFDO1FBQzdELENBQUMsQ0FDRixDQUFDO1FBRUYsbUNBQThCLEdBQUcsT0FBTyxDQUFDLEVBQUU7WUFDekMsSUFBSSxvQkFBb0IsR0FBRyxJQUFJLENBQUMsbUNBQW1DLENBQ2pFLE9BQU8sQ0FDUixDQUFDO1lBQ0YsRUFBRSxDQUFDLENBQUMsb0JBQW9CLENBQUMsQ0FBQyxDQUFDO2dCQUN6QixNQUFNLENBQUMsb0JBQW9CLENBQUM7WUFDOUIsQ0FBQztZQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNOLE1BQU0sRUFBRSx3QkFBd0IsRUFBRSxHQUFHLElBQUksQ0FBQztnQkFDMUMsa0VBQWtFO2dCQUNsRSxpRUFBaUU7Z0JBQ2pFLG9CQUFvQixHQUFHLElBQUksT0FBTyxDQUFDLFVBQVMsT0FBTyxFQUFFLE1BQU07b0JBQ3pELHdCQUF3Qjt5QkFDckIsT0FBTyxFQUFFO3lCQUNULElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxFQUFFLEtBQUssT0FBTyxDQUFDO3lCQUNqRCxNQUFNLENBQUMsTUFBTSxDQUFDO3lCQUNkLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztnQkFDbkIsQ0FBQyxDQUFDLENBQUM7Z0JBRUgsTUFBTSxDQUFDLG9CQUFvQixDQUFDO1lBQzlCLENBQUM7UUFDSCxDQUFDLENBQUM7UUFFRiw0QkFBdUIsR0FBRyxPQUFPLENBQUMsRUFBRTtZQUNsQyxJQUFJLG1CQUFtQixHQUFHLElBQUksQ0FBQyw0QkFBNEIsQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUNyRSxFQUFFLENBQUMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUM7Z0JBQ3hCLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQztZQUM3QixDQUFDO1lBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ04sTUFBTSxFQUFFLGlCQUFpQixFQUFFLEdBQUcsSUFBSSxDQUFDO2dCQUNuQyxrRUFBa0U7Z0JBQ2xFLDBEQUEwRDtnQkFDMUQsbUJBQW1CLEdBQUcsSUFBSSxPQUFPLENBQUMsVUFBUyxPQUFPLEVBQUUsTUFBTTtvQkFDeEQsaUJBQWlCO3lCQUNkLE9BQU8sRUFBRTt5QkFDVCxJQUFJLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsT0FBTyxLQUFLLE9BQU8sQ0FBQzt5QkFDcEQsTUFBTSxDQUFDLE1BQU0sQ0FBQzt5QkFDZCxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ25CLENBQUMsQ0FBQyxDQUFDO2dCQUVILE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQztZQUM3QixDQUFDO1FBQ0gsQ0FBQyxDQUFDO1FBRUYsMEJBQXFCLEdBQUcsQ0FBQyxXQUF3QixFQUFlLEVBQUU7WUFDaEUsTUFBTSxFQUFFLG1CQUFtQixFQUFFLGlCQUFpQixFQUFFLEdBQUcsSUFBSSxDQUFDO1lBQ3hELE1BQU0sb0JBQW9CLEdBQUcsbUJBQW1CLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDOUQsb0JBQW9CO1lBQ3BCLGlCQUFpQixDQUFDLEtBQUssQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO1lBQzlDLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQztRQUM5QixDQUFDLENBQUM7UUFFRixvQ0FBK0IsR0FBRyxLQUFLLENBQ3JDLENBQUMsZUFBdUIsRUFBRSxXQUFXLEVBQUUsRUFBRTtZQUN2QyxNQUFNLEVBQ0oscUJBQXFCLEVBQ3JCLHdCQUF3QixFQUN4Qix3QkFBd0IsRUFDekIsR0FBRyxJQUFJLENBQUM7WUFDVCxNQUFNLENBQUMsd0JBQXdCLENBQzdCLGVBQWUsRUFDZixxQkFBcUIsQ0FBQyxXQUFXLENBQUMsQ0FDbkMsQ0FBQztRQUNKLENBQUMsQ0FDRixDQUFDO1FBRUYsc0JBQWlCLEdBQUcsS0FBSyxDQUFDLENBQUMsV0FBd0IsRUFBZ0IsRUFBRTtZQUNuRSxNQUFNLEVBQUUsU0FBUyxFQUFFLEdBQUcsSUFBSSxDQUFDO1lBQzNCLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FDdEIsU0FBUyxDQUFDLFdBQVcsQ0FBQyxDQUFDLE1BQU0sQ0FDM0IsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLFNBQVMsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFDbEQsRUFBRSxDQUNILENBQ0YsQ0FBQztZQUNGLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQztnQkFDdEIsTUFBTSxDQUFDLFlBQVksR0FBRyxDQUFDLENBQUMsR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDO1lBQzdDLENBQUM7WUFDRCxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQ2hCLENBQUMsQ0FBQyxDQUFDO1FBRUgsNkJBQXdCLEdBQUcsS0FBSyxDQUM5QixDQUFDLGVBQXVCLEVBQUUsV0FBd0IsRUFBZ0IsRUFBRTtZQUNsRSxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsV0FBVyxDQUNuQyxlQUFlLEVBQ2YsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxDQUNwQyxDQUFDO1lBQ0YsSUFBSSxDQUFDLHdCQUF3QixDQUFDLEtBQUssQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUNsRCxNQUFNLENBQUMsWUFBWSxDQUFDO1FBQ3RCLENBQUMsQ0FDRixDQUFDO1FBRU0sZ0JBQVcsR0FBRyxLQUFLLENBQ3pCLENBQUMsZUFBdUIsRUFBRSxTQUF1QixFQUFnQixFQUFFO1lBQ2pFLE1BQU0sVUFBVSxHQUFHLGdDQUFnQyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1lBQ3JFLFNBQVMsQ0FBQyxJQUFJLEdBQUcsUUFBUSxDQUN2QixTQUFTLENBQUMsSUFBSSxFQUNkLGVBQWUsRUFDZixVQUFVLENBQ0MsQ0FBQztZQUNkLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO2dCQUNqQixTQUFTLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztZQUNwQyxDQUFDO1lBQ0QsU0FBUyxDQUFDLGVBQWUsR0FBRyxlQUFlLENBQUM7WUFDNUMsTUFBTSxDQUFDLFNBQVMsQ0FBQztRQUNuQixDQUFDLENBQ0YsQ0FBQztRQUVGLG9CQUFlLEdBQUcsWUFBWSxDQUFDLEVBQUU7WUFDL0IsTUFBTSxFQUFFLGVBQWUsRUFBRSxtQ0FBbUMsRUFBRSxHQUFHLElBQUksQ0FBQztZQUN0RSxNQUFNLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxHQUFHLFlBQVksQ0FBQztZQUVwQyxlQUFlLENBQUMsRUFBRSxDQUFDLEdBQUcsTUFBTSxDQUFDO1lBQzdCLG1DQUFtQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUM7WUFFeEUsSUFBSSxDQUFDLE1BQU0sR0FBRyxPQUFPLENBQ25CLElBQUksQ0FBQyxNQUFNLEVBQ1gsVUFBUyxDQUFDO2dCQUNSLE1BQU0sQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDO1lBQ3hCLENBQUMsRUFDRCxVQUFTLFlBQVk7Z0JBQ25CLFlBQVksQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDLEdBQUcsWUFBWSxDQUFDO2dCQUM3QyxNQUFNLENBQUMsWUFBWSxDQUFDO1lBQ3RCLENBQUMsQ0FDRixDQUFDO1FBQ0osQ0FBQyxDQUFDO1FBRUYsK0JBQTBCLEdBQUcsQ0FBQyxPQUFlLEVBQVUsRUFBRTtZQUN2RCw4RUFBOEU7WUFDOUUscUNBQXFDO1lBQ3JDLHNDQUFzQztZQUN0Qyw0Q0FBNEM7WUFDNUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ2xDLENBQUMsQ0FBQztRQUVGLG1CQUFjLEdBQUcsQ0FBQyxXQUFXLEVBQUUsT0FBZSxFQUFFLFNBQXFCLEVBQUUsRUFBRTtZQUN2RSxNQUFNLEVBQ0osMEJBQTBCLEVBQzFCLGNBQWMsRUFDZCxTQUFTLEVBQ1QsZUFBZSxFQUNmLGFBQWEsRUFDZCxHQUFHLElBQUksQ0FBQztZQUNULE1BQU0sdUJBQXVCLEdBQUcsMEJBQTBCLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDcEUsSUFBSSxXQUFXLENBQUM7WUFDaEIsSUFBSSxDQUFDO2dCQUNILEVBQUUsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsdUJBQXVCLENBQUMsQ0FBQyxDQUFDLENBQUM7b0JBQzVELE1BQU0sQ0FBQyxlQUFlLENBQUMsdUJBQXVCLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQztnQkFDL0QsQ0FBQztnQkFBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDakMsRUFBRSxDQUFDLENBQUMsYUFBYSxDQUFDLGNBQWMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7d0JBQzVDLE1BQU0sQ0FBQyxhQUFhLENBQUMsU0FBUyxDQUFDLENBQUM7b0JBQ2xDLENBQUM7b0JBQUMsSUFBSSxDQUFDLENBQUM7d0JBQ04sTUFBTSxDQUFDLFNBQVMsQ0FBQztvQkFDbkIsQ0FBQztnQkFDSCxDQUFDO2dCQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUNoQyxNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsRUFBRTt3QkFDL0IsTUFBTSxDQUFDLGNBQWMsQ0FBQyxTQUFTLEVBQUUsT0FBTyxFQUFFLFNBQVMsQ0FBQyxDQUFDO29CQUN2RCxDQUFDLENBQUMsQ0FBQztnQkFDTCxDQUFDO2dCQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO29CQUMvQixNQUFNLENBQUMsU0FBUyxDQUNkLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLEVBQW1CLEVBQUU7d0JBQ2pFLFNBQVMsQ0FBQyxTQUFTLEVBQUUsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsVUFBUyxDQUFDOzRCQUNuRCxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO3dCQUNkLENBQUMsQ0FBQyxDQUFDO3dCQUNILE1BQU0sQ0FBQyxHQUFHLENBQUM7b0JBQ2IsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUNnQixDQUFDO2dCQUMzQixDQUFDO2dCQUFDLElBQUksQ0FBQyxDQUFDO29CQUNOLE1BQU0sQ0FBQyxTQUFTLENBQUM7Z0JBQ25CLENBQUM7WUFDSCxDQUFDO1lBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDYixNQUFNLElBQUksTUFBTSxDQUNkLEdBQUcsRUFDSDs7T0FFRCxJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsRUFBRSxJQUFJLEVBQUUsRUFBRSxDQUFDO09BQ3JDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLElBQUksRUFBRSxFQUFFLENBQUM7T0FDakMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQzs7S0FFckMsQ0FDRSxDQUFDO1lBQ0osQ0FBQztRQUNILENBQUMsQ0FBQztRQUVGLGNBQVMsR0FBRyxLQUFLLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxPQUFPLEVBQUUsU0FBUyxDQUFDLEVBQW1CLEVBQUU7WUFDdkUsSUFBSSxDQUFDO2dCQUNILE1BQU0sRUFDSiwwQkFBMEIsRUFDMUIsY0FBYyxFQUNkLFdBQVcsRUFDWCxrQkFBa0IsRUFDbEIsU0FBUyxFQUNULGFBQWEsRUFDZCxHQUFHLElBQUksQ0FBQztnQkFDVCxNQUFNLHVCQUF1QixHQUFHLDBCQUEwQixDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUVwRSxFQUFFLENBQUMsQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDM0MsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDWixDQUFDO2dCQUVELEVBQUUsQ0FBQyxDQUFDLGtCQUFrQixDQUFDLGNBQWMsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDL0QsTUFBTSxDQUFDLGtCQUFrQixDQUFDLHVCQUF1QixDQUFDLENBQ2hELFdBQVcsRUFDWCxXQUFXLEVBQ1gsYUFBYSxDQUNkLENBQUM7Z0JBQ0osQ0FBQztnQkFFRCxNQUFNLFNBQVMsR0FBRyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUM7Z0JBQ3ZDLGtFQUFrRTtnQkFDbEUsK0RBQStEO2dCQUUvRCxFQUFFLENBQUMsQ0FDRCxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssR0FBRztvQkFDbEIsU0FBUyxLQUFLLGVBQWU7b0JBQzdCLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLFNBQVMsQ0FBQyxDQUNuRCxDQUFDLENBQUMsQ0FBQztvQkFDRCx5REFBeUQ7b0JBQ3pELDZCQUE2QjtvQkFDN0IsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDWixDQUFDO2dCQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxTQUFTLEtBQUssY0FBYyxDQUFDLENBQUMsQ0FBQztvQkFDeEMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxNQUFNLENBQ2hDLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxTQUFTLENBQUMsV0FBVyxFQUFFLElBQUksQ0FBQyxDQUFDLEVBQ3hELEVBQUUsQ0FDSCxDQUFDO2dCQUNKLENBQUM7Z0JBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLFNBQVMsS0FBSyxhQUFhLENBQUMsQ0FBQyxDQUFDO29CQUN2QyxxREFBcUQ7b0JBQ3JELCtEQUErRDtvQkFDL0QsTUFBTSxDQUFDLFNBQVMsQ0FDZCxTQUFTO3lCQUdOLE1BQU0sQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxjQUFjLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO3lCQUNoRSxHQUFHLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFO3dCQUN0QixNQUFNLENBQUMsU0FBUyxDQUFDLFdBQVcsRUFBRSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDO29CQUM5QyxDQUFDLENBQUM7eUJBQ0QsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxZQUFZLEVBQUUsY0FBYyxDQUFDLENBQUMsRUFBRSxFQUFFO3dCQUNoRCx5REFBeUQ7d0JBQ3pELDBEQUEwRDt3QkFDMUQsc0RBQXNEO3dCQUN0RCx3REFBd0Q7d0JBQ3hELHVEQUF1RDt3QkFDdkQsY0FBYzt3QkFDZCxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQzs0QkFDckMsR0FBRyxDQUFDLFlBQVksQ0FBQyxHQUFHLFFBQVEsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLEVBQUUsY0FBYyxDQUFDLENBQUM7d0JBQ2xFLENBQUM7d0JBQUMsSUFBSSxDQUFDLENBQUM7NEJBQ04sR0FBRyxDQUFDLFlBQVksQ0FBQyxHQUFHLGNBQWMsQ0FBQzt3QkFDckMsQ0FBQzt3QkFDRCxNQUFNLENBQUMsR0FBRyxDQUFDO29CQUNiLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FDVCxDQUFDO2dCQUNKLENBQUM7Z0JBQUMsSUFBSSxDQUFDLENBQUM7b0JBQ04sTUFBTSxXQUFXLEdBQUcsY0FBYyxDQUFDLFdBQVcsRUFBRSxPQUFPLEVBQUUsU0FBUyxDQUFDLENBQUM7b0JBQ3BFLG1FQUFtRTtvQkFDbkUsRUFBRSxDQUFDLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7d0JBQy9DLE1BQU0sQ0FBQyxDQUFDLENBQUMsU0FBUyxJQUFJLFNBQVMsQ0FBQyxPQUFPLENBQUMsRUFBRSxXQUFXLENBQUMsQ0FBQyxDQUFDO29CQUMxRCxDQUFDO29CQUFDLElBQUksQ0FBQyxDQUFDO3dCQUNOLE1BQU0sQ0FBQyxFQUFFLENBQUM7b0JBQ1osQ0FBQztnQkFDSCxDQUFDO1lBQ0gsQ0FBQztZQUFDLEtBQUssQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7Z0JBQ2IsTUFBTSxJQUFJLE1BQU0sQ0FDZCxHQUFHLEVBQ0g7b0JBQ1ksSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQzs7aUJBRTFDLE9BQU87bUJBQ0wsSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQzs7O0tBR25ELENBQ0UsQ0FBQztZQUNKLENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztRQS9ZRCxNQUFNLEVBQ0osZUFBZSxFQUNmLGtCQUFrQixFQUVsQiw0QkFBNEIsRUFDNUIsaUJBQWlCLEVBRWpCLHdCQUF3QixFQUN4QixzQkFBc0IsRUFFdEIsbUNBQW1DLEVBQ25DLHdCQUF3QixFQUN6QixHQUFHLElBQUksQ0FBQztRQUVULElBQUksQ0FBQyxXQUFXLEdBQUcsV0FBVyxDQUFDO1FBQy9CLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxrQkFBa0IsQ0FBQztRQUM3QyxJQUFJLENBQUMsYUFBYSxHQUFHLGFBQWEsQ0FBQztRQUNuQyxJQUFJLENBQUMsZUFBZSxHQUFHLGVBQWUsQ0FBQztRQUV2QyxzQkFBc0IsQ0FBQyxJQUFJLENBQUMsVUFBUyxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUM7WUFDckQsd0JBQXdCLENBQUMsT0FBTyxDQUFDLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMvRCxDQUFDLENBQUMsQ0FBQztRQUVILGlCQUFpQixDQUFDLElBQUksQ0FBQyxVQUFTLFdBQVc7WUFDekMsNEJBQTRCLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQ2pFLFdBQVcsQ0FDWixDQUFDO1FBQ0osQ0FBQyxDQUFDLENBQUM7UUFFSCx3QkFBd0I7YUFDckIsSUFBSSxDQUFDLFVBQ0osWUFJYztZQUVkLE1BQU0sRUFBRSxFQUFFLEVBQUUsTUFBTSxFQUFFLEdBQUcsWUFBWSxDQUFDO1lBRXBDLGVBQWUsQ0FBQyxFQUFFLENBQUMsR0FBRyxNQUFNLENBQUM7WUFDN0IsbUNBQW1DLENBQUMsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUMxRSxDQUFDLENBQUM7YUFDRCxNQUFNLENBQUMsVUFBUyxHQUFHLEVBQUUsSUFBSTtZQUN4QixJQUFJLENBQ0YsSUFBSSxNQUFNLENBQ1IsR0FBRyxFQUNIO09BQ0wsQ0FDSSxDQUNGLENBQUM7UUFDSixDQUFDLENBQUM7YUFDRCxJQUFJLENBQUMsVUFBUyxZQUFZLElBQUcsQ0FBQyxDQUFDLENBQUM7UUFFbkM7Ozs7Ozs7Z0JBT0U7SUFDSixDQUFDO0NBbVZGIn0=
\No newline at end of file