UNPKG

forest-cli

Version:

The Lumberjacks' toolbelt is the Forest CLI which makes easy to manage your back office application directly from the terminal.

160 lines 15.2 kB
"use strict"; /** * Rebuilds the patchable "layout" document from the serialized rendering. * * The server has no raw GET for the layout domain (GET /api/layout always * returns [] — the renderings table has no `layout` column). The frontend * reads the layout through GET /api/renderings/:project/:env/:team, a JSON:API * document (snake_case attributes, resources split into `included`). This * module inverts that serialization into the configuration shape the PATCH * paths address (camelCase, see the server's collection validators/models). * * v1 maps the curated, patchable subset: collections base props, columns, * fields, segments, actions, viewEdit.summaryView, and dashboards. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.renderingToCanonical = void 0; /** `customers-email` -> `email` (resource ids are prefixed by the collection). */ function stripCollectionPrefix(resourceId, collectionId) { const prefix = `${collectionId}-`; return resourceId.startsWith(prefix) ? resourceId.slice(prefix.length) : resourceId; } function indexIncluded(doc) { const index = new Map(); (doc.included ?? []).forEach(resource => index.set(`${resource.type}:${resource.id}`, resource)); return index; } function relatedIds(resource, relationship) { const data = resource?.relationships?.[relationship]?.data; if (Array.isArray(data)) return data; if (data && typeof data === 'object') return [data]; return []; } /** Resolve a relationship's references into the included resources they point to. */ function relatedResources(collection, index, relationship, includedType) { return relatedIds(collection, relationship) .map(ref => index.get(`${includedType}:${ref.id}`)) .filter((resource) => resource !== undefined); } /** Shallow snake_case -> camelCase for generic resources (segments, actions…). */ function camelizeShallow(attributes) { return Object.fromEntries(Object.entries(attributes).map(([key, value]) => [ key.replace(/_([a-z])/g, (_, c) => c.toUpperCase()), value, ])); } function mapColumns(collection, index) { return relatedResources(collection, index, 'columns', 'columns') .map(column => { const attrs = column.attributes ?? {}; return { id: stripCollectionPrefix(column.id, collection.id), // Wire format exposes is_hidden; the patchable config uses isVisible. isVisible: attrs.is_hidden !== true, position: attrs.position ?? 0, }; }) .sort((a, b) => a.position - b.position); } const FIELD_PATCHABLE_KEYS = [ ['display_name', 'displayName'], ['description', 'description'], ['is_read_only', 'isReadOnly'], ['is_filter_displayed', 'isFilterDisplayed'], ['is_dissociate_displayed', 'isDissociateDisplayed'], ['widget_edit', 'widgetEdit'], ['widget_display', 'widgetDisplay'], ['mapping_values', 'mappingValues'], ['conditional_formatting', 'conditionalFormatting'], ]; function mapFields(collection, index) { return relatedResources(collection, index, 'fields', 'fields') .map(field => { const attrs = field.attributes ?? {}; const mapped = { id: attrs.field ?? stripCollectionPrefix(field.id, collection.id), }; FIELD_PATCHABLE_KEYS.forEach(([wire, canonical]) => { if (wire in attrs) mapped[canonical] = attrs[wire]; }); return mapped; }) .sort((a, b) => String(a.id).localeCompare(String(b.id))); } function mapGenericList(collection, index, relationship, includedType) { return relatedResources(collection, index, relationship, includedType).map(resource => ({ id: resource.id, ...camelizeShallow(resource.attributes ?? {}), })); } function mapCollection(collection, index) { const attrs = collection.attributes ?? {}; const sortingFieldRef = relatedIds(collection, 'default_sorting_field')[0]; const viewEdit = index.get(`viewEdits:${collection.id}`); return { defaultSortingFieldName: sortingFieldRef ? stripCollectionPrefix(sortingFieldRef.id, collection.id) : null, defaultSortingOrder: attrs.default_sorting_field_order ?? null, displayName: attrs.display_name ?? null, displayNamePlural: attrs.display_name_plural ?? null, icon: attrs.icon ?? null, id: collection.id, layout: { actions: mapGenericList(collection, index, 'custom_actions', 'customActions'), columns: mapColumns(collection, index), fields: mapFields(collection, index), segments: mapGenericList(collection, index, 'segments', 'segments'), viewEdit: { summaryView: viewEdit?.attributes?.summary_view ?? null }, }, restrictedToSegments: attrs.restricted_to_segments === true, }; } /** * Workspaces carry an ordered list of components; component `options` (tabs, * filters, visible columns…) is deep and polymorphic, so it is kept opaque * (round-tripped verbatim, set as a whole on add). Addressing is by the * workspace/component `id` (the patch route's `:collectionId` param actually * receives the workspace id). */ function mapWorkspace(workspace, index) { const components = relatedResources(workspace, index, 'components', 'workspace-components').map(component => ({ id: component.id, ...camelizeShallow(component.attributes ?? {}) })); return { id: workspace.id, ...camelizeShallow(workspace.attributes ?? {}), components }; } /** Inboxes reference a collection (and, for segment inboxes, a segment) by id. */ function mapInbox(inbox) { const collectionRef = relatedIds(inbox, 'collection')[0]; const segmentRef = relatedIds(inbox, 'segment')[0]; return { id: inbox.id, ...camelizeShallow(inbox.attributes ?? {}), ...(collectionRef ? { collectionId: collectionRef.id } : {}), ...(segmentRef ? { segmentId: segmentRef.id } : {}), }; } /** Build the canonical patchable layout document from a rendering response. */ function renderingToCanonical(doc) { const index = indexIncluded(doc); const byType = (type) => (doc.included ?? []).filter(resource => resource.type === type); const collections = byType('collections') .map(collection => mapCollection(collection, index)) .sort((a, b) => a.id.localeCompare(b.id)); const dashboards = byType('dashboards').map(dashboard => ({ id: dashboard.id, ...camelizeShallow(dashboard.attributes ?? {}), })); const workspaces = byType('workspaces').map(workspace => mapWorkspace(workspace, index)); const inboxes = byType('inboxes').map(inbox => mapInbox(inbox)); return { collections, dashboards, inboxes, sections: doc.data.attributes?.sections ?? [], workspaces, }; } exports.renderingToCanonical = renderingToCanonical; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVuZGVyaW5nLW1hcHBlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zZXJ2aWNlcy9sYXlvdXQvcmVuZGVyaW5nLW1hcHBlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7OztHQVlHOzs7QUE2Qkgsa0ZBQWtGO0FBQ2xGLFNBQVMscUJBQXFCLENBQUMsVUFBa0IsRUFBRSxZQUFvQjtJQUNyRSxNQUFNLE1BQU0sR0FBRyxHQUFHLFlBQVksR0FBRyxDQUFDO0lBRWxDLE9BQU8sVUFBVSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQztBQUN0RixDQUFDO0FBRUQsU0FBUyxhQUFhLENBQUMsR0FBb0I7SUFDekMsTUFBTSxLQUFLLEdBQUcsSUFBSSxHQUFHLEVBQTJCLENBQUM7SUFDakQsQ0FBQyxHQUFHLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxRQUFRLENBQUMsSUFBSSxJQUFJLFFBQVEsQ0FBQyxFQUFFLEVBQUUsRUFBRSxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBRWpHLE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQUVELFNBQVMsVUFBVSxDQUNqQixRQUFxQyxFQUNyQyxZQUFvQjtJQUVwQixNQUFNLElBQUksR0FBRyxRQUFRLEVBQUUsYUFBYSxFQUFFLENBQUMsWUFBWSxDQUFDLEVBQUUsSUFBZSxDQUFDO0lBRXRFLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUM7UUFBRSxPQUFPLElBQTJDLENBQUM7SUFDNUUsSUFBSSxJQUFJLElBQUksT0FBTyxJQUFJLEtBQUssUUFBUTtRQUFFLE9BQU8sQ0FBQyxJQUFvQyxDQUFDLENBQUM7SUFFcEYsT0FBTyxFQUFFLENBQUM7QUFDWixDQUFDO0FBRUQscUZBQXFGO0FBQ3JGLFNBQVMsZ0JBQWdCLENBQ3ZCLFVBQTJCLEVBQzNCLEtBQW1DLEVBQ25DLFlBQW9CLEVBQ3BCLFlBQW9CO0lBRXBCLE9BQU8sVUFBVSxDQUFDLFVBQVUsRUFBRSxZQUFZLENBQUM7U0FDeEMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFlBQVksSUFBSSxHQUFHLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztTQUNsRCxNQUFNLENBQUMsQ0FBQyxRQUFRLEVBQStCLEVBQUUsQ0FBQyxRQUFRLEtBQUssU0FBUyxDQUFDLENBQUM7QUFDL0UsQ0FBQztBQUVELGtGQUFrRjtBQUNsRixTQUFTLGVBQWUsQ0FBQyxVQUFtQztJQUMxRCxPQUFPLE1BQU0sQ0FBQyxXQUFXLENBQ3ZCLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLEVBQUUsRUFBRSxDQUFDO1FBQy9DLEdBQUcsQ0FBQyxPQUFPLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQVMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQzNELEtBQUs7S0FDTixDQUFDLENBQ0gsQ0FBQztBQUNKLENBQUM7QUFFRCxTQUFTLFVBQVUsQ0FDakIsVUFBMkIsRUFDM0IsS0FBbUM7SUFFbkMsT0FBTyxnQkFBZ0IsQ0FBQyxVQUFVLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxTQUFTLENBQUM7U0FDN0QsR0FBRyxDQUFDLE1BQU0sQ0FBQyxFQUFFO1FBQ1osTUFBTSxLQUFLLEdBQUcsTUFBTSxDQUFDLFVBQVUsSUFBSSxFQUFFLENBQUM7UUFFdEMsT0FBTztZQUNMLEVBQUUsRUFBRSxxQkFBcUIsQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDbkQsc0VBQXNFO1lBQ3RFLFNBQVMsRUFBRSxLQUFLLENBQUMsU0FBUyxLQUFLLElBQUk7WUFDbkMsUUFBUSxFQUFHLEtBQUssQ0FBQyxRQUFtQixJQUFJLENBQUM7U0FDMUMsQ0FBQztJQUNKLENBQUMsQ0FBQztTQUNELElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBQzdDLENBQUM7QUFFRCxNQUFNLG9CQUFvQixHQUE2QztJQUNyRSxDQUFDLGNBQWMsRUFBRSxhQUFhLENBQUM7SUFDL0IsQ0FBQyxhQUFhLEVBQUUsYUFBYSxDQUFDO0lBQzlCLENBQUMsY0FBYyxFQUFFLFlBQVksQ0FBQztJQUM5QixDQUFDLHFCQUFxQixFQUFFLG1CQUFtQixDQUFDO0lBQzVDLENBQUMseUJBQXlCLEVBQUUsdUJBQXVCLENBQUM7SUFDcEQsQ0FBQyxhQUFhLEVBQUUsWUFBWSxDQUFDO0lBQzdCLENBQUMsZ0JBQWdCLEVBQUUsZUFBZSxDQUFDO0lBQ25DLENBQUMsZ0JBQWdCLEVBQUUsZUFBZSxDQUFDO0lBQ25DLENBQUMsd0JBQXdCLEVBQUUsdUJBQXVCLENBQUM7Q0FDcEQsQ0FBQztBQUVGLFNBQVMsU0FBUyxDQUNoQixVQUEyQixFQUMzQixLQUFtQztJQUVuQyxPQUFPLGdCQUFnQixDQUFDLFVBQVUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLFFBQVEsQ0FBQztTQUMzRCxHQUFHLENBQUMsS0FBSyxDQUFDLEVBQUU7UUFDWCxNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQztRQUNyQyxNQUFNLE1BQU0sR0FBNEI7WUFDdEMsRUFBRSxFQUFHLEtBQUssQ0FBQyxLQUFnQixJQUFJLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxFQUFFLEVBQUUsVUFBVSxDQUFDLEVBQUUsQ0FBQztTQUM5RSxDQUFDO1FBQ0Ysb0JBQW9CLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLEVBQUUsRUFBRTtZQUNqRCxJQUFJLElBQUksSUFBSSxLQUFLO2dCQUFFLE1BQU0sQ0FBQyxTQUFTLENBQUMsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDckQsQ0FBQyxDQUFDLENBQUM7UUFFSCxPQUFPLE1BQU0sQ0FBQztJQUNoQixDQUFDLENBQUM7U0FDRCxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUM5RCxDQUFDO0FBRUQsU0FBUyxjQUFjLENBQ3JCLFVBQTJCLEVBQzNCLEtBQW1DLEVBQ25DLFlBQW9CLEVBQ3BCLFlBQW9CO0lBRXBCLE9BQU8sZ0JBQWdCLENBQUMsVUFBVSxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsWUFBWSxDQUFDLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN0RixFQUFFLEVBQUUsUUFBUSxDQUFDLEVBQUU7UUFDZixHQUFHLGVBQWUsQ0FBQyxRQUFRLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQztLQUM5QyxDQUFDLENBQUMsQ0FBQztBQUNOLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FDcEIsVUFBMkIsRUFDM0IsS0FBbUM7SUFFbkMsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLFVBQVUsSUFBSSxFQUFFLENBQUM7SUFDMUMsTUFBTSxlQUFlLEdBQUcsVUFBVSxDQUFDLFVBQVUsRUFBRSx1QkFBdUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNFLE1BQU0sUUFBUSxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsYUFBYSxVQUFVLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztJQUV6RCxPQUFPO1FBQ0wsdUJBQXVCLEVBQUUsZUFBZTtZQUN0QyxDQUFDLENBQUMscUJBQXFCLENBQUMsZUFBZSxDQUFDLEVBQUUsRUFBRSxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQzFELENBQUMsQ0FBQyxJQUFJO1FBQ1IsbUJBQW1CLEVBQUcsS0FBSyxDQUFDLDJCQUFzQyxJQUFJLElBQUk7UUFDMUUsV0FBVyxFQUFHLEtBQUssQ0FBQyxZQUF1QixJQUFJLElBQUk7UUFDbkQsaUJBQWlCLEVBQUcsS0FBSyxDQUFDLG1CQUE4QixJQUFJLElBQUk7UUFDaEUsSUFBSSxFQUFHLEtBQUssQ0FBQyxJQUFlLElBQUksSUFBSTtRQUNwQyxFQUFFLEVBQUUsVUFBVSxDQUFDLEVBQUU7UUFDakIsTUFBTSxFQUFFO1lBQ04sT0FBTyxFQUFFLGNBQWMsQ0FBQyxVQUFVLEVBQUUsS0FBSyxFQUFFLGdCQUFnQixFQUFFLGVBQWUsQ0FBQztZQUM3RSxPQUFPLEVBQUUsVUFBVSxDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUM7WUFDdEMsTUFBTSxFQUFFLFNBQVMsQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDO1lBQ3BDLFFBQVEsRUFBRSxjQUFjLENBQUMsVUFBVSxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsVUFBVSxDQUFDO1lBQ25FLFFBQVEsRUFBRSxFQUFFLFdBQVcsRUFBRyxRQUFRLEVBQUUsVUFBVSxFQUFFLFlBQXdCLElBQUksSUFBSSxFQUFFO1NBQ25GO1FBQ0Qsb0JBQW9CLEVBQUUsS0FBSyxDQUFDLHNCQUFzQixLQUFLLElBQUk7S0FDNUQsQ0FBQztBQUNKLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxTQUFTLFlBQVksQ0FDbkIsU0FBMEIsRUFDMUIsS0FBbUM7SUFFbkMsTUFBTSxVQUFVLEdBQUcsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLEtBQUssRUFBRSxZQUFZLEVBQUUsc0JBQXNCLENBQUMsQ0FBQyxHQUFHLENBQzdGLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxTQUFTLENBQUMsRUFBRSxFQUFFLEdBQUcsZUFBZSxDQUFDLFNBQVMsQ0FBQyxVQUFVLElBQUksRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUNwRixDQUFDO0lBRUYsT0FBTyxFQUFFLEVBQUUsRUFBRSxTQUFTLENBQUMsRUFBRSxFQUFFLEdBQUcsZUFBZSxDQUFDLFNBQVMsQ0FBQyxVQUFVLElBQUksRUFBRSxDQUFDLEVBQUUsVUFBVSxFQUFFLENBQUM7QUFDMUYsQ0FBQztBQUVELGtGQUFrRjtBQUNsRixTQUFTLFFBQVEsQ0FBQyxLQUFzQjtJQUN0QyxNQUFNLGFBQWEsR0FBRyxVQUFVLENBQUMsS0FBSyxFQUFFLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3pELE1BQU0sVUFBVSxHQUFHLFVBQVUsQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFbkQsT0FBTztRQUNMLEVBQUUsRUFBRSxLQUFLLENBQUMsRUFBRTtRQUNaLEdBQUcsZUFBZSxDQUFDLEtBQUssQ0FBQyxVQUFVLElBQUksRUFBRSxDQUFDO1FBQzFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLEVBQUUsWUFBWSxFQUFFLGFBQWEsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQzVELEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQUUsU0FBUyxFQUFFLFVBQVUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0tBQ3BELENBQUM7QUFDSixDQUFDO0FBRUQsK0VBQStFO0FBQy9FLFNBQWdCLG9CQUFvQixDQUFDLEdBQW9CO0lBQ3ZELE1BQU0sS0FBSyxHQUFHLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNqQyxNQUFNLE1BQU0sR0FBRyxDQUFDLElBQVksRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsUUFBUSxJQUFJLEVBQUUsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLENBQUM7SUFFakcsTUFBTSxXQUFXLEdBQUcsTUFBTSxDQUFDLGFBQWEsQ0FBQztTQUN0QyxHQUFHLENBQUMsVUFBVSxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFDO1NBQ25ELElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBRTVDLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3hELEVBQUUsRUFBRSxTQUFTLENBQUMsRUFBRTtRQUNoQixHQUFHLGVBQWUsQ0FBQyxTQUFTLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQztLQUMvQyxDQUFDLENBQUMsQ0FBQztJQUVKLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxZQUFZLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDekYsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBRWhFLE9BQU87UUFDTCxXQUFXO1FBQ1gsVUFBVTtRQUNWLE9BQU87UUFDUCxRQUFRLEVBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsUUFBb0IsSUFBSSxFQUFFO1FBQzFELFVBQVU7S0FDWCxDQUFDO0FBQ0osQ0FBQztBQXZCRCxvREF1QkMifQ==