From ffc35e489cb62295555da14a003fea08a1eaa442 Mon Sep 17 00:00:00 2001 From: Alexander Marks Date: Tue, 12 Dec 2017 10:42:13 -0800 Subject: [PATCH] Update various Polymer annotations to constrain generated types. --- lib/elements/array-selector.html | 2 +- lib/elements/dom-bind.html | 5 +++- lib/elements/dom-module.html | 4 +++ lib/legacy/legacy-element-mixin.html | 29 +++++++++++----------- lib/legacy/polymer-fn.html | 2 +- lib/legacy/polymer.dom.html | 4 +-- lib/utils/async.html | 10 ++++---- lib/utils/flush.html | 2 +- lib/utils/gestures.html | 20 +++++++-------- lib/utils/import-href.html | 6 ++--- lib/utils/settings.html | 6 +---- types/lib/elements/array-selector.d.ts | 2 +- types/lib/elements/dom-bind.d.ts | 10 +++----- types/lib/elements/dom-module.d.ts | 2 +- types/lib/legacy/legacy-element-mixin.d.ts | 22 ++++++++-------- types/lib/legacy/polymer-fn.d.ts | 2 +- types/lib/legacy/polymer.dom.d.ts | 6 ++--- types/lib/utils/async.d.ts | 10 ++++---- types/lib/utils/flush.d.ts | 2 +- types/lib/utils/gestures.d.ts | 8 +++--- types/lib/utils/import-href.d.ts | 2 +- types/lib/utils/settings.d.ts | 4 +-- 22 files changed, 80 insertions(+), 80 deletions(-) diff --git a/lib/elements/array-selector.html b/lib/elements/array-selector.html index 680452cc8e..bb67a1bd91 100644 --- a/lib/elements/array-selector.html +++ b/lib/elements/array-selector.html @@ -211,7 +211,7 @@ /** * Clears the selection state. - * + * @returns {void} */ clearSelection() { // Unbind previous selection diff --git a/lib/elements/dom-bind.html b/lib/elements/dom-bind.html index 6d1283989c..3574274a4f 100644 --- a/lib/elements/dom-bind.html +++ b/lib/elements/dom-bind.html @@ -61,16 +61,19 @@ this.__children = null; } - // assumes only one observed attribute + /** @returns {void} */ attributeChangedCallback() { + // assumes only one observed attribute this.mutableData = true; } + /** @returns {void} */ connectedCallback() { this.style.display = 'none'; this.render(); } + /** @returns {void} */ disconnectedCallback() { this.__removeChildren(); } diff --git a/lib/elements/dom-module.html b/lib/elements/dom-module.html index d18837c048..1977883bc0 100644 --- a/lib/elements/dom-module.html +++ b/lib/elements/dom-module.html @@ -74,6 +74,10 @@ return null; } + /** + * @param {string} name + * @returns {void} + */ attributeChangedCallback(name, old, value) { if (old !== value) { this.register(); diff --git a/lib/legacy/legacy-element-mixin.html b/lib/legacy/legacy-element-mixin.html index 482dfeacd9..d51d7f6821 100644 --- a/lib/legacy/legacy-element-mixin.html +++ b/lib/legacy/legacy-element-mixin.html @@ -129,6 +129,7 @@ * @param {string} name Name of attribute. * @param {?string} old Old value of attribute. * @param {?string} value Current value of attribute. + * @returns {void} * @override */ attributeChangedCallback(name, old, value) { @@ -484,7 +485,7 @@ * any `` elements are replaced with the list of nodes distributed * to the ``, the result of its `getDistributedNodes` method. * @this {Element} - * @return {Array} List of effective child nodes. + * @return {!Array} List of effective child nodes. */ getEffectiveChildNodes() { const domApi = /** @type {Polymer.DomApi} */(Polymer.dom(this)); @@ -497,7 +498,7 @@ * children that are insertion points. * @param {string} selector Selector to run. * @this {Element} - * @return {Array} List of distributed elements that match selector. + * @return {!Array} List of distributed elements that match selector. */ queryDistributedElements(selector) { const domApi = /** @type {Polymer.DomApi} */(Polymer.dom(this)); @@ -510,7 +511,7 @@ * any `` elements are replaced with the list of elements * distributed to the ``. * - * @return {Array} List of effective children. + * @return {!Array} List of effective children. */ getEffectiveChildren() { let list = this.getEffectiveChildNodes(); @@ -554,7 +555,7 @@ * match `selector`. These can be dom child nodes or elements distributed * to children that are insertion points. * @param {string} selector Selector to run. - * @return {Array} List of effective child nodes that match selector. + * @return {!Array} List of effective child nodes that match selector. */ queryAllEffectiveChildren(selector) { return this.queryDistributedElements(selector); @@ -568,7 +569,7 @@ * * @param {string=} slctr CSS selector to choose the desired * ``. Defaults to `content`. - * @return {Array} List of distributed nodes for the ``. + * @return {!Array} List of distributed nodes for the ``. */ getContentChildNodes(slctr) { let content = this.root.querySelector(slctr || 'slot'); @@ -586,12 +587,12 @@ * * @param {string=} slctr CSS selector to choose the desired * ``. Defaults to `content`. - * @return {Array} List of distributed nodes for the + * @return {!Array} List of distributed nodes for the * ``. * @suppress {invalidCasts} */ getContentChildren(slctr) { - let children = /** @type {Array} */(this.getContentChildNodes(slctr).filter(function(n) { + let children = /** @type {!Array} */(this.getContentChildNodes(slctr).filter(function(n) { return (n.nodeType === Node.ELEMENT_NODE); })); return children; @@ -649,7 +650,7 @@ * } * * @param {string} jobName String to identify the debounce job. - * @param {function()} callback Function that is called (with `this` + * @param {function():void} callback Function that is called (with `this` * context) when the wait time elapses. * @param {number} wait Optional wait time in milliseconds (ms) after the * last signal that must elapse before invoking `callback` @@ -713,7 +714,7 @@ * By default (if no waitTime is specified), async callbacks are run at * microtask timing, which will occur before paint. * - * @param {Function} callback The callback function to run, bound to `this`. + * @param {!Function} callback The callback function to run, bound to `this`. * @param {number=} waitTime Time to wait before calling the * `callback`. If unspecified or 0, the callback will be run at microtask * timing (before paint). @@ -769,13 +770,13 @@ * element will contain the imported document contents. * * @param {string} href URL to document to load. - * @param {Function} onload Callback to notify when an import successfully + * @param {!Function=} onload Callback to notify when an import successfully * loaded. - * @param {Function} onerror Callback to notify when an import + * @param {!Function=} onerror Callback to notify when an import * unsuccessfully loaded. - * @param {boolean} optAsync True if the import should be loaded `async`. + * @param {boolean=} optAsync True if the import should be loaded `async`. * Defaults to `false`. - * @return {HTMLLinkElement} The link element for the URL to be loaded. + * @return {!HTMLLinkElement} The link element for the URL to be loaded. */ importHref(href, onload, onerror, optAsync) { // eslint-disable-line no-unused-vars let loadFn = onload ? onload.bind(this) : null; @@ -788,7 +789,7 @@ * prefixed. * * @param {string} selector Selector to test. - * @param {Element=} node Element to test the selector against. + * @param {!Element=} node Element to test the selector against. * @return {boolean} Whether the element matches the selector. */ elementMatches(selector, node) { diff --git a/lib/legacy/polymer-fn.html b/lib/legacy/polymer-fn.html index 579b3688cf..80106a89ed 100644 --- a/lib/legacy/polymer-fn.html +++ b/lib/legacy/polymer-fn.html @@ -29,7 +29,7 @@ * @function Polymer * @param {!PolymerInit} info Object containing Polymer metadata and functions * to become class methods. - * @return {!HTMLElement} Generated class + * @return {function(new: HTMLElement)} Generated class * @suppress {duplicate, invalidCasts, checkTypes} */ window.Polymer._polymerFn = function(info) { diff --git a/lib/legacy/polymer.dom.html b/lib/legacy/polymer.dom.html index c94ef3892b..072b730891 100644 --- a/lib/legacy/polymer.dom.html +++ b/lib/legacy/polymer.dom.html @@ -157,8 +157,8 @@ } /** - * @return {Array} Returns a flattened list of all child nodes and nodes assigned - * to child slots. + * @return {!Array} Returns a flattened list of all child nodes and + * nodes assigned to child slots. */ getEffectiveChildNodes() { return Polymer.FlattenedNodesObserver.getFlattenedNodes(this.node); diff --git a/lib/utils/async.html b/lib/utils/async.html index af8f94f10d..4941fecedc 100644 --- a/lib/utils/async.html +++ b/lib/utils/async.html @@ -68,7 +68,7 @@ * * @memberof Polymer.Async.timeOut * @param {number} delay Time to wait before calling callbacks in ms - * @return {AsyncInterface} An async timeout interface + * @return {!AsyncInterface} An async timeout interface */ after(delay) { return { @@ -81,7 +81,7 @@ * * @function * @memberof Polymer.Async.timeOut - * @param {Function} fn Callback to run + * @param {!Function} fn Callback to run * @return {number} Handle used for canceling task */ run: window.setTimeout.bind(window), @@ -109,7 +109,7 @@ * * @function * @memberof Polymer.Async.animationFrame - * @param {Function} fn Callback to run + * @param {!Function} fn Callback to run * @return {number} Handle used for canceling task */ run: window.requestAnimationFrame.bind(window), @@ -137,7 +137,7 @@ * Enqueues a function called at `requestIdleCallback` timing. * * @memberof Polymer.Async.idlePeriod - * @param {function(IdleDeadline)} fn Callback to run + * @param {function(!IdleDeadline):void} fn Callback to run * @return {number} Handle used for canceling task */ run(fn) { @@ -179,7 +179,7 @@ * Enqueues a function called at microtask timing. * * @memberof Polymer.Async.microTask - * @param {Function} callback Callback to run + * @param {!Function=} callback Callback to run * @return {number} Handle used for canceling task */ run(callback) { diff --git a/lib/utils/flush.html b/lib/utils/flush.html index 4cfcee7b3c..3feaad6166 100644 --- a/lib/utils/flush.html +++ b/lib/utils/flush.html @@ -18,7 +18,7 @@ * Adds a `Polymer.Debouncer` to a list of globally flushable tasks. * * @memberof Polymer - * @param {Polymer.Debouncer} debouncer Debouncer to enqueue + * @param {!Polymer.Debouncer} debouncer Debouncer to enqueue * @return {void} */ Polymer.enqueueDebouncer = function(debouncer) { diff --git a/lib/utils/gestures.html b/lib/utils/gestures.html index 8bdff53952..e681778014 100644 --- a/lib/utils/gestures.html +++ b/lib/utils/gestures.html @@ -427,9 +427,9 @@ * Adds an event listener to a node for the given gesture type. * * @memberof Polymer.Gestures - * @param {Node} node Node to add listener on + * @param {!Node} node Node to add listener on * @param {string} evType Gesture type: `down`, `up`, `track`, or `tap` - * @param {Function} handler Event listener function to call + * @param {!Function} handler Event listener function to call * @return {boolean} Returns true if a gesture event listener was added. * @this {Gestures} */ @@ -445,9 +445,9 @@ * Removes an event listener from a node for the given gesture type. * * @memberof Polymer.Gestures - * @param {Node} node Node to remove listener from + * @param {!Node} node Node to remove listener from * @param {string} evType Gesture type: `down`, `up`, `track`, or `tap` - * @param {Function} handler Event listener function previously passed to + * @param {!Function} handler Event listener function previously passed to * `addListener`. * @return {boolean} Returns true if a gesture event listener was removed. * @this {Gestures} @@ -464,7 +464,7 @@ * automate the event listeners for the native events * * @private - * @param {HTMLElement} node Node on which to add the event. + * @param {!HTMLElement} node Node on which to add the event. * @param {string} evType Event type to add. * @param {function(Event?)} handler Event handler function. * @return {void} @@ -504,7 +504,7 @@ * automate event listener removal for native events * * @private - * @param {HTMLElement} node Node on which to remove the event. + * @param {!HTMLElement} node Node on which to remove the event. * @param {string} evType Event type to remove. * @param {function(Event?)} handler Event handler function. * @return {void} @@ -536,7 +536,7 @@ * gesture event types. * * @memberof Polymer.Gestures - * @param {GestureRecognizer} recog Gesture recognizer descriptor + * @param {!GestureRecognizer} recog Gesture recognizer descriptor * @return {void} * @this {Gestures} */ @@ -573,7 +573,7 @@ * adding event listeners. * * @memberof Polymer.Gestures - * @param {Element} node Node to set touch action setting on + * @param {!Element} node Node to set touch action setting on * @param {string} value Touch action value * @return {void} */ @@ -588,9 +588,9 @@ * Dispatches an event on the `target` element of `type` with the given * `detail`. * @private - * @param {EventTarget} target The element on which to fire an event. + * @param {!EventTarget} target The element on which to fire an event. * @param {string} type The type of event to fire. - * @param {Object=} detail The detail object to populate on the event. + * @param {!Object=} detail The detail object to populate on the event. * @return {void} */ _fire: function(target, type, detail) { diff --git a/lib/utils/import-href.html b/lib/utils/import-href.html index 24b394159e..89402ffb5d 100644 --- a/lib/utils/import-href.html +++ b/lib/utils/import-href.html @@ -36,13 +36,13 @@ * * @memberof Polymer * @param {string} href URL to document to load. - * @param {Function=} onload Callback to notify when an import successfully + * @param {!Function=} onload Callback to notify when an import successfully * loaded. - * @param {Function=} onerror Callback to notify when an import + * @param {!Function=} onerror Callback to notify when an import * unsuccessfully loaded. * @param {boolean=} optAsync True if the import should be loaded `async`. * Defaults to `false`. - * @return {HTMLLinkElement} The link element for the URL to be loaded. + * @return {!HTMLLinkElement} The link element for the URL to be loaded. */ Polymer.importHref = function(href, onload, onerror, optAsync) { let link = /** @type {HTMLLinkElement} */ diff --git a/lib/utils/settings.html b/lib/utils/settings.html index a2c8cc30df..88304a8e13 100644 --- a/lib/utils/settings.html +++ b/lib/utils/settings.html @@ -16,11 +16,6 @@ (function() { 'use strict'; - /** - * Legacy settings. - * @namespace - * @memberof Polymer - */ const settings = Polymer.Settings || {}; settings.useShadow = !(window.ShadyDOM); settings.useNativeCSSProperties = @@ -32,6 +27,7 @@ * Sets the global, legacy settings. * * @deprecated + * @namespace * @memberof Polymer */ Polymer.Settings = settings; diff --git a/types/lib/elements/array-selector.d.ts b/types/lib/elements/array-selector.d.ts index 8b6404064b..81ffc584e3 100644 --- a/types/lib/elements/array-selector.d.ts +++ b/types/lib/elements/array-selector.d.ts @@ -68,7 +68,7 @@ declare namespace Polymer { /** * Clears the selection state. */ - clearSelection(): any; + clearSelection(): void; /** * Returns whether the item is currently selected. diff --git a/types/lib/elements/dom-bind.d.ts b/types/lib/elements/dom-bind.d.ts index a13dec78e6..716dd3f9e2 100644 --- a/types/lib/elements/dom-bind.d.ts +++ b/types/lib/elements/dom-bind.d.ts @@ -30,13 +30,9 @@ declare namespace Polymer { Polymer.OptionalMutableData( Polymer.GestureEventListeners( Polymer.Element))) { - - /** - * assumes only one observed attribute - */ - attributeChangedCallback(): any; - connectedCallback(): any; - disconnectedCallback(): any; + attributeChangedCallback(): void; + connectedCallback(): void; + disconnectedCallback(): void; /** * Forces the element to render its content. This is typically only diff --git a/types/lib/elements/dom-module.d.ts b/types/lib/elements/dom-module.d.ts index c4588237da..dabea1711e 100644 --- a/types/lib/elements/dom-module.d.ts +++ b/types/lib/elements/dom-module.d.ts @@ -33,7 +33,7 @@ declare namespace Polymer { * let img = customElements.get('dom-module').import('foo', 'img'); */ class DomModule extends HTMLElement { - attributeChangedCallback(name: any, old: any, value: any): any; + attributeChangedCallback(name: string, old: any, value: any): void; /** * Registers the dom-module at a given id. This method should only be called diff --git a/types/lib/legacy/legacy-element-mixin.d.ts b/types/lib/legacy/legacy-element-mixin.d.ts index be1256011b..d834010aa5 100644 --- a/types/lib/legacy/legacy-element-mixin.d.ts +++ b/types/lib/legacy/legacy-element-mixin.d.ts @@ -41,7 +41,7 @@ declare namespace Polymer { * @param old Old value of attribute. * @param value Current value of attribute. */ - attributeChangedCallback(name: string, old: string|null, value: string|null): any; + attributeChangedCallback(name: string, old: string|null, value: string|null): void; /** * Overrides the default `Polymer.PropertyEffects` implementation to @@ -302,7 +302,7 @@ declare namespace Polymer { * * @returns List of effective child nodes. */ - getEffectiveChildNodes(): Array|null; + getEffectiveChildNodes(): Node[]; /** * Returns a list of nodes distributed within this element that match @@ -312,7 +312,7 @@ declare namespace Polymer { * @param selector Selector to run. * @returns List of distributed elements that match selector. */ - queryDistributedElements(selector: string): Array|null; + queryDistributedElements(selector: string): Node[]; /** * Returns a list of elements that are the effective children. The effective @@ -322,7 +322,7 @@ declare namespace Polymer { * * @returns List of effective children. */ - getEffectiveChildren(): Array|null; + getEffectiveChildren(): Node[]; /** * Returns a string of text content that is the concatenation of the @@ -351,7 +351,7 @@ declare namespace Polymer { * @param selector Selector to run. * @returns List of effective child nodes that match selector. */ - queryAllEffectiveChildren(selector: string): Array|null; + queryAllEffectiveChildren(selector: string): Node[]; /** * Returns a list of nodes distributed to this element's ``. @@ -363,7 +363,7 @@ declare namespace Polymer { * ``. Defaults to `content`. * @returns List of distributed nodes for the ``. */ - getContentChildNodes(slctr?: string): Array|null; + getContentChildNodes(slctr?: string): Node[]; /** * Returns a list of element children distributed to this element's @@ -379,7 +379,7 @@ declare namespace Polymer { * @returns List of distributed nodes for the * ``. */ - getContentChildren(slctr?: string): Array|null; + getContentChildren(slctr?: string): HTMLElement[]; /** * Checks whether an element is in this element's light DOM tree. @@ -435,7 +435,7 @@ declare namespace Polymer { * `flush()` immediately invokes the debounced callback if the debouncer * is active. */ - debounce(jobName: string, callback: () => any, wait: number): Object|null; + debounce(jobName: string, callback: () => void, wait: number): Object|null; /** * Returns whether a named debouncer is active. @@ -471,7 +471,7 @@ declare namespace Polymer { * timing (before paint). * @returns Handle that may be used to cancel the async job. */ - async(callback: Function|null, waitTime?: number): number; + async(callback: Function, waitTime?: number): number; /** * Cancels an async operation started with `async`. @@ -508,7 +508,7 @@ declare namespace Polymer { * Defaults to `false`. * @returns The link element for the URL to be loaded. */ - importHref(href: string, onload: Function|null, onerror: Function|null, optAsync: boolean): HTMLLinkElement|null; + importHref(href: string, onload?: Function, onerror?: Function, optAsync?: boolean): HTMLLinkElement; /** * Polyfill for Element.prototype.matches, which is sometimes still @@ -518,7 +518,7 @@ declare namespace Polymer { * @param node Element to test the selector against. * @returns Whether the element matches the selector. */ - elementMatches(selector: string, node?: Element|null): boolean; + elementMatches(selector: string, node?: Element): boolean; /** * Toggles an HTML attribute on or off. diff --git a/types/lib/legacy/polymer-fn.d.ts b/types/lib/legacy/polymer-fn.d.ts index 36b1f5261c..bd881fd746 100644 --- a/types/lib/legacy/polymer-fn.d.ts +++ b/types/lib/legacy/polymer-fn.d.ts @@ -22,4 +22,4 @@ * * @returns Generated class */ -declare function Polymer(info: PolymerInit): HTMLElement; +declare function Polymer(info: PolymerInit): {new(): HTMLElement}; diff --git a/types/lib/legacy/polymer.dom.d.ts b/types/lib/legacy/polymer.dom.d.ts index 2fb45ca578..e06dfaf5b3 100644 --- a/types/lib/legacy/polymer.dom.d.ts +++ b/types/lib/legacy/polymer.dom.d.ts @@ -111,10 +111,10 @@ declare namespace Polymer { importNode(node: Node|null, deep: boolean): Node|null; /** - * @returns Returns a flattened list of all child nodes and nodes assigned - * to child slots. + * @returns Returns a flattened list of all child nodes and + * nodes assigned to child slots. */ - getEffectiveChildNodes(): any[]|null; + getEffectiveChildNodes(): Node[]; /** * Returns a filtered list of flattened child elements for this element based diff --git a/types/lib/utils/async.d.ts b/types/lib/utils/async.d.ts index 32bedde605..bcc3a083e7 100644 --- a/types/lib/utils/async.d.ts +++ b/types/lib/utils/async.d.ts @@ -32,7 +32,7 @@ declare namespace Polymer { * * @returns An async timeout interface */ - function after(delay: number): AsyncInterface|null; + function after(delay: number): AsyncInterface; /** @@ -40,7 +40,7 @@ declare namespace Polymer { * * @returns Handle used for canceling task */ - function run(fn: Function|null): number; + function run(fn: Function): number; /** @@ -66,7 +66,7 @@ declare namespace Polymer { * * @returns Handle used for canceling task */ - function run(fn: Function|null): number; + function run(fn: Function): number; } /** @@ -81,7 +81,7 @@ declare namespace Polymer { * * @returns Handle used for canceling task */ - function run(fn: (p0: IdleDeadline|null) => any): number; + function run(fn: (p0: IdleDeadline) => void): number; /** @@ -107,7 +107,7 @@ declare namespace Polymer { * * @returns Handle used for canceling task */ - function run(callback: Function|null): number; + function run(callback?: Function): number; /** diff --git a/types/lib/utils/flush.d.ts b/types/lib/utils/flush.d.ts index fa2533b3df..5481803ec2 100644 --- a/types/lib/utils/flush.d.ts +++ b/types/lib/utils/flush.d.ts @@ -16,7 +16,7 @@ declare namespace Polymer { /** * Adds a `Polymer.Debouncer` to a list of globally flushable tasks. */ - function enqueueDebouncer(debouncer: Polymer.Debouncer|null): void; + function enqueueDebouncer(debouncer: Polymer.Debouncer): void; /** diff --git a/types/lib/utils/gestures.d.ts b/types/lib/utils/gestures.d.ts index 55a28b2de6..1b8e300cc4 100644 --- a/types/lib/utils/gestures.d.ts +++ b/types/lib/utils/gestures.d.ts @@ -42,7 +42,7 @@ declare namespace Polymer { * * @returns Returns true if a gesture event listener was added. */ - function addListener(node: Node|null, evType: string, handler: Function|null): boolean; + function addListener(node: Node, evType: string, handler: Function): boolean; /** @@ -50,14 +50,14 @@ declare namespace Polymer { * * @returns Returns true if a gesture event listener was removed. */ - function removeListener(node: Node|null, evType: string, handler: Function|null): boolean; + function removeListener(node: Node, evType: string, handler: Function): boolean; /** * Registers a new gesture event recognizer for adding new custom * gesture event types. */ - function register(recog: GestureRecognizer|null): void; + function register(recog: GestureRecognizer): void; /** @@ -66,7 +66,7 @@ declare namespace Polymer { * This value is checked on first move, thus it should be called prior to * adding event listeners. */ - function setTouchAction(node: Element|null, value: string): void; + function setTouchAction(node: Element, value: string): void; /** diff --git a/types/lib/utils/import-href.d.ts b/types/lib/utils/import-href.d.ts index 352cb04bed..5f1c8fe8c0 100644 --- a/types/lib/utils/import-href.d.ts +++ b/types/lib/utils/import-href.d.ts @@ -23,5 +23,5 @@ declare namespace Polymer { * * @returns The link element for the URL to be loaded. */ - function importHref(href: string, onload?: Function|null, onerror?: Function|null, optAsync?: boolean): HTMLLinkElement|null; + function importHref(href: string, onload?: Function, onerror?: Function, optAsync?: boolean): HTMLLinkElement; } diff --git a/types/lib/utils/settings.d.ts b/types/lib/utils/settings.d.ts index 8766f1d5be..b2f90ffe76 100644 --- a/types/lib/utils/settings.d.ts +++ b/types/lib/utils/settings.d.ts @@ -14,9 +14,9 @@ declare namespace Polymer { /** - * Legacy settings. + * Sets the global, legacy settings. */ - namespace settings { + namespace Settings { }