| /* |
| * Copyright 2008 Google Inc. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| * use this file except in compliance with the License. You may obtain a copy of |
| * the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations under |
| * the License. |
| */ |
| package com.google.gwt.dom.client; |
| |
| import com.google.gwt.core.client.JavaScriptObject; |
| import com.google.gwt.safehtml.shared.SafeHtml; |
| import com.google.gwt.safehtml.shared.annotations.IsSafeHtml; |
| |
| /** |
| * All HTML element interfaces derive from this class. |
| */ |
| public class Element extends Node { |
| |
| /** |
| * Fast helper method to convert small doubles to 32-bit int. |
| * |
| * <p>Note: you should be aware that this uses JavaScript rounding and thus |
| * does NOT provide the same semantics as <code>int b = (int) someDouble;</code>. |
| * In particular, if x is outside the range [-2^31,2^31), then toInt32(x) would return a value |
| * equivalent to x modulo 2^32, whereas (int) x would evaluate to either MIN_INT or MAX_INT. |
| */ |
| private static native int toInt32(double val) /*-{ |
| return val | 0; |
| }-*/; |
| |
| /** |
| * Constant returned from {@link #getDraggable()}. |
| */ |
| public static final String DRAGGABLE_AUTO = "auto"; |
| |
| /** |
| * Constant returned from {@link #getDraggable()}. |
| */ |
| public static final String DRAGGABLE_FALSE = "false"; |
| |
| /** |
| * Constant returned from {@link #getDraggable()}. |
| */ |
| public static final String DRAGGABLE_TRUE = "true"; |
| |
| /** |
| * Assert that the given {@link Node} is an {@link Element} and automatically |
| * typecast it. |
| */ |
| public static Element as(JavaScriptObject o) { |
| assert is(o); |
| return (Element) o; |
| } |
| |
| /** |
| * Assert that the given {@link Node} is an {@link Element} and automatically |
| * typecast it. |
| */ |
| public static Element as(Node node) { |
| assert is(node); |
| return (Element) node; |
| } |
| |
| /** |
| * Determines whether the given {@link JavaScriptObject} can be cast to an |
| * {@link Element}. A <code>null</code> object will cause this method to |
| * return <code>false</code>. |
| */ |
| public static boolean is(JavaScriptObject o) { |
| if (Node.is(o)) { |
| return is((Node) o); |
| } |
| return false; |
| } |
| |
| /** |
| * Determine whether the given {@link Node} can be cast to an {@link Element}. |
| * A <code>null</code> node will cause this method to return |
| * <code>false</code>. |
| */ |
| public static boolean is(Node node) { |
| return (node != null) && (node.getNodeType() == Node.ELEMENT_NODE); |
| } |
| |
| protected Element() { |
| } |
| |
| /** |
| * Adds a name to this element's class property. If the name is already |
| * present, this method has no effect. |
| * |
| * @param className the class name to be added |
| * @return <code>true</code> if this element did not already have the specified class name |
| * @see #setClassName(String) |
| */ |
| public final boolean addClassName(String className) { |
| className = trimClassName(className); |
| |
| // Get the current style string. |
| String oldClassName = getClassName(); |
| int idx = indexOfName(oldClassName, className); |
| |
| // Only add the style if it's not already present. |
| if (idx == -1) { |
| if (oldClassName.length() > 0) { |
| setClassName(oldClassName + " " + className); |
| } else { |
| setClassName(className); |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Removes keyboard focus from this element. |
| */ |
| public final native void blur() /*-{ |
| this.blur(); |
| }-*/; |
| |
| /** |
| * Dispatched the given event with this element as its target. The event will |
| * go through all phases of the browser's normal event dispatch mechanism. |
| * |
| * Note: Because the browser's normal dispatch mechanism is used, exceptions |
| * thrown from within handlers triggered by this method cannot be caught by |
| * wrapping this method in a try/catch block. Such exceptions will be caught |
| * by the |
| * {@link com.google.gwt.core.client.GWT#setUncaughtExceptionHandler(com.google.gwt.core.client.GWT.UncaughtExceptionHandler) uncaught exception handler} |
| * as usual. |
| * |
| * @param evt the event to be dispatched |
| */ |
| public final void dispatchEvent(NativeEvent evt) { |
| DOMImpl.impl.dispatchEvent(this, evt); |
| } |
| |
| /** |
| * Gives keyboard focus to this element. |
| */ |
| public final native void focus() /*-{ |
| this.focus(); |
| }-*/; |
| |
| /** |
| * Gets an element's absolute bottom coordinate in the document's coordinate |
| * system. |
| */ |
| public final int getAbsoluteBottom() { |
| return getAbsoluteTop() + getOffsetHeight(); |
| } |
| |
| /** |
| * Gets an element's absolute left coordinate in the document's coordinate |
| * system. |
| */ |
| public final int getAbsoluteLeft() { |
| return DOMImpl.impl.getAbsoluteLeft(this); |
| } |
| |
| /** |
| * Gets an element's absolute right coordinate in the document's coordinate |
| * system. |
| */ |
| public final int getAbsoluteRight() { |
| return getAbsoluteLeft() + getOffsetWidth(); |
| } |
| |
| /** |
| * Gets an element's absolute top coordinate in the document's coordinate |
| * system. |
| */ |
| public final int getAbsoluteTop() { |
| return DOMImpl.impl.getAbsoluteTop(this); |
| } |
| |
| /** |
| * Retrieves an attribute value by name. Attribute support can be |
| * inconsistent across various browsers. Consider using the accessors in |
| * {@link Element} and its specific subclasses to retrieve attributes and |
| * properties. |
| * |
| * @param name The name of the attribute to retrieve |
| * @return The Attr value as a string, or the empty string if that attribute |
| * does not have a specified or default value |
| */ |
| public final String getAttribute(String name) { |
| return DOMImpl.impl.getAttribute(this, name); |
| } |
| |
| /** |
| * The class attribute of the element. This attribute has been renamed due to |
| * conflicts with the "class" keyword exposed by many languages. |
| * |
| * @see <a |
| * href="http://www.w3.org/TR/1999/REC-html401-19991224/struct/global.html#adef-class">W3C |
| * HTML Specification</a> |
| */ |
| public final native String getClassName() /*-{ |
| return this.className || ""; |
| }-*/; |
| |
| /** |
| * Returns the inner height of an element in pixels, including padding but not |
| * the horizontal scrollbar height, border, or margin. |
| * |
| * @return the element's client height |
| */ |
| public final int getClientHeight() { |
| return toInt32(getSubPixelClientHeight()); |
| } |
| |
| /** |
| * Returns the inner width of an element in pixels, including padding but not |
| * the vertical scrollbar width, border, or margin. |
| * |
| * @return the element's client width |
| */ |
| public final int getClientWidth() { |
| return toInt32(getSubPixelClientWidth()); |
| } |
| |
| /** |
| * Specifies the base direction of directionally neutral text and the |
| * directionality of tables. |
| */ |
| public final native String getDir() /*-{ |
| return this.dir; |
| }-*/; |
| |
| /** |
| * Returns the draggable attribute of this element. |
| * |
| * @return one of {@link #DRAGGABLE_AUTO}, {@link #DRAGGABLE_FALSE}, or |
| * {@link #DRAGGABLE_TRUE} |
| */ |
| public final native String getDraggable() /*-{ |
| return this.draggable || null; |
| }-*/; |
| |
| /** |
| * Returns a NodeList of all descendant Elements with a given tag name, in the |
| * order in which they are encountered in a preorder traversal of this Element |
| * tree. |
| * |
| * @param name The name of the tag to match on. The special value "*" matches |
| * all tags |
| * @return A list of matching Element nodes |
| */ |
| public final native NodeList<Element> getElementsByTagName(String name) /*-{ |
| return this.getElementsByTagName(name); |
| }-*/; |
| |
| /** |
| * The first child of element this element. If there is no such element, this |
| * returns null. |
| */ |
| public final Element getFirstChildElement() { |
| return DOMImpl.impl.getFirstChildElement(this); |
| } |
| |
| /** |
| * The element's identifier. |
| * |
| * @see <a |
| * href="http://www.w3.org/TR/1999/REC-html401-19991224/struct/global.html#adef-id">W3C |
| * HTML Specification</a> |
| */ |
| public final native String getId() /*-{ |
| return this.id; |
| }-*/; |
| |
| /** |
| * All of the markup and content within a given element. |
| */ |
| public final String getInnerHTML() { |
| return DOMImpl.impl.getInnerHTML(this); |
| } |
| |
| /** |
| * The text between the start and end tags of the object. |
| */ |
| public final String getInnerText() { |
| return DOMImpl.impl.getInnerText(this); |
| } |
| |
| /** |
| * Language code defined in RFC 1766. |
| */ |
| public final native String getLang() /*-{ |
| return this.lang; |
| }-*/; |
| |
| /** |
| * The element immediately following this element. If there is no such |
| * element, this returns null. |
| */ |
| public final Element getNextSiblingElement() { |
| return DOMImpl.impl.getNextSiblingElement(this); |
| } |
| |
| /** |
| * The height of an element relative to the layout. |
| */ |
| public final int getOffsetHeight() { |
| return toInt32(getSubPixelOffsetHeight()); |
| } |
| |
| /** |
| * The number of pixels that the upper left corner of the current element is |
| * offset to the left within the offsetParent node. |
| */ |
| public final int getOffsetLeft() { |
| return toInt32(getSubPixelOffsetLeft()); |
| } |
| |
| /** |
| * Returns a reference to the object which is the closest (nearest in the |
| * containment hierarchy) positioned containing element. |
| */ |
| public final native Element getOffsetParent() /*-{ |
| return this.offsetParent; |
| }-*/; |
| |
| /** |
| * The number of pixels that the upper top corner of the current element is |
| * offset to the top within the offsetParent node. |
| */ |
| public final int getOffsetTop() { |
| return toInt32(getSubPixelOffsetTop()); |
| } |
| |
| /** |
| * The width of an element relative to the layout. |
| */ |
| public final int getOffsetWidth() { |
| return toInt32(getSubPixelOffsetWidth()); |
| } |
| |
| /** |
| * The element immediately preceding this element. If there is no such |
| * element, this returns null. |
| */ |
| public final Element getPreviousSiblingElement() { |
| return DOMImpl.impl.getPreviousSiblingElement(this); |
| } |
| |
| /** |
| * Gets a boolean property from this element. |
| * |
| * @param name the name of the property to be retrieved |
| * @return the property value |
| */ |
| public final native boolean getPropertyBoolean(String name) /*-{ |
| return !!this[name]; |
| }-*/; |
| |
| /** |
| * Gets a double property from this element. |
| * |
| * @param name the name of the property to be retrieved |
| * @return the property value |
| */ |
| public final native double getPropertyDouble(String name) /*-{ |
| return parseFloat(this[name]) || 0.0; |
| }-*/; |
| |
| /** |
| * Gets an integer property from this element. |
| * |
| * @param name the name of the property to be retrieved |
| * @return the property value |
| */ |
| public final native int getPropertyInt(String name) /*-{ |
| return parseInt(this[name]) | 0; |
| }-*/; |
| |
| /** |
| * Gets a JSO property from this element. |
| * |
| * @param name the name of the property to be retrieved |
| * @return the property value |
| */ |
| public final native JavaScriptObject getPropertyJSO(String name) /*-{ |
| return this[name] || null; |
| }-*/; |
| |
| /** |
| * Gets an object property from this element. |
| * |
| * @param name the name of the property to be retrieved |
| * @return the property value |
| */ |
| public final native Object getPropertyObject(String name) /*-{ |
| return this[name]; |
| }-*/; |
| |
| /** |
| * Gets a property from this element. |
| * |
| * @param name the name of the property to be retrieved |
| * @return the property value |
| */ |
| public final native String getPropertyString(String name) /*-{ |
| return (this[name] == null) ? null : String(this[name]); |
| }-*/; |
| |
| /** |
| * The height of the scroll view of an element. |
| */ |
| public final int getScrollHeight() { |
| return toInt32(getSubPixelScrollHeight()); |
| } |
| |
| /** |
| * The number of pixels that an element's content is scrolled from the left. |
| * |
| * <p> |
| * If the element is in RTL mode, this method will return a negative value of |
| * the number of pixels scrolled from the right. |
| * </p> |
| */ |
| public final int getScrollLeft() { |
| return DOMImpl.impl.getScrollLeft(this); |
| } |
| |
| /** |
| * The number of pixels that an element's content is scrolled from the top. |
| */ |
| public final int getScrollTop() { |
| return toInt32(getSubPixelScrollTop()); |
| } |
| |
| /** |
| * The width of the scroll view of an element. |
| */ |
| public final int getScrollWidth() { |
| return toInt32(getSubPixelScrollWidth()); |
| } |
| |
| /** |
| * Gets a string representation of this element (as outer HTML). |
| * |
| * We do not override {@link #toString()} because it is final in |
| * {@link com.google.gwt.core.client.JavaScriptObject}. |
| * |
| * @return the string representation of this element |
| */ |
| public final String getString() { |
| return DOMImpl.impl.toString(this); |
| } |
| |
| /** |
| * Gets this element's {@link Style} object. |
| */ |
| public final native Style getStyle() /*-{ |
| return this.style; |
| }-*/; |
| |
| /** |
| * The index that represents the element's position in the tabbing order. |
| * |
| * @see <a href="http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#adef-tabindex">W3C HTML Specification</a> |
| */ |
| public final int getTabIndex() { |
| return DOMImpl.impl.getTabIndex(this); |
| } |
| |
| /** |
| * Gets the element's full tag name, including the namespace-prefix if |
| * present. |
| * |
| * @return the element's tag name |
| */ |
| public final String getTagName() { |
| return DOMImpl.impl.getTagName(this); |
| } |
| |
| /** |
| * The element's advisory title. |
| */ |
| public final native String getTitle() /*-{ |
| return this.title; |
| }-*/; |
| |
| /** |
| * Determines whether an element has an attribute with a given name. |
| * |
| * <p> |
| * Note that IE, prior to version 8, will return false-positives for names |
| * that collide with element properties (e.g., style, width, and so forth). |
| * </p> |
| * |
| * @param name the name of the attribute |
| * @return <code>true</code> if this element has the specified attribute |
| */ |
| public final boolean hasAttribute(String name) { |
| return DOMImpl.impl.hasAttribute(this, name); |
| } |
| |
| /** |
| * Checks if this element's class property contains specified class name. |
| * |
| * @param className the class name to be added |
| * @return <code>true</code> if this element has the specified class name |
| */ |
| public final boolean hasClassName(String className) { |
| className = trimClassName(className); |
| int idx = indexOfName(getClassName(), className); |
| return idx != -1; |
| } |
| |
| /** |
| * Determines whether this element has the given tag name. |
| * |
| * @param tagName the tag name, including namespace-prefix (if present) |
| * @return <code>true</code> if the element has the given tag name |
| */ |
| public final boolean hasTagName(String tagName) { |
| assert tagName != null : "tagName must not be null"; |
| return tagName.equalsIgnoreCase(getTagName()); |
| } |
| |
| /** |
| * Removes an attribute by name. |
| */ |
| public final native void removeAttribute(String name) /*-{ |
| this.removeAttribute(name); |
| }-*/; |
| |
| /** |
| * Removes a name from this element's class property. If the name is not |
| * present, this method has no effect. |
| * |
| * @param className the class name to be removed |
| * @return <code>true</code> if this element had the specified class name |
| * @see #setClassName(String) |
| */ |
| public final boolean removeClassName(String className) { |
| className = trimClassName(className); |
| |
| // Get the current style string. |
| String oldStyle = getClassName(); |
| int idx = indexOfName(oldStyle, className); |
| |
| // Don't try to remove the style if it's not there. |
| if (idx != -1) { |
| // Get the leading and trailing parts, without the removed name. |
| String begin = oldStyle.substring(0, idx).trim(); |
| String end = oldStyle.substring(idx + className.length()).trim(); |
| |
| // Some contortions to make sure we don't leave extra spaces. |
| String newClassName; |
| if (begin.length() == 0) { |
| newClassName = end; |
| } else if (end.length() == 0) { |
| newClassName = begin; |
| } else { |
| newClassName = begin + " " + end; |
| } |
| |
| setClassName(newClassName); |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the index of the first occurrence of name in a space-separated list of names, |
| * or -1 if not found. |
| * |
| * @param nameList list of space delimited names |
| * @param name a non-empty string. Should be already trimmed. |
| */ |
| static int indexOfName(String nameList, String name) { |
| int idx = nameList.indexOf(name); |
| |
| // Calculate matching index. |
| while (idx != -1) { |
| if (idx == 0 || nameList.charAt(idx - 1) == ' ') { |
| int last = idx + name.length(); |
| int lastPos = nameList.length(); |
| if ((last == lastPos) |
| || ((last < lastPos) && (nameList.charAt(last) == ' '))) { |
| break; |
| } |
| } |
| idx = nameList.indexOf(name, idx + 1); |
| } |
| |
| return idx; |
| } |
| |
| private static String trimClassName(String className) { |
| assert (className != null) : "Unexpectedly null class name"; |
| className = className.trim(); |
| assert !className.isEmpty() : "Unexpectedly empty class name"; |
| return className; |
| } |
| |
| /** |
| * Add the class name if it doesn't exist or removes it if does. |
| * |
| * @param className the class name to be toggled |
| */ |
| public final void toggleClassName(String className) { |
| boolean added = addClassName(className); |
| if (!added) { |
| removeClassName(className); |
| } |
| } |
| |
| /** |
| * Replace one class name with another. |
| * |
| * @param oldClassName the class name to be replaced |
| * @param newClassName the class name to replace it |
| */ |
| public final void replaceClassName(String oldClassName, String newClassName) { |
| removeClassName(oldClassName); |
| addClassName(newClassName); |
| } |
| |
| /** |
| * Scrolls this element into view. |
| * |
| * <p> |
| * This method crawls up the DOM hierarchy, adjusting the scrollLeft and |
| * scrollTop properties of each scrollable element to ensure that the |
| * specified element is completely in view. It adjusts each scroll position by |
| * the minimum amount necessary. |
| * </p> |
| */ |
| public final void scrollIntoView() { |
| DOMImpl.impl.scrollIntoView(this); |
| } |
| |
| /** |
| * Adds a new attribute. If an attribute with that name is already present in |
| * the element, its value is changed to be that of the value parameter. |
| * |
| * @param name The name of the attribute to create or alter |
| * @param value Value to set in string form |
| */ |
| public final native void setAttribute(String name, String value) /*-{ |
| this.setAttribute(name, value); |
| }-*/; |
| |
| /** |
| * The class attribute of the element. This attribute has been renamed due to |
| * conflicts with the "class" keyword exposed by many languages. |
| * |
| * @see <a |
| * href="http://www.w3.org/TR/1999/REC-html401-19991224/struct/global.html#adef-class">W3C |
| * HTML Specification</a> |
| */ |
| public final native void setClassName(String className) /*-{ |
| this.className = className || ""; |
| }-*/; |
| |
| /** |
| * Specifies the base direction of directionally neutral text and the |
| * directionality of tables. |
| */ |
| public final native void setDir(String dir) /*-{ |
| this.dir = dir; |
| }-*/; |
| |
| /** |
| * Changes the draggable attribute to one of {@link #DRAGGABLE_AUTO}, |
| * {@link #DRAGGABLE_FALSE}, or {@link #DRAGGABLE_TRUE}. |
| * |
| * @param draggable a String constants |
| */ |
| public final void setDraggable(String draggable) { |
| DOMImpl.impl.setDraggable(this, draggable); |
| } |
| |
| /** |
| * The element's identifier. |
| * |
| * @see <a |
| * href="http://www.w3.org/TR/1999/REC-html401-19991224/struct/global.html#adef-id">W3C |
| * HTML Specification</a> |
| */ |
| public final native void setId(String id) /*-{ |
| this.id = id; |
| }-*/; |
| |
| /** |
| * All of the markup and content within a given element. |
| */ |
| public final native void setInnerHTML(@IsSafeHtml String html) /*-{ |
| this.innerHTML = html || ''; |
| }-*/; |
| |
| /** |
| * All of the markup and content within a given element. |
| */ |
| public final void setInnerSafeHtml(SafeHtml html) { |
| setInnerHTML(html.asString()); |
| } |
| |
| /** |
| * The text between the start and end tags of the object. |
| */ |
| public final void setInnerText(String text) { |
| DOMImpl.impl.setInnerText(this, text); |
| } |
| |
| /** |
| * Language code defined in RFC 1766. |
| */ |
| public final native void setLang(String lang) /*-{ |
| this.lang = lang; |
| }-*/; |
| |
| /** |
| * Sets a boolean property on this element. |
| * |
| * @param name the name of the property to be set |
| * @param value the new property value |
| */ |
| public final native void setPropertyBoolean(String name, boolean value) /*-{ |
| this[name] = value; |
| }-*/; |
| |
| /** |
| * Sets a double property on this element. |
| * |
| * @param name the name of the property to be set |
| * @param value the new property value |
| */ |
| public final native void setPropertyDouble(String name, double value) /*-{ |
| this[name] = value; |
| }-*/; |
| |
| /** |
| * Sets an integer property on this element. |
| * |
| * @param name the name of the property to be set |
| * @param value the new property value |
| */ |
| public final native void setPropertyInt(String name, int value) /*-{ |
| this[name] = value; |
| }-*/; |
| |
| /** |
| * Sets a JSO property on this element. |
| * |
| * @param name the name of the property to be set |
| * @param value the new property value |
| */ |
| public final native void setPropertyJSO(String name, JavaScriptObject value) /*-{ |
| this[name] = value; |
| }-*/; |
| |
| /** |
| * Sets an object property on this element. |
| * |
| * @param name the name of the property to be set |
| * @param value the new property value |
| */ |
| public final native void setPropertyObject(String name, Object value) /*-{ |
| this[name] = value; |
| }-*/; |
| |
| /** |
| * Sets a property on this element. |
| * |
| * @param name the name of the property to be set |
| * @param value the new property value |
| */ |
| public final native void setPropertyString(String name, String value) /*-{ |
| this[name] = value; |
| }-*/; |
| |
| /** |
| * The number of pixels that an element's content is scrolled to the left. |
| */ |
| public final void setScrollLeft(int scrollLeft) { |
| DOMImpl.impl.setScrollLeft(this, scrollLeft); |
| } |
| |
| /** |
| * The number of pixels that an element's content is scrolled to the top. |
| */ |
| public final native void setScrollTop(int scrollTop) /*-{ |
| this.scrollTop = scrollTop; |
| }-*/; |
| |
| /** |
| * The index that represents the element's position in the tabbing order. |
| * |
| * @see <a href="http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#adef-tabindex">W3C HTML Specification</a> |
| */ |
| public final native void setTabIndex(int tabIndex) /*-{ |
| this.tabIndex = tabIndex; |
| }-*/; |
| |
| /** |
| * The element's advisory title. |
| */ |
| public final native void setTitle(String title) /*-{ |
| // Setting the title to null results in the string "null" being displayed |
| // on some browsers. |
| this.title = title || ''; |
| }-*/; |
| |
| private final native double getSubPixelClientHeight() /*-{ |
| return this.clientHeight; |
| }-*/; |
| |
| private final native double getSubPixelClientWidth() /*-{ |
| return this.clientWidth; |
| }-*/; |
| |
| private final native double getSubPixelOffsetHeight() /*-{ |
| return this.offsetHeight || 0; |
| }-*/; |
| |
| private final native double getSubPixelOffsetLeft() /*-{ |
| return this.offsetLeft || 0; |
| }-*/; |
| |
| private final native double getSubPixelOffsetTop() /*-{ |
| return this.offsetTop || 0; |
| }-*/; |
| |
| private final native double getSubPixelOffsetWidth() /*-{ |
| return this.offsetWidth || 0; |
| }-*/; |
| |
| private final native double getSubPixelScrollHeight() /*-{ |
| return this.scrollHeight || 0; |
| }-*/; |
| |
| private final native double getSubPixelScrollTop() /*-{ |
| return this.scrollTop || 0; |
| }-*/; |
| |
| private final native double getSubPixelScrollWidth() /*-{ |
| return this.scrollWidth || 0; |
| }-*/; |
| } |