http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/browserrange/browserrange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/browserrange/browserrange.js 
b/externs/GCL/externs/goog/dom/browserrange/browserrange.js
new file mode 100644
index 0000000..0cd70e7
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/browserrange/browserrange.js
@@ -0,0 +1,149 @@
+// Copyright 2007 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview Definition of the browser range namespace and interface, as
+ * well as several useful utility functions.
+ *
+ * DO NOT USE THIS FILE DIRECTLY.  Use goog.dom.Range instead.
+ *
+ * @author [email protected] (Robby Walker)
+ *
+ * @supported IE6, IE7, FF1.5+, Safari.
+ */
+
+
+goog.provide('goog.dom.browserrange');
+goog.provide('goog.dom.browserrange.Error');
+
+goog.require('goog.dom');
+goog.require('goog.dom.BrowserFeature');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.browserrange.GeckoRange');
+goog.require('goog.dom.browserrange.IeRange');
+goog.require('goog.dom.browserrange.OperaRange');
+goog.require('goog.dom.browserrange.W3cRange');
+goog.require('goog.dom.browserrange.WebKitRange');
+goog.require('goog.userAgent');
+
+
+/**
+ * Common error constants.
+ * @enum {string}
+ */
+goog.dom.browserrange.Error = {
+  NOT_IMPLEMENTED: 'Not Implemented'
+};
+
+
+// NOTE(robbyw): While it would be nice to eliminate the duplicate switches
+//               below, doing so uncovers bugs in the JsCompiler in which
+//               necessary code is stripped out.
+
+
+/**
+ * Static method that returns the proper type of browser range.
+ * @param {Range|TextRange} range A browser range object.
+ * @return {!goog.dom.browserrange.AbstractRange} A wrapper object.
+ */
+goog.dom.browserrange.createRange = function(range) {
+  if (goog.dom.BrowserFeature.LEGACY_IE_RANGES) {
+    return new goog.dom.browserrange.IeRange(
+        /** @type {TextRange} */ (range),
+        goog.dom.getOwnerDocument(range.parentElement()));
+  } else if (goog.userAgent.WEBKIT) {
+    return new goog.dom.browserrange.WebKitRange(
+        /** @type {Range} */ (range));
+  } else if (goog.userAgent.GECKO) {
+    return new goog.dom.browserrange.GeckoRange(
+        /** @type {Range} */ (range));
+  } else if (goog.userAgent.OPERA) {
+    return new goog.dom.browserrange.OperaRange(
+        /** @type {Range} */ (range));
+  } else {
+    // Default other browsers, including Opera, to W3c ranges.
+    return new goog.dom.browserrange.W3cRange(
+        /** @type {Range} */ (range));
+  }
+};
+
+
+/**
+ * Static method that returns the proper type of browser range.
+ * @param {Node} node The node to select.
+ * @return {!goog.dom.browserrange.AbstractRange} A wrapper object.
+ */
+goog.dom.browserrange.createRangeFromNodeContents = function(node) {
+  if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) {
+    return goog.dom.browserrange.IeRange.createFromNodeContents(node);
+  } else if (goog.userAgent.WEBKIT) {
+    return goog.dom.browserrange.WebKitRange.createFromNodeContents(node);
+  } else if (goog.userAgent.GECKO) {
+    return goog.dom.browserrange.GeckoRange.createFromNodeContents(node);
+  } else if (goog.userAgent.OPERA) {
+    return goog.dom.browserrange.OperaRange.createFromNodeContents(node);
+  } else {
+    // Default other browsers to W3c ranges.
+    return goog.dom.browserrange.W3cRange.createFromNodeContents(node);
+  }
+};
+
+
+/**
+ * Static method that returns the proper type of browser range.
+ * @param {Node} startNode The node to start with.
+ * @param {number} startOffset The offset within the node to start.  This is
+ *     either the index into the childNodes array for element startNodes or
+ *     the index into the character array for text startNodes.
+ * @param {Node} endNode The node to end with.
+ * @param {number} endOffset The offset within the node to end.  This is
+ *     either the index into the childNodes array for element endNodes or
+ *     the index into the character array for text endNodes.
+ * @return {!goog.dom.browserrange.AbstractRange} A wrapper object.
+ */
+goog.dom.browserrange.createRangeFromNodes = function(startNode, startOffset,
+    endNode, endOffset) {
+  if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) {
+    return goog.dom.browserrange.IeRange.createFromNodes(startNode, 
startOffset,
+        endNode, endOffset);
+  } else if (goog.userAgent.WEBKIT) {
+    return goog.dom.browserrange.WebKitRange.createFromNodes(startNode,
+        startOffset, endNode, endOffset);
+  } else if (goog.userAgent.GECKO) {
+    return goog.dom.browserrange.GeckoRange.createFromNodes(startNode,
+        startOffset, endNode, endOffset);
+  } else if (goog.userAgent.OPERA) {
+    return goog.dom.browserrange.OperaRange.createFromNodes(startNode,
+        startOffset, endNode, endOffset);
+  } else {
+    // Default other browsers to W3c ranges.
+    return goog.dom.browserrange.W3cRange.createFromNodes(startNode,
+        startOffset, endNode, endOffset);
+  }
+};
+
+
+/**
+ * Tests whether the given node can contain a range end point.
+ * @param {Node} node The node to check.
+ * @return {boolean} Whether the given node can contain a range end point.
+ */
+goog.dom.browserrange.canContainRangeEndpoint = function(node) {
+  // NOTE(user, bloom): This is not complete, as divs with style -
+  // 'display:inline-block' or 'position:absolute' can also not contain range
+  // endpoints. A more complete check is to see if that element can be 
partially
+  // selected (can be container) or not.
+  return goog.dom.canHaveChildren(node) ||
+      node.nodeType == goog.dom.NodeType.TEXT;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/browserrange/geckorange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/browserrange/geckorange.js 
b/externs/GCL/externs/goog/dom/browserrange/geckorange.js
new file mode 100644
index 0000000..b01f2dd
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/browserrange/geckorange.js
@@ -0,0 +1,88 @@
+// Copyright 2007 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview Definition of the Gecko specific range wrapper.  Inherits most
+ * functionality from W3CRange, but adds exceptions as necessary.
+ *
+ * DO NOT USE THIS FILE DIRECTLY.  Use goog.dom.Range instead.
+ *
+ * @author [email protected] (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.browserrange.GeckoRange');
+
+goog.require('goog.dom.browserrange.W3cRange');
+
+
+
+/**
+ * The constructor for Gecko specific browser ranges.
+ * @param {Range} range The range object.
+ * @constructor
+ * @extends {goog.dom.browserrange.W3cRange}
+ * @final
+ */
+goog.dom.browserrange.GeckoRange = function(range) {
+  goog.dom.browserrange.W3cRange.call(this, range);
+};
+goog.inherits(goog.dom.browserrange.GeckoRange, 
goog.dom.browserrange.W3cRange);
+
+
+/**
+ * Creates a range object that selects the given node's text.
+ * @param {Node} node The node to select.
+ * @return {!goog.dom.browserrange.GeckoRange} A Gecko range wrapper object.
+ */
+goog.dom.browserrange.GeckoRange.createFromNodeContents = function(node) {
+  return new goog.dom.browserrange.GeckoRange(
+      goog.dom.browserrange.W3cRange.getBrowserRangeForNode(node));
+};
+
+
+/**
+ * Creates a range object that selects between the given nodes.
+ * @param {Node} startNode The node to start with.
+ * @param {number} startOffset The offset within the node to start.
+ * @param {Node} endNode The node to end with.
+ * @param {number} endOffset The offset within the node to end.
+ * @return {!goog.dom.browserrange.GeckoRange} A wrapper object.
+ */
+goog.dom.browserrange.GeckoRange.createFromNodes = function(startNode,
+    startOffset, endNode, endOffset) {
+  return new goog.dom.browserrange.GeckoRange(
+      goog.dom.browserrange.W3cRange.getBrowserRangeForNodes(startNode,
+          startOffset, endNode, endOffset));
+};
+
+
+/** @override */
+goog.dom.browserrange.GeckoRange.prototype.selectInternal = function(
+    selection, reversed) {
+  if (!reversed || this.isCollapsed()) {
+    // The base implementation for select() is more robust, and works fine for
+    // collapsed and forward ranges.  This works around
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=773137, and is tested by
+    // range_test.html's testFocusedElementDisappears.
+    goog.dom.browserrange.GeckoRange.base(
+        this, 'selectInternal', selection, reversed);
+  } else {
+    // Reversed selection -- start with a caret on the end node, and extend it
+    // back to the start.  Unfortunately, collapse() fails when focus is
+    // invalid.
+    selection.collapse(this.getEndNode(), this.getEndOffset());
+    selection.extend(this.getStartNode(), this.getStartOffset());
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/browserrange/ierange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/browserrange/ierange.js 
b/externs/GCL/externs/goog/dom/browserrange/ierange.js
new file mode 100644
index 0000000..a2add21
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/browserrange/ierange.js
@@ -0,0 +1,935 @@
+// Copyright 2007 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview Definition of the IE browser specific range wrapper.
+ *
+ * DO NOT USE THIS FILE DIRECTLY.  Use goog.dom.Range instead.
+ *
+ * @author [email protected] (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.browserrange.IeRange');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.RangeEndpoint');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.browserrange.AbstractRange');
+goog.require('goog.log');
+goog.require('goog.string');
+
+
+
+/**
+ * The constructor for IE specific browser ranges.
+ * @param {TextRange} range The range object.
+ * @param {Document} doc The document the range exists in.
+ * @constructor
+ * @extends {goog.dom.browserrange.AbstractRange}
+ * @final
+ */
+goog.dom.browserrange.IeRange = function(range, doc) {
+  /**
+   * Lazy cache of the node containing the entire selection.
+   * @private {Node}
+   */
+  this.parentNode_ = null;
+
+  /**
+   * Lazy cache of the node containing the start of the selection.
+   * @private {Node}
+   */
+  this.startNode_ = null;
+
+  /**
+   * Lazy cache of the node containing the end of the selection.
+   * @private {Node}
+   */
+  this.endNode_ = null;
+
+  /**
+   * Lazy cache of the offset in startNode_ where this range starts.
+   * @private {number}
+   */
+  this.startOffset_ = -1;
+
+  /**
+   * Lazy cache of the offset in endNode_ where this range ends.
+   * @private {number}
+   */
+  this.endOffset_ = -1;
+
+  /**
+   * The browser range object this class wraps.
+   * @private {TextRange}
+   */
+  this.range_ = range;
+
+  /**
+   * The document the range exists in.
+   * @private {Document}
+   */
+  this.doc_ = doc;
+};
+goog.inherits(goog.dom.browserrange.IeRange,
+    goog.dom.browserrange.AbstractRange);
+
+
+/**
+ * Logging object.
+ * @type {goog.log.Logger}
+ * @private
+ */
+goog.dom.browserrange.IeRange.logger_ =
+    goog.log.getLogger('goog.dom.browserrange.IeRange');
+
+
+/**
+ * Returns a browser range spanning the given node's contents.
+ * @param {Node} node The node to select.
+ * @return {!TextRange} A browser range spanning the node's contents.
+ * @private
+ */
+goog.dom.browserrange.IeRange.getBrowserRangeForNode_ = function(node) {
+  var nodeRange = goog.dom.getOwnerDocument(node).body.createTextRange();
+  if (node.nodeType == goog.dom.NodeType.ELEMENT) {
+    // Elements are easy.
+    nodeRange.moveToElementText(node);
+    // Note(user) : If there are no child nodes of the element, the
+    // range.htmlText includes the element's outerHTML. The range created above
+    // is not collapsed, and should be collapsed explicitly.
+    // Example : node = <div></div>
+    // But if the node is sth like <br>, it shouldnt be collapsed.
+    if (goog.dom.browserrange.canContainRangeEndpoint(node) &&
+        !node.childNodes.length) {
+      nodeRange.collapse(false);
+    }
+  } else {
+    // Text nodes are hard.
+    // Compute the offset from the nearest element related position.
+    var offset = 0;
+    var sibling = node;
+    while (sibling = sibling.previousSibling) {
+      var nodeType = sibling.nodeType;
+      if (nodeType == goog.dom.NodeType.TEXT) {
+        offset += sibling.length;
+      } else if (nodeType == goog.dom.NodeType.ELEMENT) {
+        // Move to the space after this element.
+        nodeRange.moveToElementText(sibling);
+        break;
+      }
+    }
+
+    if (!sibling) {
+      nodeRange.moveToElementText(node.parentNode);
+    }
+
+    nodeRange.collapse(!sibling);
+
+    if (offset) {
+      nodeRange.move('character', offset);
+    }
+
+    nodeRange.moveEnd('character', node.length);
+  }
+
+  return nodeRange;
+};
+
+
+/**
+ * Returns a browser range spanning the given nodes.
+ * @param {Node} startNode The node to start with.
+ * @param {number} startOffset The offset within the start node.
+ * @param {Node} endNode The node to end with.
+ * @param {number} endOffset The offset within the end node.
+ * @return {!TextRange} A browser range spanning the node's contents.
+ * @private
+ */
+goog.dom.browserrange.IeRange.getBrowserRangeForNodes_ = function(startNode,
+    startOffset, endNode, endOffset) {
+  // Create a range starting at the correct start position.
+  var child, collapse = false;
+  if (startNode.nodeType == goog.dom.NodeType.ELEMENT) {
+    if (startOffset > startNode.childNodes.length) {
+      goog.log.error(goog.dom.browserrange.IeRange.logger_,
+          'Cannot have startOffset > startNode child count');
+    }
+    child = startNode.childNodes[startOffset];
+    collapse = !child;
+    startNode = child || startNode.lastChild || startNode;
+    startOffset = 0;
+  }
+  var leftRange = goog.dom.browserrange.IeRange.
+      getBrowserRangeForNode_(startNode);
+
+  // This happens only when startNode is a text node.
+  if (startOffset) {
+    leftRange.move('character', startOffset);
+  }
+
+
+  // The range movements in IE are still an approximation to the standard W3C
+  // behavior, and IE has its trickery when it comes to htmlText and text
+  // properties of the range. So we short-circuit computation whenever we can.
+  if (startNode == endNode && startOffset == endOffset) {
+    leftRange.collapse(true);
+    return leftRange;
+  }
+
+  // This can happen only when the startNode is an element, and there is no 
node
+  // at the given offset. We start at the last point inside the startNode in
+  // that case.
+  if (collapse) {
+    leftRange.collapse(false);
+  }
+
+  // Create a range that ends at the right position.
+  collapse = false;
+  if (endNode.nodeType == goog.dom.NodeType.ELEMENT) {
+    if (endOffset > endNode.childNodes.length) {
+      goog.log.error(goog.dom.browserrange.IeRange.logger_,
+          'Cannot have endOffset > endNode child count');
+    }
+    child = endNode.childNodes[endOffset];
+    endNode = child || endNode.lastChild || endNode;
+    endOffset = 0;
+    collapse = !child;
+  }
+  var rightRange = goog.dom.browserrange.IeRange.
+      getBrowserRangeForNode_(endNode);
+  rightRange.collapse(!collapse);
+  if (endOffset) {
+    rightRange.moveEnd('character', endOffset);
+  }
+
+  // Merge and return.
+  leftRange.setEndPoint('EndToEnd', rightRange);
+  return leftRange;
+};
+
+
+/**
+ * Create a range object that selects the given node's text.
+ * @param {Node} node The node to select.
+ * @return {!goog.dom.browserrange.IeRange} An IE range wrapper object.
+ */
+goog.dom.browserrange.IeRange.createFromNodeContents = function(node) {
+  var range = new goog.dom.browserrange.IeRange(
+      goog.dom.browserrange.IeRange.getBrowserRangeForNode_(node),
+      goog.dom.getOwnerDocument(node));
+
+  if (!goog.dom.browserrange.canContainRangeEndpoint(node)) {
+    range.startNode_ = range.endNode_ = range.parentNode_ = node.parentNode;
+    range.startOffset_ = goog.array.indexOf(range.parentNode_.childNodes, 
node);
+    range.endOffset_ = range.startOffset_ + 1;
+  } else {
+    // Note(user) : Emulate the behavior of W3CRange - Go to deepest possible
+    // range containers on both edges. It seems W3CRange did this to match the
+    // IE behavior, and now it is a circle. Changing W3CRange may break clients
+    // in all sorts of ways.
+    var tempNode, leaf = node;
+    while ((tempNode = leaf.firstChild) &&
+           goog.dom.browserrange.canContainRangeEndpoint(tempNode)) {
+      leaf = tempNode;
+    }
+    range.startNode_ = leaf;
+    range.startOffset_ = 0;
+
+    leaf = node;
+    while ((tempNode = leaf.lastChild) &&
+           goog.dom.browserrange.canContainRangeEndpoint(tempNode)) {
+      leaf = tempNode;
+    }
+    range.endNode_ = leaf;
+    range.endOffset_ = leaf.nodeType == goog.dom.NodeType.ELEMENT ?
+                       leaf.childNodes.length : leaf.length;
+    range.parentNode_ = node;
+  }
+  return range;
+};
+
+
+/**
+ * Static method that returns the proper type of browser range.
+ * @param {Node} startNode The node to start with.
+ * @param {number} startOffset The offset within the start node.
+ * @param {Node} endNode The node to end with.
+ * @param {number} endOffset The offset within the end node.
+ * @return {!goog.dom.browserrange.AbstractRange} A wrapper object.
+ */
+goog.dom.browserrange.IeRange.createFromNodes = function(startNode,
+    startOffset, endNode, endOffset) {
+  var range = new goog.dom.browserrange.IeRange(
+      goog.dom.browserrange.IeRange.getBrowserRangeForNodes_(startNode,
+          startOffset, endNode, endOffset),
+      goog.dom.getOwnerDocument(startNode));
+  range.startNode_ = startNode;
+  range.startOffset_ = startOffset;
+  range.endNode_ = endNode;
+  range.endOffset_ = endOffset;
+  return range;
+};
+
+
+/**
+ * @return {!goog.dom.browserrange.IeRange} A clone of this range.
+ * @override
+ */
+goog.dom.browserrange.IeRange.prototype.clone = function() {
+  var range = new goog.dom.browserrange.IeRange(
+      this.range_.duplicate(), this.doc_);
+  range.parentNode_ = this.parentNode_;
+  range.startNode_ = this.startNode_;
+  range.endNode_ = this.endNode_;
+  return range;
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.getBrowserRange = function() {
+  return this.range_;
+};
+
+
+/**
+ * Clears the cached values for containers.
+ * @private
+ */
+goog.dom.browserrange.IeRange.prototype.clearCachedValues_ = function() {
+  this.parentNode_ = this.startNode_ = this.endNode_ = null;
+  this.startOffset_ = this.endOffset_ = -1;
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.getContainer = function() {
+  if (!this.parentNode_) {
+    var selectText = this.range_.text;
+
+    // If the selection ends with spaces, we need to remove these to get the
+    // parent container of only the real contents.  This is to get around IE's
+    // inconsistency where it selects the spaces after a word when you double
+    // click, but leaves out the spaces during execCommands.
+    var range = this.range_.duplicate();
+    // We can't use goog.string.trimRight, as that will remove other whitespace
+    // too.
+    var rightTrimmedSelectText = selectText.replace(/ +$/, '');
+    var numSpacesAtEnd = selectText.length - rightTrimmedSelectText.length;
+    if (numSpacesAtEnd) {
+      range.moveEnd('character', -numSpacesAtEnd);
+    }
+
+    // Get the parent node.  This should be the end, but alas, it is not.
+    var parent = range.parentElement();
+
+    var htmlText = range.htmlText;
+    var htmlTextLen = goog.string.stripNewlines(htmlText).length;
+    if (this.isCollapsed() && htmlTextLen > 0) {
+      return (this.parentNode_ = parent);
+    }
+
+    // Deal with selection bug where IE thinks one of the selection's children
+    // is actually the selection's parent. Relies on the assumption that the
+    // HTML text of the parent container is longer than the length of the
+    // selection's HTML text.
+
+    // Also note IE will sometimes insert \r and \n whitespace, which should be
+    // disregarded. Otherwise the loop may run too long and return wrong parent
+    while (htmlTextLen > goog.string.stripNewlines(parent.outerHTML).length) {
+      parent = parent.parentNode;
+    }
+
+    // Deal with IE's selecting the outer tags when you double click
+    // If the innerText is the same, then we just want the inner node
+    while (parent.childNodes.length == 1 &&
+           parent.innerText == goog.dom.browserrange.IeRange.getNodeText_(
+               parent.firstChild)) {
+      // A container should be an element which can have children or a text
+      // node. Elements like IMG, BR, etc. can not be containers.
+      if (!goog.dom.browserrange.canContainRangeEndpoint(parent.firstChild)) {
+        break;
+      }
+      parent = parent.firstChild;
+    }
+
+    // If the selection is empty, we may need to do extra work to position it
+    // properly.
+    if (selectText.length == 0) {
+      parent = this.findDeepestContainer_(parent);
+    }
+
+    this.parentNode_ = parent;
+  }
+
+  return this.parentNode_;
+};
+
+
+/**
+ * Helper method to find the deepest parent for this range, starting
+ * the search from {@code node}, which must contain the range.
+ * @param {Node} node The node to start the search from.
+ * @return {Node} The deepest parent for this range.
+ * @private
+ */
+goog.dom.browserrange.IeRange.prototype.findDeepestContainer_ = function(node) 
{
+  var childNodes = node.childNodes;
+  for (var i = 0, len = childNodes.length; i < len; i++) {
+    var child = childNodes[i];
+
+    if (goog.dom.browserrange.canContainRangeEndpoint(child)) {
+      var childRange =
+          goog.dom.browserrange.IeRange.getBrowserRangeForNode_(child);
+      var start = goog.dom.RangeEndpoint.START;
+      var end = goog.dom.RangeEndpoint.END;
+
+      // There are two types of erratic nodes where the range over node has
+      // different htmlText than the node's outerHTML.
+      // Case 1 - A node with magic &nbsp; child. In this case :
+      //    nodeRange.htmlText shows &nbsp; ('<p>&nbsp;</p>), while
+      //    node.outerHTML doesn't show the magic node (<p></p>).
+      // Case 2 - Empty span. In this case :
+      //    node.outerHTML shows '<span></span>'
+      //    node.htmlText is just empty string ''.
+      var isChildRangeErratic = (childRange.htmlText != child.outerHTML);
+
+      // Moreover the inRange comparison fails only when the
+      var isNativeInRangeErratic = this.isCollapsed() && isChildRangeErratic;
+
+      // In case 2 mentioned above, childRange is also collapsed. So we need to
+      // compare start of this range with both start and end of child range.
+      var inChildRange = isNativeInRangeErratic ?
+          (this.compareBrowserRangeEndpoints(childRange, start, start) >= 0 &&
+              this.compareBrowserRangeEndpoints(childRange, start, end) <= 0) :
+          this.range_.inRange(childRange);
+      if (inChildRange) {
+        return this.findDeepestContainer_(child);
+      }
+    }
+  }
+
+  return node;
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.getStartNode = function() {
+  if (!this.startNode_) {
+    this.startNode_ = this.getEndpointNode_(goog.dom.RangeEndpoint.START);
+    if (this.isCollapsed()) {
+      this.endNode_ = this.startNode_;
+    }
+  }
+  return this.startNode_;
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.getStartOffset = function() {
+  if (this.startOffset_ < 0) {
+    this.startOffset_ = this.getOffset_(goog.dom.RangeEndpoint.START);
+    if (this.isCollapsed()) {
+      this.endOffset_ = this.startOffset_;
+    }
+  }
+  return this.startOffset_;
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.getEndNode = function() {
+  if (this.isCollapsed()) {
+    return this.getStartNode();
+  }
+  if (!this.endNode_) {
+    this.endNode_ = this.getEndpointNode_(goog.dom.RangeEndpoint.END);
+  }
+  return this.endNode_;
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.getEndOffset = function() {
+  if (this.isCollapsed()) {
+    return this.getStartOffset();
+  }
+  if (this.endOffset_ < 0) {
+    this.endOffset_ = this.getOffset_(goog.dom.RangeEndpoint.END);
+    if (this.isCollapsed()) {
+      this.startOffset_ = this.endOffset_;
+    }
+  }
+  return this.endOffset_;
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.compareBrowserRangeEndpoints = 
function(
+    range, thisEndpoint, otherEndpoint) {
+  return this.range_.compareEndPoints(
+      (thisEndpoint == goog.dom.RangeEndpoint.START ? 'Start' : 'End') +
+      'To' +
+      (otherEndpoint == goog.dom.RangeEndpoint.START ? 'Start' : 'End'),
+      range);
+};
+
+
+/**
+ * Recurses to find the correct node for the given endpoint.
+ * @param {goog.dom.RangeEndpoint} endpoint The endpoint to get the node for.
+ * @param {Node=} opt_node Optional node to start the search from.
+ * @return {Node} The deepest node containing the endpoint.
+ * @private
+ */
+goog.dom.browserrange.IeRange.prototype.getEndpointNode_ = function(endpoint,
+    opt_node) {
+
+  /** @type {Node} */
+  var node = opt_node || this.getContainer();
+
+  // If we're at a leaf in the DOM, we're done.
+  if (!node || !node.firstChild) {
+    return node;
+  }
+
+  var start = goog.dom.RangeEndpoint.START, end = goog.dom.RangeEndpoint.END;
+  var isStartEndpoint = endpoint == start;
+
+  // Find the first/last child that overlaps the selection.
+  // NOTE(user) : One of the children can be the magic &nbsp; node. This
+  // node will have only nodeType property as valid and accessible. All other
+  // dom related properties like ownerDocument, parentNode, nextSibling etc
+  // cause error when accessed. Therefore use the for-loop on childNodes to
+  // iterate.
+  for (var j = 0, length = node.childNodes.length; j < length; j++) {
+    var i = isStartEndpoint ? j : length - j - 1;
+    var child = node.childNodes[i];
+    var childRange;
+    try {
+      childRange = goog.dom.browserrange.createRangeFromNodeContents(child);
+    } catch (e) {
+      // If the child is the magic &nbsp; node, then the above will throw
+      // error. The magic node exists only when editing using keyboard, so can
+      // not add any unit test.
+      continue;
+    }
+    var ieRange = childRange.getBrowserRange();
+
+    // Case 1 : Finding end points when this range is collapsed.
+    // Note that in case of collapsed range, getEnd{Node,Offset} call
+    // getStart{Node,Offset}.
+    if (this.isCollapsed()) {
+      // Handle situations where caret is not in a text node. In such cases,
+      // the adjacent child won't be a valid range endpoint container.
+      if (!goog.dom.browserrange.canContainRangeEndpoint(child)) {
+        // The following handles a scenario like <div><BR>[caret]<BR></div>,
+        // where point should be (div, 1).
+        if (this.compareBrowserRangeEndpoints(ieRange, start, start) == 0) {
+          this.startOffset_ = this.endOffset_ = i;
+          return node;
+        }
+      } else if (childRange.containsRange(this)) {
+        // For collapsed range, we should invert the containsRange check with
+        // childRange.
+        return this.getEndpointNode_(endpoint, child);
+      }
+
+    // Case 2 - The first child encountered to have overlap this range is
+    // contained entirely in this range.
+    } else if (this.containsRange(childRange)) {
+      // If it is an element which can not be a range endpoint container, the
+      // current child offset can be used to deduce the endpoint offset.
+      if (!goog.dom.browserrange.canContainRangeEndpoint(child)) {
+
+        // Container can't be any deeper, so current node is the container.
+        if (isStartEndpoint) {
+          this.startOffset_ = i;
+        } else {
+          this.endOffset_ = i + 1;
+        }
+        return node;
+      }
+
+      // If child can contain range endpoints, recurse inside this child.
+      return this.getEndpointNode_(endpoint, child);
+
+    // Case 3 - Partial non-adjacency overlap.
+    } else if (this.compareBrowserRangeEndpoints(ieRange, start, end) < 0 &&
+               this.compareBrowserRangeEndpoints(ieRange, end, start) > 0) {
+      // If this child overlaps the selection partially, recurse down to find
+      // the first/last child the next level down that overlaps the selection
+      // completely. We do not consider edge-adjacency (== 0) as overlap.
+      return this.getEndpointNode_(endpoint, child);
+    }
+
+  }
+
+  // None of the children of this node overlapped the selection, that means
+  // the selection starts/ends in this node directly.
+  return node;
+};
+
+
+/**
+ * Compares one endpoint of this range with the endpoint of a node.
+ * For internal methods, we should prefer this method to containsNode.
+ * containsNode has a lot of false negatives when we're dealing with
+ * {@code <br>} tags.
+ *
+ * @param {Node} node The node to compare against.
+ * @param {goog.dom.RangeEndpoint} thisEndpoint The endpoint of this range
+ *     to compare with.
+ * @param {goog.dom.RangeEndpoint} otherEndpoint The endpoint of the node
+ *     to compare with.
+ * @return {number} 0 if the endpoints are equal, negative if this range
+ *     endpoint comes before the other node endpoint, and positive otherwise.
+ * @private
+ */
+goog.dom.browserrange.IeRange.prototype.compareNodeEndpoints_ =
+    function(node, thisEndpoint, otherEndpoint) {
+  return this.range_.compareEndPoints(
+      (thisEndpoint == goog.dom.RangeEndpoint.START ? 'Start' : 'End') +
+      'To' +
+      (otherEndpoint == goog.dom.RangeEndpoint.START ? 'Start' : 'End'),
+      goog.dom.browserrange.createRangeFromNodeContents(node).
+          getBrowserRange());
+};
+
+
+/**
+ * Returns the offset into the start/end container.
+ * @param {goog.dom.RangeEndpoint} endpoint The endpoint to get the offset for.
+ * @param {Node=} opt_container The container to get the offset relative to.
+ *     Defaults to the value returned by getStartNode/getEndNode.
+ * @return {number} The offset.
+ * @private
+ */
+goog.dom.browserrange.IeRange.prototype.getOffset_ = function(endpoint,
+    opt_container) {
+  var isStartEndpoint = endpoint == goog.dom.RangeEndpoint.START;
+  var container = opt_container ||
+      (isStartEndpoint ? this.getStartNode() : this.getEndNode());
+
+  if (container.nodeType == goog.dom.NodeType.ELEMENT) {
+    // Find the first/last child that overlaps the selection
+    var children = container.childNodes;
+    var len = children.length;
+    var edge = isStartEndpoint ? 0 : len - 1;
+    var sign = isStartEndpoint ? 1 : - 1;
+
+    // We find the index in the child array of the endpoint of the selection.
+    for (var i = edge; i >= 0 && i < len; i += sign) {
+      var child = children[i];
+      // Ignore the child nodes, which could be end point containers.
+      if (goog.dom.browserrange.canContainRangeEndpoint(child)) {
+        continue;
+      }
+      // Stop looping when we reach the edge of the selection.
+      var endPointCompare =
+          this.compareNodeEndpoints_(child, endpoint, endpoint);
+      if (endPointCompare == 0) {
+        return isStartEndpoint ? i : i + 1;
+      }
+    }
+
+    // When starting from the end in an empty container, we erroneously return
+    // -1: fix this to return 0.
+    return i == -1 ? 0 : i;
+  } else {
+    // Get a temporary range object.
+    var range = this.range_.duplicate();
+
+    // Create a range that selects the entire container.
+    var nodeRange = goog.dom.browserrange.IeRange.getBrowserRangeForNode_(
+        container);
+
+    // Now, intersect our range with the container range - this should give us
+    // the part of our selection that is in the container.
+    range.setEndPoint(isStartEndpoint ? 'EndToEnd' : 'StartToStart', 
nodeRange);
+
+    var rangeLength = range.text.length;
+    return isStartEndpoint ? container.length - rangeLength : rangeLength;
+  }
+};
+
+
+/**
+ * Returns the text of the given node.  Uses IE specific properties.
+ * @param {Node} node The node to retrieve the text of.
+ * @return {string} The node's text.
+ * @private
+ */
+goog.dom.browserrange.IeRange.getNodeText_ = function(node) {
+  return node.nodeType == goog.dom.NodeType.TEXT ?
+         node.nodeValue : node.innerText;
+};
+
+
+/**
+ * Tests whether this range is valid (i.e. whether its endpoints are still in
+ * the document).  A range becomes invalid when, after this object was created,
+ * either one or both of its endpoints are removed from the document.  Use of
+ * an invalid range can lead to runtime errors, particularly in IE.
+ * @return {boolean} Whether the range is valid.
+ */
+goog.dom.browserrange.IeRange.prototype.isRangeInDocument = function() {
+  var range = this.doc_.body.createTextRange();
+  range.moveToElementText(this.doc_.body);
+
+  return this.containsRange(
+      new goog.dom.browserrange.IeRange(range, this.doc_), true);
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.isCollapsed = function() {
+  // Note(user) : The earlier implementation used (range.text == ''), but this
+  // fails when (range.htmlText == '<br>')
+  // Alternative: this.range_.htmlText == '';
+  return this.range_.compareEndPoints('StartToEnd', this.range_) == 0;
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.getText = function() {
+  return this.range_.text;
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.getValidHtml = function() {
+  return this.range_.htmlText;
+};
+
+
+// SELECTION MODIFICATION
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.select = function(opt_reverse) {
+  // IE doesn't support programmatic reversed selections.
+  this.range_.select();
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.removeContents = function() {
+  // NOTE: Sometimes htmlText is non-empty, but the range is actually empty.
+  // TODO(gboyer): The htmlText check is probably unnecessary, but I left it in
+  // for paranoia.
+  if (!this.isCollapsed() && this.range_.htmlText) {
+    // Store some before-removal state.
+    var startNode = this.getStartNode();
+    var endNode = this.getEndNode();
+    var oldText = this.range_.text;
+
+    // IE sometimes deletes nodes unrelated to the selection.  This trick fixes
+    // that problem most of the time.  Even though it looks like a no-op, it is
+    // somehow changing IE's internal state such that empty unrelated nodes are
+    // no longer deleted.
+    var clone = this.range_.duplicate();
+    clone.moveStart('character', 1);
+    clone.moveStart('character', -1);
+
+    // However, sometimes moving the start back and forth ends up changing the
+    // range.
+    // TODO(gboyer): This condition used to happen for empty ranges, but (1)
+    // never worked, and (2) the isCollapsed call should protect against empty
+    // ranges better than before.  However, this is left for paranoia.
+    if (clone.text == oldText) {
+      this.range_ = clone;
+    }
+
+    // Use the browser's native deletion code.
+    this.range_.text = '';
+    this.clearCachedValues_();
+
+    // Unfortunately, when deleting a portion of a single text node, IE creates
+    // an extra text node unlike other browsers which just change the text in
+    // the node.  We normalize for that behavior here, making IE behave like 
all
+    // the other browsers.
+    var newStartNode = this.getStartNode();
+    var newStartOffset = this.getStartOffset();
+    /** @preserveTry */
+    try {
+      var sibling = startNode.nextSibling;
+      if (startNode == endNode && startNode.parentNode &&
+          startNode.nodeType == goog.dom.NodeType.TEXT &&
+          sibling && sibling.nodeType == goog.dom.NodeType.TEXT) {
+        startNode.nodeValue += sibling.nodeValue;
+        goog.dom.removeNode(sibling);
+
+        // Make sure to reselect the appropriate position.
+        this.range_ = goog.dom.browserrange.IeRange.getBrowserRangeForNode_(
+            newStartNode);
+        this.range_.move('character', newStartOffset);
+        this.clearCachedValues_();
+      }
+    } catch (e) {
+      // IE throws errors on orphaned nodes.
+    }
+  }
+};
+
+
+/**
+ * @param {TextRange} range The range to get a dom helper for.
+ * @return {!goog.dom.DomHelper} A dom helper for the document the range
+ *     resides in.
+ * @private
+ */
+goog.dom.browserrange.IeRange.getDomHelper_ = function(range) {
+  return goog.dom.getDomHelper(range.parentElement());
+};
+
+
+/**
+ * Pastes the given element into the given range, returning the resulting
+ * element.
+ * @param {TextRange} range The range to paste into.
+ * @param {Element} element The node to insert a copy of.
+ * @param {goog.dom.DomHelper=} opt_domHelper DOM helper object for the 
document
+ *     the range resides in.
+ * @return {Element} The resulting copy of element.
+ * @private
+ */
+goog.dom.browserrange.IeRange.pasteElement_ = function(range, element,
+    opt_domHelper) {
+  opt_domHelper = opt_domHelper || goog.dom.browserrange.IeRange.getDomHelper_(
+      range);
+
+  // Make sure the node has a unique id.
+  var id;
+  var originalId = id = element.id;
+  if (!id) {
+    id = element.id = goog.string.createUniqueString();
+  }
+
+  // Insert (a clone of) the node.
+  range.pasteHTML(element.outerHTML);
+
+  // Pasting the outerHTML of the modified element into the document creates
+  // a clone of the element argument.  We want to return a reference to the
+  // clone, not the original.  However we need to remove the temporary ID
+  // first.
+  element = opt_domHelper.getElement(id);
+
+  // If element is null here, we failed.
+  if (element) {
+    if (!originalId) {
+      element.removeAttribute('id');
+    }
+  }
+
+  return element;
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.surroundContents = function(element) {
+  // Make sure the element is detached from the document.
+  goog.dom.removeNode(element);
+
+  // IE more or less guarantees that range.htmlText is well-formed & valid.
+  element.innerHTML = this.range_.htmlText;
+  element = goog.dom.browserrange.IeRange.pasteElement_(this.range_, element);
+
+  // If element is null here, we failed.
+  if (element) {
+    this.range_.moveToElementText(element);
+  }
+
+  this.clearCachedValues_();
+
+  return element;
+};
+
+
+/**
+ * Internal handler for inserting a node.
+ * @param {TextRange} clone A clone of this range's browser range object.
+ * @param {Node} node The node to insert.
+ * @param {boolean} before Whether to insert the node before or after the 
range.
+ * @param {goog.dom.DomHelper=} opt_domHelper The dom helper to use.
+ * @return {Node} The resulting copy of node.
+ * @private
+ */
+goog.dom.browserrange.IeRange.insertNode_ = function(clone, node,
+    before, opt_domHelper) {
+  // Get a DOM helper.
+  opt_domHelper = opt_domHelper || goog.dom.browserrange.IeRange.getDomHelper_(
+      clone);
+
+  // If it's not an element, wrap it in one.
+  var isNonElement;
+  if (node.nodeType != goog.dom.NodeType.ELEMENT) {
+    isNonElement = true;
+    node = opt_domHelper.createDom(goog.dom.TagName.DIV, null, node);
+  }
+
+  clone.collapse(before);
+  node = goog.dom.browserrange.IeRange.pasteElement_(clone,
+      /** @type {!Element} */ (node), opt_domHelper);
+
+  // If we didn't want an element, unwrap the element and return the node.
+  if (isNonElement) {
+    // pasteElement_() may have returned a copy of the wrapper div, and the
+    // node it wraps could also be a new copy. So we must extract that new
+    // node from the new wrapper.
+    var newNonElement = node.firstChild;
+    opt_domHelper.flattenElement(node);
+    node = newNonElement;
+  }
+
+  return node;
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.insertNode = function(node, before) {
+  var output = goog.dom.browserrange.IeRange.insertNode_(
+      this.range_.duplicate(), node, before);
+  this.clearCachedValues_();
+  return output;
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.surroundWithNodes = function(
+    startNode, endNode) {
+  var clone1 = this.range_.duplicate();
+  var clone2 = this.range_.duplicate();
+  goog.dom.browserrange.IeRange.insertNode_(clone1, startNode, true);
+  goog.dom.browserrange.IeRange.insertNode_(clone2, endNode, false);
+
+  this.clearCachedValues_();
+};
+
+
+/** @override */
+goog.dom.browserrange.IeRange.prototype.collapse = function(toStart) {
+  this.range_.collapse(toStart);
+
+  if (toStart) {
+    this.endNode_ = this.startNode_;
+    this.endOffset_ = this.startOffset_;
+  } else {
+    this.startNode_ = this.endNode_;
+    this.startOffset_ = this.endOffset_;
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/browserrange/operarange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/browserrange/operarange.js 
b/externs/GCL/externs/goog/dom/browserrange/operarange.js
new file mode 100644
index 0000000..f277dc1
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/browserrange/operarange.js
@@ -0,0 +1,84 @@
+// Copyright 2009 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview Definition of the Opera specific range wrapper.  Inherits most
+ * functionality from W3CRange, but adds exceptions as necessary.
+ *
+ * DO NOT USE THIS FILE DIRECTLY.  Use goog.dom.Range instead.
+ *
+ */
+
+
+goog.provide('goog.dom.browserrange.OperaRange');
+
+goog.require('goog.dom.browserrange.W3cRange');
+
+
+
+/**
+ * The constructor for Opera specific browser ranges.
+ * @param {Range} range The range object.
+ * @constructor
+ * @extends {goog.dom.browserrange.W3cRange}
+ * @final
+ */
+goog.dom.browserrange.OperaRange = function(range) {
+  goog.dom.browserrange.W3cRange.call(this, range);
+};
+goog.inherits(goog.dom.browserrange.OperaRange, 
goog.dom.browserrange.W3cRange);
+
+
+/**
+ * Creates a range object that selects the given node's text.
+ * @param {Node} node The node to select.
+ * @return {!goog.dom.browserrange.OperaRange} A Opera range wrapper object.
+ */
+goog.dom.browserrange.OperaRange.createFromNodeContents = function(node) {
+  return new goog.dom.browserrange.OperaRange(
+      goog.dom.browserrange.W3cRange.getBrowserRangeForNode(node));
+};
+
+
+/**
+ * Creates a range object that selects between the given nodes.
+ * @param {Node} startNode The node to start with.
+ * @param {number} startOffset The offset within the node to start.
+ * @param {Node} endNode The node to end with.
+ * @param {number} endOffset The offset within the node to end.
+ * @return {!goog.dom.browserrange.OperaRange} A wrapper object.
+ */
+goog.dom.browserrange.OperaRange.createFromNodes = function(startNode,
+    startOffset, endNode, endOffset) {
+  return new goog.dom.browserrange.OperaRange(
+      goog.dom.browserrange.W3cRange.getBrowserRangeForNodes(startNode,
+          startOffset, endNode, endOffset));
+};
+
+
+/** @override */
+goog.dom.browserrange.OperaRange.prototype.selectInternal = function(
+    selection, reversed) {
+  // Avoid using addRange as we have to removeAllRanges first, which
+  // blurs editable fields in Opera.
+  selection.collapse(this.getStartNode(), this.getStartOffset());
+  if (this.getEndNode() != this.getStartNode() ||
+      this.getEndOffset() != this.getStartOffset()) {
+    selection.extend(this.getEndNode(), this.getEndOffset());
+  }
+  // This can happen if the range isn't in an editable field.
+  if (selection.rangeCount == 0) {
+    selection.addRange(this.range_);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/browserrange/w3crange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/browserrange/w3crange.js 
b/externs/GCL/externs/goog/dom/browserrange/w3crange.js
new file mode 100644
index 0000000..994f19f
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/browserrange/w3crange.js
@@ -0,0 +1,396 @@
+// Copyright 2007 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview Definition of the W3C spec following range wrapper.
+ *
+ * DO NOT USE THIS FILE DIRECTLY.  Use goog.dom.Range instead.
+ *
+ * @author [email protected] (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.browserrange.W3cRange');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.RangeEndpoint');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.browserrange.AbstractRange');
+goog.require('goog.string');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * The constructor for W3C specific browser ranges.
+ * @param {Range} range The range object.
+ * @constructor
+ * @extends {goog.dom.browserrange.AbstractRange}
+ */
+goog.dom.browserrange.W3cRange = function(range) {
+  this.range_ = range;
+};
+goog.inherits(goog.dom.browserrange.W3cRange,
+              goog.dom.browserrange.AbstractRange);
+
+
+/**
+ * Returns a browser range spanning the given node's contents.
+ * @param {Node} node The node to select.
+ * @return {!Range} A browser range spanning the node's contents.
+ * @protected
+ */
+goog.dom.browserrange.W3cRange.getBrowserRangeForNode = function(node) {
+  var nodeRange = goog.dom.getOwnerDocument(node).createRange();
+
+  if (node.nodeType == goog.dom.NodeType.TEXT) {
+    nodeRange.setStart(node, 0);
+    nodeRange.setEnd(node, node.length);
+  } else {
+    /** @suppress {missingRequire} */
+    if (!goog.dom.browserrange.canContainRangeEndpoint(node)) {
+      var rangeParent = node.parentNode;
+      var rangeStartOffset = goog.array.indexOf(rangeParent.childNodes, node);
+      nodeRange.setStart(rangeParent, rangeStartOffset);
+      nodeRange.setEnd(rangeParent, rangeStartOffset + 1);
+    } else {
+      var tempNode, leaf = node;
+      while ((tempNode = leaf.firstChild) &&
+          /** @suppress {missingRequire} */
+          goog.dom.browserrange.canContainRangeEndpoint(tempNode)) {
+        leaf = tempNode;
+      }
+      nodeRange.setStart(leaf, 0);
+
+      leaf = node;
+      while ((tempNode = leaf.lastChild) &&
+          /** @suppress {missingRequire} */
+          goog.dom.browserrange.canContainRangeEndpoint(tempNode)) {
+        leaf = tempNode;
+      }
+      nodeRange.setEnd(leaf, leaf.nodeType == goog.dom.NodeType.ELEMENT ?
+          leaf.childNodes.length : leaf.length);
+    }
+  }
+
+  return nodeRange;
+};
+
+
+/**
+ * Returns a browser range spanning the given nodes.
+ * @param {Node} startNode The node to start with - should not be a BR.
+ * @param {number} startOffset The offset within the start node.
+ * @param {Node} endNode The node to end with - should not be a BR.
+ * @param {number} endOffset The offset within the end node.
+ * @return {!Range} A browser range spanning the node's contents.
+ * @protected
+ */
+goog.dom.browserrange.W3cRange.getBrowserRangeForNodes = function(startNode,
+    startOffset, endNode, endOffset) {
+  // Create and return the range.
+  var nodeRange = goog.dom.getOwnerDocument(startNode).createRange();
+  nodeRange.setStart(startNode, startOffset);
+  nodeRange.setEnd(endNode, endOffset);
+  return nodeRange;
+};
+
+
+/**
+ * Creates a range object that selects the given node's text.
+ * @param {Node} node The node to select.
+ * @return {!goog.dom.browserrange.W3cRange} A Gecko range wrapper object.
+ */
+goog.dom.browserrange.W3cRange.createFromNodeContents = function(node) {
+  return new goog.dom.browserrange.W3cRange(
+      goog.dom.browserrange.W3cRange.getBrowserRangeForNode(node));
+};
+
+
+/**
+ * Creates a range object that selects between the given nodes.
+ * @param {Node} startNode The node to start with.
+ * @param {number} startOffset The offset within the start node.
+ * @param {Node} endNode The node to end with.
+ * @param {number} endOffset The offset within the end node.
+ * @return {!goog.dom.browserrange.W3cRange} A wrapper object.
+ */
+goog.dom.browserrange.W3cRange.createFromNodes = function(startNode,
+    startOffset, endNode, endOffset) {
+  return new goog.dom.browserrange.W3cRange(
+      goog.dom.browserrange.W3cRange.getBrowserRangeForNodes(startNode,
+          startOffset, endNode, endOffset));
+};
+
+
+/**
+ * @return {!goog.dom.browserrange.W3cRange} A clone of this range.
+ * @override
+ */
+goog.dom.browserrange.W3cRange.prototype.clone = function() {
+  return new this.constructor(this.range_.cloneRange());
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.getBrowserRange = function() {
+  return this.range_;
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.getContainer = function() {
+  return this.range_.commonAncestorContainer;
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.getStartNode = function() {
+  return this.range_.startContainer;
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.getStartOffset = function() {
+  return this.range_.startOffset;
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.getEndNode = function() {
+  return this.range_.endContainer;
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.getEndOffset = function() {
+  return this.range_.endOffset;
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.compareBrowserRangeEndpoints =
+    function(range, thisEndpoint, otherEndpoint) {
+  return this.range_.compareBoundaryPoints(
+      otherEndpoint == goog.dom.RangeEndpoint.START ?
+          (thisEndpoint == goog.dom.RangeEndpoint.START ?
+              goog.global['Range'].START_TO_START :
+              goog.global['Range'].START_TO_END) :
+          (thisEndpoint == goog.dom.RangeEndpoint.START ?
+              goog.global['Range'].END_TO_START :
+              goog.global['Range'].END_TO_END),
+      /** @type {Range} */ (range));
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.isCollapsed = function() {
+  return this.range_.collapsed;
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.getText = function() {
+  return this.range_.toString();
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.getValidHtml = function() {
+  var div = goog.dom.getDomHelper(this.range_.startContainer).createDom(
+      goog.dom.TagName.DIV);
+  div.appendChild(this.range_.cloneContents());
+  var result = div.innerHTML;
+
+  if (goog.string.startsWith(result, '<') ||
+      !this.isCollapsed() && !goog.string.contains(result, '<')) {
+    // We attempt to mimic IE, which returns no containing element when a
+    // only text nodes are selected, does return the containing element when
+    // the selection is empty, and does return the element when multiple nodes
+    // are selected.
+    return result;
+  }
+
+  var container = this.getContainer();
+  container = container.nodeType == goog.dom.NodeType.ELEMENT ? container :
+      container.parentNode;
+
+  var html = goog.dom.getOuterHtml(
+      /** @type {!Element} */ (container.cloneNode(false)));
+  return html.replace('>', '>' + result);
+};
+
+
+// SELECTION MODIFICATION
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.select = function(reverse) {
+  var win = goog.dom.getWindow(goog.dom.getOwnerDocument(this.getStartNode()));
+  this.selectInternal(win.getSelection(), reverse);
+};
+
+
+/**
+ * Select this range.
+ * @param {Selection} selection Browser selection object.
+ * @param {*} reverse Whether to select this range in reverse.
+ * @protected
+ */
+goog.dom.browserrange.W3cRange.prototype.selectInternal = function(selection,
+                                                                   reverse) {
+  // Browser-specific tricks are needed to create reversed selections
+  // programatically. For this generic W3C codepath, ignore the reverse
+  // parameter.
+  selection.removeAllRanges();
+  selection.addRange(this.range_);
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.removeContents = function() {
+  var range = this.range_;
+  range.extractContents();
+
+  if (range.startContainer.hasChildNodes()) {
+    // Remove any now empty nodes surrounding the extracted contents.
+    var rangeStartContainer =
+        range.startContainer.childNodes[range.startOffset];
+    if (rangeStartContainer) {
+      var rangePrevious = rangeStartContainer.previousSibling;
+
+      if (goog.dom.getRawTextContent(rangeStartContainer) == '') {
+        goog.dom.removeNode(rangeStartContainer);
+      }
+
+      if (rangePrevious && goog.dom.getRawTextContent(rangePrevious) == '') {
+        goog.dom.removeNode(rangePrevious);
+      }
+    }
+  }
+
+  if (goog.userAgent.IE) {
+    // Unfortunately, when deleting a portion of a single text node, IE creates
+    // an extra text node instead of modifying the nodeValue of the start node.
+    // We normalize for that behavior here, similar to code in
+    // goog.dom.browserrange.IeRange#removeContents
+    // See https://connect.microsoft.com/IE/feedback/details/746591
+    var startNode = this.getStartNode();
+    var startOffset = this.getStartOffset();
+    var endNode = this.getEndNode();
+    var endOffset = this.getEndOffset();
+    var sibling = startNode.nextSibling;
+    if (startNode == endNode && startNode.parentNode &&
+        startNode.nodeType == goog.dom.NodeType.TEXT &&
+        sibling && sibling.nodeType == goog.dom.NodeType.TEXT) {
+      startNode.nodeValue += sibling.nodeValue;
+      goog.dom.removeNode(sibling);
+
+      // Modifying the node value clears the range offsets. Reselect the
+      // position in the modified start node.
+      range.setStart(startNode, startOffset);
+      range.setEnd(endNode, endOffset);
+    }
+  }
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.surroundContents = function(element) {
+  this.range_.surroundContents(element);
+  return element;
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.insertNode = function(node, before) {
+  var range = this.range_.cloneRange();
+  range.collapse(before);
+  range.insertNode(node);
+  range.detach();
+
+  return node;
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.surroundWithNodes = function(
+    startNode, endNode) {
+  var win = goog.dom.getWindow(
+      goog.dom.getOwnerDocument(this.getStartNode()));
+  /** @suppress {missingRequire} */
+  var selectionRange = goog.dom.Range.createFromWindow(win);
+  if (selectionRange) {
+    var sNode = selectionRange.getStartNode();
+    var eNode = selectionRange.getEndNode();
+    var sOffset = selectionRange.getStartOffset();
+    var eOffset = selectionRange.getEndOffset();
+  }
+
+  var clone1 = this.range_.cloneRange();
+  var clone2 = this.range_.cloneRange();
+
+  clone1.collapse(false);
+  clone2.collapse(true);
+
+  clone1.insertNode(endNode);
+  clone2.insertNode(startNode);
+
+  clone1.detach();
+  clone2.detach();
+
+  if (selectionRange) {
+    // There are 4 ways that surroundWithNodes can wreck the saved
+    // selection object. All of them happen when an inserted node splits
+    // a text node, and one of the end points of the selection was in the
+    // latter half of that text node.
+    //
+    // Clients of this library should use saveUsingCarets to avoid this
+    // problem. Unfortunately, saveUsingCarets uses this method, so that's
+    // not really an option for us. :( We just recompute the offsets.
+    var isInsertedNode = function(n) {
+      return n == startNode || n == endNode;
+    };
+    if (sNode.nodeType == goog.dom.NodeType.TEXT) {
+      while (sOffset > sNode.length) {
+        sOffset -= sNode.length;
+        do {
+          sNode = sNode.nextSibling;
+        } while (isInsertedNode(sNode));
+      }
+    }
+
+    if (eNode.nodeType == goog.dom.NodeType.TEXT) {
+      while (eOffset > eNode.length) {
+        eOffset -= eNode.length;
+        do {
+          eNode = eNode.nextSibling;
+        } while (isInsertedNode(eNode));
+      }
+    }
+
+    /** @suppress {missingRequire} */
+    goog.dom.Range.createFromNodes(
+        sNode, /** @type {number} */ (sOffset),
+        eNode, /** @type {number} */ (eOffset)).select();
+  }
+};
+
+
+/** @override */
+goog.dom.browserrange.W3cRange.prototype.collapse = function(toStart) {
+  this.range_.collapse(toStart);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/browserrange/webkitrange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/browserrange/webkitrange.js 
b/externs/GCL/externs/goog/dom/browserrange/webkitrange.js
new file mode 100644
index 0000000..dd428bd
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/browserrange/webkitrange.js
@@ -0,0 +1,108 @@
+// Copyright 2007 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview Definition of the WebKit specific range wrapper.  Inherits 
most
+ * functionality from W3CRange, but adds exceptions as necessary.
+ *
+ * DO NOT USE THIS FILE DIRECTLY.  Use goog.dom.Range instead.
+ *
+ * @author [email protected] (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.browserrange.WebKitRange');
+
+goog.require('goog.dom.RangeEndpoint');
+goog.require('goog.dom.browserrange.W3cRange');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * The constructor for WebKit specific browser ranges.
+ * @param {Range} range The range object.
+ * @constructor
+ * @extends {goog.dom.browserrange.W3cRange}
+ * @final
+ */
+goog.dom.browserrange.WebKitRange = function(range) {
+  goog.dom.browserrange.W3cRange.call(this, range);
+};
+goog.inherits(goog.dom.browserrange.WebKitRange,
+              goog.dom.browserrange.W3cRange);
+
+
+/**
+ * Creates a range object that selects the given node's text.
+ * @param {Node} node The node to select.
+ * @return {!goog.dom.browserrange.WebKitRange} A WebKit range wrapper object.
+ */
+goog.dom.browserrange.WebKitRange.createFromNodeContents = function(node) {
+  return new goog.dom.browserrange.WebKitRange(
+      goog.dom.browserrange.W3cRange.getBrowserRangeForNode(node));
+};
+
+
+/**
+ * Creates a range object that selects between the given nodes.
+ * @param {Node} startNode The node to start with.
+ * @param {number} startOffset The offset within the start node.
+ * @param {Node} endNode The node to end with.
+ * @param {number} endOffset The offset within the end node.
+ * @return {!goog.dom.browserrange.WebKitRange} A wrapper object.
+ */
+goog.dom.browserrange.WebKitRange.createFromNodes = function(startNode,
+    startOffset, endNode, endOffset) {
+  return new goog.dom.browserrange.WebKitRange(
+      goog.dom.browserrange.W3cRange.getBrowserRangeForNodes(startNode,
+          startOffset, endNode, endOffset));
+};
+
+
+/** @override */
+goog.dom.browserrange.WebKitRange.prototype.compareBrowserRangeEndpoints =
+    function(range, thisEndpoint, otherEndpoint) {
+  // Webkit pre-528 has some bugs where compareBoundaryPoints() doesn't work 
the
+  // way it is supposed to, but if we reverse the sense of two comparisons,
+  // it works fine.
+  // https://bugs.webkit.org/show_bug.cgi?id=20738
+  if (goog.userAgent.isVersionOrHigher('528')) {
+    return (goog.dom.browserrange.WebKitRange.superClass_.
+                compareBrowserRangeEndpoints.call(
+                    this, range, thisEndpoint, otherEndpoint));
+  }
+  return this.range_.compareBoundaryPoints(
+      otherEndpoint == goog.dom.RangeEndpoint.START ?
+          (thisEndpoint == goog.dom.RangeEndpoint.START ?
+              goog.global['Range'].START_TO_START :
+              goog.global['Range'].END_TO_START) : // Sense reversed
+          (thisEndpoint == goog.dom.RangeEndpoint.START ?
+              goog.global['Range'].START_TO_END : // Sense reversed
+              goog.global['Range'].END_TO_END),
+      /** @type {Range} */ (range));
+};
+
+
+/** @override */
+goog.dom.browserrange.WebKitRange.prototype.selectInternal = function(
+    selection, reversed) {
+  if (reversed) {
+    selection.setBaseAndExtent(this.getEndNode(), this.getEndOffset(),
+        this.getStartNode(), this.getStartOffset());
+  } else {
+    selection.setBaseAndExtent(this.getStartNode(), this.getStartOffset(),
+        this.getEndNode(), this.getEndOffset());
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/bufferedviewportsizemonitor.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/bufferedviewportsizemonitor.js 
b/externs/GCL/externs/goog/dom/bufferedviewportsizemonitor.js
new file mode 100644
index 0000000..2909d26
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/bufferedviewportsizemonitor.js
@@ -0,0 +1,201 @@
+// Copyright 2012 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview A viewport size monitor that buffers RESIZE events until the
+ * window size has stopped changing, within a specified period of time.  For
+ * every RESIZE event dispatched, this will dispatch up to two *additional*
+ * events:
+ * - {@link #EventType.RESIZE_WIDTH} if the viewport's width has changed since
+ *   the last buffered dispatch.
+ * - {@link #EventType.RESIZE_HEIGHT} if the viewport's height has changed 
since
+ *   the last buffered dispatch.
+ * You likely only need to listen to one of the three events.  But if you need
+ * more, just be cautious of duplicating effort.
+ *
+ */
+
+goog.provide('goog.dom.BufferedViewportSizeMonitor');
+
+goog.require('goog.asserts');
+goog.require('goog.async.Delay');
+goog.require('goog.events');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+
+
+
+/**
+ * Creates a new BufferedViewportSizeMonitor.
+ * @param {!goog.dom.ViewportSizeMonitor} viewportSizeMonitor The
+ *     underlying viewport size monitor.
+ * @param {number=} opt_bufferMs The buffer time, in ms. If not specified, this
+ *     value defaults to {@link #RESIZE_EVENT_DELAY_MS_}.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @final
+ */
+goog.dom.BufferedViewportSizeMonitor = function(
+    viewportSizeMonitor, opt_bufferMs) {
+  goog.dom.BufferedViewportSizeMonitor.base(this, 'constructor');
+
+  /**
+   * Delay for the resize event.
+   * @private {goog.async.Delay}
+   */
+  this.resizeDelay_;
+
+  /**
+   * The underlying viewport size monitor.
+   * @type {goog.dom.ViewportSizeMonitor}
+   * @private
+   */
+  this.viewportSizeMonitor_ = viewportSizeMonitor;
+
+  /**
+   * The current size of the viewport.
+   * @type {goog.math.Size}
+   * @private
+   */
+  this.currentSize_ = this.viewportSizeMonitor_.getSize();
+
+  /**
+   * The resize buffer time in ms.
+   * @type {number}
+   * @private
+   */
+  this.resizeBufferMs_ = opt_bufferMs ||
+      goog.dom.BufferedViewportSizeMonitor.RESIZE_EVENT_DELAY_MS_;
+
+  /**
+   * Listener key for the viewport size monitor.
+   * @type {goog.events.Key}
+   * @private
+   */
+  this.listenerKey_ = goog.events.listen(
+      viewportSizeMonitor,
+      goog.events.EventType.RESIZE,
+      this.handleResize_,
+      false,
+      this);
+};
+goog.inherits(goog.dom.BufferedViewportSizeMonitor, goog.events.EventTarget);
+
+
+/**
+ * Additional events to dispatch.
+ * @enum {string}
+ */
+goog.dom.BufferedViewportSizeMonitor.EventType = {
+  RESIZE_HEIGHT: goog.events.getUniqueId('resizeheight'),
+  RESIZE_WIDTH: goog.events.getUniqueId('resizewidth')
+};
+
+
+/**
+ * Default number of milliseconds to wait after a resize event to relayout the
+ * page.
+ * @type {number}
+ * @const
+ * @private
+ */
+goog.dom.BufferedViewportSizeMonitor.RESIZE_EVENT_DELAY_MS_ = 100;
+
+
+/** @override */
+goog.dom.BufferedViewportSizeMonitor.prototype.disposeInternal =
+    function() {
+  goog.events.unlistenByKey(this.listenerKey_);
+  goog.dom.BufferedViewportSizeMonitor.base(this, 'disposeInternal');
+};
+
+
+/**
+ * Handles resize events on the underlying ViewportMonitor.
+ * @private
+ */
+goog.dom.BufferedViewportSizeMonitor.prototype.handleResize_ =
+    function() {
+  // Lazily create when needed.
+  if (!this.resizeDelay_) {
+    this.resizeDelay_ = new goog.async.Delay(
+        this.onWindowResize_,
+        this.resizeBufferMs_,
+        this);
+    this.registerDisposable(this.resizeDelay_);
+  }
+  this.resizeDelay_.start();
+};
+
+
+/**
+ * Window resize callback that determines whether to reflow the view contents.
+ * @private
+ */
+goog.dom.BufferedViewportSizeMonitor.prototype.onWindowResize_ =
+    function() {
+  if (this.viewportSizeMonitor_.isDisposed()) {
+    return;
+  }
+
+  var previousSize = this.currentSize_;
+  var currentSize = this.viewportSizeMonitor_.getSize();
+
+  goog.asserts.assert(currentSize,
+      'Viewport size should be set at this point');
+
+  this.currentSize_ = currentSize;
+
+  if (previousSize) {
+
+    var resized = false;
+
+    // Width has changed
+    if (previousSize.width != currentSize.width) {
+      this.dispatchEvent(
+          goog.dom.BufferedViewportSizeMonitor.EventType.RESIZE_WIDTH);
+      resized = true;
+    }
+
+    // Height has changed
+    if (previousSize.height != currentSize.height) {
+      this.dispatchEvent(
+          goog.dom.BufferedViewportSizeMonitor.EventType.RESIZE_HEIGHT);
+      resized = true;
+    }
+
+    // If either has changed, this is a resize event.
+    if (resized) {
+      this.dispatchEvent(goog.events.EventType.RESIZE);
+    }
+
+  } else {
+    // If we didn't have a previous size, we consider all events to have
+    // changed.
+    this.dispatchEvent(
+        goog.dom.BufferedViewportSizeMonitor.EventType.RESIZE_HEIGHT);
+    this.dispatchEvent(
+        goog.dom.BufferedViewportSizeMonitor.EventType.RESIZE_WIDTH);
+    this.dispatchEvent(goog.events.EventType.RESIZE);
+  }
+};
+
+
+/**
+ * Returns the current size of the viewport.
+ * @return {goog.math.Size?} The current viewport size.
+ */
+goog.dom.BufferedViewportSizeMonitor.prototype.getSize = function() {
+  return this.currentSize_ ? this.currentSize_.clone() : null;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/classes.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/classes.js 
b/externs/GCL/externs/goog/dom/classes.js
new file mode 100644
index 0000000..0f1db74
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/classes.js
@@ -0,0 +1,239 @@
+// Copyright 2006 The Closure Library Authors. All Rights Reserved.
+//
+// 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.
+
+/**
+ * @fileoverview Utilities for adding, removing and setting classes.  Prefer
+ * {@link goog.dom.classlist} over these utilities since goog.dom.classlist
+ * conforms closer to the semantics of Element.classList, is faster (uses
+ * native methods rather than parsing strings on every call) and compiles
+ * to smaller code as a result.
+ *
+ * Note: these utilities are meant to operate on HTMLElements and
+ * will not work on elements with differing interfaces (such as SVGElements).
+ *
+ * @author [email protected] (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.dom.classes');
+
+goog.require('goog.array');
+
+
+/**
+ * Sets the entire class name of an element.
+ * @param {Node} element DOM node to set class of.
+ * @param {string} className Class name(s) to apply to element.
+ * @deprecated Use goog.dom.classlist.set instead.
+ */
+goog.dom.classes.set = function(element, className) {
+  element.className = className;
+};
+
+
+/**
+ * Gets an array of class names on an element
+ * @param {Node} element DOM node to get class of.
+ * @return {!Array<?>} Class names on {@code element}. Some browsers add extra
+ *     properties to the array. Do not depend on any of these!
+ * @deprecated Use goog.dom.classlist.get instead.
+ */
+goog.dom.classes.get = function(element) {
+  var className = element.className;
+  // Some types of elements don't have a className in IE (e.g. iframes).
+  // Furthermore, in Firefox, className is not a string when the element is
+  // an SVG element.
+  return goog.isString(className) && className.match(/\S+/g) || [];
+};
+
+
+/**
+ * Adds a class or classes to an element. Does not add multiples of class 
names.
+ * @param {Node} element DOM node to add class to.
+ * @param {...string} var_args Class names to add.
+ * @return {boolean} Whether class was added (or all classes were added).
+ * @deprecated Use goog.dom.classlist.add or goog.dom.classlist.addAll instead.
+ */
+goog.dom.classes.add = function(element, var_args) {
+  var classes = goog.dom.classes.get(element);
+  var args = goog.array.slice(arguments, 1);
+  var expectedCount = classes.length + args.length;
+  goog.dom.classes.add_(classes, args);
+  goog.dom.classes.set(element, classes.join(' '));
+  return classes.length == expectedCount;
+};
+
+
+/**
+ * Removes a class or classes from an element.
+ * @param {Node} element DOM node to remove class from.
+ * @param {...string} var_args Class name(s) to remove.
+ * @return {boolean} Whether all classes in {@code var_args} were found and
+ *     removed.
+ * @deprecated Use goog.dom.classlist.remove or goog.dom.classlist.removeAll
+ *     instead.
+ */
+goog.dom.classes.remove = function(element, var_args) {
+  var classes = goog.dom.classes.get(element);
+  var args = goog.array.slice(arguments, 1);
+  var newClasses = goog.dom.classes.getDifference_(classes, args);
+  goog.dom.classes.set(element, newClasses.join(' '));
+  return newClasses.length == classes.length - args.length;
+};
+
+
+/**
+ * Helper method for {@link goog.dom.classes.add} and
+ * {@link goog.dom.classes.addRemove}. Adds one or more classes to the supplied
+ * classes array.
+ * @param {Array<string>} classes All class names for the element, will be
+ *     updated to have the classes supplied in {@code args} added.
+ * @param {Array<string>} args Class names to add.
+ * @private
+ */
+goog.dom.classes.add_ = function(classes, args) {
+  for (var i = 0; i < args.length; i++) {
+    if (!goog.array.contains(classes, args[i])) {
+      classes.push(args[i]);
+    }
+  }
+};
+
+
+/**
+ * Helper method for {@link goog.dom.classes.remove} and
+ * {@link goog.dom.classes.addRemove}. Calculates the difference of two arrays.
+ * @param {!Array<string>} arr1 First array.
+ * @param {!Array<string>} arr2 Second array.
+ * @return {!Array<string>} The first array without the elements of the second
+ *     array.
+ * @private
+ */
+goog.dom.classes.getDifference_ = function(arr1, arr2) {
+  return goog.array.filter(arr1, function(item) {
+    return !goog.array.contains(arr2, item);
+  });
+};
+
+
+/**
+ * Switches a class on an element from one to another without disturbing other
+ * classes. If the fromClass isn't removed, the toClass won't be added.
+ * @param {Node} element DOM node to swap classes on.
+ * @param {string} fromClass Class to remove.
+ * @param {string} toClass Class to add.
+ * @return {boolean} Whether classes were switched.
+ * @deprecated Use goog.dom.classlist.swap instead.
+ */
+goog.dom.classes.swap = function(element, fromClass, toClass) {
+  var classes = goog.dom.classes.get(element);
+
+  var removed = false;
+  for (var i = 0; i < classes.length; i++) {
+    if (classes[i] == fromClass) {
+      goog.array.splice(classes, i--, 1);
+      removed = true;
+    }
+  }
+
+  if (removed) {
+    classes.push(toClass);
+    goog.dom.classes.set(element, classes.join(' '));
+  }
+
+  return removed;
+};
+
+
+/**
+ * Adds zero or more classes to an element and removes zero or more as a single
+ * operation. Unlike calling {@link goog.dom.classes.add} and
+ * {@link goog.dom.classes.remove} separately, this is more efficient as it 
only
+ * parses the class property once.
+ *
+ * If a class is in both the remove and add lists, it will be added. Thus,
+ * you can use this instead of {@link goog.dom.classes.swap} when you have
+ * more than two class names that you want to swap.
+ *
+ * @param {Node} element DOM node to swap classes on.
+ * @param {?(string|Array<string>)} classesToRemove Class or classes to
+ *     remove, if null no classes are removed.
+ * @param {?(string|Array<string>)} classesToAdd Class or classes to add, if
+ *     null no classes are added.
+ * @deprecated Use goog.dom.classlist.addRemove instead.
+ */
+goog.dom.classes.addRemove = function(element, classesToRemove, classesToAdd) {
+  var classes = goog.dom.classes.get(element);
+  if (goog.isString(classesToRemove)) {
+    goog.array.remove(classes, classesToRemove);
+  } else if (goog.isArray(classesToRemove)) {
+    classes = goog.dom.classes.getDifference_(classes, classesToRemove);
+  }
+
+  if (goog.isString(classesToAdd) &&
+      !goog.array.contains(classes, classesToAdd)) {
+    classes.push(classesToAdd);
+  } else if (goog.isArray(classesToAdd)) {
+    goog.dom.classes.add_(classes, classesToAdd);
+  }
+
+  goog.dom.classes.set(element, classes.join(' '));
+};
+
+
+/**
+ * Returns true if an element has a class.
+ * @param {Node} element DOM node to test.
+ * @param {string} className Class name to test for.
+ * @return {boolean} Whether element has the class.
+ * @deprecated Use goog.dom.classlist.contains instead.
+ */
+goog.dom.classes.has = function(element, className) {
+  return goog.array.contains(goog.dom.classes.get(element), className);
+};
+
+
+/**
+ * Adds or removes a class depending on the enabled argument.
+ * @param {Node} element DOM node to add or remove the class on.
+ * @param {string} className Class name to add or remove.
+ * @param {boolean} enabled Whether to add or remove the class (true adds,
+ *     false removes).
+ * @deprecated Use goog.dom.classlist.enable or goog.dom.classlist.enableAll
+ *     instead.
+ */
+goog.dom.classes.enable = function(element, className, enabled) {
+  if (enabled) {
+    goog.dom.classes.add(element, className);
+  } else {
+    goog.dom.classes.remove(element, className);
+  }
+};
+
+
+/**
+ * Removes a class if an element has it, and adds it the element doesn't have
+ * it.  Won't affect other classes on the node.
+ * @param {Node} element DOM node to toggle class on.
+ * @param {string} className Class to toggle.
+ * @return {boolean} True if class was added, false if it was removed
+ *     (in other words, whether element has the class after this function has
+ *     been called).
+ * @deprecated Use goog.dom.classlist.toggle instead.
+ */
+goog.dom.classes.toggle = function(element, className) {
+  var add = !goog.dom.classes.has(element, className);
+  goog.dom.classes.enable(element, className, add);
+  return add;
+};

Reply via email to