UNPKG

@pictogrammers/element

Version:

Web Component Element for TypeScript

831 lines 120 kB
import './global.js'; import { Mutation, createProxy, addObserver, removeObserver, swapObserver, hasObserver, isProxy, getTarget } from './proxy.js'; class PropError extends Error { constructor(message, ignore) { super(message); this.name = 'PropError'; // @ts-ignore if (Error.captureStackTrace) { // @ts-ignore Error.captureStackTrace(this, ignore); } } } export const index = Symbol('index'); const init = Symbol('init'); const template = Symbol('template'); const style = Symbol('style'); const parent = Symbol('parent'); const renderList = Symbol('renderList'); export function getProxyValue(obj) { return obj[isProxy] && obj[getTarget]; } function extendTemplate(base, append) { if (append && append.match(/<parent\/>/)) { return append.replace(/<parent\/>/, base); } else if (base.match(/<child\/>/)) { return base.replace(/<child\/>/, append || ''); } else { return `${base}${append || ''}`; } } function camelToDash(str) { return str.replace(/([a-zA-Z])(?=[A-Z])/g, '$1-').toLowerCase(); } function dashToCamel(str) { return str.replace(/-([a-z])/g, m => m[1].toUpperCase()); } export function Component(config = {}) { return function (cls, context) { if (context.kind !== 'class') { throw new Error('@Component() can only decorate a class'); } // webpack removes class names, override name Reflect.defineProperty(cls, 'name', { value: config.selector, writable: false, configurable: false, }); // ToDo: Clean up naming. cls is not used only render if (cls[parent]) { cls[parent] = [...cls[parent], cls]; if (cls.prototype.render) { cls[renderList] = [...cls[renderList], cls.prototype.render]; } if (config.style) { cls[style] = [...cls[style], config.style]; } cls[template] = extendTemplate(cls[parent][cls[parent].length - 1][template], config.template || null); } else if (cls.prototype instanceof HTMLElement) { cls[parent] = [cls]; cls[renderList] = cls.prototype.render ? [cls.prototype.render] : []; cls[style] = config.style ? [config.style] : []; cls[template] = config.template || ''; } else { throw new Error(`Must extend from HTMLElement`); } const connectedCallback = cls.prototype.connectedCallback || (() => { }); const disconnectedCallback = cls.prototype.disconnectedCallback || (() => { }); cls.prototype.connectedCallback = function () { if (!this[init] && config.template === undefined && config.style === undefined) { if (config.useShadow === false) { // Base class with no template } else { this.attachShadow({ mode: 'open' }); } } else if (!this[init]) { if (config.useShadow === false) { throw new Error('unsupported'); } else { const $template = document.createElement('template'); $template.innerHTML = cls[template] || ''; const $node = document.importNode($template.content, true); const shadowRoot = this.attachShadow({ mode: 'open' }); shadowRoot.adoptedStyleSheets = cls[style].reduce((acc, value) => { if (!value) { return acc; } if (value instanceof CSSStyleSheet) { acc.push(value); return acc; } var s = new CSSStyleSheet(); s.replaceSync(value.toString()); acc.push(s); return acc; }, []); shadowRoot.appendChild($node); } } else if (this[init] && config.style) { /*if (this.shadowRoot) { const style = document.createElement('style'); style.appendChild(document.createTextNode(config.style)); this.appendChild(style); }*/ // } else if (this[init] && config.template) { // This is allowed now via <parent/> // throw new Error('template from base class cannot be overriden. Fix: remove template from @Component'); } else if (this[init] && config.selector && !config.template) { throw new Error('You need to pass a template for an extended element.'); } const tags = new Set(); for (const ele of this.shadowRoot.querySelectorAll('*')) { if (ele.localName.indexOf('-') !== -1) { tags.add(ele.localName); } } const promises = Array.from(tags.values()).map(tag => { return customElements.get(tag) ? Promise.resolve() : customElements.whenDefined(tag); }); const render = () => { this.constructor[renderList].map((renderFn) => { renderFn.call(this, cls.observedAttributes ? cls.observedAttributes.reduce((a, c) => { const n = dashToCamel(c); a[n] = true; return a; }, {}) : {}); }); }; if (promises.length === 0) { this[init] = true; connectedCallback.call(this); render(); } else { Promise.all(promises).then(() => { this[init] = true; connectedCallback.call(this); // dispatch slotchange for (const slot of this.shadowRoot.querySelectorAll('slot')) { slot.dispatchEvent(new CustomEvent('slotchange')); } render(); }); } }; cls.prototype.disconnectedCallback = function () { disconnectedCallback.call(this); }; cls.prototype.attributeChangedCallback = function (name, oldValue, newValue) { const normalizedName = dashToCamel(name); this[normalizedName] = newValue; }; // Base components may not define a selector context.addInitializer(function () { if (config.selector) { if (window.customElements.get(config.selector)) { throw new Error(`@Component() ${context.name} duplicate selector '${config.selector}'`); } window.customElements.define(config.selector, cls); } }); }; } const transmute = Symbol('transmute'); export function TransmutePart(part, selector) { return function (cls) { if (cls.prototype[transmute]) { cls.prototype[transmute][part] = selector; } else { cls.prototype[transmute] = { [part]: selector }; } }; } function isArray(a) { return (!!a) && (a.constructor === Array); } function isObject(a) { return (!!a) && (a.constructor === Object); } function render(self, propertyKey) { if (self[init]) { self.constructor[renderList].map((renderFn) => { renderFn.call(self, { [propertyKey]: true }); }); } } function getSymbolType(value) { if (value === null) { return 'null'; } return isArray(value) ? 'array' : typeof value; } export function Prop(normalize) { return function (_, context) { const propertyKey = context.name; const symbol = Symbol(propertyKey); const symbolType = Symbol(`${propertyKey}:type`); const symbolMeta = Symbol(`${propertyKey}:meta`); context.addInitializer(function () { if (context.private) { return; } Reflect.defineProperty(this, propertyKey, { get: () => { if (this[symbolType] === 'object') { if (this[symbol][isProxy]) { return this[symbol]; } else { return createProxy(this[symbol]); } } if (this[symbolType] === 'array') { if (this[symbol][isProxy]) { return this[symbol]; } else { return createProxy(this[symbol]); } } return this[symbol]; }, set: (value) => { // ToDo: cleanup const newSymbolType = getSymbolType(normalize ? normalize(value) : value); if (propertyKey !== 'index' && this[symbolType] !== newSymbolType && this[symbolType] !== 'null' && newSymbolType !== 'null') { throw new Error(`@Prop() ${propertyKey} with type '${this[symbolType]}' cannot be set to ${newSymbolType}.`); } if (this[symbolType] === 'array') { if (!isArray(value)) { throw new PropError(`Array "${propertyKey}" (Prop) initialized already. Reassignments must be array type.`, Object.getOwnPropertyDescriptor(this, propertyKey)?.set); } const unproxyValue = value[isProxy] ? value[getTarget] : value; if (this[symbol] === unproxyValue) { throw new Error('Setting an array to itself is not allowed.'); } // Unwrap proxied items (e.g. from items.filter(...)) so observers // stay keyed by the raw item objects. for (let i = 0; i < unproxyValue.length; i++) { const item = unproxyValue[i]; if (item && item[isProxy]) { unproxyValue[i] = item[getTarget]; } } const proxified = createProxy(this[symbol]); if (proxified[hasObserver](this)) { proxified[swapObserver](this, unproxyValue); // render(this, propertyKey); // do we need to trigger this for arrays being remapped? } this[symbol] = unproxyValue; } else { this[symbol] = normalize ? normalize(value) : value; render(this, propertyKey); } } }); }); return function (initialValue) { if (initialValue === undefined && propertyKey !== 'index') { throw new Error(`@Prop() ${propertyKey} must have an initial value defined.`); } else if (initialValue !== undefined && propertyKey === 'index') { throw new Error(`@Prop() index must not have an initial value defined.`); } if (initialValue === true) { throw new Error(`@Prop() ${propertyKey} boolean must initialize to false.`); } // Web Component, todo: refactor to only be called once if (!context.private) { const { constructor } = this; constructor.observedAttributes ??= []; if (!constructor.symbols) { constructor.symbols = {}; } const { symbols } = constructor; const normalizedPropertyKey = camelToDash(propertyKey); if (!symbols[propertyKey]) { constructor.observedAttributes.push(normalizedPropertyKey); symbols[propertyKey] = symbol; } } // Rest this[symbolType] = getSymbolType(initialValue); if (this[symbolType] === 'array') { this[symbol] = initialValue; if (context.private) { return createProxy(initialValue); } return new Proxy(initialValue, { get: (target, key) => { if (key === meta) { return this[symbolMeta]; } return Reflect.get(this[symbol], key); }, set: (target, key, v) => { if (key === meta) { this[symbolMeta] = v; return true; } const x = Reflect.set(target, key, v); if (!(key === 'length' && this[symbol].length === v)) { render(this, propertyKey); } this[symbol] = v; return x; } }); } // todo watch objects??? if (context.private) { this[symbol] = normalize ? normalize(initialValue) : initialValue; return this[symbol]; } this[symbol] = normalize ? normalize(this.getAttribute(propertyKey) ?? initialValue) : this.getAttribute(propertyKey) ?? initialValue; return this[symbol]; }; }; } export function Part() { return function (_, context) { const propertyKey = context.name; const key = propertyKey.replace(/^\$/, ''); context.addInitializer(function () { let cache = null; Reflect.defineProperty(this, propertyKey, { get() { return cache ?? (cache = this.shadowRoot?.querySelector(`[part~=${key}]`)); } }); }); }; } /** * Store data via a Map into LocalStorage * @param key String * @returns Value */ export function Local(key) { return function (_, context) { const propertyKey = context.name; return function (initialValue) { if (!(initialValue instanceof Map)) { throw new Error('@Local(key) property must be type Map'); } return new Proxy(initialValue, { get(target, prop) { switch (prop) { case 'get': return (k) => { if (!initialValue.has(k)) { throw new Error(`@Local(key) missing key ${k}`); } const storeKey = `${key}:${k}`; if (window.localStorage.getItem(storeKey) === null) { const keyValue = initialValue.get(k); return Array.isArray(keyValue) || isObject(keyValue) ? JSON.parse(JSON.stringify(keyValue)) : keyValue; } else { return JSON.parse(window.localStorage.getItem(storeKey) ?? 'null'); } }; case 'set': return (k, v) => { if (!initialValue.has(k)) { throw new Error(`@Local(key) missing key ${k}`); } const storeKey = `${key}:${k}`; if (v === null || JSON.stringify(v) === JSON.stringify(initialValue.get(k))) { window.localStorage.removeItem(storeKey); } else { window.localStorage.setItem(storeKey, JSON.stringify(v)); } }; default: throw new Error(`@Local(key) supported method ${prop}`); } } }); }; }; } export function node(template, init) { const $template = document.createElement('template'); $template.innerHTML = template; const $node = document.importNode($template.content, true); for (const [part, attributes] of Object.entries(init)) { const $part = $node.querySelector(`[part~="${part}"]`); if ($part) { for (const [prop, value] of Object.entries(attributes)) { if (value instanceof Function) { const val = value(); if (val === null) { $part.removeAttribute(prop); } else { $part.setAttribute(prop, value()); } } else { $part[prop] = value; } } } } return $node; } export function normalizeInt(value) { return parseInt(`${value}`, 10); } export function normalizeFloat(value) { return parseFloat(`${value}`); } export function normalizeBoolean(value) { return value === '' || value === true ? true : value === null || value === false ? false : value || true; } export function normalizeString(value) { return `${value}`; } const trackProxy = Symbol('hasProxy'); function hasProxy(obj) { if (obj === null || typeof obj !== "object") return false; return obj[trackProxy]; } const meta = Symbol('meta'); function intersect(arr1, arr2) { const set1 = new Set(arr1); return arr2.filter(item => set1.has(item)); } function difference(arr1, arr2) { return arr1.filter(str => !arr2.includes(str)); } const PROP_ALIAS = { id: 'itemId' }; function mapPropKey(key, allProps) { const alias = PROP_ALIAS[key]; return alias && allProps.includes(alias) ? alias : key; } export function forEach({ container, items, type, create, connect, disconnect, update }) { if (!Array.isArray(items)) { throw new Error('forEach `items` must be an array'); } const elementMap = new WeakMap(); // Tracks raw item objects in items-array order; used to recover pre-mutation state. const localItems = []; function raw(item) { return item && item[isProxy] ? item[getTarget] : item; } function isRendered(rawItem) { return elementMap.has(rawItem); } function renderedCountBefore(logicalIndex) { let count = 0; for (let i = 0; i < logicalIndex && i < localItems.length; i++) { if (isRendered(localItems[i])) count++; } return count; } function newItem(item, domIndex) { const comp = type(item); if (comp === null) return null; const $new = document.createElement(camelToDash(comp.name), comp); const allProps = Object.keys(comp.symbols); const props = intersect(Object.keys(item), allProps); if (allProps.includes('index')) { //@ts-ignore $new['index'] = domIndex; } props.forEach((attr) => { // index is already written if (attr === 'index') { return; } //@ts-ignore $new[attr] = item[attr]; }); // Apply prop aliases (e.g., data `id` → component `itemId`) when not already set above for (const [dataKey, compKey] of Object.entries(PROP_ALIAS)) { if (dataKey in item && allProps.includes(compKey) && !props.includes(compKey)) { //@ts-ignore $new[compKey] = item[dataKey]; } } const rawItem = raw(item); create && create($new, createProxy(rawItem)); createProxy(rawItem)[addObserver]($new, (prop, value) => { // @ts-ignore $new[mapPropKey(prop, allProps)] = value; }); elementMap.set(rawItem, $new); return $new; } // Add initial items let initDomIndex = 0; items.forEach((item) => { const rawItem = raw(item); localItems.push(rawItem); const $new = newItem(item, initDomIndex); if ($new === null) return; container.appendChild($new); connect && connect($new, createProxy(rawItem)); initDomIndex++; }); // Handle each mutation items[addObserver](container, (target, prop, args) => { if (prop === Mutation.swap) { // Reconcile the newly assigned array against the current items by // identity, reusing DOM nodes for items present in both arrays. const newArr = args[0]; items = createProxy(newArr); const newRaws = newArr.map((item) => raw(item)); const newSet = new Set(newRaws); let changed = false; // Remove items missing from the new array. let write = 0; for (let read = 0; read < localItems.length; read++) { const rawItem = localItems[read]; if (newSet.has(rawItem)) { localItems[write++] = rawItem; continue; } if (isRendered(rawItem)) { const $el = elementMap.get(rawItem); disconnect && disconnect($el, createProxy(rawItem)); $el.remove(); createProxy(rawItem)[removeObserver]($el); elementMap.delete(rawItem); } changed = true; } localItems.length = write; // Reorder kept items when their relative order changed. const newIndexes = new Map(newRaws.map((rawItem, i) => [rawItem, i])); let ordered = true; let previous = -1; for (const rawItem of localItems) { const newIndex = newIndexes.get(rawItem); if (newIndex < previous) { ordered = false; break; } previous = newIndex; } if (!ordered) { localItems.sort((a, b) => newIndexes.get(a) - newIndexes.get(b)); localItems.forEach((rawItem) => { const $el = elementMap.get(rawItem); if ($el) container.appendChild($el); }); changed = true; } // Insert added items, batching contiguous runs into single insertions. const connectQueue = []; for (let i = 0; i < newRaws.length; i++) { if (localItems[i] === newRaws[i]) continue; const anchor = i < localItems.length ? localItems[i] : undefined; let runEnd = i; while (runEnd < newRaws.length && newRaws[runEnd] !== anchor) runEnd++; const runRaws = newRaws.slice(i, runEnd); const domStart = renderedCountBefore(i); const nItems = []; runRaws.forEach((rawItem) => { const $new = newItem(rawItem, domStart + nItems.length); if ($new !== null) { nItems.push($new); connectQueue.push([$new, rawItem]); } }); if (nItems.length > 0) { if (domStart === 0) { container.prepend(...nItems); } else { container.children[domStart - 1].after(...nItems); } } localItems.splice(i, 0, ...runRaws); changed = true; i = runEnd - 1; } // Single index pass instead of one per mutation. if (changed) { for (let i = 0; i < container.children.length; i++) { // @ts-ignore container.children[i].index = i; } } connectQueue.forEach(([$el, rawItem]) => { connect && connect($el, createProxy(rawItem)); }); return; } switch (prop) { case Mutation.fill: { const [value, start, end] = args; const fillStart = start || 0; const fillEnd = end || localItems.length; let domFillIdx = renderedCountBefore(fillStart); for (let i = fillStart; i < fillEnd; i++) { if (isRendered(localItems[i])) { const $child = container.children[domFillIdx]; const childAllProps = Object.keys($child.constructor?.symbols ?? {}); Object.keys(value).forEach((key) => { // @ts-ignore $child[mapPropKey(key, childAllProps)] = value[key]; }); domFillIdx++; } localItems[i] = value; } break; } case Mutation.pop: { const poppedRaw = localItems[localItems.length - 1]; if (poppedRaw !== undefined && isRendered(poppedRaw)) { const $el = elementMap.get(poppedRaw); disconnect && disconnect($el, createProxy(poppedRaw)); $el.remove(); createProxy(poppedRaw)[removeObserver]($el); elementMap.delete(poppedRaw); } localItems.pop(); break; } case Mutation.push: { [...args].forEach((item) => { const rawItem = raw(item); localItems.push(rawItem); const $new = newItem(item, container.children.length); if ($new === null) return; container.appendChild($new); connect && connect($new, createProxy(rawItem)); }); break; } case Mutation.reverse: { for (var i = 1; i < container.children.length; i++) { container.insertBefore(container.children[i], container.children[0]); } localItems.reverse(); break; } case Mutation.shift: { const shiftedRaw = localItems[0]; if (shiftedRaw !== undefined && isRendered(shiftedRaw)) { const $el = elementMap.get(shiftedRaw); disconnect && disconnect($el, createProxy(shiftedRaw)); $el.remove(); createProxy(shiftedRaw)[removeObserver]($el); elementMap.delete(shiftedRaw); } localItems.shift(); for (let i = 0; i < container.children.length; i++) { // @ts-ignore container.children[i].index = i; } break; } case Mutation.sort: { target.forEach((item) => { const rawItem = raw(item); const $el = elementMap.get(rawItem); if ($el) container.appendChild($el); }); for (let i = 0; i < container.children.length; i++) { // @ts-ignore container.children[i].index = i; } localItems.length = 0; target.forEach((item) => localItems.push(raw(item))); break; } case Mutation.splice: { const [startIndex, deleteCount, ...newItems] = args; if (startIndex < 0) { throw new Error('invalid startIndex, must be greater than or equal to 0'); } // Determine the DOM insertion/deletion point by counting rendered items before startIndex. const domStart = renderedCountBefore(startIndex); // Remove deleted items from DOM (always remove at domStart since children shift up). const deletedRaws = localItems.slice(startIndex, startIndex + deleteCount); deletedRaws.forEach((rawItem) => { if (isRendered(rawItem)) { const $el = elementMap.get(rawItem); disconnect && disconnect($el, createProxy(rawItem)); $el.remove(); createProxy(rawItem)[removeObserver]($el); elementMap.delete(rawItem); } }); // Create elements for new items, skipping null-typed ones. const nItems = []; newItems.forEach((item) => { const $new = newItem(item, domStart + nItems.length); if ($new !== null) nItems.push($new); }); if (nItems.length > 0) { if (domStart === 0) { container.prepend(...nItems); } else { container.children[domStart - 1].after(...nItems); } } // Update indices for all items from the insertion point onward. for (let i = domStart; i < container.children.length; i++) { // @ts-ignore container.children[i].index = i; } // Fire connect for each newly rendered item. let nIdx = 0; newItems.forEach((item) => { const rawItem = raw(item); if (isRendered(rawItem)) { connect && connect(nItems[nIdx++], createProxy(rawItem)); } }); localItems.splice(startIndex, deleteCount, ...newItems.map(raw)); break; } case Mutation.unshift: { const unshiftItems = [...args]; const firstChild = container.children.length ? container.children[0] : null; const nItems = []; unshiftItems.forEach((item) => { const $new = newItem(item, nItems.length); if ($new !== null) nItems.push($new); }); if (nItems.length > 0) { if (firstChild) { firstChild.before(...nItems); } else { container.append(...nItems); } } // Update indices for all items (new ones first, then existing). for (let i = 0; i < container.children.length; i++) { // @ts-ignore container.children[i].index = i; } localItems.unshift(...unshiftItems.map(raw)); // Fire connect for each newly rendered item. let nIdx = 0; unshiftItems.forEach((item) => { const rawItem = raw(item); if (isRendered(rawItem)) { connect && connect(nItems[nIdx++], createProxy(rawItem)); } }); break; } } }); } // JEST export function selectComponent(tagName) { const component = document.querySelector(tagName); const tags = new Set(); let shadowRoot; try { shadowRoot = component.shadowRoot; } catch (error) { throw new Error('Add the component via document.body.appendChild(...) before selectComponent.'); } for (const ele of shadowRoot.querySelectorAll('*')) { if (ele.localName.indexOf('-') !== -1) { tags.add(ele.localName); } } for (var it = tags.values(), tag = null; tag = it.next().value;) { if (!customElements.get(tag)) { const namespaceMatch = tag.match(/^([^-]+)/); if (namespaceMatch === null || namespaceMatch.length > 1) { throw new Error('Failed to parse namespace.'); } const namespace = namespaceMatch[1]; const componentMatch = tag.match(/^[^-]+-(.+)/); if (componentMatch === null || componentMatch.length > 1) { throw new Error('Failed to parse component name.'); } const componentName = dashToCamel(componentMatch[1]); throw new Error(`Missing \`import '../${componentName}/${componentName}';\` in spec.ts file.`); } } return component; } export function selectPart(component, name) { return component.shadowRoot.querySelector(`[part=${name}]`); } export function getProps(tag) { const { symbols } = customElements.get(tag); return Object.keys(symbols ?? {}); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWxlbWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9lbGVtZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFDTCxRQUFRLEVBQ1IsV0FBVyxFQUNYLFdBQVcsRUFDWCxjQUFjLEVBQ2QsWUFBWSxFQUNaLFdBQVcsRUFDWCxPQUFPLEVBQ1AsU0FBUyxFQUNWLE1BQU0sWUFBWSxDQUFDO0FBY3BCLE1BQU0sU0FBVSxTQUFRLEtBQUs7SUFDM0IsWUFBWSxPQUFlLEVBQUUsTUFBVztRQUN0QyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsSUFBSSxHQUFHLFdBQVcsQ0FBQztRQUN4QixhQUFhO1FBQ2IsSUFBSSxLQUFLLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztZQUM1QixhQUFhO1lBQ2IsS0FBSyxDQUFDLGlCQUFpQixDQUFDLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQztRQUN4QyxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBRUQsTUFBTSxDQUFDLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUNyQyxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDNUIsTUFBTSxRQUFRLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0FBQ3BDLE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztBQUM5QixNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDaEMsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFDO0FBRXhDLE1BQU0sVUFBVSxhQUFhLENBQUMsR0FBUTtJQUNwQyxPQUFPLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7QUFDeEMsQ0FBQztBQUVELFNBQVMsY0FBYyxDQUFDLElB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