You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ft...@apache.org on 2015/09/17 17:28:16 UTC

[01/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Repository: flex-falcon
Updated Branches:
  refs/heads/JsToAs bb6425450 -> e2cad6e69


http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/i18n/currency.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/i18n/currency.js b/externs/GCL/externs/goog/i18n/currency.js
new file mode 100644
index 0000000..6396efd
--- /dev/null
+++ b/externs/GCL/externs/goog/i18n/currency.js
@@ -0,0 +1,437 @@
+// 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 A utility to get better currency format pattern.
+ *
+ * This module implements a new currency format representation model. It
+ * provides 3 currency representation forms: global, portable and local. Local
+ * format is the most popular format people use to represent currency in its
+ * circulating country without worrying about how it should be distinguished
+ * from other currencies.  Global format is a formal representation in context
+ * of multiple currencies in same page, it is ISO 4217 currency code. Portable
+ * format is a compromise between global and local. It looks similar to how
+ * people would like to see how their currency is being represented in other
+ * media. While at the same time, it should be distinguishable to world's
+ * popular currencies (like USD, EUR) and currencies somewhat relevant in the
+ * area (like CNY in HK, though native currency is HKD). There is no guarantee
+ * of uniqueness.
+ *
+ */
+
+
+goog.provide('goog.i18n.currency');
+goog.provide('goog.i18n.currency.CurrencyInfo');
+goog.provide('goog.i18n.currency.CurrencyInfoTier2');
+
+
+/**
+ * The mask of precision field.
+ * @private
+ */
+goog.i18n.currency.PRECISION_MASK_ = 0x07;
+
+
+/**
+ * Whether the currency sign should be positioned after the number.
+ * @private
+ */
+goog.i18n.currency.POSITION_FLAG_ = 0x10;
+
+
+/**
+ * Whether a space should be inserted between the number and currency sign.
+ * @private
+ */
+goog.i18n.currency.SPACE_FLAG_ = 0x20;
+
+
+/**
+ * Whether tier2 was enabled already by calling addTier2Support().
+ * @private
+ */
+goog.i18n.currency.tier2Enabled_ = false;
+
+
+/**
+ * This function will add tier2 currency support. Be default, only tier1
+ * (most popular currencies) are supported. If an application really needs
+ * to support some of the rarely used currencies, it should call this function
+ * before any other functions in this namespace.
+ */
+goog.i18n.currency.addTier2Support = function() {
+  // Protection from executing this these again and again.
+  if (!goog.i18n.currency.tier2Enabled_) {
+    for (var key in goog.i18n.currency.CurrencyInfoTier2) {
+      goog.i18n.currency.CurrencyInfo[key] =
+          goog.i18n.currency.CurrencyInfoTier2[key];
+    }
+    goog.i18n.currency.tier2Enabled_ = true;
+  }
+};
+
+
+/**
+ * Global currency pattern always uses ISO-4217 currency code as prefix. Local
+ * currency sign is added if it is different from currency code. Each currency
+ * is unique in this form. The negative side is that ISO code looks weird in
+ * some countries as people normally do not use it. Local currency sign
+ * alleviates the problem, but also makes it a little verbose.
+ *
+ * @param {string} currencyCode ISO-4217 3-letter currency code.
+ * @return {string} Global currency pattern string for given currency.
+ */
+goog.i18n.currency.getGlobalCurrencyPattern = function(currencyCode) {
+  var info = goog.i18n.currency.CurrencyInfo[currencyCode];
+  var patternNum = info[0];
+  if (currencyCode == info[1]) {
+    return goog.i18n.currency.getCurrencyPattern_(patternNum, info[1]);
+  }
+  return currencyCode + ' ' +
+      goog.i18n.currency.getCurrencyPattern_(patternNum, info[1]);
+};
+
+
+/**
+ * Return global currency sign string for those applications
+ * that want to handle currency sign themselves.
+ *
+ * @param {string} currencyCode ISO-4217 3-letter currency code.
+ * @return {string} Global currency sign for given currency.
+ */
+goog.i18n.currency.getGlobalCurrencySign = function(currencyCode) {
+  var info = goog.i18n.currency.CurrencyInfo[currencyCode];
+  return (currencyCode == info[1]) ? currencyCode :
+      currencyCode + ' ' + info[1];
+};
+
+
+/**
+ * Local currency pattern is the most frequently used pattern in currency's
+ * native region. It does not care about how it is distinguished from other
+ * currencies.
+ *
+ * @param {string} currencyCode ISO-4217 3-letter currency code.
+ * @return {string} Local currency pattern string for given currency.
+ */
+goog.i18n.currency.getLocalCurrencyPattern = function(currencyCode) {
+  var info = goog.i18n.currency.CurrencyInfo[currencyCode];
+  return goog.i18n.currency.getCurrencyPattern_(info[0], info[1]);
+};
+
+
+/**
+ * Returns local currency sign string for those applications that need to
+ * handle currency sign separately.
+ *
+ * @param {string} currencyCode ISO-4217 3-letter currency code.
+ * @return {string} Local currency sign for given currency.
+ */
+goog.i18n.currency.getLocalCurrencySign = function(currencyCode) {
+  return goog.i18n.currency.CurrencyInfo[currencyCode][1];
+};
+
+
+/**
+ * Portable currency pattern is a compromise between local and global. It is
+ * not a mere blend or mid-way between the two. Currency sign is chosen so that
+ * it looks familiar to native users. It also has enough information to
+ * distinguish itself from other popular currencies in its native region.
+ * In this pattern, currency sign symbols that has availability problem in
+ * popular fonts are also avoided.
+ *
+ * @param {string} currencyCode ISO-4217 3-letter currency code.
+ * @return {string} Portable currency pattern string for given currency.
+ */
+goog.i18n.currency.getPortableCurrencyPattern = function(currencyCode) {
+  var info = goog.i18n.currency.CurrencyInfo[currencyCode];
+  return goog.i18n.currency.getCurrencyPattern_(info[0], info[2]);
+};
+
+
+/**
+ * Return portable currency sign string for those applications that need to
+ * handle currency sign themselves.
+ *
+ * @param {string} currencyCode ISO-4217 3-letter currency code.
+ * @return {string} Portable currency sign for given currency.
+ */
+goog.i18n.currency.getPortableCurrencySign = function(currencyCode) {
+  return goog.i18n.currency.CurrencyInfo[currencyCode][2];
+};
+
+
+/**
+ * This function returns the default currency sign position. Some applications
+ * may want to handle currency sign and currency amount separately. This
+ * function can be used in such situations to correctly position the currency
+ * sign relative to the amount.
+ *
+ * To match the behavior of ICU, position is not determined by display locale.
+ *
+ * @param {string} currencyCode ISO-4217 3-letter currency code.
+ * @return {boolean} true if currency should be positioned before amount field.
+ */
+goog.i18n.currency.isPrefixSignPosition = function(currencyCode) {
+  return (goog.i18n.currency.CurrencyInfo[currencyCode][0] &
+          goog.i18n.currency.POSITION_FLAG_) == 0;
+};
+
+
+/**
+ * This function constructs the currency pattern. Currency sign is provided. The
+ * pattern information is encoded in patternNum.
+ *
+ * @param {number} patternNum Encoded pattern number that has
+ *     currency pattern information.
+ * @param {string} sign The currency sign that will be used in pattern.
+ * @return {string} currency pattern string.
+ * @private
+ */
+goog.i18n.currency.getCurrencyPattern_ = function(patternNum, sign) {
+  var strParts = ['#,##0'];
+  var precision = patternNum & goog.i18n.currency.PRECISION_MASK_;
+  if (precision > 0) {
+    strParts.push('.');
+    for (var i = 0; i < precision; i++) {
+      strParts.push('0');
+    }
+  }
+  if ((patternNum & goog.i18n.currency.POSITION_FLAG_) == 0) {
+    strParts.unshift((patternNum & goog.i18n.currency.SPACE_FLAG_) ?
+                     "' " : "'");
+    strParts.unshift(sign);
+    strParts.unshift("'");
+  } else {
+    strParts.push((patternNum & goog.i18n.currency.SPACE_FLAG_) ? " '" : "'",
+                  sign, "'");
+  }
+  return strParts.join('');
+};
+
+
+/**
+ * Modify currency pattern string by adjusting precision for given currency.
+ * Standard currency pattern will have 2 digit after decimal point.
+ * Examples:
+ *   $#,##0.00 ->  $#,##0    (precision == 0)
+ *   $#,##0.00 ->  $#,##0.0  (precision == 1)
+ *   $#,##0.00 ->  $#,##0.000  (precision == 3)
+ *
+ * @param {string} pattern currency pattern string.
+ * @param {string} currencyCode 3-letter currency code.
+ * @return {string} modified currency pattern string.
+ */
+goog.i18n.currency.adjustPrecision = function(pattern, currencyCode) {
+  var strParts = ['0'];
+  var info = goog.i18n.currency.CurrencyInfo[currencyCode];
+  var precision = info[0] & goog.i18n.currency.PRECISION_MASK_;
+  if (precision > 0) {
+    strParts.push('.');
+    for (var i = 0; i < precision; i++) {
+      strParts.push('0');
+    }
+  }
+  return pattern.replace(/0.00/g, strParts.join(''));
+};
+
+
+/**
+ * Tier 1 currency information.
+ *
+ * The first number in the array is a combination of the precision mask and
+ * other flags. The precision mask indicates how many decimal places to show for
+ * the currency. Valid values are [0..7]. The position flag indicates whether
+ * the currency sign should be positioned after the number. Valid values are 0
+ * (before the number) or 16 (after the number). The space flag indicates
+ * whether a space should be inserted between the currency sign and number.
+ * Valid values are 0 (no space) and 32 (space).
+ *
+ * The number in the array is calculated by adding together the mask and flag
+ * values. For example:
+ *
+ * 0: no precision (0), currency sign first (0), no space (0)
+ * 2: two decimals precision (2), currency sign first (0), no space (0)
+ * 18: two decimals precision (2), currency sign last (16), no space (0)
+ * 50: two decimals precision (2), currency sign last (16), space (32)
+ *
+ * @const {!Object<!Array<?>>}
+ */
+goog.i18n.currency.CurrencyInfo = {
+  'AED': [2, 'dh', '\u062f.\u0625.', 'DH'],
+  'ALL': [0, 'Lek', 'Lek'],
+  'AUD': [2, '$', 'AU$'],
+  'BDT': [2, '\u09F3', 'Tk'],
+  'BGN': [2, 'lev', 'lev'],
+  'BRL': [2, 'R$', 'R$'],
+  'CAD': [2, '$', 'C$'],
+  'CDF': [2, 'FrCD', 'CDF'],
+  'CHF': [2, 'CHF', 'CHF'],
+  'CLP': [0, '$', 'CL$'],
+  'CNY': [2, '¥', 'RMB¥'],
+  'COP': [0, '$', 'COL$'],
+  'CRC': [0, '\u20a1', 'CR\u20a1'],
+  'CZK': [50, 'K\u010d', 'K\u010d'],
+  'DKK': [18, 'kr', 'kr'],
+  'DOP': [2, '$', 'RD$'],
+  'EGP': [2, '£', 'LE'],
+  'ETB': [2, 'Birr', 'Birr'],
+  'EUR': [2, '€', '€'],
+  'GBP': [2, '£', 'GB£'],
+  'HKD': [2, '$', 'HK$'],
+  'HRK': [2, 'kn', 'kn'],
+  'HUF': [0, 'Ft', 'Ft'],
+  'IDR': [0, 'Rp', 'Rp'],
+  'ILS': [2, '\u20AA', 'IL\u20AA'],
+  'INR': [2, '\u20B9', 'Rs'],
+  'IRR': [0, 'Rial', 'IRR'],
+  'ISK': [0, 'kr', 'kr'],
+  'JMD': [2, '$', 'JA$'],
+  'JPY': [0, '¥', 'JP¥'],
+  'KRW': [0, '\u20A9', 'KR₩'],
+  'LKR': [2, 'Rs', 'SLRs'],
+  'LTL': [2, 'Lt', 'Lt'],
+  'MNT': [0, '\u20AE', 'MN₮'],
+  'MVR': [2, 'Rf', 'MVR'],
+  'MXN': [2, '$', 'Mex$'],
+  'MYR': [2, 'RM', 'RM'],
+  'NOK': [50, 'kr', 'NOkr'],
+  'PAB': [2, 'B/.', 'B/.'],
+  'PEN': [2, 'S/.', 'S/.'],
+  'PHP': [2, '\u20B1', 'Php'],
+  'PKR': [0, 'Rs', 'PKRs.'],
+  'PLN': [50, 'z\u0142', 'z\u0142'],
+  'RON': [2, 'RON', 'RON'],
+  'RSD': [0, 'din', 'RSD'],
+  'RUB': [50, 'руб.', 'руб.'],
+  'SAR': [2, 'Rial', 'Rial'],
+  'SEK': [2, 'kr', 'kr'],
+  'SGD': [2, '$', 'S$'],
+  'THB': [2, '\u0e3f', 'THB'],
+  'TRY': [2, 'TL', 'YTL'],
+  'TWD': [2, 'NT$', 'NT$'],
+  'TZS': [0, 'TSh', 'TSh'],
+  'UAH': [2, '\u20B4', 'UAH'],
+  'USD': [2, '$', 'US$'],
+  'UYU': [2, '$', '$U'],
+  'VND': [0, '\u20AB', 'VN\u20AB'],
+  'YER': [0, 'Rial', 'Rial'],
+  'ZAR': [2, 'R', 'ZAR']
+};
+
+
+/**
+ * Tier 2 currency information.
+ * @const {!Object<!Array<?>>}
+ */
+goog.i18n.currency.CurrencyInfoTier2 = {
+  'AFN': [48, 'Af.', 'AFN'],
+  'AMD': [0, 'Dram', 'dram'],
+  'ANG': [2, 'NAf.', 'ANG'],
+  'AOA': [2, 'Kz', 'Kz'],
+  'ARS': [2, '$', 'AR$'],
+  'AWG': [2, 'Afl.', 'Afl.'],
+  'AZN': [2, 'man.', 'man.'],
+  'BAM': [2, 'KM', 'KM'],
+  'BBD': [2, '$', 'Bds$'],
+  'BHD': [3, 'din', 'din'],
+  'BIF': [0, 'FBu', 'FBu'],
+  'BMD': [2, '$', 'BD$'],
+  'BND': [2, '$', 'B$'],
+  'BOB': [2, 'Bs', 'Bs'],
+  'BSD': [2, '$', 'BS$'],
+  'BTN': [2, 'Nu.', 'Nu.'],
+  'BWP': [2, 'P', 'pula'],
+  'BYR': [0, 'BYR', 'BYR'],
+  'BZD': [2, '$', 'BZ$'],
+  'CUC': [1, '$', 'CUC$'],
+  'CUP': [2, '$', 'CU$'],
+  'CVE': [2, 'CVE', 'Esc'],
+  'DJF': [0, 'Fdj', 'Fdj'],
+  'DZD': [2, 'din', 'din'],
+  'ERN': [2, 'Nfk', 'Nfk'],
+  'FJD': [2, '$', 'FJ$'],
+  'FKP': [2, '£', 'FK£'],
+  'GEL': [2, 'GEL', 'GEL'],
+  'GHS': [2, 'GHS', 'GHS'],
+  'GIP': [2, '£', 'GI£'],
+  'GMD': [2, 'GMD', 'GMD'],
+  'GNF': [0, 'FG', 'FG'],
+  'GTQ': [2, 'Q', 'GTQ'],
+  'GYD': [0, '$', 'GY$'],
+  'HNL': [2, 'L', 'HNL'],
+  'HTG': [2, 'HTG', 'HTG'],
+  'IQD': [0, 'din', 'IQD'],
+  'JOD': [3, 'din', 'JOD'],
+  'KES': [2, 'Ksh', 'Ksh'],
+  'KGS': [2, 'KGS', 'KGS'],
+  'KHR': [2, 'Riel', 'KHR'],
+  'KMF': [0, 'CF', 'KMF'],
+  'KPW': [0, '\u20A9KP', 'KPW'],
+  'KWD': [3, 'din', 'KWD'],
+  'KYD': [2, '$', 'KY$'],
+  'KZT': [2, '\u20B8', 'KZT'],
+  'LAK': [0, '\u20AD', '\u20AD'],
+  'LBP': [0, 'L£', 'LBP'],
+  'LRD': [2, '$', 'L$'],
+  'LSL': [2, 'LSL', 'LSL'],
+  'LYD': [3, 'din', 'LD'],
+  'MAD': [2, 'dh', 'MAD'],
+  'MDL': [2, 'MDL', 'MDL'],
+  'MGA': [0, 'Ar', 'MGA'],
+  'MKD': [2, 'din', 'MKD'],
+  'MMK': [0, 'K', 'MMK'],
+  'MOP': [2, 'MOP', 'MOP$'],
+  'MRO': [0, 'MRO', 'MRO'],
+  'MUR': [0, 'MURs', 'MURs'],
+  'MWK': [2, 'MWK', 'MWK'],
+  'MZN': [2, 'MTn', 'MTn'],
+  'NAD': [2, '$', 'N$'],
+  'NGN': [2, '\u20A6', 'NG\u20A6'],
+  'NIO': [2, 'C$', 'C$'],
+  'NPR': [2, 'Rs', 'NPRs'],
+  'NZD': [2, '$', 'NZ$'],
+  'OMR': [3, 'Rial', 'OMR'],
+  'PGK': [2, 'PGK', 'PGK'],
+  'PYG': [0, 'Gs', 'PYG'],
+  'QAR': [2, 'Rial', 'QR'],
+  'RWF': [0, 'RF', 'RF'],
+  'SBD': [2, '$', 'SI$'],
+  'SCR': [2, 'SCR', 'SCR'],
+  'SDG': [2, 'SDG', 'SDG'],
+  'SHP': [2, '£', 'SH£'],
+  'SLL': [0, 'SLL', 'SLL'],
+  'SOS': [0, 'SOS', 'SOS'],
+  'SRD': [2, '$', 'SR$'],
+  'SSP': [2, '£', 'SSP'],
+  'STD': [0, 'Db', 'Db'],
+  'SYP': [0, '£', 'SY£'],
+  'SZL': [2, 'SZL', 'SZL'],
+  'TJS': [2, 'Som', 'TJS'],
+  'TND': [3, 'din', 'DT'],
+  'TOP': [2, 'T$', 'T$'],
+  'TTD': [2, '$', 'TT$'],
+  'UGX': [0, 'UGX', 'UGX'],
+  'UZS': [0, 'so\u02bcm', 'UZS'],
+  'VEF': [2, 'Bs', 'Bs'],
+  'VUV': [0, 'VUV', 'VUV'],
+  'WST': [2, 'WST', 'WST'],
+  'XAF': [0, 'FCFA', 'FCFA'],
+  'XCD': [2, '$', 'EC$'],
+  'XOF': [0, 'CFA', 'CFA'],
+  'XPF': [0, 'FCFP', 'FCFP'],
+  'ZMW': [0, 'ZMW', 'ZMW'],
+  'ZWD': [0, '$', 'Z$']
+};


[02/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/i18n/compactnumberformatsymbols_ext.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/i18n/compactnumberformatsymbols_ext.js b/externs/GCL/externs/goog/i18n/compactnumberformatsymbols_ext.js
new file mode 100644
index 0000000..c4c49c6
--- /dev/null
+++ b/externs/GCL/externs/goog/i18n/compactnumberformatsymbols_ext.js
@@ -0,0 +1,27778 @@
+// Copyright 2013 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 Compact number formatting symbols.
+ *
+ * This file is autogenerated by script:
+ * http://go/generate_number_constants.py
+ * using the --for_closure flag.
+ * File generated from CLDR ver. 27.0.1
+ *
+ * This file coveres those locales that are not covered in
+ * "compactnumberformatsymbols.js".
+ *
+ * Before checkin, this file could have been manually edited. This is
+ * to incorporate changes before we could fix CLDR. All manual
+ * modification must be documented in this section, and should be
+ * removed after those changes land to CLDR.
+ */
+
+goog.provide('goog.i18n.CompactNumberFormatSymbolsExt');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_af_NA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_agq');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_agq_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ak');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ak_GH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_AE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_BH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_DJ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_DZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_EH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_ER');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_IL');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_IQ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_JO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_KM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_KW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_LB');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_LY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_MA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_MR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_OM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_PS');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_QA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_SA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_SD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_SO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_SS');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_SY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_TD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_TN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_YE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_as');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_as_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_asa');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_asa_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ast');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ast_ES');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_az_Cyrl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_az_Cyrl_AZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bas');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bas_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_be');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_be_BY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bem');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bem_ZM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bez');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bez_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bm');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bm_Latn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bm_Latn_ML');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bn_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bo');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bo_CN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bo_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_brx');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_brx_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bs');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bs_Cyrl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bs_Cyrl_BA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bs_Latn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bs_Latn_BA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_cgg');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_cgg_UG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ckb');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ckb_Arab');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ckb_Arab_IQ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ckb_Arab_IR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ckb_IQ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ckb_IR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ckb_Latn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ckb_Latn_IQ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_dav');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_dav_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_de_LI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_dje');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_dje_NE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_dsb');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_dsb_DE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_dua');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_dua_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_dyo');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_dyo_SN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_dz');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_dz_BT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ebu');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ebu_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ee');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ee_GH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ee_TG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_150');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_AG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_AI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_BB');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_BE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_BM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_BS');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_BW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_BZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_CA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_CC');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_CK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_CX');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_DM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_ER');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_FJ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_FK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_GD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_GG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_GH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_GI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_GM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_GY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_HK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_IM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_JE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_JM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_KI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_KN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_KY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_LC');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_LR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_LS');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_MG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_MO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_MS');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_MT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_MU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_MW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_MY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_NA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_NF');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_NG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_NR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_NU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_NZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_PG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_PH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_PK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_PN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_RW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_SB');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_SC');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_SD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_SH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_SL');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_SS');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_SX');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_SZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_TK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_TO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_TT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_TV');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_UG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_VC');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_VU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_WS');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_ZM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_eo');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_eo_001');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_AR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_BO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_CL');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_CO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_CR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_CU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_DO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_EC');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_GQ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_GT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_HN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_MX');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_NI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_PA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_PE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_PH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_PR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_PY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_SV');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_US');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_UY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_VE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ewo');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ewo_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fa_AF');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ff');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ff_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ff_GN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ff_MR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ff_SN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fo');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fo_FO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_BE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_BF');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_BI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_BJ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_CD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_CF');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_CG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_CH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_CI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_DJ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_DZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_GA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_GN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_GQ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_HT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_KM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_LU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_MA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_MG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_ML');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_MR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_MU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_NC');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_NE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_PF');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_RW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_SC');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_SN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_SY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_TD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_TG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_TN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_VU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_WF');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fur');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fur_IT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fy');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fy_NL');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_gd');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_gd_GB');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_gsw_FR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_guz');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_guz_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_gv');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_gv_IM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ha');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ha_Latn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ha_Latn_GH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ha_Latn_NE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ha_Latn_NG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_hr_BA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_hsb');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_hsb_DE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ig');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ig_NG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ii');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ii_CN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_it_CH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_jgo');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_jgo_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_jmc');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_jmc_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kab');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kab_DZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kam');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kam_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kde');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kde_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kea');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kea_CV');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_khq');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_khq_ML');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ki');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ki_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kkj');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kkj_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kl_GL');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kln');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kln_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ko_KP');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kok');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kok_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ks');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ks_Arab');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ks_Arab_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ksb');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ksb_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ksf');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ksf_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ksh');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ksh_DE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kw');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kw_GB');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lag');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lag_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lb');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lb_LU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lg');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lg_UG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lkt');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lkt_US');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ln_AO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ln_CF');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ln_CG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lu');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lu_CD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_luo');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_luo_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_luy');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_luy_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mas');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mas_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mas_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mer');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mer_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mfe');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mfe_MU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mg');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mg_MG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mgh');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mgh_MZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mgo');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mgo_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ms_Latn_BN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ms_Latn_SG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mua');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mua_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_naq');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_naq_NA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nd');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nd_ZW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ne_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nl_AW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nl_BE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nl_BQ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nl_CW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nl_SR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nl_SX');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nmg');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nmg_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nn_NO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nnh');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nnh_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nus');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nus_SD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nyn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nyn_UG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_om');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_om_ET');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_om_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_os');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_os_GE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_os_RU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pa_Arab');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pa_Arab_PK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ps');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ps_AF');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pt_AO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pt_CV');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pt_GW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pt_MO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pt_MZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pt_ST');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pt_TL');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_qu');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_qu_BO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_qu_EC');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_qu_PE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_rm');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_rm_CH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_rn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_rn_BI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ro_MD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_rof');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_rof_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ru_BY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ru_KG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ru_KZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ru_MD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ru_UA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_rw');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_rw_RW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_rwk');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_rwk_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sah');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sah_RU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_saq');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_saq_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sbp');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sbp_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_se');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_se_FI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_se_NO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_se_SE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_seh');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_seh_MZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ses');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ses_ML');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sg');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sg_CF');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_shi');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_shi_Latn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_shi_Latn_MA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_shi_Tfng');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_shi_Tfng_MA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_smn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_smn_FI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sn_ZW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_so');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_so_DJ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_so_ET');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_so_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_so_SO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sq_MK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sq_XK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sr_Cyrl_BA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sr_Cyrl_ME');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sr_Cyrl_XK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sr_Latn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sr_Latn_BA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sr_Latn_ME');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sr_Latn_RS');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sr_Latn_XK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sv_AX');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sv_FI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sw_CD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sw_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sw_UG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ta_LK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ta_MY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ta_SG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_teo');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_teo_KE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_teo_UG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ti');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ti_ER');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ti_ET');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_to');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_to_TO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_tr_CY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_twq');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_twq_NE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_tzm');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_tzm_Latn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_tzm_Latn_MA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ug');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ug_Arab');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ug_Arab_CN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ur_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_uz_Arab');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_uz_Arab_AF');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_uz_Cyrl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_uz_Cyrl_UZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_vai');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_vai_Latn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_vai_Latn_LR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_vai_Vaii');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_vai_Vaii_LR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_vun');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_vun_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_wae');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_wae_CH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_xog');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_xog_UG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_yav');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_yav_CM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_yi');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_yi_001');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_yo');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_yo_BJ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_yo_NG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zgh');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zgh_MA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh_Hans_HK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh_Hans_MO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh_Hans_SG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh_Hant');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh_Hant_HK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh_Hant_MO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh_Hant_TW');
+
+
+/**
+ * Compact number formatting symbols for locale af_NA.
+ */
+goog.i18n.CompactNumberFormatSymbols_af_NA = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0'
+    },
+    '10000': {
+      'other': '0'
+    },
+    '100000': {
+      'other': '0'
+    },
+    '1000000': {
+      'other': '0\u00A0m'
+    },
+    '10000000': {
+      'other': '00\u00A0m'
+    },
+    '100000000': {
+      'other': '000\u00A0m'
+    },
+    '1000000000': {
+      'other': '0\u00A0mjd'
+    },
+    '10000000000': {
+      'other': '00\u00A0mjd'
+    },
+    '100000000000': {
+      'other': '000\u00A0mjd'
+    },
+    '1000000000000': {
+      'other': '0\u00A0bn'
+    },
+    '10000000000000': {
+      'other': '00\u00A0bn'
+    },
+    '100000000000000': {
+      'other': '000\u00A0bn'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 duisend'
+    },
+    '10000': {
+      'other': '00 duisend'
+    },
+    '100000': {
+      'other': '000 duisend'
+    },
+    '1000000': {
+      'other': '0 miljoen'
+    },
+    '10000000': {
+      'other': '00 miljoen'
+    },
+    '100000000': {
+      'other': '000 miljoen'
+    },
+    '1000000000': {
+      'other': '0 miljard'
+    },
+    '10000000000': {
+      'other': '00 miljard'
+    },
+    '100000000000': {
+      'other': '000 miljard'
+    },
+    '1000000000000': {
+      'other': '0 biljoen'
+    },
+    '10000000000000': {
+      'other': '00 biljoen'
+    },
+    '100000000000000': {
+      'other': '000 biljoen'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale agq.
+ */
+goog.i18n.CompactNumberFormatSymbols_agq = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0G'
+    },
+    '10000000000': {
+      'other': '00G'
+    },
+    '100000000000': {
+      'other': '000G'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale agq_CM.
+ */
+goog.i18n.CompactNumberFormatSymbols_agq_CM =
+    goog.i18n.CompactNumberFormatSymbols_agq;
+
+
+/**
+ * Compact number formatting symbols for locale ak.
+ */
+goog.i18n.CompactNumberFormatSymbols_ak = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0G'
+    },
+    '10000000000': {
+      'other': '00G'
+    },
+    '100000000000': {
+      'other': '000G'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ak_GH.
+ */
+goog.i18n.CompactNumberFormatSymbols_ak_GH =
+    goog.i18n.CompactNumberFormatSymbols_ak;
+
+
+/**
+ * Compact number formatting symbols for locale ar_AE.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_AE = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_BH.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_BH = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_DJ.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_DJ = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_DZ.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_DZ = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_EH.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_EH = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_ER.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_ER = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_IL.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_IL = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_IQ.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_IQ = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_JO.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_JO = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_KM.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_KM = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_KW.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_KW = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_LB.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_LB = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_LY.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_LY = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_MA.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_MA = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_MR.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_MR = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_OM.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_OM = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_PS.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_PS = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_QA.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_QA = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_SA.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_SA = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_SD.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_SD = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_SO.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_SO = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_SS.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_SS = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_SY.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_SY = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_TD.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_TD = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_TN.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_TN = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_YE.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_YE = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': 

<TRUNCATED>

[50/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/GCL-compile-config.xml
----------------------------------------------------------------------
diff --git a/externs/GCL/GCL-compile-config.xml b/externs/GCL/GCL-compile-config.xml
new file mode 100644
index 0000000..76c85a6
--- /dev/null
+++ b/externs/GCL/GCL-compile-config.xml
@@ -0,0 +1,901 @@
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License</name></exclude> 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.
+
+-->
+<flex-config>
+
+    <as-root>out/as</as-root>
+
+    <compiler>
+        <accessible>true</accessible>
+
+        <locale/>
+
+        <source-path>
+            <path-element>src</path-element>
+        </source-path>
+
+        <warn-no-constructor>false</warn-no-constructor>
+    </compiler>
+
+    <external>
+        <!--<path-element>externs/goog/base.js</path-element>
+        <path-element>externs/goog/a11y/aria/announcer.js</path-element>
+        <path-element>externs/goog/a11y/aria/aria.js</path-element>
+        <path-element>externs/goog/a11y/aria/attributes.js</path-element>
+        <path-element>externs/goog/a11y/aria/datatables.js</path-element>
+        <path-element>externs/goog/a11y/aria/roles.js</path-element>
+        <path-element>externs/goog/array/array.js</path-element>
+        <path-element>externs/goog/asserts/asserts.js</path-element>
+        <path-element>externs/goog/async/animationdelay.js</path-element>
+        <path-element>externs/goog/async/conditionaldelay.js</path-element>
+        <path-element>externs/goog/async/delay.js</path-element>
+        <path-element>externs/goog/async/freelist.js</path-element>
+        <path-element>externs/goog/async/nexttick.js</path-element>
+        <path-element>externs/goog/async/run.js</path-element>
+        <path-element>externs/goog/async/throttle.js</path-element>
+        <path-element>externs/goog/async/workqueue.js</path-element>
+        <path-element>externs/goog/bootstrap/nodejs.js</path-element>
+        <path-element>externs/goog/bootstrap/webworkers.js</path-element>
+        <path-element>externs/goog/color/alpha.js</path-element>
+        <path-element>externs/goog/color/color.js</path-element>
+        <path-element>externs/goog/color/names.js</path-element>
+        <path-element>externs/goog/crypt/aes.js</path-element>
+        <path-element>externs/goog/crypt/arc4.js</path-element>
+        <path-element>externs/goog/crypt/base64.js</path-element>
+        <path-element>externs/goog/crypt/basen.js</path-element>
+        <path-element>externs/goog/crypt/blobhasher.js</path-element>
+        <path-element>externs/goog/crypt/blockcipher.js</path-element>
+        <path-element>externs/goog/crypt/cbc.js</path-element>
+        <path-element>externs/goog/crypt/crypt.js</path-element>
+        <path-element>externs/goog/crypt/hash.js</path-element>
+        <path-element>externs/goog/crypt/hash32.js</path-element>
+        <path-element>externs/goog/crypt/hmac.js</path-element>
+        <path-element>externs/goog/crypt/md5.js</path-element>
+        <path-element>externs/goog/crypt/pbkdf2.js</path-element>
+        <path-element>externs/goog/crypt/sha1.js</path-element>
+        <path-element>externs/goog/crypt/sha2.js</path-element>
+        <path-element>externs/goog/crypt/sha224.js</path-element>
+        <path-element>externs/goog/crypt/sha256.js</path-element>
+        <path-element>externs/goog/crypt/sha2_64bit.js</path-element>
+        <path-element>externs/goog/crypt/sha384.js</path-element>
+        <path-element>externs/goog/crypt/sha512.js</path-element>
+        <path-element>externs/goog/crypt/sha512_256.js</path-element>
+        <path-element>externs/goog/cssom/cssom.js</path-element>
+        <path-element>externs/goog/cssom/iframe/style.js</path-element>
+        <path-element>externs/goog/datasource/datamanager.js</path-element>
+        <path-element>externs/goog/datasource/datasource.js</path-element>
+        <path-element>externs/goog/datasource/expr.js</path-element>
+        <path-element>externs/goog/datasource/fastdatanode.js</path-element>
+        <path-element>externs/goog/datasource/jsdatasource.js</path-element>
+        <path-element>externs/goog/datasource/jsondatasource.js</path-element>
+        <path-element>externs/goog/datasource/jsxmlhttpdatasource.js</path-element>
+        <path-element>externs/goog/datasource/xmldatasource.js</path-element>
+        <path-element>externs/goog/date/date.js</path-element>
+        <path-element>externs/goog/date/datelike.js</path-element>
+        <path-element>externs/goog/date/daterange.js</path-element>
+        <path-element>externs/goog/date/duration.js</path-element>
+        <path-element>externs/goog/date/relative.js</path-element>
+        <path-element>externs/goog/date/relativewithplurals.js</path-element>
+        <path-element>externs/goog/date/utcdatetime.js</path-element>
+        <path-element>externs/goog/db/cursor.js</path-element>
+        <path-element>externs/goog/db/db.js</path-element>
+        <path-element>externs/goog/db/error.js</path-element>
+        <path-element>externs/goog/db/index.js</path-element>
+        <path-element>externs/goog/db/indexeddb.js</path-element>
+        <path-element>externs/goog/db/keyrange.js</path-element>
+        <path-element>externs/goog/db/objectstore.js</path-element>
+        <path-element>externs/goog/db/transaction.js</path-element>
+        <path-element>externs/goog/debug/console.js</path-element>
+        <path-element>externs/goog/debug/debug.js</path-element>
+        <path-element>externs/goog/debug/debugwindow.js</path-element>
+        <path-element>externs/goog/debug/divconsole.js</path-element>
+        <path-element>externs/goog/debug/entrypointregistry.js</path-element>
+        <path-element>externs/goog/debug/error.js</path-element>
+        <path-element>externs/goog/debug/errorhandler.js</path-element>
+        <path-element>externs/goog/debug/errorhandlerweakdep.js</path-element>
+        <path-element>externs/goog/debug/errorreporter.js</path-element>
+        <path-element>externs/goog/debug/fancywindow.js</path-element>
+        <path-element>externs/goog/debug/formatter.js</path-element>
+        <path-element>externs/goog/debug/fpsdisplay.js</path-element>
+        <path-element>externs/goog/debug/gcdiagnostics.js</path-element>
+        <path-element>externs/goog/debug/logbuffer.js</path-element>
+        <path-element>externs/goog/debug/logger.js</path-element>
+        <path-element>externs/goog/debug/logrecord.js</path-element>
+        <path-element>externs/goog/debug/logrecordserializer.js</path-element>
+        <path-element>externs/goog/debug/relativetimeprovider.js</path-element>
+        <path-element>externs/goog/debug/tracer.js</path-element>
+        <path-element>externs/goog/debug/devcss/devcss.js</path-element>
+        <path-element>externs/goog/debug/devcss/devcssrunner.js</path-element>
+        <path-element>externs/goog/demos/autocompleteremotedata.js</path-element>
+        <path-element>externs/goog/demos/autocompleterichremotedata.js</path-element>
+        <path-element>externs/goog/demos/samplecomponent.js</path-element>
+        <path-element>externs/goog/demos/editor/deps.js</path-element>
+        <path-element>externs/goog/demos/editor/helloworld.js</path-element>
+        <path-element>externs/goog/demos/editor/helloworlddialog.js</path-element>
+        <path-element>externs/goog/demos/editor/helloworlddialogplugin.js</path-element>
+        <path-element>externs/goog/demos/graphics/tigerdata.js</path-element>
+        <path-element>externs/goog/demos/xpc/xpcdemo.js</path-element>
+        <path-element>externs/goog/dom/abstractmultirange.js</path-element>
+        <path-element>externs/goog/dom/abstractrange.js</path-element>
+        <path-element>externs/goog/dom/annotate.js</path-element>
+        <path-element>externs/goog/dom/browserfeature.js</path-element>
+        <path-element>externs/goog/dom/bufferedviewportsizemonitor.js</path-element>
+        <path-element>externs/goog/dom/classes.js</path-element>
+        <path-element>externs/goog/dom/classlist.js</path-element>
+        <path-element>externs/goog/dom/controlrange.js</path-element>
+        <path-element>externs/goog/dom/dataset.js</path-element>
+        <path-element>externs/goog/dom/dom.js</path-element>
+        <path-element>externs/goog/dom/fontsizemonitor.js</path-element>
+        <path-element>externs/goog/dom/forms.js</path-element>
+        <path-element>externs/goog/dom/fullscreen.js</path-element>
+        <path-element>externs/goog/dom/iframe.js</path-element>
+        <path-element>externs/goog/dom/inputtype.js</path-element>
+        <path-element>externs/goog/dom/iter.js</path-element>
+        <path-element>externs/goog/dom/multirange.js</path-element>
+        <path-element>externs/goog/dom/nodeiterator.js</path-element>
+        <path-element>externs/goog/dom/nodeoffset.js</path-element>
+        <path-element>externs/goog/dom/nodetype.js</path-element>
+        <path-element>externs/goog/dom/range.js</path-element>
+        <path-element>externs/goog/dom/rangeendpoint.js</path-element>
+        <path-element>externs/goog/dom/safe.js</path-element>
+        <path-element>externs/goog/dom/savedcaretrange.js</path-element>
+        <path-element>externs/goog/dom/savedrange.js</path-element>
+        <path-element>externs/goog/dom/selection.js</path-element>
+        <path-element>externs/goog/dom/tagiterator.js</path-element>
+        <path-element>externs/goog/dom/tagname.js</path-element>
+        <path-element>externs/goog/dom/tags.js</path-element>
+        <path-element>externs/goog/dom/textrange.js</path-element>
+        <path-element>externs/goog/dom/textrangeiterator.js</path-element>
+        <path-element>externs/goog/dom/vendor.js</path-element>
+        <path-element>externs/goog/dom/viewportsizemonitor.js</path-element>
+        <path-element>externs/goog/dom/xml.js</path-element>
+        <path-element>externs/goog/dom/animationframe/animationframe.js</path-element>
+        <path-element>externs/goog/dom/animationframe/polyfill.js</path-element>
+        <path-element>externs/goog/dom/browserrange/abstractrange.js</path-element>
+        <path-element>externs/goog/dom/browserrange/browserrange.js</path-element>
+        <path-element>externs/goog/dom/browserrange/geckorange.js</path-element>
+        <path-element>externs/goog/dom/browserrange/ierange.js</path-element>
+        <path-element>externs/goog/dom/browserrange/operarange.js</path-element>
+        <path-element>externs/goog/dom/browserrange/w3crange.js</path-element>
+        <path-element>externs/goog/dom/browserrange/webkitrange.js</path-element>
+        <path-element>externs/goog/dom/pattern/abstractpattern.js</path-element>
+        <path-element>externs/goog/dom/pattern/allchildren.js</path-element>
+        <path-element>externs/goog/dom/pattern/childmatches.js</path-element>
+        <path-element>externs/goog/dom/pattern/endtag.js</path-element>
+        <path-element>externs/goog/dom/pattern/fulltag.js</path-element>
+        <path-element>externs/goog/dom/pattern/matcher.js</path-element>
+        <path-element>externs/goog/dom/pattern/nodetype.js</path-element>
+        <path-element>externs/goog/dom/pattern/pattern.js</path-element>
+        <path-element>externs/goog/dom/pattern/repeat.js</path-element>
+        <path-element>externs/goog/dom/pattern/sequence.js</path-element>
+        <path-element>externs/goog/dom/pattern/starttag.js</path-element>
+        <path-element>externs/goog/dom/pattern/tag.js</path-element>
+        <path-element>externs/goog/dom/pattern/text.js</path-element>
+        <path-element>externs/goog/dom/pattern/callback/callback.js</path-element>
+        <path-element>externs/goog/dom/pattern/callback/counter.js</path-element>
+        <path-element>externs/goog/editor/browserfeature.js</path-element>
+        <path-element>externs/goog/editor/clicktoeditwrapper.js</path-element>
+        <path-element>externs/goog/editor/command.js</path-element>
+        <path-element>externs/goog/editor/contenteditablefield.js</path-element>
+        <path-element>externs/goog/editor/defines.js</path-element>
+        <path-element>externs/goog/editor/field.js</path-element>
+        <path-element>externs/goog/editor/focus.js</path-element>
+        <path-element>externs/goog/editor/icontent.js</path-element>
+        <path-element>externs/goog/editor/link.js</path-element>
+        <path-element>externs/goog/editor/node.js</path-element>
+        <path-element>externs/goog/editor/plugin.js</path-element>
+        <path-element>externs/goog/editor/range.js</path-element>
+        <path-element>externs/goog/editor/seamlessfield.js</path-element>
+        <path-element>externs/goog/editor/style.js</path-element>
+        <path-element>externs/goog/editor/table.js</path-element>
+        <path-element>externs/goog/editor/plugins/abstractbubbleplugin.js</path-element>
+        <path-element>externs/goog/editor/plugins/abstractdialogplugin.js</path-element>
+        <path-element>externs/goog/editor/plugins/abstracttabhandler.js</path-element>
+        <path-element>externs/goog/editor/plugins/basictextformatter.js</path-element>
+        <path-element>externs/goog/editor/plugins/blockquote.js</path-element>
+        <path-element>externs/goog/editor/plugins/emoticons.js</path-element>
+        <path-element>externs/goog/editor/plugins/enterhandler.js</path-element>
+        <path-element>externs/goog/editor/plugins/firststrong.js</path-element>
+        <path-element>externs/goog/editor/plugins/headerformatter.js</path-element>
+        <path-element>externs/goog/editor/plugins/linkbubble.js</path-element>
+        <path-element>externs/goog/editor/plugins/linkdialogplugin.js</path-element>
+        <path-element>externs/goog/editor/plugins/linkshortcutplugin.js</path-element>
+        <path-element>externs/goog/editor/plugins/listtabhandler.js</path-element>
+        <path-element>externs/goog/editor/plugins/loremipsum.js</path-element>
+        <path-element>externs/goog/editor/plugins/removeformatting.js</path-element>
+        <path-element>externs/goog/editor/plugins/spacestabhandler.js</path-element>
+        <path-element>externs/goog/editor/plugins/tableeditor.js</path-element>
+        <path-element>externs/goog/editor/plugins/tagonenterhandler.js</path-element>
+        <path-element>externs/goog/editor/plugins/undoredo.js</path-element>
+        <path-element>externs/goog/editor/plugins/undoredomanager.js</path-element>
+        <path-element>externs/goog/editor/plugins/undoredostate.js</path-element>
+        <path-element>externs/goog/events/actioneventwrapper.js</path-element>
+        <path-element>externs/goog/events/actionhandler.js</path-element>-->
+        <!--<path-element>externs/goog/events/browserfeature.js</path-element>-->
+        <!--<path-element>externs/goog/events/eventhandler.js</path-element>
+        <path-element>externs/goog/events/eventid.js</path-element>-->
+        <path-element>externs/goog/disposable/disposable.js</path-element>
+        <path-element>externs/goog/disposable/idisposable.js</path-element>
+        <path-element>externs/goog/events/browserevent.js</path-element>
+        <path-element>externs/goog/events/event.js</path-element>
+        <path-element>externs/goog/events/events.js</path-element>
+        <path-element>externs/goog/events/eventtarget.js</path-element>
+        <path-element>externs/goog/events/eventtype.js</path-element>
+        <path-element>externs/goog/events/listenable.js</path-element>
+        <!--<path-element>externs/goog/events/eventwrapper.js</path-element>
+        <path-element>externs/goog/events/filedrophandler.js</path-element>
+        <path-element>externs/goog/events/focushandler.js</path-element>
+        <path-element>externs/goog/events/imehandler.js</path-element>
+        <path-element>externs/goog/events/inputhandler.js</path-element>
+        <path-element>externs/goog/events/keycodes.js</path-element>
+        <path-element>externs/goog/events/keyhandler.js</path-element>
+        <path-element>externs/goog/events/keynames.js</path-element>
+        <path-element>externs/goog/events/listener.js</path-element>
+        <path-element>externs/goog/events/listenermap.js</path-element>
+        <path-element>externs/goog/events/mousewheelhandler.js</path-element>
+        <path-element>externs/goog/events/onlinehandler.js</path-element>
+        <path-element>externs/goog/events/pastehandler.js</path-element>
+        <path-element>externs/goog/events/wheelevent.js</path-element>
+        <path-element>externs/goog/events/wheelhandler.js</path-element>-->
+        <!--<path-element>externs/goog/format/emailaddress.js</path-element>
+        <path-element>externs/goog/format/format.js</path-element>
+        <path-element>externs/goog/format/htmlprettyprinter.js</path-element>
+        <path-element>externs/goog/format/internationalizedemailaddress.js</path-element>
+        <path-element>externs/goog/format/jsonprettyprinter.js</path-element>
+        <path-element>externs/goog/fs/entry.js</path-element>
+        <path-element>externs/goog/fs/entryimpl.js</path-element>
+        <path-element>externs/goog/fs/error.js</path-element>
+        <path-element>externs/goog/fs/filereader.js</path-element>
+        <path-element>externs/goog/fs/filesaver.js</path-element>
+        <path-element>externs/goog/fs/filesystem.js</path-element>
+        <path-element>externs/goog/fs/filesystemimpl.js</path-element>
+        <path-element>externs/goog/fs/filewriter.js</path-element>
+        <path-element>externs/goog/fs/fs.js</path-element>
+        <path-element>externs/goog/fs/progressevent.js</path-element>
+        <path-element>externs/goog/fs/url.js</path-element>
+        <path-element>externs/goog/functions/functions.js</path-element>
+        <path-element>externs/goog/fx/abstractdragdrop.js</path-element>
+        <path-element>externs/goog/fx/animation.js</path-element>
+        <path-element>externs/goog/fx/animationqueue.js</path-element>
+        <path-element>externs/goog/fx/cssspriteanimation.js</path-element>
+        <path-element>externs/goog/fx/dom.js</path-element>
+        <path-element>externs/goog/fx/dragdrop.js</path-element>
+        <path-element>externs/goog/fx/dragdropgroup.js</path-element>
+        <path-element>externs/goog/fx/dragger.js</path-element>
+        <path-element>externs/goog/fx/draglistgroup.js</path-element>
+        <path-element>externs/goog/fx/dragscrollsupport.js</path-element>
+        <path-element>externs/goog/fx/easing.js</path-element>
+        <path-element>externs/goog/fx/fx.js</path-element>
+        <path-element>externs/goog/fx/transition.js</path-element>
+        <path-element>externs/goog/fx/transitionbase.js</path-element>
+        <path-element>externs/goog/fx/anim/anim.js</path-element>
+        <path-element>externs/goog/fx/css3/fx.js</path-element>
+        <path-element>externs/goog/fx/css3/transition.js</path-element>
+        <path-element>externs/goog/graphics/abstractgraphics.js</path-element>
+        <path-element>externs/goog/graphics/affinetransform.js</path-element>
+        <path-element>externs/goog/graphics/canvaselement.js</path-element>
+        <path-element>externs/goog/graphics/canvasgraphics.js</path-element>
+        <path-element>externs/goog/graphics/element.js</path-element>
+        <path-element>externs/goog/graphics/ellipseelement.js</path-element>
+        <path-element>externs/goog/graphics/fill.js</path-element>
+        <path-element>externs/goog/graphics/font.js</path-element>
+        <path-element>externs/goog/graphics/graphics.js</path-element>
+        <path-element>externs/goog/graphics/groupelement.js</path-element>
+        <path-element>externs/goog/graphics/imageelement.js</path-element>
+        <path-element>externs/goog/graphics/lineargradient.js</path-element>
+        <path-element>externs/goog/graphics/path.js</path-element>
+        <path-element>externs/goog/graphics/pathelement.js</path-element>
+        <path-element>externs/goog/graphics/paths.js</path-element>
+        <path-element>externs/goog/graphics/rectelement.js</path-element>
+        <path-element>externs/goog/graphics/solidfill.js</path-element>
+        <path-element>externs/goog/graphics/stroke.js</path-element>
+        <path-element>externs/goog/graphics/strokeandfillelement.js</path-element>
+        <path-element>externs/goog/graphics/svgelement.js</path-element>
+        <path-element>externs/goog/graphics/svggraphics.js</path-element>
+        <path-element>externs/goog/graphics/textelement.js</path-element>
+        <path-element>externs/goog/graphics/vmlelement.js</path-element>
+        <path-element>externs/goog/graphics/vmlgraphics.js</path-element>
+        <path-element>externs/goog/graphics/ext/coordinates.js</path-element>
+        <path-element>externs/goog/graphics/ext/element.js</path-element>
+        <path-element>externs/goog/graphics/ext/ellipse.js</path-element>
+        <path-element>externs/goog/graphics/ext/ext.js</path-element>
+        <path-element>externs/goog/graphics/ext/graphics.js</path-element>
+        <path-element>externs/goog/graphics/ext/group.js</path-element>
+        <path-element>externs/goog/graphics/ext/image.js</path-element>
+        <path-element>externs/goog/graphics/ext/path.js</path-element>
+        <path-element>externs/goog/graphics/ext/rectangle.js</path-element>
+        <path-element>externs/goog/graphics/ext/shape.js</path-element>
+        <path-element>externs/goog/graphics/ext/strokeandfillelement.js</path-element>
+        <path-element>externs/goog/history/event.js</path-element>
+        <path-element>externs/goog/history/eventtype.js</path-element>
+        <path-element>externs/goog/history/history.js</path-element>
+        <path-element>externs/goog/history/html5history.js</path-element>
+        <path-element>externs/goog/html/flash.js</path-element>
+        <path-element>externs/goog/html/legacyconversions.js</path-element>
+        <path-element>externs/goog/html/safehtml.js</path-element>
+        <path-element>externs/goog/html/safescript.js</path-element>
+        <path-element>externs/goog/html/safestyle.js</path-element>
+        <path-element>externs/goog/html/safestylesheet.js</path-element>
+        <path-element>externs/goog/html/safeurl.js</path-element>
+        <path-element>externs/goog/html/silverlight.js</path-element>
+        <path-element>externs/goog/html/trustedresourceurl.js</path-element>
+        <path-element>externs/goog/html/uncheckedconversions.js</path-element>
+        <path-element>externs/goog/html/utils.js</path-element>
+        <path-element>externs/goog/i18n/bidi.js</path-element>
+        <path-element>externs/goog/i18n/bidiformatter.js</path-element>
+        <path-element>externs/goog/i18n/charlistdecompressor.js</path-element>
+        <path-element>externs/goog/i18n/charpickerdata.js</path-element>
+        <path-element>externs/goog/i18n/collation.js</path-element>
+        <path-element>externs/goog/i18n/compactnumberformatsymbols.js</path-element>
+        <path-element>externs/goog/i18n/compactnumberformatsymbols_ext.js</path-element>
+        <path-element>externs/goog/i18n/currency.js</path-element>
+        <path-element>externs/goog/i18n/currencycodemap.js</path-element>
+        <path-element>externs/goog/i18n/datetimeformat.js</path-element>
+        <path-element>externs/goog/i18n/datetimeparse.js</path-element>
+        <path-element>externs/goog/i18n/datetimepatterns.js</path-element>
+        <path-element>externs/goog/i18n/datetimepatternsext.js</path-element>
+        <path-element>externs/goog/i18n/datetimesymbols.js</path-element>
+        <path-element>externs/goog/i18n/datetimesymbolsext.js</path-element>
+        <path-element>externs/goog/i18n/graphemebreak.js</path-element>
+        <path-element>externs/goog/i18n/messageformat.js</path-element>
+        <path-element>externs/goog/i18n/mime.js</path-element>
+        <path-element>externs/goog/i18n/numberformat.js</path-element>
+        <path-element>externs/goog/i18n/numberformatsymbols.js</path-element>
+        <path-element>externs/goog/i18n/numberformatsymbolsext.js</path-element>
+        <path-element>externs/goog/i18n/ordinalrules.js</path-element>
+        <path-element>externs/goog/i18n/pluralrules.js</path-element>
+        <path-element>externs/goog/i18n/timezone.js</path-element>
+        <path-element>externs/goog/i18n/uchar.js</path-element>
+        <path-element>externs/goog/i18n/ucharnames.js</path-element>
+        <path-element>externs/goog/i18n/uchar/localnamefetcher.js</path-element>
+        <path-element>externs/goog/i18n/uchar/namefetcher.js</path-element>
+        <path-element>externs/goog/i18n/uchar/remotenamefetcher.js</path-element>
+        <path-element>externs/goog/iter/iter.js</path-element>
+        <path-element>externs/goog/json/evaljsonprocessor.js</path-element>
+        <path-element>externs/goog/json/hybrid.js</path-element>
+        <path-element>externs/goog/json/hybridjsonprocessor.js</path-element>
+        <path-element>externs/goog/json/json.js</path-element>
+        <path-element>externs/goog/json/json_perf.js</path-element>
+        <path-element>externs/goog/json/nativejsonprocessor.js</path-element>
+        <path-element>externs/goog/json/processor.js</path-element>
+        <path-element>externs/goog/labs/dom/pagevisibilitymonitor.js</path-element>
+        <path-element>externs/goog/labs/events/nondisposableeventtarget.js</path-element>
+        <path-element>externs/goog/labs/events/touch.js</path-element>
+        <path-element>externs/goog/labs/format/csv.js</path-element>
+        <path-element>externs/goog/labs/html/attribute_rewriter.js</path-element>
+        <path-element>externs/goog/labs/html/sanitizer.js</path-element>
+        <path-element>externs/goog/labs/html/scrubber.js</path-element>
+        <path-element>externs/goog/labs/i18n/listformat.js</path-element>
+        <path-element>externs/goog/labs/i18n/listsymbols.js</path-element>
+        <path-element>externs/goog/labs/i18n/listsymbolsext.js</path-element>
+        <path-element>externs/goog/labs/iterable/iterable.js</path-element>
+        <path-element>externs/goog/labs/mock/mock.js</path-element>
+        <path-element>externs/goog/labs/net/image.js</path-element>
+        <path-element>externs/goog/labs/net/webchannel.js</path-element>
+        <path-element>externs/goog/labs/net/webchanneltransport.js</path-element>
+        <path-element>externs/goog/labs/net/webchanneltransportfactory.js</path-element>
+        <path-element>externs/goog/labs/net/xhr.js</path-element>
+        <path-element>externs/goog/labs/net/webchannel/channel.js</path-element>
+        <path-element>externs/goog/labs/net/webchannel/channelrequest.js</path-element>
+        <path-element>externs/goog/labs/net/webchannel/connectionstate.js</path-element>
+        <path-element>externs/goog/labs/net/webchannel/forwardchannelrequestpool.js</path-element>
+        <path-element>externs/goog/labs/net/webchannel/netutils.js</path-element>
+        <path-element>externs/goog/labs/net/webchannel/requeststats.js</path-element>
+        <path-element>externs/goog/labs/net/webchannel/webchannelbase.js</path-element>
+        <path-element>externs/goog/labs/net/webchannel/webchannelbasetransport.js</path-element>
+        <path-element>externs/goog/labs/net/webchannel/webchanneldebug.js</path-element>
+        <path-element>externs/goog/labs/net/webchannel/wire.js</path-element>
+        <path-element>externs/goog/labs/net/webchannel/wirev8.js</path-element>
+        <path-element>externs/goog/labs/object/object.js</path-element>
+        <path-element>externs/goog/labs/pubsub/broadcastpubsub.js</path-element>
+        <path-element>externs/goog/labs/storage/boundedcollectablestorage.js</path-element>
+        <path-element>externs/goog/labs/structs/map.js</path-element>
+        <path-element>externs/goog/labs/structs/map_perf.js</path-element>
+        <path-element>externs/goog/labs/structs/multimap.js</path-element>
+        <path-element>externs/goog/labs/style/pixeldensitymonitor.js</path-element>
+        <path-element>externs/goog/labs/testing/assertthat.js</path-element>
+        <path-element>externs/goog/labs/testing/decoratormatcher.js</path-element>
+        <path-element>externs/goog/labs/testing/dictionarymatcher.js</path-element>
+        <path-element>externs/goog/labs/testing/environment.js</path-element>
+        <path-element>externs/goog/labs/testing/logicmatcher.js</path-element>
+        <path-element>externs/goog/labs/testing/matcher.js</path-element>
+        <path-element>externs/goog/labs/testing/numbermatcher.js</path-element>
+        <path-element>externs/goog/labs/testing/objectmatcher.js</path-element>
+        <path-element>externs/goog/labs/testing/stringmatcher.js</path-element>
+        <path-element>externs/goog/labs/useragent/browser.js</path-element>
+        <path-element>externs/goog/labs/useragent/device.js</path-element>
+        <path-element>externs/goog/labs/useragent/engine.js</path-element>
+        <path-element>externs/goog/labs/useragent/platform.js</path-element>
+        <path-element>externs/goog/labs/useragent/util.js</path-element>
+        <path-element>externs/goog/locale/countries.js</path-element>
+        <path-element>externs/goog/locale/defaultlocalenameconstants.js</path-element>
+        <path-element>externs/goog/locale/genericfontnames.js</path-element>
+        <path-element>externs/goog/locale/genericfontnamesdata.js</path-element>
+        <path-element>externs/goog/locale/locale.js</path-element>
+        <path-element>externs/goog/locale/nativenameconstants.js</path-element>
+        <path-element>externs/goog/locale/scriptToLanguages.js</path-element>
+        <path-element>externs/goog/locale/timezonedetection.js</path-element>
+        <path-element>externs/goog/locale/timezonefingerprint.js</path-element>
+        <path-element>externs/goog/locale/timezonelist.js</path-element>
+        <path-element>externs/goog/log/log.js</path-element>
+        <path-element>externs/goog/math/affinetransform.js</path-element>
+        <path-element>externs/goog/math/bezier.js</path-element>
+        <path-element>externs/goog/math/box.js</path-element>
+        <path-element>externs/goog/math/coordinate.js</path-element>
+        <path-element>externs/goog/math/coordinate3.js</path-element>
+        <path-element>externs/goog/math/exponentialbackoff.js</path-element>
+        <path-element>externs/goog/math/integer.js</path-element>
+        <path-element>externs/goog/math/line.js</path-element>
+        <path-element>externs/goog/math/long.js</path-element>
+        <path-element>externs/goog/math/math.js</path-element>
+        <path-element>externs/goog/math/matrix.js</path-element>
+        <path-element>externs/goog/math/path.js</path-element>
+        <path-element>externs/goog/math/paths.js</path-element>
+        <path-element>externs/goog/math/range.js</path-element>
+        <path-element>externs/goog/math/rangeset.js</path-element>
+        <path-element>externs/goog/math/rect.js</path-element>
+        <path-element>externs/goog/math/size.js</path-element>
+        <path-element>externs/goog/math/tdma.js</path-element>
+        <path-element>externs/goog/math/vec2.js</path-element>
+        <path-element>externs/goog/math/vec3.js</path-element>
+        <path-element>externs/goog/math/interpolator/interpolator1.js</path-element>
+        <path-element>externs/goog/math/interpolator/linear1.js</path-element>
+        <path-element>externs/goog/math/interpolator/pchip1.js</path-element>
+        <path-element>externs/goog/math/interpolator/spline1.js</path-element>
+        <path-element>externs/goog/memoize/memoize.js</path-element>
+        <path-element>externs/goog/messaging/abstractchannel.js</path-element>
+        <path-element>externs/goog/messaging/bufferedchannel.js</path-element>
+        <path-element>externs/goog/messaging/deferredchannel.js</path-element>
+        <path-element>externs/goog/messaging/loggerclient.js</path-element>
+        <path-element>externs/goog/messaging/loggerserver.js</path-element>
+        <path-element>externs/goog/messaging/messagechannel.js</path-element>
+        <path-element>externs/goog/messaging/messaging.js</path-element>
+        <path-element>externs/goog/messaging/multichannel.js</path-element>
+        <path-element>externs/goog/messaging/portcaller.js</path-element>
+        <path-element>externs/goog/messaging/portchannel.js</path-element>
+        <path-element>externs/goog/messaging/portnetwork.js</path-element>
+        <path-element>externs/goog/messaging/portoperator.js</path-element>
+        <path-element>externs/goog/messaging/respondingchannel.js</path-element>
+        <path-element>externs/goog/messaging/testdata/portchannel_worker.js</path-element>
+        <path-element>externs/goog/messaging/testdata/portnetwork_worker1.js</path-element>
+        <path-element>externs/goog/messaging/testdata/portnetwork_worker2.js</path-element>
+        <path-element>externs/goog/module/abstractmoduleloader.js</path-element>
+        <path-element>externs/goog/module/basemodule.js</path-element>
+        <path-element>externs/goog/module/loader.js</path-element>
+        <path-element>externs/goog/module/module.js</path-element>
+        <path-element>externs/goog/module/moduleinfo.js</path-element>
+        <path-element>externs/goog/module/moduleloadcallback.js</path-element>
+        <path-element>externs/goog/module/moduleloader.js</path-element>
+        <path-element>externs/goog/module/modulemanager.js</path-element>
+        <path-element>externs/goog/module/testdata/modA_1.js</path-element>
+        <path-element>externs/goog/module/testdata/modA_2.js</path-element>
+        <path-element>externs/goog/module/testdata/modB_1.js</path-element>
+        <path-element>externs/goog/net/browserchannel.js</path-element>
+        <path-element>externs/goog/net/bulkloader.js</path-element>
+        <path-element>externs/goog/net/bulkloaderhelper.js</path-element>
+        <path-element>externs/goog/net/channeldebug.js</path-element>
+        <path-element>externs/goog/net/channelrequest.js</path-element>
+        <path-element>externs/goog/net/cookies.js</path-element>
+        <path-element>externs/goog/net/corsxmlhttpfactory.js</path-element>
+        <path-element>externs/goog/net/crossdomainrpc.js</path-element>
+        <path-element>externs/goog/net/errorcode.js</path-element>
+        <path-element>externs/goog/net/eventtype.js</path-element>
+        <path-element>externs/goog/net/filedownloader.js</path-element>
+        <path-element>externs/goog/net/httpstatus.js</path-element>
+        <path-element>externs/goog/net/iframeio.js</path-element>
+        <path-element>externs/goog/net/iframeloadmonitor.js</path-element>
+        <path-element>externs/goog/net/imageloader.js</path-element>
+        <path-element>externs/goog/net/ipaddress.js</path-element>
+        <path-element>externs/goog/net/jsloader.js</path-element>
+        <path-element>externs/goog/net/jsonp.js</path-element>
+        <path-element>externs/goog/net/mockiframeio.js</path-element>
+        <path-element>externs/goog/net/multiiframeloadmonitor.js</path-element>
+        <path-element>externs/goog/net/networkstatusmonitor.js</path-element>
+        <path-element>externs/goog/net/tmpnetwork.js</path-element>
+        <path-element>externs/goog/net/websocket.js</path-element>
+        <path-element>externs/goog/net/wrapperxmlhttpfactory.js</path-element>
+        <path-element>externs/goog/net/xhrio.js</path-element>
+        <path-element>externs/goog/net/xhriopool.js</path-element>
+        <path-element>externs/goog/net/xhrlike.js</path-element>
+        <path-element>externs/goog/net/xhrmanager.js</path-element>
+        <path-element>externs/goog/net/xmlhttp.js</path-element>
+        <path-element>externs/goog/net/xmlhttpfactory.js</path-element>
+        <path-element>externs/goog/net/xpc/crosspagechannel.js</path-element>
+        <path-element>externs/goog/net/xpc/crosspagechannelrole.js</path-element>
+        <path-element>externs/goog/net/xpc/directtransport.js</path-element>
+        <path-element>externs/goog/net/xpc/frameelementmethodtransport.js</path-element>
+        <path-element>externs/goog/net/xpc/iframepollingtransport.js</path-element>
+        <path-element>externs/goog/net/xpc/iframerelaytransport.js</path-element>
+        <path-element>externs/goog/net/xpc/nativemessagingtransport.js</path-element>
+        <path-element>externs/goog/net/xpc/nixtransport.js</path-element>
+        <path-element>externs/goog/net/xpc/relay.js</path-element>
+        <path-element>externs/goog/net/xpc/transport.js</path-element>
+        <path-element>externs/goog/net/xpc/xpc.js</path-element>
+        <path-element>externs/goog/object/object.js</path-element>
+        <path-element>externs/goog/positioning/absoluteposition.js</path-element>
+        <path-element>externs/goog/positioning/abstractposition.js</path-element>
+        <path-element>externs/goog/positioning/anchoredposition.js</path-element>
+        <path-element>externs/goog/positioning/anchoredviewportposition.js</path-element>
+        <path-element>externs/goog/positioning/clientposition.js</path-element>
+        <path-element>externs/goog/positioning/menuanchoredposition.js</path-element>
+        <path-element>externs/goog/positioning/positioning.js</path-element>
+        <path-element>externs/goog/positioning/viewportclientposition.js</path-element>
+        <path-element>externs/goog/positioning/viewportposition.js</path-element>
+        <path-element>externs/goog/promise/promise.js</path-element>
+        <path-element>externs/goog/promise/resolver.js</path-element>
+        <path-element>externs/goog/promise/thenable.js</path-element>
+        <path-element>externs/goog/proto/proto.js</path-element>
+        <path-element>externs/goog/proto/serializer.js</path-element>
+        <path-element>externs/goog/proto2/descriptor.js</path-element>
+        <path-element>externs/goog/proto2/fielddescriptor.js</path-element>
+        <path-element>externs/goog/proto2/lazydeserializer.js</path-element>
+        <path-element>externs/goog/proto2/message.js</path-element>
+        <path-element>externs/goog/proto2/objectserializer.js</path-element>
+        <path-element>externs/goog/proto2/pbliteserializer.js</path-element>
+        <path-element>externs/goog/proto2/serializer.js</path-element>
+        <path-element>externs/goog/proto2/textformatserializer.js</path-element>
+        <path-element>externs/goog/proto2/util.js</path-element>
+        <path-element>externs/goog/pubsub/pubsub.js</path-element>
+        <path-element>externs/goog/pubsub/topicid.js</path-element>
+        <path-element>externs/goog/pubsub/typedpubsub.js</path-element>
+        <path-element>externs/goog/reflect/reflect.js</path-element>
+        <path-element>externs/goog/result/deferredadaptor.js</path-element>
+        <path-element>externs/goog/result/dependentresult.js</path-element>
+        <path-element>externs/goog/result/resultutil.js</path-element>
+        <path-element>externs/goog/result/result_interface.js</path-element>
+        <path-element>externs/goog/result/simpleresult.js</path-element>
+        <path-element>externs/goog/soy/data.js</path-element>
+        <path-element>externs/goog/soy/renderer.js</path-element>
+        <path-element>externs/goog/soy/soy.js</path-element>
+        <path-element>externs/goog/spell/spellcheck.js</path-element>
+        <path-element>externs/goog/stats/basicstat.js</path-element>
+        <path-element>externs/goog/storage/collectablestorage.js</path-element>
+        <path-element>externs/goog/storage/encryptedstorage.js</path-element>
+        <path-element>externs/goog/storage/errorcode.js</path-element>
+        <path-element>externs/goog/storage/expiringstorage.js</path-element>
+        <path-element>externs/goog/storage/richstorage.js</path-element>
+        <path-element>externs/goog/storage/storage.js</path-element>
+        <path-element>externs/goog/storage/mechanism/errorcode.js</path-element>
+        <path-element>externs/goog/storage/mechanism/errorhandlingmechanism.js</path-element>
+        <path-element>externs/goog/storage/mechanism/html5localstorage.js</path-element>
+        <path-element>externs/goog/storage/mechanism/html5sessionstorage.js</path-element>
+        <path-element>externs/goog/storage/mechanism/html5webstorage.js</path-element>
+        <path-element>externs/goog/storage/mechanism/ieuserdata.js</path-element>
+        <path-element>externs/goog/storage/mechanism/iterablemechanism.js</path-element>
+        <path-element>externs/goog/storage/mechanism/mechanism.js</path-element>
+        <path-element>externs/goog/storage/mechanism/mechanismfactory.js</path-element>
+        <path-element>externs/goog/storage/mechanism/prefixedmechanism.js</path-element>
+        <path-element>externs/goog/string/const.js</path-element>
+        <path-element>externs/goog/string/linkify.js</path-element>
+        <path-element>externs/goog/string/newlines.js</path-element>
+        <path-element>externs/goog/string/parser.js</path-element>
+        <path-element>externs/goog/string/path.js</path-element>
+        <path-element>externs/goog/string/string.js</path-element>
+        <path-element>externs/goog/string/stringbuffer.js</path-element>
+        <path-element>externs/goog/string/stringformat.js</path-element>
+        <path-element>externs/goog/string/stringifier.js</path-element>
+        <path-element>externs/goog/string/typedstring.js</path-element>
+        <path-element>externs/goog/structs/avltree.js</path-element>
+        <path-element>externs/goog/structs/circularbuffer.js</path-element>
+        <path-element>externs/goog/structs/collection.js</path-element>
+        <path-element>externs/goog/structs/heap.js</path-element>
+        <path-element>externs/goog/structs/inversionmap.js</path-element>
+        <path-element>externs/goog/structs/linkedmap.js</path-element>
+        <path-element>externs/goog/structs/map.js</path-element>
+        <path-element>externs/goog/structs/node.js</path-element>
+        <path-element>externs/goog/structs/pool.js</path-element>
+        <path-element>externs/goog/structs/prioritypool.js</path-element>
+        <path-element>externs/goog/structs/priorityqueue.js</path-element>
+        <path-element>externs/goog/structs/quadtree.js</path-element>
+        <path-element>externs/goog/structs/queue.js</path-element>
+        <path-element>externs/goog/structs/set.js</path-element>
+        <path-element>externs/goog/structs/simplepool.js</path-element>
+        <path-element>externs/goog/structs/stringset.js</path-element>
+        <path-element>externs/goog/structs/structs.js</path-element>
+        <path-element>externs/goog/structs/treenode.js</path-element>
+        <path-element>externs/goog/structs/trie.js</path-element>
+        <path-element>externs/goog/structs/weak/weak.js</path-element>
+        <path-element>externs/goog/style/bidi.js</path-element>
+        <path-element>externs/goog/style/cursor.js</path-element>
+        <path-element>externs/goog/style/style.js</path-element>
+        <path-element>externs/goog/style/transform.js</path-element>
+        <path-element>externs/goog/style/transition.js</path-element>
+        <path-element>externs/goog/testing/asserts.js</path-element>
+        <path-element>externs/goog/testing/benchmark.js</path-element>
+        <path-element>externs/goog/testing/dom.js</path-element>
+        <path-element>externs/goog/testing/expectedfailures.js</path-element>
+        <path-element>externs/goog/testing/functionmock.js</path-element>
+        <path-element>externs/goog/testing/graphics.js</path-element>
+        <path-element>externs/goog/testing/jsunit.js</path-element>
+        <path-element>externs/goog/testing/loosemock.js</path-element>
+        <path-element>externs/goog/testing/mock.js</path-element>
+        <path-element>externs/goog/testing/mockclassfactory.js</path-element>
+        <path-element>externs/goog/testing/mockclock.js</path-element>
+        <path-element>externs/goog/testing/mockcontrol.js</path-element>
+        <path-element>externs/goog/testing/mockinterface.js</path-element>
+        <path-element>externs/goog/testing/mockmatchers.js</path-element>
+        <path-element>externs/goog/testing/mockrandom.js</path-element>
+        <path-element>externs/goog/testing/mockrange.js</path-element>
+        <path-element>externs/goog/testing/mockstorage.js</path-element>
+        <path-element>externs/goog/testing/mockuseragent.js</path-element>
+        <path-element>externs/goog/testing/objectpropertystring.js</path-element>
+        <path-element>externs/goog/testing/performancetable.js</path-element>
+        <path-element>externs/goog/testing/performancetimer.js</path-element>
+        <path-element>externs/goog/testing/propertyreplacer.js</path-element>
+        <path-element>externs/goog/testing/pseudorandom.js</path-element>
+        <path-element>externs/goog/testing/recordfunction.js</path-element>
+        <path-element>externs/goog/testing/singleton.js</path-element>
+        <path-element>externs/goog/testing/stacktrace.js</path-element>
+        <path-element>externs/goog/testing/strictmock.js</path-element>
+        <path-element>externs/goog/testing/watchers.js</path-element>
+        <path-element>externs/goog/testing/async/mockcontrol.js</path-element>
+        <path-element>externs/goog/testing/editor/dom.js</path-element>
+        <path-element>externs/goog/testing/editor/fieldmock.js</path-element>
+        <path-element>externs/goog/testing/events/eventobserver.js</path-element>
+        <path-element>externs/goog/testing/events/events.js</path-element>
+        <path-element>externs/goog/testing/events/matchers.js</path-element>
+        <path-element>externs/goog/testing/events/onlinehandler.js</path-element>
+        <path-element>externs/goog/testing/fs/blob.js</path-element>
+        <path-element>externs/goog/testing/fs/entry.js</path-element>
+        <path-element>externs/goog/testing/fs/file.js</path-element>
+        <path-element>externs/goog/testing/fs/filereader.js</path-element>
+        <path-element>externs/goog/testing/fs/filesystem.js</path-element>
+        <path-element>externs/goog/testing/fs/filewriter.js</path-element>
+        <path-element>externs/goog/testing/fs/fs.js</path-element>
+        <path-element>externs/goog/testing/fs/progressevent.js</path-element>
+        <path-element>externs/goog/testing/i18n/asserts.js</path-element>
+        <path-element>externs/goog/testing/messaging/mockmessagechannel.js</path-element>
+        <path-element>externs/goog/testing/messaging/mockmessageevent.js</path-element>
+        <path-element>externs/goog/testing/messaging/mockmessageport.js</path-element>
+        <path-element>externs/goog/testing/messaging/mockportnetwork.js</path-element>
+        <path-element>externs/goog/testing/net/xhrio.js</path-element>
+        <path-element>externs/goog/testing/net/xhriopool.js</path-element>
+        <path-element>externs/goog/testing/proto2/proto2.js</path-element>
+        <path-element>externs/goog/testing/storage/fakemechanism.js</path-element>
+        <path-element>externs/goog/testing/style/layoutasserts.js</path-element>
+        <path-element>externs/goog/testing/style/style.js</path-element>
+        <path-element>externs/goog/testing/ui/rendererasserts.js</path-element>
+        <path-element>externs/goog/testing/ui/rendererharness.js</path-element>
+        <path-element>externs/goog/testing/ui/style.js</path-element>
+        <path-element>externs/goog/timer/timer.js</path-element>
+        <path-element>externs/goog/tweak/entries.js</path-element>
+        <path-element>externs/goog/tweak/registry.js</path-element>
+        <path-element>externs/goog/tweak/tweak.js</path-element>
+        <path-element>externs/goog/tweak/tweakui.js</path-element>
+        <path-element>externs/goog/ui/abstractspellchecker.js</path-element>
+        <path-element>externs/goog/ui/activitymonitor.js</path-element>
+        <path-element>externs/goog/ui/advancedtooltip.js</path-element>
+        <path-element>externs/goog/ui/animatedzippy.js</path-element>
+        <path-element>externs/goog/ui/attachablemenu.js</path-element>
+        <path-element>externs/goog/ui/bidiinput.js</path-element>
+        <path-element>externs/goog/ui/bubble.js</path-element>
+        <path-element>externs/goog/ui/button.js</path-element>
+        <path-element>externs/goog/ui/buttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/buttonside.js</path-element>
+        <path-element>externs/goog/ui/charcounter.js</path-element>
+        <path-element>externs/goog/ui/charpicker.js</path-element>
+        <path-element>externs/goog/ui/checkbox.js</path-element>
+        <path-element>externs/goog/ui/checkboxmenuitem.js</path-element>
+        <path-element>externs/goog/ui/checkboxrenderer.js</path-element>
+        <path-element>externs/goog/ui/colorbutton.js</path-element>
+        <path-element>externs/goog/ui/colorbuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/colormenubutton.js</path-element>
+        <path-element>externs/goog/ui/colormenubuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/colorpalette.js</path-element>
+        <path-element>externs/goog/ui/colorpicker.js</path-element>
+        <path-element>externs/goog/ui/colorsplitbehavior.js</path-element>
+        <path-element>externs/goog/ui/combobox.js</path-element>
+        <path-element>externs/goog/ui/component.js</path-element>
+        <path-element>externs/goog/ui/container.js</path-element>
+        <path-element>externs/goog/ui/containerrenderer.js</path-element>
+        <path-element>externs/goog/ui/containerscroller.js</path-element>
+        <path-element>externs/goog/ui/control.js</path-element>
+        <path-element>externs/goog/ui/controlcontent.js</path-element>
+        <path-element>externs/goog/ui/controlrenderer.js</path-element>
+        <path-element>externs/goog/ui/cookieeditor.js</path-element>
+        <path-element>externs/goog/ui/css3buttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/css3menubuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/cssnames.js</path-element>
+        <path-element>externs/goog/ui/custombutton.js</path-element>
+        <path-element>externs/goog/ui/custombuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/customcolorpalette.js</path-element>
+        <path-element>externs/goog/ui/datepicker.js</path-element>
+        <path-element>externs/goog/ui/datepickerrenderer.js</path-element>
+        <path-element>externs/goog/ui/decorate.js</path-element>
+        <path-element>externs/goog/ui/defaultdatepickerrenderer.js</path-element>
+        <path-element>externs/goog/ui/dialog.js</path-element>
+        <path-element>externs/goog/ui/dimensionpicker.js</path-element>
+        <path-element>externs/goog/ui/dimensionpickerrenderer.js</path-element>
+        <path-element>externs/goog/ui/dragdropdetector.js</path-element>
+        <path-element>externs/goog/ui/drilldownrow.js</path-element>
+        <path-element>externs/goog/ui/filteredmenu.js</path-element>
+        <path-element>externs/goog/ui/filterobservingmenuitem.js</path-element>
+        <path-element>externs/goog/ui/filterobservingmenuitemrenderer.js</path-element>
+        <path-element>externs/goog/ui/flatbuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/flatmenubuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/formpost.js</path-element>
+        <path-element>externs/goog/ui/gauge.js</path-element>
+        <path-element>externs/goog/ui/gaugetheme.js</path-element>
+        <path-element>externs/goog/ui/hovercard.js</path-element>
+        <path-element>externs/goog/ui/hsvapalette.js</path-element>
+        <path-element>externs/goog/ui/hsvpalette.js</path-element>
+        <path-element>externs/goog/ui/idgenerator.js</path-element>
+        <path-element>externs/goog/ui/idletimer.js</path-element>
+        <path-element>externs/goog/ui/iframemask.js</path-element>
+        <path-element>externs/goog/ui/imagelessbuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/imagelessmenubuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/inputdatepicker.js</path-element>
+        <path-element>externs/goog/ui/itemevent.js</path-element>
+        <path-element>externs/goog/ui/keyboardshortcuthandler.js</path-element>
+        <path-element>externs/goog/ui/labelinput.js</path-element>
+        <path-element>externs/goog/ui/linkbuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/menu.js</path-element>
+        <path-element>externs/goog/ui/menubar.js</path-element>
+        <path-element>externs/goog/ui/menubardecorator.js</path-element>
+        <path-element>externs/goog/ui/menubarrenderer.js</path-element>
+        <path-element>externs/goog/ui/menubase.js</path-element>
+        <path-element>externs/goog/ui/menubutton.js</path-element>
+        <path-element>externs/goog/ui/menubuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/menuheader.js</path-element>
+        <path-element>externs/goog/ui/menuheaderrenderer.js</path-element>
+        <path-element>externs/goog/ui/menuitem.js</path-element>
+        <path-element>externs/goog/ui/menuitemrenderer.js</path-element>
+        <path-element>externs/goog/ui/menurenderer.js</path-element>
+        <path-element>externs/goog/ui/menuseparator.js</path-element>
+        <path-element>externs/goog/ui/menuseparatorrenderer.js</path-element>
+        <path-element>externs/goog/ui/mockactivitymonitor.js</path-element>
+        <path-element>externs/goog/ui/modalariavisibilityhelper.js</path-element>
+        <path-element>externs/goog/ui/modalpopup.js</path-element>
+        <path-element>externs/goog/ui/nativebuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/option.js</path-element>
+        <path-element>externs/goog/ui/palette.js</path-element>
+        <path-element>externs/goog/ui/paletterenderer.js</path-element>
+        <path-element>externs/goog/ui/plaintextspellchecker.js</path-element>
+        <path-element>externs/goog/ui/popup.js</path-element>
+        <path-element>externs/goog/ui/popupbase.js</path-element>
+        <path-element>externs/goog/ui/popupcolorpicker.js</path-element>
+        <path-element>externs/goog/ui/popupdatepicker.js</path-element>
+        <path-element>externs/goog/ui/popupmenu.js</path-element>
+        <path-element>externs/goog/ui/progressbar.js</path-element>
+        <path-element>externs/goog/ui/prompt.js</path-element>
+        <path-element>externs/goog/ui/rangemodel.js</path-element>
+        <path-element>externs/goog/ui/ratings.js</path-element>
+        <path-element>externs/goog/ui/registry.js</path-element>
+        <path-element>externs/goog/ui/richtextspellchecker.js</path-element>
+        <path-element>externs/goog/ui/roundedpanel.js</path-element>
+        <path-element>externs/goog/ui/roundedtabrenderer.js</path-element>
+        <path-element>externs/goog/ui/scrollfloater.js</path-element>
+        <path-element>externs/goog/ui/select.js</path-element>
+        <path-element>externs/goog/ui/selectionmenubutton.js</path-element>
+        <path-element>externs/goog/ui/selectionmodel.js</path-element>
+        <path-element>externs/goog/ui/separator.js</path-element>
+        <path-element>externs/goog/ui/serverchart.js</path-element>
+        <path-element>externs/goog/ui/slider.js</path-element>
+        <path-element>externs/goog/ui/sliderbase.js</path-element>
+        <path-element>externs/goog/ui/splitbehavior.js</path-element>
+        <path-element>externs/goog/ui/splitpane.js</path-element>
+        <path-element>externs/goog/ui/submenu.js</path-element>
+        <path-element>externs/goog/ui/submenurenderer.js</path-element>
+        <path-element>externs/goog/ui/tab.js</path-element>
+        <path-element>externs/goog/ui/tabbar.js</path-element>
+        <path-element>externs/goog/ui/tabbarrenderer.js</path-element>
+        <path-element>externs/goog/ui/tablesorter.js</path-element>
+        <path-element>externs/goog/ui/tabpane.js</path-element>
+        <path-element>externs/goog/ui/tabrenderer.js</path-element>
+        <path-element>externs/goog/ui/textarea.js</path-element>
+        <path-element>externs/goog/ui/textarearenderer.js</path-element>
+        <path-element>externs/goog/ui/togglebutton.js</path-element>
+        <path-element>externs/goog/ui/toolbar.js</path-element>
+        <path-element>externs/goog/ui/toolbarbutton.js</path-element>
+        <path-element>externs/goog/ui/toolbarbuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/toolbarcolormenubutton.js</path-element>
+        <path-element>externs/goog/ui/toolbarcolormenubuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/toolbarmenubutton.js</path-element>
+        <path-element>externs/goog/ui/toolbarmenubuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/toolbarrenderer.js</path-element>
+        <path-element>externs/goog/ui/toolbarselect.js</path-element>
+        <path-element>externs/goog/ui/toolbarseparator.js</path-element>
+        <path-element>externs/goog/ui/toolbarseparatorrenderer.js</path-element>
+        <path-element>externs/goog/ui/toolbartogglebutton.js</path-element>
+        <path-element>externs/goog/ui/tooltip.js</path-element>
+        <path-element>externs/goog/ui/tristatemenuitem.js</path-element>
+        <path-element>externs/goog/ui/tristatemenuitemrenderer.js</path-element>
+        <path-element>externs/goog/ui/twothumbslider.js</path-element>
+        <path-element>externs/goog/ui/zippy.js</path-element>
+        <path-element>externs/goog/ui/ac/ac.js</path-element>
+        <path-element>externs/goog/ui/ac/arraymatcher.js</path-element>
+        <path-element>externs/goog/ui/ac/autocomplete.js</path-element>
+        <path-element>externs/goog/ui/ac/cachingmatcher.js</path-element>
+        <path-element>externs/goog/ui/ac/inputhandler.js</path-element>
+        <path-element>externs/goog/ui/ac/remote.js</path-element>
+        <path-element>externs/goog/ui/ac/remotearraymatcher.js</path-element>
+        <path-element>externs/goog/ui/ac/renderer.js</path-element>
+        <path-element>externs/goog/ui/ac/renderoptions.js</path-element>
+        <path-element>externs/goog/ui/ac/richinputhandler.js</path-element>
+        <path-element>externs/goog/ui/ac/richremote.js</path-element>
+        <path-element>externs/goog/ui/ac/richremotearraymatcher.js</path-element>
+        <path-element>externs/goog/ui/editor/abstractdialog.js</path-element>
+        <path-element>externs/goog/ui/editor/bubble.js</path-element>
+        <path-element>externs/goog/ui/editor/defaulttoolbar.js</path-element>
+        <path-element>externs/goog/ui/editor/linkdialog.js</path-element>
+        <path-element>externs/goog/ui/editor/messages.js</path-element>
+        <path-element>externs/goog/ui/editor/tabpane.js</path-element>
+        <path-element>externs/goog/ui/editor/toolbarcontroller.js</path-element>
+        <path-element>externs/goog/ui/editor/toolbarfactory.js</path-element>
+        <path-element>externs/goog/ui/emoji/emoji.js</path-element>
+        <path-element>externs/goog/ui/emoji/emojipalette.js</path-element>
+        <path-element>externs/goog/ui/emoji/emojipaletterenderer.js</path-element>
+        <path-element>externs/goog/ui/emoji/emojipicker.js</path-element>
+        <path-element>externs/goog/ui/emoji/popupemojipicker.js</path-element>
+        <path-element>externs/goog/ui/emoji/progressiveemojipaletterenderer.js</path-element>
+        <path-element>externs/goog/ui/emoji/spriteinfo.js</path-element>
+        <path-element>externs/goog/ui/media/flashobject.js</path-element>
+        <path-element>externs/goog/ui/media/flickr.js</path-element>
+        <path-element>externs/goog/ui/media/googlevideo.js</path-element>
+        <path-element>externs/goog/ui/media/media.js</path-element>
+        <path-element>externs/goog/ui/media/mediamodel.js</path-element>
+        <path-element>externs/goog/ui/media/mp3.js</path-element>
+        <path-element>externs/goog/ui/media/photo.js</path-element>
+        <path-element>externs/goog/ui/media/picasa.js</path-element>
+        <path-element>externs/goog/ui/media/vimeo.js</path-element>
+        <path-element>externs/goog/ui/media/youtube.js</path-element>
+        <path-element>externs/goog/ui/style/app/buttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/style/app/menubuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/style/app/primaryactionbuttonrenderer.js</path-element>
+        <path-element>externs/goog/ui/tree/basenode.js</path-element>
+        <path-element>externs/goog/ui/tree/treecontrol.js</path-element>
+        <path-element>externs/goog/ui/tree/treenode.js</path-element>
+        <path-element>externs/goog/ui/tree/typeahead.js</path-element>
+        <path-element>externs/goog/uri/uri.js</path-element>
+        <path-element>externs/goog/uri/utils.js</path-element>
+        <path-element>externs/goog/useragent/adobereader.js</path-element>
+        <path-element>externs/goog/useragent/flash.js</path-element>
+        <path-element>externs/goog/useragent/iphoto.js</path-element>
+        <path-element>externs/goog/useragent/jscript.js</path-element>
+        <path-element>externs/goog/useragent/keyboard.js</path-element>
+        <path-element>externs/goog/useragent/platform.js</path-element>
+        <path-element>externs/goog/useragent/product.js</path-element>
+        <path-element>externs/goog/useragent/product_isversion.js</path-element>
+        <path-element>externs/goog/useragent/useragent.js</path-element>
+        <path-element>externs/goog/vec/float32array.js</path-element>
+        <path-element>externs/goog/vec/float64array.js</path-element>
+        <path-element>externs/goog/vec/mat3.js</path-element>
+        <path-element>externs/goog/vec/mat3d.js</path-element>
+        <path-element>externs/goog/vec/mat3f.js</path-element>
+        <path-element>externs/goog/vec/mat4.js</path-element>
+        <path-element>externs/goog/vec/mat4d.js</path-element>
+        <path-element>externs/goog/vec/mat4f.js</path-element>
+        <path-element>externs/goog/vec/matrix3.js</path-element>
+        <path-element>externs/goog/vec/matrix4.js</path-element>
+        <path-element>externs/goog/vec/quaternion.js</path-element>
+        <path-element>externs/goog/vec/ray.js</path-element>
+        <path-element>externs/goog/vec/vec.js</path-element>
+        <path-element>externs/goog/vec/vec2.js</path-element>
+        <path-element>externs/goog/vec/vec2d.js</path-element>
+        <path-element>externs/goog/vec/vec2f.js</path-element>
+        <path-element>externs/goog/vec/vec3.js</path-element>
+        <path-element>externs/goog/vec/vec3d.js</path-element>
+        <path-element>externs/goog/vec/vec3f.js</path-element>
+        <path-element>externs/goog/vec/vec4.js</path-element>
+        <path-element>externs/goog/vec/vec4d.js</path-element>
+        <path-element>externs/goog/vec/vec4f.js</path-element>
+        <path-element>externs/goog/webgl/webgl.js</path-element>
+        <path-element>externs/goog/window/window.js</path-element>-->
+    </external>
+
+</flex-config>

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/compile-config.xml
----------------------------------------------------------------------
diff --git a/externs/GCL/compile-config.xml b/externs/GCL/compile-config.xml
new file mode 100644
index 0000000..e8b8911
--- /dev/null
+++ b/externs/GCL/compile-config.xml
@@ -0,0 +1,99 @@
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You 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.
+
+-->
+<flex-config>
+
+    <compiler>
+
+        <accessible>true</accessible>
+
+        <!--
+        <external-library-path>
+            <path-element>${env.PLAYERGLOBAL_HOME}/${playerglobal.version}/playerglobal.swc</path-element>
+            <path-element>../../libs/framework.swc</path-element>
+            <path-element>../../libs/mx/mx.swc</path-element>
+            <path-element>../../libs/osmf.swc</path-element>
+            <path-element>../../libs/textLayout.swc</path-element>
+        </external-library-path>
+
+        <keep-as3-metadata>
+            <name>SkinPart</name>
+        </keep-as3-metadata>
+
+        <mxml>
+            <minimum-supported-version>4.0.0</minimum-supported-version>
+        </mxml>
+
+        <locale/>
+
+        <library-path/>
+
+        <namespaces>
+            <namespace>
+                <uri>library://ns.adobe.com/flex/spark</uri>
+                <manifest>manifest.xml</manifest>
+            </namespace>
+        </namespaces>
+        -->
+
+        <source-path>
+            <path-element>src</path-element>
+            <!--<path-element>out/as/classes</path-element>
+            <path-element>out/as/interfaces</path-element>
+            <path-element>out/as/constants</path-element>
+            <path-element>out/as/functions</path-element>
+            <path-element>out/as/interfaces</path-element>
+            <path-element>out/as/typedefs</path-element>-->
+        </source-path>
+
+        <warn-no-constructor>false</warn-no-constructor>
+    </compiler>
+
+    <include-sources>
+            <path-element>src</path-element>
+        <!--<path-element>out/as/classes</path-element>
+        <path-element>out/as/interfaces</path-element>
+        <path-element>out/as/constants</path-element>
+        <path-element>out/as/functions</path-element>
+        <path-element>out/as/interfaces</path-element>
+        <path-element>out/as/typedefs</path-element>-->
+    </include-sources>
+
+    <!--
+    <include-file>
+        <name>defaults.css</name>
+        <path>defaults.css</path>
+    </include-file>
+    <include-file>
+        <name>assets/ErrorIndicator.png</name>
+        <path>assets/ErrorIndicator.png</path>
+    </include-file>
+    <include-file>
+        <name>assets/RequiredIndicator.png</name>
+        <path>assets/RequiredIndicator.png</path>
+    </include-file>
+
+    <include-namespaces>
+        <uri>library://ns.adobe.com/flex/spark</uri>
+    </include-namespaces>
+
+    <resource-bundle-list>bundles.properties</resource-bundle-list>
+
+    <target-player>${playerglobal.version}</target-player>
+     -->
+</flex-config>

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/a11y/aria/announcer.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/a11y/aria/announcer.js b/externs/GCL/externs/goog/a11y/aria/announcer.js
new file mode 100644
index 0000000..6818264
--- /dev/null
+++ b/externs/GCL/externs/goog/a11y/aria/announcer.js
@@ -0,0 +1,123 @@
+// 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 Announcer that allows messages to be spoken by assistive
+ * technologies.
+ */
+
+goog.provide('goog.a11y.aria.Announcer');
+
+goog.require('goog.Disposable');
+goog.require('goog.Timer');
+goog.require('goog.a11y.aria');
+goog.require('goog.a11y.aria.LivePriority');
+goog.require('goog.a11y.aria.State');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.object');
+
+
+
+/**
+ * Class that allows messages to be spoken by assistive technologies that the
+ * user may have active.
+ *
+ * @param {goog.dom.DomHelper=} opt_domHelper DOM helper.
+ * @constructor
+ * @extends {goog.Disposable}
+ * @final
+ */
+goog.a11y.aria.Announcer = function(opt_domHelper) {
+  goog.a11y.aria.Announcer.base(this, 'constructor');
+
+  /**
+   * @type {goog.dom.DomHelper}
+   * @private
+   */
+  this.domHelper_ = opt_domHelper || goog.dom.getDomHelper();
+
+  /**
+   * Map of priority to live region elements to use for communicating updates.
+   * Elements are created on demand.
+   * @type {Object<goog.a11y.aria.LivePriority, !Element>}
+   * @private
+   */
+  this.liveRegions_ = {};
+};
+goog.inherits(goog.a11y.aria.Announcer, goog.Disposable);
+
+
+/** @override */
+goog.a11y.aria.Announcer.prototype.disposeInternal = function() {
+  goog.object.forEach(
+      this.liveRegions_, this.domHelper_.removeNode, this.domHelper_);
+  this.liveRegions_ = null;
+  this.domHelper_ = null;
+  goog.a11y.aria.Announcer.base(this, 'disposeInternal');
+};
+
+
+/**
+ * Announce a message to be read by any assistive technologies the user may
+ * have active.
+ * @param {string} message The message to announce to screen readers.
+ * @param {goog.a11y.aria.LivePriority=} opt_priority The priority of the
+ *     message. Defaults to POLITE.
+ */
+goog.a11y.aria.Announcer.prototype.say = function(message, opt_priority) {
+  var priority = opt_priority || goog.a11y.aria.LivePriority.POLITE;
+  var liveRegion = this.getLiveRegion_(priority);
+  // Resets text content to force a DOM mutation (so that the setTextContent
+  // post-timeout function will be noticed by the screen reader). This is to
+  // avoid the problem of when the same message is "said" twice, which doesn't
+  // trigger a DOM mutation.
+  goog.dom.setTextContent(liveRegion, '');
+  // Uses non-zero timer to make VoiceOver and NVDA work
+  goog.Timer.callOnce(function() {
+    goog.dom.setTextContent(liveRegion, message);
+  }, 1);
+};
+
+
+/**
+ * Returns an aria-live region that can be used to communicate announcements.
+ * @param {!goog.a11y.aria.LivePriority} priority The required priority.
+ * @return {!Element} A live region of the requested priority.
+ * @private
+ */
+goog.a11y.aria.Announcer.prototype.getLiveRegion_ = function(priority) {
+  var liveRegion = this.liveRegions_[priority];
+  if (liveRegion) {
+    // Make sure the live region is not aria-hidden.
+    goog.a11y.aria.removeState(liveRegion, goog.a11y.aria.State.HIDDEN);
+    return liveRegion;
+  }
+
+  liveRegion = this.domHelper_.createElement(goog.dom.TagName.DIV);
+  // Note that IE has a habit of declaring things that aren't display:none as
+  // invisible to third-party tools like JAWs, so we can't just use height:0.
+  liveRegion.style.position = 'absolute';
+  liveRegion.style.top = '-1000px';
+  liveRegion.style.height = '1px';
+  liveRegion.style.overflow = 'hidden';
+  goog.a11y.aria.setState(liveRegion, goog.a11y.aria.State.LIVE,
+      priority);
+  goog.a11y.aria.setState(liveRegion, goog.a11y.aria.State.ATOMIC,
+      'true');
+  this.domHelper_.getDocument().body.appendChild(liveRegion);
+  this.liveRegions_[priority] = liveRegion;
+  return liveRegion;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/a11y/aria/aria.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/a11y/aria/aria.js b/externs/GCL/externs/goog/a11y/aria/aria.js
new file mode 100644
index 0000000..1220d23
--- /dev/null
+++ b/externs/GCL/externs/goog/a11y/aria/aria.js
@@ -0,0 +1,386 @@
+// 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 Utilities for adding, removing and setting ARIA roles and
+ * states as defined by W3C ARIA standard: http://www.w3.org/TR/wai-aria/
+ * All modern browsers have some form of ARIA support, so no browser checks are
+ * performed when adding ARIA to components.
+ *
+ */
+
+goog.provide('goog.a11y.aria');
+
+goog.require('goog.a11y.aria.Role');
+goog.require('goog.a11y.aria.State');
+goog.require('goog.a11y.aria.datatables');
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.object');
+goog.require('goog.string');
+
+
+/**
+ * ARIA states/properties prefix.
+ * @private
+ */
+goog.a11y.aria.ARIA_PREFIX_ = 'aria-';
+
+
+/**
+ * ARIA role attribute.
+ * @private
+ */
+goog.a11y.aria.ROLE_ATTRIBUTE_ = 'role';
+
+
+/**
+ * A list of tag names for which we don't need to set ARIA role and states
+ * because they have well supported semantics for screen readers or because
+ * they don't contain content to be made accessible.
+ * @private
+ */
+goog.a11y.aria.TAGS_WITH_ASSUMED_ROLES_ = [
+  goog.dom.TagName.A,
+  goog.dom.TagName.AREA,
+  goog.dom.TagName.BUTTON,
+  goog.dom.TagName.HEAD,
+  goog.dom.TagName.INPUT,
+  goog.dom.TagName.LINK,
+  goog.dom.TagName.MENU,
+  goog.dom.TagName.META,
+  goog.dom.TagName.OPTGROUP,
+  goog.dom.TagName.OPTION,
+  goog.dom.TagName.PROGRESS,
+  goog.dom.TagName.STYLE,
+  goog.dom.TagName.SELECT,
+  goog.dom.TagName.SOURCE,
+  goog.dom.TagName.TEXTAREA,
+  goog.dom.TagName.TITLE,
+  goog.dom.TagName.TRACK
+];
+
+
+/**
+ * Sets the role of an element. If the roleName is
+ * empty string or null, the role for the element is removed.
+ * We encourage clients to call the goog.a11y.aria.removeRole
+ * method instead of setting null and empty string values.
+ * Special handling for this case is added to ensure
+ * backword compatibility with existing code.
+ *
+ * @param {!Element} element DOM node to set role of.
+ * @param {!goog.a11y.aria.Role|string} roleName role name(s).
+ */
+goog.a11y.aria.setRole = function(element, roleName) {
+  if (!roleName) {
+    // Setting the ARIA role to empty string is not allowed
+    // by the ARIA standard.
+    goog.a11y.aria.removeRole(element);
+  } else {
+    if (goog.asserts.ENABLE_ASSERTS) {
+      goog.asserts.assert(goog.object.containsValue(
+          goog.a11y.aria.Role, roleName), 'No such ARIA role ' + roleName);
+    }
+    element.setAttribute(goog.a11y.aria.ROLE_ATTRIBUTE_, roleName);
+  }
+};
+
+
+/**
+ * Gets role of an element.
+ * @param {!Element} element DOM element to get role of.
+ * @return {goog.a11y.aria.Role} ARIA Role name.
+ */
+goog.a11y.aria.getRole = function(element) {
+  var role = element.getAttribute(goog.a11y.aria.ROLE_ATTRIBUTE_);
+  return /** @type {goog.a11y.aria.Role} */ (role) || null;
+};
+
+
+/**
+ * Removes role of an element.
+ * @param {!Element} element DOM element to remove the role from.
+ */
+goog.a11y.aria.removeRole = function(element) {
+  element.removeAttribute(goog.a11y.aria.ROLE_ATTRIBUTE_);
+};
+
+
+/**
+ * Sets the state or property of an element.
+ * @param {!Element} element DOM node where we set state.
+ * @param {!(goog.a11y.aria.State|string)} stateName State attribute being set.
+ *     Automatically adds prefix 'aria-' to the state name if the attribute is
+ *     not an extra attribute.
+ * @param {string|boolean|number|!Array<string>} value Value
+ * for the state attribute.
+ */
+goog.a11y.aria.setState = function(element, stateName, value) {
+  if (goog.isArray(value)) {
+    value = value.join(' ');
+  }
+  var attrStateName = goog.a11y.aria.getAriaAttributeName_(stateName);
+  if (value === '' || value == undefined) {
+    var defaultValueMap = goog.a11y.aria.datatables.getDefaultValuesMap();
+    // Work around for browsers that don't properly support ARIA.
+    // According to the ARIA W3C standard, user agents should allow
+    // setting empty value which results in setting the default value
+    // for the ARIA state if such exists. The exact text from the ARIA W3C
+    // standard (http://www.w3.org/TR/wai-aria/states_and_properties):
+    // "When a value is indicated as the default, the user agent
+    // MUST follow the behavior prescribed by this value when the state or
+    // property is empty or undefined."
+    // The defaultValueMap contains the default values for the ARIA states
+    // and has as a key the goog.a11y.aria.State constant for the state.
+    if (stateName in defaultValueMap) {
+      element.setAttribute(attrStateName, defaultValueMap[stateName]);
+    } else {
+      element.removeAttribute(attrStateName);
+    }
+  } else {
+    element.setAttribute(attrStateName, value);
+  }
+};
+
+
+/**
+ * Toggles the ARIA attribute of an element.
+ * Meant for attributes with a true/false value, but works with any attribute.
+ * If the attribute does not have a true/false value, the following rules apply:
+ * A not empty attribute will be removed.
+ * An empty attribute will be set to true.
+ * @param {!Element} el DOM node for which to set attribute.
+ * @param {!(goog.a11y.aria.State|string)} attr ARIA attribute being set.
+ *     Automatically adds prefix 'aria-' to the attribute name if the attribute
+ *     is not an extra attribute.
+ */
+goog.a11y.aria.toggleState = function(el, attr) {
+  var val = goog.a11y.aria.getState(el, attr);
+  if (!goog.string.isEmptyOrWhitespace(goog.string.makeSafe(val)) &&
+      !(val == 'true' || val == 'false')) {
+    goog.a11y.aria.removeState(el, /** @type {!goog.a11y.aria.State} */ (attr));
+    return;
+  }
+  goog.a11y.aria.setState(el, attr, val == 'true' ? 'false' : 'true');
+};
+
+
+/**
+ * Remove the state or property for the element.
+ * @param {!Element} element DOM node where we set state.
+ * @param {!goog.a11y.aria.State} stateName State name.
+ */
+goog.a11y.aria.removeState = function(element, stateName) {
+  element.removeAttribute(goog.a11y.aria.getAriaAttributeName_(stateName));
+};
+
+
+/**
+ * Gets value of specified state or property.
+ * @param {!Element} element DOM node to get state from.
+ * @param {!goog.a11y.aria.State|string} stateName State name.
+ * @return {string} Value of the state attribute.
+ */
+goog.a11y.aria.getState = function(element, stateName) {
+  // TODO(user): return properly typed value result --
+  // boolean, number, string, null. We should be able to chain
+  // getState(...) and setState(...) methods.
+
+  var attr =
+      /** @type {string|number|boolean} */ (element.getAttribute(
+      goog.a11y.aria.getAriaAttributeName_(stateName)));
+  var isNullOrUndefined = attr == null || attr == undefined;
+  return isNullOrUndefined ? '' : String(attr);
+};
+
+
+/**
+ * Returns the activedescendant element for the input element by
+ * using the activedescendant ARIA property of the given element.
+ * @param {!Element} element DOM node to get activedescendant
+ *     element for.
+ * @return {?Element} DOM node of the activedescendant, if found.
+ */
+goog.a11y.aria.getActiveDescendant = function(element) {
+  var id = goog.a11y.aria.getState(
+      element, goog.a11y.aria.State.ACTIVEDESCENDANT);
+  return goog.dom.getOwnerDocument(element).getElementById(id);
+};
+
+
+/**
+ * Sets the activedescendant ARIA property value for an element.
+ * If the activeElement is not null, it should have an id set.
+ * @param {!Element} element DOM node to set activedescendant ARIA property to.
+ * @param {?Element} activeElement DOM node being set as activedescendant.
+ */
+goog.a11y.aria.setActiveDescendant = function(element, activeElement) {
+  var id = '';
+  if (activeElement) {
+    id = activeElement.id;
+    goog.asserts.assert(id, 'The active element should have an id.');
+  }
+
+  goog.a11y.aria.setState(element, goog.a11y.aria.State.ACTIVEDESCENDANT, id);
+};
+
+
+/**
+ * Gets the label of the given element.
+ * @param {!Element} element DOM node to get label from.
+ * @return {string} label The label.
+ */
+goog.a11y.aria.getLabel = function(element) {
+  return goog.a11y.aria.getState(element, goog.a11y.aria.State.LABEL);
+};
+
+
+/**
+ * Sets the label of the given element.
+ * @param {!Element} element DOM node to set label to.
+ * @param {string} label The label to set.
+ */
+goog.a11y.aria.setLabel = function(element, label) {
+  goog.a11y.aria.setState(element, goog.a11y.aria.State.LABEL, label);
+};
+
+
+/**
+ * Asserts that the element has a role set if it's not an HTML element whose
+ * semantics is well supported by most screen readers.
+ * Only to be used internally by the ARIA library in goog.a11y.aria.*.
+ * @param {!Element} element The element to assert an ARIA role set.
+ * @param {!goog.array.ArrayLike<string>} allowedRoles The child roles of
+ * the roles.
+ */
+goog.a11y.aria.assertRoleIsSetInternalUtil = function(element, allowedRoles) {
+  if (goog.array.contains(goog.a11y.aria.TAGS_WITH_ASSUMED_ROLES_,
+      element.tagName)) {
+    return;
+  }
+  var elementRole = /** @type {string}*/ (goog.a11y.aria.getRole(element));
+  goog.asserts.assert(elementRole != null,
+      'The element ARIA role cannot be null.');
+
+  goog.asserts.assert(goog.array.contains(allowedRoles, elementRole),
+      'Non existing or incorrect role set for element.' +
+      'The role set is "' + elementRole +
+      '". The role should be any of "' + allowedRoles +
+      '". Check the ARIA specification for more details ' +
+      'http://www.w3.org/TR/wai-aria/roles.');
+};
+
+
+/**
+ * Gets the boolean value of an ARIA state/property.
+ * @param {!Element} element The element to get the ARIA state for.
+ * @param {!goog.a11y.aria.State|string} stateName the ARIA state name.
+ * @return {?boolean} Boolean value for the ARIA state value or null if
+ *     the state value is not 'true', not 'false', or not set.
+ */
+goog.a11y.aria.getStateBoolean = function(element, stateName) {
+  var attr =
+      /** @type {string|boolean} */ (element.getAttribute(
+          goog.a11y.aria.getAriaAttributeName_(stateName)));
+  goog.asserts.assert(
+      goog.isBoolean(attr) || attr == null || attr == 'true' ||
+          attr == 'false');
+  if (attr == null) {
+    return attr;
+  }
+  return goog.isBoolean(attr) ? attr : attr == 'true';
+};
+
+
+/**
+ * Gets the number value of an ARIA state/property.
+ * @param {!Element} element The element to get the ARIA state for.
+ * @param {!goog.a11y.aria.State|string} stateName the ARIA state name.
+ * @return {?number} Number value for the ARIA state value or null if
+ *     the state value is not a number or not set.
+ */
+goog.a11y.aria.getStateNumber = function(element, stateName) {
+  var attr =
+      /** @type {string|number} */ (element.getAttribute(
+          goog.a11y.aria.getAriaAttributeName_(stateName)));
+  goog.asserts.assert((attr == null || !isNaN(Number(attr))) &&
+      !goog.isBoolean(attr));
+  return attr == null ? null : Number(attr);
+};
+
+
+/**
+ * Gets the string value of an ARIA state/property.
+ * @param {!Element} element The element to get the ARIA state for.
+ * @param {!goog.a11y.aria.State|string} stateName the ARIA state name.
+ * @return {?string} String value for the ARIA state value or null if
+ *     the state value is empty string or not set.
+ */
+goog.a11y.aria.getStateString = function(element, stateName) {
+  var attr = element.getAttribute(
+      goog.a11y.aria.getAriaAttributeName_(stateName));
+  goog.asserts.assert((attr == null || goog.isString(attr)) &&
+      isNaN(Number(attr)) && attr != 'true' && attr != 'false');
+  return attr == null ? null : attr;
+};
+
+
+/**
+ * Gets array of strings value of the specified state or
+ * property for the element.
+ * Only to be used internally by the ARIA library in goog.a11y.aria.*.
+ * @param {!Element} element DOM node to get state from.
+ * @param {!goog.a11y.aria.State} stateName State name.
+ * @return {!goog.array.ArrayLike<string>} string Array
+ *     value of the state attribute.
+ */
+goog.a11y.aria.getStringArrayStateInternalUtil = function(element, stateName) {
+  var attrValue = element.getAttribute(
+      goog.a11y.aria.getAriaAttributeName_(stateName));
+  return goog.a11y.aria.splitStringOnWhitespace_(attrValue);
+};
+
+
+/**
+ * Splits the input stringValue on whitespace.
+ * @param {string} stringValue The value of the string to split.
+ * @return {!goog.array.ArrayLike<string>} string Array
+ *     value as result of the split.
+ * @private
+ */
+goog.a11y.aria.splitStringOnWhitespace_ = function(stringValue) {
+  return stringValue ? stringValue.split(/\s+/) : [];
+};
+
+
+/**
+ * Adds the 'aria-' prefix to ariaName.
+ * @param {string} ariaName ARIA state/property name.
+ * @private
+ * @return {string} The ARIA attribute name with added 'aria-' prefix.
+ * @throws {Error} If no such attribute exists.
+ */
+goog.a11y.aria.getAriaAttributeName_ = function(ariaName) {
+  if (goog.asserts.ENABLE_ASSERTS) {
+    goog.asserts.assert(ariaName, 'ARIA attribute cannot be empty.');
+    goog.asserts.assert(goog.object.containsValue(
+        goog.a11y.aria.State, ariaName),
+        'No such ARIA attribute ' + ariaName);
+  }
+  return goog.a11y.aria.ARIA_PREFIX_ + ariaName;
+};


[12/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/transitionbase.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/transitionbase.js b/externs/GCL/externs/goog/fx/transitionbase.js
new file mode 100644
index 0000000..0a2c184
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/transitionbase.js
@@ -0,0 +1,236 @@
+// Copyright 2011 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 An abstract base class for transitions. This is a simple
+ * interface that allows for playing, pausing and stopping an animation. It adds
+ * a simple event model, and animation status.
+ */
+goog.provide('goog.fx.TransitionBase');
+goog.provide('goog.fx.TransitionBase.State');
+
+goog.require('goog.events.EventTarget');
+goog.require('goog.fx.Transition');  // Unreferenced: interface
+
+
+
+/**
+ * Constructor for a transition object.
+ *
+ * @constructor
+ * @implements {goog.fx.Transition}
+ * @extends {goog.events.EventTarget}
+ */
+goog.fx.TransitionBase = function() {
+  goog.fx.TransitionBase.base(this, 'constructor');
+
+  /**
+   * The internal state of the animation.
+   * @type {goog.fx.TransitionBase.State}
+   * @private
+   */
+  this.state_ = goog.fx.TransitionBase.State.STOPPED;
+
+  /**
+   * Timestamp for when the animation was started.
+   * @type {?number}
+   * @protected
+   */
+  this.startTime = null;
+
+  /**
+   * Timestamp for when the animation finished or was stopped.
+   * @type {?number}
+   * @protected
+   */
+  this.endTime = null;
+};
+goog.inherits(goog.fx.TransitionBase, goog.events.EventTarget);
+
+
+/**
+ * Enum for the possible states of an animation.
+ * @enum {number}
+ */
+goog.fx.TransitionBase.State = {
+  STOPPED: 0,
+  PAUSED: -1,
+  PLAYING: 1
+};
+
+
+/**
+ * Plays the animation.
+ *
+ * @param {boolean=} opt_restart Optional parameter to restart the animation.
+ * @return {boolean} True iff the animation was started.
+ * @override
+ */
+goog.fx.TransitionBase.prototype.play = goog.abstractMethod;
+
+
+/**
+ * Stops the animation.
+ *
+ * @param {boolean=} opt_gotoEnd Optional boolean parameter to go the the end of
+ *     the animation.
+ * @override
+ */
+goog.fx.TransitionBase.prototype.stop = goog.abstractMethod;
+
+
+/**
+ * Pauses the animation.
+ */
+goog.fx.TransitionBase.prototype.pause = goog.abstractMethod;
+
+
+/**
+ * Returns the current state of the animation.
+ * @return {goog.fx.TransitionBase.State} State of the animation.
+ */
+goog.fx.TransitionBase.prototype.getStateInternal = function() {
+  return this.state_;
+};
+
+
+/**
+ * Sets the current state of the animation to playing.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.setStatePlaying = function() {
+  this.state_ = goog.fx.TransitionBase.State.PLAYING;
+};
+
+
+/**
+ * Sets the current state of the animation to paused.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.setStatePaused = function() {
+  this.state_ = goog.fx.TransitionBase.State.PAUSED;
+};
+
+
+/**
+ * Sets the current state of the animation to stopped.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.setStateStopped = function() {
+  this.state_ = goog.fx.TransitionBase.State.STOPPED;
+};
+
+
+/**
+ * @return {boolean} True iff the current state of the animation is playing.
+ */
+goog.fx.TransitionBase.prototype.isPlaying = function() {
+  return this.state_ == goog.fx.TransitionBase.State.PLAYING;
+};
+
+
+/**
+ * @return {boolean} True iff the current state of the animation is paused.
+ */
+goog.fx.TransitionBase.prototype.isPaused = function() {
+  return this.state_ == goog.fx.TransitionBase.State.PAUSED;
+};
+
+
+/**
+ * @return {boolean} True iff the current state of the animation is stopped.
+ */
+goog.fx.TransitionBase.prototype.isStopped = function() {
+  return this.state_ == goog.fx.TransitionBase.State.STOPPED;
+};
+
+
+/**
+ * Dispatches the BEGIN event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onBegin = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.BEGIN);
+};
+
+
+/**
+ * Dispatches the END event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onEnd = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.END);
+};
+
+
+/**
+ * Dispatches the FINISH event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onFinish = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.FINISH);
+};
+
+
+/**
+ * Dispatches the PAUSE event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onPause = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.PAUSE);
+};
+
+
+/**
+ * Dispatches the PLAY event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onPlay = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.PLAY);
+};
+
+
+/**
+ * Dispatches the RESUME event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onResume = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.RESUME);
+};
+
+
+/**
+ * Dispatches the STOP event. Sub classes should override this instead
+ * of listening to the event, and call this instead of dispatching the event.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.onStop = function() {
+  this.dispatchAnimationEvent(goog.fx.Transition.EventType.STOP);
+};
+
+
+/**
+ * Dispatches an event object for the current animation.
+ * @param {string} type Event type that will be dispatched.
+ * @protected
+ */
+goog.fx.TransitionBase.prototype.dispatchAnimationEvent = function(type) {
+  this.dispatchEvent(type);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/abstractgraphics.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/abstractgraphics.js b/externs/GCL/externs/goog/graphics/abstractgraphics.js
new file mode 100644
index 0000000..0ae1776
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/abstractgraphics.js
@@ -0,0 +1,454 @@
+// 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 Graphics utility functions and factory methods.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.AbstractGraphics');
+
+goog.require('goog.dom');
+goog.require('goog.graphics.Path');
+goog.require('goog.math.Coordinate');
+goog.require('goog.math.Size');
+goog.require('goog.style');
+goog.require('goog.ui.Component');
+
+
+
+/**
+ * Base class for the different graphics. You should never construct objects
+ * of this class. Instead us goog.graphics.createGraphics
+ * @param {number|string} width The width in pixels or percent.
+ * @param {number|string} height The height in pixels or percent.
+ * @param {?number=} opt_coordWidth Optional coordinate system width - if
+ *     omitted or null, defaults to same as width.
+ * @param {?number=} opt_coordHeight Optional coordinate system height - if
+ *     omitted or null, defaults to same as height.
+ * @param {goog.dom.DomHelper=} opt_domHelper The DOM helper object for the
+ *     document we want to render in.
+ * @constructor
+ * @extends {goog.ui.Component}
+ */
+goog.graphics.AbstractGraphics = function(width, height,
+                                          opt_coordWidth, opt_coordHeight,
+                                          opt_domHelper) {
+  goog.ui.Component.call(this, opt_domHelper);
+
+  /**
+   * Width of graphics in pixels or percentage points.
+   * @type {number|string}
+   * @protected
+   */
+  this.width = width;
+
+  /**
+   * Height of graphics in pixels or precentage points.
+   * @type {number|string}
+   * @protected
+   */
+  this.height = height;
+
+  /**
+   * Width of coordinate system in units.
+   * @type {?number}
+   * @protected
+   */
+  this.coordWidth = opt_coordWidth || null;
+
+  /**
+   * Height of coordinate system in units.
+   * @type {?number}
+   * @protected
+   */
+  this.coordHeight = opt_coordHeight || null;
+};
+goog.inherits(goog.graphics.AbstractGraphics, goog.ui.Component);
+
+
+/**
+ * The root level group element.
+ * @type {goog.graphics.GroupElement?}
+ * @protected
+ */
+goog.graphics.AbstractGraphics.prototype.canvasElement = null;
+
+
+/**
+ * Left coordinate of the view box
+ * @type {number}
+ * @protected
+ */
+goog.graphics.AbstractGraphics.prototype.coordLeft = 0;
+
+
+/**
+ * Top coordinate of the view box
+ * @type {number}
+ * @protected
+ */
+goog.graphics.AbstractGraphics.prototype.coordTop = 0;
+
+
+/**
+ * @return {goog.graphics.GroupElement} The root level canvas element.
+ */
+goog.graphics.AbstractGraphics.prototype.getCanvasElement = function() {
+  return this.canvasElement;
+};
+
+
+/**
+ * Changes the coordinate size.
+ * @param {number} coordWidth  The coordinate width.
+ * @param {number} coordHeight  The coordinate height.
+ */
+goog.graphics.AbstractGraphics.prototype.setCoordSize = function(coordWidth,
+                                                                 coordHeight) {
+  this.coordWidth = coordWidth;
+  this.coordHeight = coordHeight;
+};
+
+
+/**
+ * @return {goog.math.Size} The coordinate size.
+ */
+goog.graphics.AbstractGraphics.prototype.getCoordSize = function() {
+  if (this.coordWidth) {
+    return new goog.math.Size(this.coordWidth,
+        /** @type {number} */ (this.coordHeight));
+  } else {
+    return this.getPixelSize();
+  }
+};
+
+
+/**
+ * Changes the coordinate system position.
+ * @param {number} left  The coordinate system left bound.
+ * @param {number} top  The coordinate system top bound.
+ */
+goog.graphics.AbstractGraphics.prototype.setCoordOrigin = goog.abstractMethod;
+
+
+/**
+ * @return {!goog.math.Coordinate} The coordinate system position.
+ */
+goog.graphics.AbstractGraphics.prototype.getCoordOrigin = function() {
+  return new goog.math.Coordinate(this.coordLeft, this.coordTop);
+};
+
+
+/**
+ * Change the size of the canvas.
+ * @param {number} pixelWidth  The width in pixels.
+ * @param {number} pixelHeight  The height in pixels.
+ */
+goog.graphics.AbstractGraphics.prototype.setSize = goog.abstractMethod;
+
+
+/**
+ * @return {goog.math.Size} The size of canvas.
+ * @deprecated Use getPixelSize.
+ */
+goog.graphics.AbstractGraphics.prototype.getSize = function() {
+  return this.getPixelSize();
+};
+
+
+/**
+ * @return {goog.math.Size?} Returns the number of pixels spanned by the
+ *     surface, or null if the size could not be computed due to the size being
+ *     specified in percentage points and the component not being in the
+ *     document.
+ */
+goog.graphics.AbstractGraphics.prototype.getPixelSize = function() {
+  if (this.isInDocument()) {
+    return goog.style.getSize(this.getElement());
+  }
+  if (goog.isNumber(this.width) && goog.isNumber(this.height)) {
+    return new goog.math.Size(this.width, this.height);
+  }
+  return null;
+};
+
+
+/**
+ * @return {number} Returns the number of pixels per unit in the x direction.
+ */
+goog.graphics.AbstractGraphics.prototype.getPixelScaleX = function() {
+  var pixelSize = this.getPixelSize();
+  return pixelSize ? pixelSize.width / this.getCoordSize().width : 0;
+};
+
+
+/**
+ * @return {number} Returns the number of pixels per unit in the y direction.
+ */
+goog.graphics.AbstractGraphics.prototype.getPixelScaleY = function() {
+  var pixelSize = this.getPixelSize();
+  return pixelSize ? pixelSize.height / this.getCoordSize().height : 0;
+};
+
+
+/**
+ * Remove all drawing elements from the graphics.
+ */
+goog.graphics.AbstractGraphics.prototype.clear = goog.abstractMethod;
+
+
+/**
+ * Remove a single drawing element from the surface.  The default implementation
+ * assumes a DOM based drawing surface.
+ * @param {goog.graphics.Element} element The element to remove.
+ */
+goog.graphics.AbstractGraphics.prototype.removeElement = function(element) {
+  goog.dom.removeNode(element.getElement());
+};
+
+
+/**
+ * Sets the fill for the given element.
+ * @param {goog.graphics.StrokeAndFillElement} element The element wrapper.
+ * @param {goog.graphics.Fill?} fill The fill object.
+ */
+goog.graphics.AbstractGraphics.prototype.setElementFill = goog.abstractMethod;
+
+
+/**
+ * Sets the stroke for the given element.
+ * @param {goog.graphics.StrokeAndFillElement} element The element wrapper.
+ * @param {goog.graphics.Stroke?} stroke The stroke object.
+ */
+goog.graphics.AbstractGraphics.prototype.setElementStroke = goog.abstractMethod;
+
+
+/**
+ * Set the transformation of an element.
+ *
+ * If a more general affine transform is needed than this provides
+ * (e.g. skew and scale) then use setElementAffineTransform.
+ * @param {goog.graphics.Element} element The element wrapper.
+ * @param {number} x The x coordinate of the translation transform.
+ * @param {number} y The y coordinate of the translation transform.
+ * @param {number} angle The angle of the rotation transform.
+ * @param {number} centerX The horizontal center of the rotation transform.
+ * @param {number} centerY The vertical center of the rotation transform.
+ */
+goog.graphics.AbstractGraphics.prototype.setElementTransform =
+    goog.abstractMethod;
+
+
+/**
+ * Set the affine transform of an element.
+ * @param {!goog.graphics.Element} element The element wrapper.
+ * @param {!goog.graphics.AffineTransform} affineTransform The
+ *     transformation applied to this element.
+ */
+goog.graphics.AbstractGraphics.prototype.setElementAffineTransform =
+    goog.abstractMethod;
+
+
+/**
+ * Draw a circle
+ *
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @param {number} r Radius length.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.EllipseElement} The newly created element.
+ */
+goog.graphics.AbstractGraphics.prototype.drawCircle = function(
+    cx, cy, r, stroke, fill, opt_group) {
+  return this.drawEllipse(cx, cy, r, r, stroke, fill, opt_group);
+};
+
+
+/**
+ * Draw an ellipse
+ *
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @param {number} rx Radius length for the x-axis.
+ * @param {number} ry Radius length for the y-axis.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.EllipseElement} The newly created element.
+ */
+goog.graphics.AbstractGraphics.prototype.drawEllipse = goog.abstractMethod;
+
+
+/**
+ * Draw a rectangle
+ *
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.RectElement} The newly created element.
+ */
+goog.graphics.AbstractGraphics.prototype.drawRect = goog.abstractMethod;
+
+
+/**
+ * Draw a text string within a rectangle (drawing is horizontal)
+ *
+ * @param {string} text The text to draw.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @param {string} align Horizontal alignment: left (default), center, right.
+ * @param {string} vAlign Vertical alignment: top (default), center, bottom.
+ * @param {goog.graphics.Font} font Font describing the font properties.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill  Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.TextElement} The newly created element.
+ */
+goog.graphics.AbstractGraphics.prototype.drawText = function(
+    text, x, y, width, height, align, vAlign, font, stroke, fill, opt_group) {
+  var baseline = font.size / 2; // Baseline is middle of line
+  var textY;
+  if (vAlign == 'bottom') {
+    textY = y + height - baseline;
+  } else if (vAlign == 'center') {
+    textY = y + height / 2;
+  } else {
+    textY = y + baseline;
+  }
+
+  return this.drawTextOnLine(text, x, textY, x + width, textY, align,
+      font, stroke, fill, opt_group);
+};
+
+
+/**
+ * Draw a text string vertically centered on a given line.
+ *
+ * @param {string} text  The text to draw.
+ * @param {number} x1 X coordinate of start of line.
+ * @param {number} y1 Y coordinate of start of line.
+ * @param {number} x2 X coordinate of end of line.
+ * @param {number} y2 Y coordinate of end of line.
+ * @param {string} align Horizontal alingnment: left (default), center, right.
+ * @param {goog.graphics.Font} font Font describing the font properties.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.TextElement} The newly created element.
+ */
+goog.graphics.AbstractGraphics.prototype.drawTextOnLine = goog.abstractMethod;
+
+
+/**
+ * Draw a path.
+ *
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.PathElement} The newly created element.
+ */
+goog.graphics.AbstractGraphics.prototype.drawPath = goog.abstractMethod;
+
+
+/**
+ * Create an empty group of drawing elements.
+ *
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element to
+ *     append to. If not specified, appends to the main canvas.
+ *
+ * @return {goog.graphics.GroupElement} The newly created group.
+ */
+goog.graphics.AbstractGraphics.prototype.createGroup = goog.abstractMethod;
+
+
+/**
+ * Create an empty path.
+ *
+ * @return {!goog.graphics.Path} The path.
+ * @deprecated Use {@code new goog.graphics.Path()}.
+ */
+goog.graphics.AbstractGraphics.prototype.createPath = function() {
+  return new goog.graphics.Path();
+};
+
+
+/**
+ * Measure and return the width (in pixels) of a given text string.
+ * Text measurement is needed to make sure a text can fit in the allocated
+ * area. The way text length is measured is by writing it into a div that is
+ * after the visible area, measure the div width, and immediatly erase the
+ * written value.
+ *
+ * @param {string} text The text string to measure.
+ * @param {goog.graphics.Font} font The font object describing the font style.
+ *
+ * @return {number} The width in pixels of the text strings.
+ */
+goog.graphics.AbstractGraphics.prototype.getTextWidth = goog.abstractMethod;
+
+
+/**
+ * @return {boolean} Whether the underlying element can be cloned resulting in
+ *     an accurate reproduction of the graphics contents.
+ */
+goog.graphics.AbstractGraphics.prototype.isDomClonable = function() {
+  return false;
+};
+
+
+/**
+ * Start preventing redraws - useful for chaining large numbers of changes
+ * together.  Not guaranteed to do anything - i.e. only use this for
+ * optimization of a single code path.
+ */
+goog.graphics.AbstractGraphics.prototype.suspend = function() {
+};
+
+
+/**
+ * Stop preventing redraws.  If any redraws had been prevented, a redraw will
+ * be done now.
+ */
+goog.graphics.AbstractGraphics.prototype.resume = function() {
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/affinetransform.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/affinetransform.js b/externs/GCL/externs/goog/graphics/affinetransform.js
new file mode 100644
index 0000000..ec328f2
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/affinetransform.js
@@ -0,0 +1,588 @@
+// Copyright 2008 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 Provides an object representation of an AffineTransform and
+ * methods for working with it.
+ */
+
+
+goog.provide('goog.graphics.AffineTransform');
+
+goog.require('goog.math');
+
+
+
+/**
+ * Creates a 2D affine transform. An affine transform performs a linear
+ * mapping from 2D coordinates to other 2D coordinates that preserves the
+ * "straightness" and "parallelness" of lines.
+ *
+ * Such a coordinate transformation can be represented by a 3 row by 3 column
+ * matrix with an implied last row of [ 0 0 1 ]. This matrix transforms source
+ * coordinates (x,y) into destination coordinates (x',y') by considering them
+ * to be a column vector and multiplying the coordinate vector by the matrix
+ * according to the following process:
+ * <pre>
+ *      [ x']   [  m00  m01  m02  ] [ x ]   [ m00x + m01y + m02 ]
+ *      [ y'] = [  m10  m11  m12  ] [ y ] = [ m10x + m11y + m12 ]
+ *      [ 1 ]   [   0    0    1   ] [ 1 ]   [         1         ]
+ * </pre>
+ *
+ * This class is optimized for speed and minimizes calculations based on its
+ * knowledge of the underlying matrix (as opposed to say simply performing
+ * matrix multiplication).
+ *
+ * @param {number=} opt_m00 The m00 coordinate of the transform.
+ * @param {number=} opt_m10 The m10 coordinate of the transform.
+ * @param {number=} opt_m01 The m01 coordinate of the transform.
+ * @param {number=} opt_m11 The m11 coordinate of the transform.
+ * @param {number=} opt_m02 The m02 coordinate of the transform.
+ * @param {number=} opt_m12 The m12 coordinate of the transform.
+ * @constructor
+ * @final
+ */
+goog.graphics.AffineTransform = function(opt_m00, opt_m10, opt_m01,
+    opt_m11, opt_m02, opt_m12) {
+  if (arguments.length == 6) {
+    this.setTransform(/** @type {number} */ (opt_m00),
+                      /** @type {number} */ (opt_m10),
+                      /** @type {number} */ (opt_m01),
+                      /** @type {number} */ (opt_m11),
+                      /** @type {number} */ (opt_m02),
+                      /** @type {number} */ (opt_m12));
+  } else if (arguments.length != 0) {
+    throw Error('Insufficient matrix parameters');
+  } else {
+    this.m00_ = this.m11_ = 1;
+    this.m10_ = this.m01_ = this.m02_ = this.m12_ = 0;
+  }
+};
+
+
+/**
+ * @return {boolean} Whether this transform is the identity transform.
+ */
+goog.graphics.AffineTransform.prototype.isIdentity = function() {
+  return this.m00_ == 1 && this.m10_ == 0 && this.m01_ == 0 &&
+      this.m11_ == 1 && this.m02_ == 0 && this.m12_ == 0;
+};
+
+
+/**
+ * @return {!goog.graphics.AffineTransform} A copy of this transform.
+ */
+goog.graphics.AffineTransform.prototype.clone = function() {
+  return new goog.graphics.AffineTransform(this.m00_, this.m10_, this.m01_,
+      this.m11_, this.m02_, this.m12_);
+};
+
+
+/**
+ * Sets this transform to the matrix specified by the 6 values.
+ *
+ * @param {number} m00 The m00 coordinate of the transform.
+ * @param {number} m10 The m10 coordinate of the transform.
+ * @param {number} m01 The m01 coordinate of the transform.
+ * @param {number} m11 The m11 coordinate of the transform.
+ * @param {number} m02 The m02 coordinate of the transform.
+ * @param {number} m12 The m12 coordinate of the transform.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.setTransform = function(m00, m10, m01,
+    m11, m02, m12) {
+  if (!goog.isNumber(m00) || !goog.isNumber(m10) || !goog.isNumber(m01) ||
+      !goog.isNumber(m11) || !goog.isNumber(m02) || !goog.isNumber(m12)) {
+    throw Error('Invalid transform parameters');
+  }
+  this.m00_ = m00;
+  this.m10_ = m10;
+  this.m01_ = m01;
+  this.m11_ = m11;
+  this.m02_ = m02;
+  this.m12_ = m12;
+  return this;
+};
+
+
+/**
+ * Sets this transform to be identical to the given transform.
+ *
+ * @param {!goog.graphics.AffineTransform} tx The transform to copy.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.copyFrom = function(tx) {
+  this.m00_ = tx.m00_;
+  this.m10_ = tx.m10_;
+  this.m01_ = tx.m01_;
+  this.m11_ = tx.m11_;
+  this.m02_ = tx.m02_;
+  this.m12_ = tx.m12_;
+  return this;
+};
+
+
+/**
+ * Concatenates this transform with a scaling transformation.
+ *
+ * @param {number} sx The x-axis scaling factor.
+ * @param {number} sy The y-axis scaling factor.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.scale = function(sx, sy) {
+  this.m00_ *= sx;
+  this.m10_ *= sx;
+  this.m01_ *= sy;
+  this.m11_ *= sy;
+  return this;
+};
+
+
+/**
+ * Pre-concatenates this transform with a scaling transformation,
+ * i.e. calculates the following matrix product:
+ *
+ * <pre>
+ * [sx  0 0] [m00 m01 m02]
+ * [ 0 sy 0] [m10 m11 m12]
+ * [ 0  0 1] [  0   0   1]
+ * </pre>
+ *
+ * @param {number} sx The x-axis scaling factor.
+ * @param {number} sy The y-axis scaling factor.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.preScale = function(sx, sy) {
+  this.m00_ *= sx;
+  this.m01_ *= sx;
+  this.m02_ *= sx;
+  this.m10_ *= sy;
+  this.m11_ *= sy;
+  this.m12_ *= sy;
+  return this;
+};
+
+
+/**
+ * Concatenates this transform with a translate transformation.
+ *
+ * @param {number} dx The distance to translate in the x direction.
+ * @param {number} dy The distance to translate in the y direction.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.translate = function(dx, dy) {
+  this.m02_ += dx * this.m00_ + dy * this.m01_;
+  this.m12_ += dx * this.m10_ + dy * this.m11_;
+  return this;
+};
+
+
+/**
+ * Pre-concatenates this transform with a translate transformation,
+ * i.e. calculates the following matrix product:
+ *
+ * <pre>
+ * [1 0 dx] [m00 m01 m02]
+ * [0 1 dy] [m10 m11 m12]
+ * [0 0  1] [  0   0   1]
+ * </pre>
+ *
+ * @param {number} dx The distance to translate in the x direction.
+ * @param {number} dy The distance to translate in the y direction.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.preTranslate = function(dx, dy) {
+  this.m02_ += dx;
+  this.m12_ += dy;
+  return this;
+};
+
+
+/**
+ * Concatenates this transform with a rotation transformation around an anchor
+ * point.
+ *
+ * @param {number} theta The angle of rotation measured in radians.
+ * @param {number} x The x coordinate of the anchor point.
+ * @param {number} y The y coordinate of the anchor point.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.rotate = function(theta, x, y) {
+  return this.concatenate(
+      goog.graphics.AffineTransform.getRotateInstance(theta, x, y));
+};
+
+
+/**
+ * Pre-concatenates this transform with a rotation transformation around an
+ * anchor point.
+ *
+ * @param {number} theta The angle of rotation measured in radians.
+ * @param {number} x The x coordinate of the anchor point.
+ * @param {number} y The y coordinate of the anchor point.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.preRotate = function(theta, x, y) {
+  return this.preConcatenate(
+      goog.graphics.AffineTransform.getRotateInstance(theta, x, y));
+};
+
+
+/**
+ * Concatenates this transform with a shear transformation.
+ *
+ * @param {number} shx The x shear factor.
+ * @param {number} shy The y shear factor.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.shear = function(shx, shy) {
+  var m00 = this.m00_;
+  var m10 = this.m10_;
+  this.m00_ += shy * this.m01_;
+  this.m10_ += shy * this.m11_;
+  this.m01_ += shx * m00;
+  this.m11_ += shx * m10;
+  return this;
+};
+
+
+/**
+ * Pre-concatenates this transform with a shear transformation.
+ * i.e. calculates the following matrix product:
+ *
+ * <pre>
+ * [  1 shx 0] [m00 m01 m02]
+ * [shy   1 0] [m10 m11 m12]
+ * [  0   0 1] [  0   0   1]
+ * </pre>
+ *
+ * @param {number} shx The x shear factor.
+ * @param {number} shy The y shear factor.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.preShear = function(shx, shy) {
+  var m00 = this.m00_;
+  var m01 = this.m01_;
+  var m02 = this.m02_;
+  this.m00_ += shx * this.m10_;
+  this.m01_ += shx * this.m11_;
+  this.m02_ += shx * this.m12_;
+  this.m10_ += shy * m00;
+  this.m11_ += shy * m01;
+  this.m12_ += shy * m02;
+  return this;
+};
+
+
+/**
+ * @return {string} A string representation of this transform. The format of
+ *     of the string is compatible with SVG matrix notation, i.e.
+ *     "matrix(a,b,c,d,e,f)".
+ * @override
+ */
+goog.graphics.AffineTransform.prototype.toString = function() {
+  return 'matrix(' +
+      [this.m00_, this.m10_, this.m01_, this.m11_, this.m02_, this.m12_].join(
+          ',') +
+      ')';
+};
+
+
+/**
+ * @return {number} The scaling factor in the x-direction (m00).
+ */
+goog.graphics.AffineTransform.prototype.getScaleX = function() {
+  return this.m00_;
+};
+
+
+/**
+ * @return {number} The scaling factor in the y-direction (m11).
+ */
+goog.graphics.AffineTransform.prototype.getScaleY = function() {
+  return this.m11_;
+};
+
+
+/**
+ * @return {number} The translation in the x-direction (m02).
+ */
+goog.graphics.AffineTransform.prototype.getTranslateX = function() {
+  return this.m02_;
+};
+
+
+/**
+ * @return {number} The translation in the y-direction (m12).
+ */
+goog.graphics.AffineTransform.prototype.getTranslateY = function() {
+  return this.m12_;
+};
+
+
+/**
+ * @return {number} The shear factor in the x-direction (m01).
+ */
+goog.graphics.AffineTransform.prototype.getShearX = function() {
+  return this.m01_;
+};
+
+
+/**
+ * @return {number} The shear factor in the y-direction (m10).
+ */
+goog.graphics.AffineTransform.prototype.getShearY = function() {
+  return this.m10_;
+};
+
+
+/**
+ * Concatenates an affine transform to this transform.
+ *
+ * @param {!goog.graphics.AffineTransform} tx The transform to concatenate.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.concatenate = function(tx) {
+  var m0 = this.m00_;
+  var m1 = this.m01_;
+  this.m00_ = tx.m00_ * m0 + tx.m10_ * m1;
+  this.m01_ = tx.m01_ * m0 + tx.m11_ * m1;
+  this.m02_ += tx.m02_ * m0 + tx.m12_ * m1;
+
+  m0 = this.m10_;
+  m1 = this.m11_;
+  this.m10_ = tx.m00_ * m0 + tx.m10_ * m1;
+  this.m11_ = tx.m01_ * m0 + tx.m11_ * m1;
+  this.m12_ += tx.m02_ * m0 + tx.m12_ * m1;
+  return this;
+};
+
+
+/**
+ * Pre-concatenates an affine transform to this transform.
+ *
+ * @param {!goog.graphics.AffineTransform} tx The transform to preconcatenate.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.preConcatenate = function(tx) {
+  var m0 = this.m00_;
+  var m1 = this.m10_;
+  this.m00_ = tx.m00_ * m0 + tx.m01_ * m1;
+  this.m10_ = tx.m10_ * m0 + tx.m11_ * m1;
+
+  m0 = this.m01_;
+  m1 = this.m11_;
+  this.m01_ = tx.m00_ * m0 + tx.m01_ * m1;
+  this.m11_ = tx.m10_ * m0 + tx.m11_ * m1;
+
+  m0 = this.m02_;
+  m1 = this.m12_;
+  this.m02_ = tx.m00_ * m0 + tx.m01_ * m1 + tx.m02_;
+  this.m12_ = tx.m10_ * m0 + tx.m11_ * m1 + tx.m12_;
+  return this;
+};
+
+
+/**
+ * Transforms an array of coordinates by this transform and stores the result
+ * into a destination array.
+ *
+ * @param {!Array<number>} src The array containing the source points
+ *     as x, y value pairs.
+ * @param {number} srcOff The offset to the first point to be transformed.
+ * @param {!Array<number>} dst The array into which to store the transformed
+ *     point pairs.
+ * @param {number} dstOff The offset of the location of the first transformed
+ *     point in the destination array.
+ * @param {number} numPts The number of points to tranform.
+ */
+goog.graphics.AffineTransform.prototype.transform = function(src, srcOff, dst,
+    dstOff, numPts) {
+  var i = srcOff;
+  var j = dstOff;
+  var srcEnd = srcOff + 2 * numPts;
+  while (i < srcEnd) {
+    var x = src[i++];
+    var y = src[i++];
+    dst[j++] = x * this.m00_ + y * this.m01_ + this.m02_;
+    dst[j++] = x * this.m10_ + y * this.m11_ + this.m12_;
+  }
+};
+
+
+/**
+ * @return {number} The determinant of this transform.
+ */
+goog.graphics.AffineTransform.prototype.getDeterminant = function() {
+  return this.m00_ * this.m11_ - this.m01_ * this.m10_;
+};
+
+
+/**
+ * Returns whether the transform is invertible. A transform is not invertible
+ * if the determinant is 0 or any value is non-finite or NaN.
+ *
+ * @return {boolean} Whether the transform is invertible.
+ */
+goog.graphics.AffineTransform.prototype.isInvertible = function() {
+  var det = this.getDeterminant();
+  return goog.math.isFiniteNumber(det) &&
+      goog.math.isFiniteNumber(this.m02_) &&
+      goog.math.isFiniteNumber(this.m12_) &&
+      det != 0;
+};
+
+
+/**
+ * @return {!goog.graphics.AffineTransform} An AffineTransform object
+ *     representing the inverse transformation.
+ */
+goog.graphics.AffineTransform.prototype.createInverse = function() {
+  var det = this.getDeterminant();
+  return new goog.graphics.AffineTransform(
+      this.m11_ / det,
+      -this.m10_ / det,
+      -this.m01_ / det,
+      this.m00_ / det,
+      (this.m01_ * this.m12_ - this.m11_ * this.m02_) / det,
+      (this.m10_ * this.m02_ - this.m00_ * this.m12_) / det);
+};
+
+
+/**
+ * Creates a transform representing a scaling transformation.
+ *
+ * @param {number} sx The x-axis scaling factor.
+ * @param {number} sy The y-axis scaling factor.
+ * @return {!goog.graphics.AffineTransform} A transform representing a scaling
+ *     transformation.
+ */
+goog.graphics.AffineTransform.getScaleInstance = function(sx, sy) {
+  return new goog.graphics.AffineTransform().setToScale(sx, sy);
+};
+
+
+/**
+ * Creates a transform representing a translation transformation.
+ *
+ * @param {number} dx The distance to translate in the x direction.
+ * @param {number} dy The distance to translate in the y direction.
+ * @return {!goog.graphics.AffineTransform} A transform representing a
+ *     translation transformation.
+ */
+goog.graphics.AffineTransform.getTranslateInstance = function(dx, dy) {
+  return new goog.graphics.AffineTransform().setToTranslation(dx, dy);
+};
+
+
+/**
+ * Creates a transform representing a shearing transformation.
+ *
+ * @param {number} shx The x-axis shear factor.
+ * @param {number} shy The y-axis shear factor.
+ * @return {!goog.graphics.AffineTransform} A transform representing a shearing
+ *     transformation.
+ */
+goog.graphics.AffineTransform.getShearInstance = function(shx, shy) {
+  return new goog.graphics.AffineTransform().setToShear(shx, shy);
+};
+
+
+/**
+ * Creates a transform representing a rotation transformation.
+ *
+ * @param {number} theta The angle of rotation measured in radians.
+ * @param {number} x The x coordinate of the anchor point.
+ * @param {number} y The y coordinate of the anchor point.
+ * @return {!goog.graphics.AffineTransform} A transform representing a rotation
+ *     transformation.
+ */
+goog.graphics.AffineTransform.getRotateInstance = function(theta, x, y) {
+  return new goog.graphics.AffineTransform().setToRotation(theta, x, y);
+};
+
+
+/**
+ * Sets this transform to a scaling transformation.
+ *
+ * @param {number} sx The x-axis scaling factor.
+ * @param {number} sy The y-axis scaling factor.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.setToScale = function(sx, sy) {
+  return this.setTransform(sx, 0, 0, sy, 0, 0);
+};
+
+
+/**
+ * Sets this transform to a translation transformation.
+ *
+ * @param {number} dx The distance to translate in the x direction.
+ * @param {number} dy The distance to translate in the y direction.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.setToTranslation = function(dx, dy) {
+  return this.setTransform(1, 0, 0, 1, dx, dy);
+};
+
+
+/**
+ * Sets this transform to a shearing transformation.
+ *
+ * @param {number} shx The x-axis shear factor.
+ * @param {number} shy The y-axis shear factor.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.setToShear = function(shx, shy) {
+  return this.setTransform(1, shy, shx, 1, 0, 0);
+};
+
+
+/**
+ * Sets this transform to a rotation transformation.
+ *
+ * @param {number} theta The angle of rotation measured in radians.
+ * @param {number} x The x coordinate of the anchor point.
+ * @param {number} y The y coordinate of the anchor point.
+ * @return {!goog.graphics.AffineTransform} This affine transform.
+ */
+goog.graphics.AffineTransform.prototype.setToRotation = function(theta, x, y) {
+  var cos = Math.cos(theta);
+  var sin = Math.sin(theta);
+  return this.setTransform(cos, sin, -sin, cos,
+      x - x * cos + y * sin, y - x * sin - y * cos);
+};
+
+
+/**
+ * Compares two affine transforms for equality.
+ *
+ * @param {goog.graphics.AffineTransform} tx The other affine transform.
+ * @return {boolean} whether the two transforms are equal.
+ */
+goog.graphics.AffineTransform.prototype.equals = function(tx) {
+  if (this == tx) {
+    return true;
+  }
+  if (!tx) {
+    return false;
+  }
+  return this.m00_ == tx.m00_ &&
+      this.m01_ == tx.m01_ &&
+      this.m02_ == tx.m02_ &&
+      this.m10_ == tx.m10_ &&
+      this.m11_ == tx.m11_ &&
+      this.m12_ == tx.m12_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/canvaselement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/canvaselement.js b/externs/GCL/externs/goog/graphics/canvaselement.js
new file mode 100644
index 0000000..6c400db
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/canvaselement.js
@@ -0,0 +1,812 @@
+// 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 Objects representing shapes drawn on a canvas.
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.graphics.CanvasEllipseElement');
+goog.provide('goog.graphics.CanvasGroupElement');
+goog.provide('goog.graphics.CanvasImageElement');
+goog.provide('goog.graphics.CanvasPathElement');
+goog.provide('goog.graphics.CanvasRectElement');
+goog.provide('goog.graphics.CanvasTextElement');
+
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.safe');
+goog.require('goog.graphics.EllipseElement');
+goog.require('goog.graphics.GroupElement');
+goog.require('goog.graphics.ImageElement');
+goog.require('goog.graphics.Path');
+goog.require('goog.graphics.PathElement');
+goog.require('goog.graphics.RectElement');
+goog.require('goog.graphics.TextElement');
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.uncheckedconversions');
+goog.require('goog.math');
+goog.require('goog.string');
+goog.require('goog.string.Const');
+
+
+
+/**
+ * Object representing a group of objects in a canvas.
+ * This is an implementation of the goog.graphics.GroupElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {goog.graphics.CanvasGraphics} graphics The graphics creating
+ *     this element.
+ * @constructor
+ * @extends {goog.graphics.GroupElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.CanvasGroupElement = function(graphics) {
+  goog.graphics.GroupElement.call(this, null, graphics);
+
+
+  /**
+   * Children contained by this group.
+   * @type {Array<goog.graphics.Element>}
+   * @private
+   */
+  this.children_ = [];
+};
+goog.inherits(goog.graphics.CanvasGroupElement, goog.graphics.GroupElement);
+
+
+/**
+ * Remove all drawing elements from the group.
+ * @override
+ */
+goog.graphics.CanvasGroupElement.prototype.clear = function() {
+  if (this.children_.length) {
+    this.children_.length = 0;
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Set the size of the group element.
+ * @param {number|string} width The width of the group element.
+ * @param {number|string} height The height of the group element.
+ * @override
+ */
+goog.graphics.CanvasGroupElement.prototype.setSize = function(width, height) {
+  // Do nothing.
+};
+
+
+/**
+ * Append a child to the group.  Does not draw it
+ * @param {goog.graphics.Element} element The child to append.
+ */
+goog.graphics.CanvasGroupElement.prototype.appendChild = function(element) {
+  this.children_.push(element);
+};
+
+
+/**
+ * Draw the group.
+ * @param {CanvasRenderingContext2D} ctx The context to draw the element in.
+ */
+goog.graphics.CanvasGroupElement.prototype.draw = function(ctx) {
+  for (var i = 0, len = this.children_.length; i < len; i++) {
+    this.getGraphics().drawElement(this.children_[i]);
+  }
+};
+
+
+
+/**
+ * Thin wrapper for canvas ellipse elements.
+ * This is an implementation of the goog.graphics.EllipseElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.CanvasGraphics} graphics  The graphics creating
+ *     this element.
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @param {number} rx Radius length for the x-axis.
+ * @param {number} ry Radius length for the y-axis.
+ * @param {goog.graphics.Stroke} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.EllipseElement}
+ * @final
+ */
+goog.graphics.CanvasEllipseElement = function(element, graphics,
+    cx, cy, rx, ry, stroke, fill) {
+  goog.graphics.EllipseElement.call(this, element, graphics, stroke, fill);
+
+  /**
+   * X coordinate of the ellipse center.
+   * @type {number}
+   * @private
+   */
+  this.cx_ = cx;
+
+
+  /**
+   * Y coordinate of the ellipse center.
+   * @type {number}
+   * @private
+   */
+  this.cy_ = cy;
+
+
+  /**
+   * Radius length for the x-axis.
+   * @type {number}
+   * @private
+   */
+  this.rx_ = rx;
+
+
+  /**
+   * Radius length for the y-axis.
+   * @type {number}
+   * @private
+   */
+  this.ry_ = ry;
+
+
+  /**
+   * Internal path approximating an ellipse.
+   * @type {goog.graphics.Path}
+   * @private
+   */
+  this.path_ = new goog.graphics.Path();
+  this.setUpPath_();
+
+  /**
+   * Internal path element that actually does the drawing.
+   * @type {goog.graphics.CanvasPathElement}
+   * @private
+   */
+  this.pathElement_ = new goog.graphics.CanvasPathElement(null, graphics,
+      this.path_, stroke, fill);
+};
+goog.inherits(goog.graphics.CanvasEllipseElement, goog.graphics.EllipseElement);
+
+
+/**
+ * Sets up the path.
+ * @private
+ */
+goog.graphics.CanvasEllipseElement.prototype.setUpPath_ = function() {
+  this.path_.clear();
+  this.path_.moveTo(this.cx_ + goog.math.angleDx(0, this.rx_),
+                    this.cy_ + goog.math.angleDy(0, this.ry_));
+  this.path_.arcTo(this.rx_, this.ry_, 0, 360);
+  this.path_.close();
+};
+
+
+/**
+ * Update the center point of the ellipse.
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @override
+ */
+goog.graphics.CanvasEllipseElement.prototype.setCenter = function(cx, cy) {
+  this.cx_ = cx;
+  this.cy_ = cy;
+  this.setUpPath_();
+  this.pathElement_.setPath(/** @type {!goog.graphics.Path} */ (this.path_));
+};
+
+
+/**
+ * Update the radius of the ellipse.
+ * @param {number} rx Center X coordinate.
+ * @param {number} ry Center Y coordinate.
+ * @override
+ */
+goog.graphics.CanvasEllipseElement.prototype.setRadius = function(rx, ry) {
+  this.rx_ = rx;
+  this.ry_ = ry;
+  this.setUpPath_();
+  this.pathElement_.setPath(/** @type {!goog.graphics.Path} */ (this.path_));
+};
+
+
+/**
+ * Draw the ellipse.  Should be treated as package scope.
+ * @param {CanvasRenderingContext2D} ctx The context to draw the element in.
+ */
+goog.graphics.CanvasEllipseElement.prototype.draw = function(ctx) {
+  this.pathElement_.draw(ctx);
+};
+
+
+
+/**
+ * Thin wrapper for canvas rectangle elements.
+ * This is an implementation of the goog.graphics.RectElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.CanvasGraphics} graphics The graphics creating
+ *     this element.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} w Width of rectangle.
+ * @param {number} h Height of rectangle.
+ * @param {goog.graphics.Stroke} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.RectElement}
+ * @final
+ */
+goog.graphics.CanvasRectElement = function(element, graphics, x, y, w, h,
+    stroke, fill) {
+  goog.graphics.RectElement.call(this, element, graphics, stroke, fill);
+
+  /**
+   * X coordinate of the top left corner.
+   * @type {number}
+   * @private
+   */
+  this.x_ = x;
+
+
+  /**
+   * Y coordinate of the top left corner.
+   * @type {number}
+   * @private
+   */
+  this.y_ = y;
+
+
+  /**
+   * Width of the rectangle.
+   * @type {number}
+   * @private
+   */
+  this.w_ = w;
+
+
+  /**
+   * Height of the rectangle.
+   * @type {number}
+   * @private
+   */
+  this.h_ = h;
+};
+goog.inherits(goog.graphics.CanvasRectElement, goog.graphics.RectElement);
+
+
+/**
+ * Update the position of the rectangle.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @override
+ */
+goog.graphics.CanvasRectElement.prototype.setPosition = function(x, y) {
+  this.x_ = x;
+  this.y_ = y;
+  if (this.drawn_) {
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Whether the rectangle has been drawn yet.
+ * @type {boolean}
+ * @private
+ */
+goog.graphics.CanvasRectElement.prototype.drawn_ = false;
+
+
+/**
+ * Update the size of the rectangle.
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @override
+ */
+goog.graphics.CanvasRectElement.prototype.setSize = function(width, height) {
+  this.w_ = width;
+  this.h_ = height;
+  if (this.drawn_) {
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Draw the rectangle.  Should be treated as package scope.
+ * @param {CanvasRenderingContext2D} ctx The context to draw the element in.
+ */
+goog.graphics.CanvasRectElement.prototype.draw = function(ctx) {
+  this.drawn_ = true;
+  ctx.beginPath();
+  ctx.moveTo(this.x_, this.y_);
+  ctx.lineTo(this.x_, this.y_ + this.h_);
+  ctx.lineTo(this.x_ + this.w_, this.y_ + this.h_);
+  ctx.lineTo(this.x_ + this.w_, this.y_);
+  ctx.closePath();
+};
+
+
+
+/**
+ * Thin wrapper for canvas path elements.
+ * This is an implementation of the goog.graphics.PathElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.CanvasGraphics} graphics The graphics creating
+ *     this element.
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @param {goog.graphics.Stroke} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.PathElement}
+ * @final
+ */
+goog.graphics.CanvasPathElement = function(element, graphics, path, stroke,
+    fill) {
+  goog.graphics.PathElement.call(this, element, graphics, stroke, fill);
+
+  this.setPath(path);
+};
+goog.inherits(goog.graphics.CanvasPathElement, goog.graphics.PathElement);
+
+
+/**
+ * Whether the shape has been drawn yet.
+ * @type {boolean}
+ * @private
+ */
+goog.graphics.CanvasPathElement.prototype.drawn_ = false;
+
+
+/**
+ * The path to draw.
+ * @type {goog.graphics.Path}
+ * @private
+ */
+goog.graphics.CanvasPathElement.prototype.path_;
+
+
+/**
+ * Update the underlying path.
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @override
+ */
+goog.graphics.CanvasPathElement.prototype.setPath = function(path) {
+  this.path_ = path.isSimple() ? path :
+      goog.graphics.Path.createSimplifiedPath(path);
+  if (this.drawn_) {
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Draw the path.  Should be treated as package scope.
+ * @param {CanvasRenderingContext2D} ctx The context to draw the element in.
+ * @suppress {deprecated} goog.graphics is deprecated.
+ */
+goog.graphics.CanvasPathElement.prototype.draw = function(ctx) {
+  this.drawn_ = true;
+
+  ctx.beginPath();
+  this.path_.forEachSegment(function(segment, args) {
+    switch (segment) {
+      case goog.graphics.Path.Segment.MOVETO:
+        ctx.moveTo(args[0], args[1]);
+        break;
+      case goog.graphics.Path.Segment.LINETO:
+        for (var i = 0; i < args.length; i += 2) {
+          ctx.lineTo(args[i], args[i + 1]);
+        }
+        break;
+      case goog.graphics.Path.Segment.CURVETO:
+        for (var i = 0; i < args.length; i += 6) {
+          ctx.bezierCurveTo(args[i], args[i + 1], args[i + 2],
+              args[i + 3], args[i + 4], args[i + 5]);
+        }
+        break;
+      case goog.graphics.Path.Segment.ARCTO:
+        throw Error('Canvas paths cannot contain arcs');
+      case goog.graphics.Path.Segment.CLOSE:
+        ctx.closePath();
+        break;
+    }
+  });
+};
+
+
+
+/**
+ * Thin wrapper for canvas text elements.
+ * This is an implementation of the goog.graphics.TextElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {!goog.graphics.CanvasGraphics} graphics The graphics creating
+ *     this element.
+ * @param {string} text The text to draw.
+ * @param {number} x1 X coordinate of start of line.
+ * @param {number} y1 Y coordinate of start of line.
+ * @param {number} x2 X coordinate of end of line.
+ * @param {number} y2 Y coordinate of end of line.
+ * @param {?string} align Horizontal alignment: left (default), center, right.
+ * @param {!goog.graphics.Font} font Font describing the font properties.
+ * @param {goog.graphics.Stroke} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.TextElement}
+ * @final
+ */
+goog.graphics.CanvasTextElement = function(graphics, text, x1, y1, x2, y2,
+    align, font, stroke, fill) {
+  var element = goog.dom.createDom(goog.dom.TagName.DIV, {
+    'style': 'display:table;position:absolute;padding:0;margin:0;border:0'
+  });
+  goog.graphics.TextElement.call(this, element, graphics, stroke, fill);
+
+  /**
+   * The text to draw.
+   * @type {string}
+   * @private
+   */
+  this.text_ = text;
+
+  /**
+   * X coordinate of the start of the line the text is drawn on.
+   * @type {number}
+   * @private
+   */
+  this.x1_ = x1;
+
+  /**
+   * Y coordinate of the start of the line the text is drawn on.
+   * @type {number}
+   * @private
+   */
+  this.y1_ = y1;
+
+  /**
+   * X coordinate of the end of the line the text is drawn on.
+   * @type {number}
+   * @private
+   */
+  this.x2_ = x2;
+
+  /**
+   * Y coordinate of the end of the line the text is drawn on.
+   * @type {number}
+   * @private
+   */
+  this.y2_ = y2;
+
+  /**
+   * Horizontal alignment: left (default), center, right.
+   * @type {string}
+   * @private
+   */
+  this.align_ = align || 'left';
+
+  /**
+   * Font object describing the font properties.
+   * @type {goog.graphics.Font}
+   * @private
+   */
+  this.font_ = font;
+
+  /**
+   * The inner element that contains the text.
+   * @type {Element}
+   * @private
+   */
+  this.innerElement_ = goog.dom.createDom(goog.dom.TagName.DIV, {
+    'style': 'display:table-cell;padding: 0;margin: 0;border: 0'
+  });
+
+  this.updateStyle_();
+  this.updateText_();
+
+  // Append to the DOM.
+  graphics.getElement().appendChild(element);
+  element.appendChild(this.innerElement_);
+};
+goog.inherits(goog.graphics.CanvasTextElement, goog.graphics.TextElement);
+
+
+/**
+ * Update the displayed text of the element.
+ * @param {string} text The text to draw.
+ * @override
+ */
+goog.graphics.CanvasTextElement.prototype.setText = function(text) {
+  this.text_ = text;
+  this.updateText_();
+};
+
+
+/**
+ * Sets the fill for this element.
+ * @param {goog.graphics.Fill} fill The fill object.
+ * @override
+ */
+goog.graphics.CanvasTextElement.prototype.setFill = function(fill) {
+  this.fill = fill;
+  var element = this.getElement();
+  if (element) {
+    element.style.color = fill.getColor() || fill.getColor1();
+  }
+};
+
+
+/**
+ * Sets the stroke for this element.
+ * @param {goog.graphics.Stroke} stroke The stroke object.
+ * @override
+ */
+goog.graphics.CanvasTextElement.prototype.setStroke = function(stroke) {
+  // Ignore stroke
+};
+
+
+/**
+ * Draw the text.  Should be treated as package scope.
+ * @param {CanvasRenderingContext2D} ctx The context to draw the element in.
+ */
+goog.graphics.CanvasTextElement.prototype.draw = function(ctx) {
+  // Do nothing - the text is already drawn.
+};
+
+
+/**
+ * Update the styles of the DIVs.
+ * @private
+ */
+goog.graphics.CanvasTextElement.prototype.updateStyle_ = function() {
+  var x1 = this.x1_;
+  var x2 = this.x2_;
+  var y1 = this.y1_;
+  var y2 = this.y2_;
+  var align = this.align_;
+  var font = this.font_;
+  var style = this.getElement().style;
+  var scaleX = this.getGraphics().getPixelScaleX();
+  var scaleY = this.getGraphics().getPixelScaleY();
+
+  if (x1 == x2) {
+    // Special case vertical text
+    style.lineHeight = '90%';
+
+    this.innerElement_.style.verticalAlign = align == 'center' ? 'middle' :
+        align == 'left' ? (y1 < y2 ? 'top' : 'bottom') :
+        y1 < y2 ? 'bottom' : 'top';
+    style.textAlign = 'center';
+
+    var w = font.size * scaleX;
+    style.top = Math.round(Math.min(y1, y2) * scaleY) + 'px';
+    style.left = Math.round((x1 - w / 2) * scaleX) + 'px';
+    style.width = Math.round(w) + 'px';
+    style.height = Math.abs(y1 - y2) * scaleY + 'px';
+
+    style.fontSize = font.size * 0.6 * scaleY + 'pt';
+  } else {
+    style.lineHeight = '100%';
+    this.innerElement_.style.verticalAlign = 'top';
+    style.textAlign = align;
+
+    style.top = Math.round(((y1 + y2) / 2 - font.size * 2 / 3) * scaleY) + 'px';
+    style.left = Math.round(x1 * scaleX) + 'px';
+    style.width = Math.round(Math.abs(x2 - x1) * scaleX) + 'px';
+    style.height = 'auto';
+
+    style.fontSize = font.size * scaleY + 'pt';
+  }
+
+  style.fontWeight = font.bold ? 'bold' : 'normal';
+  style.fontStyle = font.italic ? 'italic' : 'normal';
+  style.fontFamily = font.family;
+
+  var fill = this.getFill();
+  style.color = fill.getColor() || fill.getColor1();
+};
+
+
+/**
+ * Update the text content.
+ * @private
+ */
+goog.graphics.CanvasTextElement.prototype.updateText_ = function() {
+  if (this.x1_ == this.x2_) {
+    // Special case vertical text
+    var html =
+        goog.array.map(
+            this.text_.split(''),
+            function(entry) { return goog.string.htmlEscape(entry); })
+        .join('<br>');
+    // Creating a SafeHtml for each character would be quite expensive, and it's
+    // obvious that this is safe, so an unchecked conversion is appropriate.
+    var safeHtml = goog.html.uncheckedconversions
+        .safeHtmlFromStringKnownToSatisfyTypeContract(
+            goog.string.Const.from('Concatenate escaped chars and <br>'),
+            html);
+    goog.dom.safe.setInnerHtml(
+        /** @type {!Element} */ (this.innerElement_), safeHtml);
+  } else {
+    goog.dom.safe.setInnerHtml(
+        /** @type {!Element} */ (this.innerElement_),
+        goog.html.SafeHtml.htmlEscape(this.text_));
+  }
+};
+
+
+
+/**
+ * Thin wrapper for canvas image elements.
+ * This is an implementation of the goog.graphics.ImageElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.CanvasGraphics} graphics The graphics creating
+ *     this element.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} w Width of rectangle.
+ * @param {number} h Height of rectangle.
+ * @param {string} src Source of the image.
+ * @constructor
+ * @extends {goog.graphics.ImageElement}
+ * @final
+ */
+goog.graphics.CanvasImageElement = function(element, graphics, x, y, w, h,
+    src) {
+  goog.graphics.ImageElement.call(this, element, graphics);
+
+  /**
+   * X coordinate of the top left corner.
+   * @type {number}
+   * @private
+   */
+  this.x_ = x;
+
+
+  /**
+   * Y coordinate of the top left corner.
+   * @type {number}
+   * @private
+   */
+  this.y_ = y;
+
+
+  /**
+   * Width of the rectangle.
+   * @type {number}
+   * @private
+   */
+  this.w_ = w;
+
+
+  /**
+   * Height of the rectangle.
+   * @type {number}
+   * @private
+   */
+  this.h_ = h;
+
+
+  /**
+   * URL of the image source.
+   * @type {string}
+   * @private
+   */
+  this.src_ = src;
+};
+goog.inherits(goog.graphics.CanvasImageElement, goog.graphics.ImageElement);
+
+
+/**
+ * Whether the image has been drawn yet.
+ * @type {boolean}
+ * @private
+ */
+goog.graphics.CanvasImageElement.prototype.drawn_ = false;
+
+
+/**
+ * Update the position of the image.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @override
+ */
+goog.graphics.CanvasImageElement.prototype.setPosition = function(x, y) {
+  this.x_ = x;
+  this.y_ = y;
+  if (this.drawn_) {
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Update the size of the image.
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @override
+ */
+goog.graphics.CanvasImageElement.prototype.setSize = function(width, height) {
+  this.w_ = width;
+  this.h_ = height;
+  if (this.drawn_) {
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Update the source of the image.
+ * @param {string} src Source of the image.
+ * @override
+ */
+goog.graphics.CanvasImageElement.prototype.setSource = function(src) {
+  this.src_ = src;
+  if (this.drawn_) {
+    // TODO(robbyw): Probably need to reload the image here.
+    this.getGraphics().redraw();
+  }
+};
+
+
+/**
+ * Draw the image.  Should be treated as package scope.
+ * @param {CanvasRenderingContext2D} ctx The context to draw the element in.
+ */
+goog.graphics.CanvasImageElement.prototype.draw = function(ctx) {
+  if (this.img_) {
+    if (this.w_ && this.h_) {
+      // If the image is already loaded, draw it.
+      ctx.drawImage(this.img_, this.x_, this.y_, this.w_, this.h_);
+    }
+    this.drawn_ = true;
+
+  } else {
+    // Otherwise, load it.
+    var img = new Image();
+    img.onload = goog.bind(this.handleImageLoad_, this, img);
+    // TODO(robbyw): Handle image load errors.
+    img.src = this.src_;
+  }
+};
+
+
+/**
+ * Handle an image load.
+ * @param {Element} img The image element that finished loading.
+ * @private
+ */
+goog.graphics.CanvasImageElement.prototype.handleImageLoad_ = function(img) {
+  this.img_ = img;
+
+  // TODO(robbyw): Add a small delay to catch batched images
+  this.getGraphics().redraw();
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/canvasgraphics.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/canvasgraphics.js b/externs/GCL/externs/goog/graphics/canvasgraphics.js
new file mode 100644
index 0000000..2c55938
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/canvasgraphics.js
@@ -0,0 +1,670 @@
+// 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 CanvasGraphics sub class that uses the canvas tag for drawing.
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.graphics.CanvasGraphics');
+
+
+goog.require('goog.dom.TagName');
+goog.require('goog.events.EventType');
+goog.require('goog.graphics.AbstractGraphics');
+goog.require('goog.graphics.CanvasEllipseElement');
+goog.require('goog.graphics.CanvasGroupElement');
+goog.require('goog.graphics.CanvasImageElement');
+goog.require('goog.graphics.CanvasPathElement');
+goog.require('goog.graphics.CanvasRectElement');
+goog.require('goog.graphics.CanvasTextElement');
+goog.require('goog.graphics.SolidFill');
+goog.require('goog.math.Size');
+goog.require('goog.style');
+
+
+
+/**
+ * A Graphics implementation for drawing using canvas.
+ * @param {string|number} width The (non-zero) width in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {string|number} height The (non-zero) height in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {?number=} opt_coordWidth The coordinate width - if
+ *     omitted or null, defaults to same as width.
+ * @param {?number=} opt_coordHeight The coordinate height - if
+ *     omitted or null, defaults to same as height.
+ * @param {goog.dom.DomHelper=} opt_domHelper The DOM helper object for the
+ *     document we want to render in.
+ * @constructor
+ * @extends {goog.graphics.AbstractGraphics}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.CanvasGraphics = function(width, height,
+                                        opt_coordWidth, opt_coordHeight,
+                                        opt_domHelper) {
+  goog.graphics.AbstractGraphics.call(this, width, height,
+                                      opt_coordWidth, opt_coordHeight,
+                                      opt_domHelper);
+};
+goog.inherits(goog.graphics.CanvasGraphics, goog.graphics.AbstractGraphics);
+
+
+/**
+ * Sets the fill for the given element.
+ * @param {goog.graphics.StrokeAndFillElement} element The element
+ *     wrapper.
+ * @param {goog.graphics.Fill} fill The fill object.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setElementFill = function(element,
+    fill) {
+  this.redraw();
+};
+
+
+/**
+ * Sets the stroke for the given element.
+ * @param {goog.graphics.StrokeAndFillElement} element The element
+ *     wrapper.
+ * @param {goog.graphics.Stroke} stroke The stroke object.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setElementStroke = function(
+    element, stroke) {
+  this.redraw();
+};
+
+
+/**
+ * Set the translation and rotation of an element.
+ *
+ * If a more general affine transform is needed than this provides
+ * (e.g. skew and scale) then use setElementAffineTransform.
+ * @param {goog.graphics.Element} element The element wrapper.
+ * @param {number} x The x coordinate of the translation transform.
+ * @param {number} y The y coordinate of the translation transform.
+ * @param {number} angle The angle of the rotation transform.
+ * @param {number} centerX The horizontal center of the rotation transform.
+ * @param {number} centerY The vertical center of the rotation transform.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setElementTransform = function(element,
+    x, y, angle, centerX, centerY) {
+  this.redraw();
+};
+
+
+/**
+ * Set the transformation of an element.
+ *
+ * Note that in this implementation this method just calls this.redraw()
+ * and the affineTransform param is unused.
+ * @param {!goog.graphics.Element} element The element wrapper.
+ * @param {!goog.graphics.AffineTransform} affineTransform The
+ *     transformation applied to this element.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setElementAffineTransform =
+    function(element, affineTransform) {
+  this.redraw();
+};
+
+
+/**
+ * Push an element transform on to the transform stack.
+ * @param {goog.graphics.Element} element The transformed element.
+ */
+goog.graphics.CanvasGraphics.prototype.pushElementTransform = function(
+    element) {
+  var ctx = this.getContext();
+  ctx.save();
+
+  var transform = element.getTransform();
+
+  // TODO(robbyw): Test for unsupported transforms i.e. skews.
+  var tx = transform.getTranslateX();
+  var ty = transform.getTranslateY();
+  if (tx || ty) {
+    ctx.translate(tx, ty);
+  }
+
+  var sinTheta = transform.getShearY();
+  if (sinTheta) {
+    ctx.rotate(Math.asin(sinTheta));
+  }
+};
+
+
+/**
+ * Pop an element transform off of the transform stack.
+ */
+goog.graphics.CanvasGraphics.prototype.popElementTransform = function() {
+  this.getContext().restore();
+};
+
+
+/**
+ * Creates the DOM representation of the graphics area.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.createDom = function() {
+  var element = this.dom_.createDom(goog.dom.TagName.DIV,
+      {'style': 'position:relative;overflow:hidden'});
+  this.setElementInternal(element);
+
+  this.canvas_ = this.dom_.createDom(goog.dom.TagName.CANVAS);
+  element.appendChild(this.canvas_);
+
+  /**
+   * The main canvas element.
+   * @type {goog.graphics.CanvasGroupElement}
+   */
+  this.canvasElement = new goog.graphics.CanvasGroupElement(this);
+
+  this.lastGroup_ = this.canvasElement;
+  this.redrawTimeout_ = 0;
+
+  this.updateSize();
+};
+
+
+/**
+ * Clears the drawing context object in response to actions that make the old
+ * context invalid - namely resize of the canvas element.
+ * @private
+ */
+goog.graphics.CanvasGraphics.prototype.clearContext_ = function() {
+  this.context_ = null;
+};
+
+
+/**
+ * Returns the drawing context.
+ * @return {Object} The canvas element rendering context.
+ */
+goog.graphics.CanvasGraphics.prototype.getContext = function() {
+  if (!this.getElement()) {
+    this.createDom();
+  }
+  if (!this.context_) {
+    this.context_ = this.canvas_.getContext('2d');
+    this.context_.save();
+  }
+  return this.context_;
+};
+
+
+/**
+ * Changes the coordinate system position.
+ * @param {number} left The coordinate system left bound.
+ * @param {number} top The coordinate system top bound.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setCoordOrigin = function(left, top) {
+  this.coordLeft = left;
+  this.coordTop = top;
+  this.redraw();
+};
+
+
+/**
+ * Changes the coordinate size.
+ * @param {number} coordWidth The coordinate width.
+ * @param {number} coordHeight The coordinate height.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setCoordSize = function(coordWidth,
+                                                               coordHeight) {
+  goog.graphics.CanvasGraphics.superClass_.setCoordSize.apply(this, arguments);
+  this.redraw();
+};
+
+
+/**
+ * Change the size of the canvas.
+ * @param {number} pixelWidth The width in pixels.
+ * @param {number} pixelHeight The height in pixels.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.setSize = function(pixelWidth,
+    pixelHeight) {
+  this.width = pixelWidth;
+  this.height = pixelHeight;
+
+  this.updateSize();
+  this.redraw();
+};
+
+
+/** @override */
+goog.graphics.CanvasGraphics.prototype.getPixelSize = function() {
+  // goog.style.getSize does not work for Canvas elements.  We
+  // have to compute the size manually if it is percentage based.
+  var width = this.width;
+  var height = this.height;
+  var computeWidth = goog.isString(width) && width.indexOf('%') != -1;
+  var computeHeight = goog.isString(height) && height.indexOf('%') != -1;
+
+  if (!this.isInDocument() && (computeWidth || computeHeight)) {
+    return null;
+  }
+
+  var parent;
+  var parentSize;
+
+  if (computeWidth) {
+    parent = /** @type {Element} */ (this.getElement().parentNode);
+    parentSize = goog.style.getSize(parent);
+    width = parseFloat(/** @type {string} */ (width)) * parentSize.width / 100;
+  }
+
+  if (computeHeight) {
+    parent = parent || /** @type {Element} */ (this.getElement().parentNode);
+    parentSize = parentSize || goog.style.getSize(parent);
+    height = parseFloat(/** @type {string} */ (height)) * parentSize.height /
+        100;
+  }
+
+  return new goog.math.Size(/** @type {number} */ (width),
+      /** @type {number} */ (height));
+};
+
+
+/**
+ * Update the size of the canvas.
+ */
+goog.graphics.CanvasGraphics.prototype.updateSize = function() {
+  goog.style.setSize(this.getElement(), this.width, this.height);
+
+  var pixels = this.getPixelSize();
+  if (pixels) {
+    goog.style.setSize(this.canvas_,
+        /** @type {number} */ (pixels.width),
+        /** @type {number} */ (pixels.height));
+    this.canvas_.width = pixels.width;
+    this.canvas_.height = pixels.height;
+    this.clearContext_();
+  }
+};
+
+
+/**
+ * Reset the canvas.
+ */
+goog.graphics.CanvasGraphics.prototype.reset = function() {
+  var ctx = this.getContext();
+  ctx.restore();
+  var size = this.getPixelSize();
+  if (size.width && size.height) {
+    ctx.clearRect(0, 0, size.width, size.height);
+  }
+  ctx.save();
+};
+
+
+/**
+ * Remove all drawing elements from the graphics.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.clear = function() {
+  this.reset();
+  this.canvasElement.clear();
+  var el = this.getElement();
+
+  // Remove all children (text nodes) except the canvas (which is at index 0)
+  while (el.childNodes.length > 1) {
+    el.removeChild(el.lastChild);
+  }
+};
+
+
+/**
+ * Redraw the entire canvas.
+ */
+goog.graphics.CanvasGraphics.prototype.redraw = function() {
+  if (this.preventRedraw_) {
+    this.needsRedraw_ = true;
+    return;
+  }
+
+  if (this.isInDocument()) {
+    this.reset();
+
+    if (this.coordWidth) {
+      var pixels = this.getPixelSize();
+      this.getContext().scale(pixels.width / this.coordWidth,
+          pixels.height / this.coordHeight);
+    }
+    if (this.coordLeft || this.coordTop) {
+      this.getContext().translate(-this.coordLeft, -this.coordTop);
+    }
+    this.pushElementTransform(this.canvasElement);
+    this.canvasElement.draw(this.context_);
+    this.popElementTransform();
+  }
+};
+
+
+/**
+ * Draw an element, including any stroke or fill.
+ * @param {goog.graphics.Element} element The element to draw.
+ */
+goog.graphics.CanvasGraphics.prototype.drawElement = function(element) {
+  if (element instanceof goog.graphics.CanvasTextElement) {
+    // Don't draw text since that is not implemented using canvas.
+    return;
+  }
+
+  var ctx = this.getContext();
+  this.pushElementTransform(element);
+
+  if (!element.getFill || !element.getStroke) {
+    // Draw without stroke or fill (e.g. the element is an image or group).
+    element.draw(ctx);
+    this.popElementTransform();
+    return;
+  }
+
+  var fill = element.getFill();
+  if (fill) {
+    if (fill instanceof goog.graphics.SolidFill) {
+      if (fill.getOpacity() != 0) {
+        ctx.globalAlpha = fill.getOpacity();
+        ctx.fillStyle = fill.getColor();
+        element.draw(ctx);
+        ctx.fill();
+        ctx.globalAlpha = 1;
+      }
+    } else { // (fill instanceof goog.graphics.LinearGradient)
+      var linearGradient = ctx.createLinearGradient(fill.getX1(), fill.getY1(),
+          fill.getX2(), fill.getY2());
+      linearGradient.addColorStop(0.0, fill.getColor1());
+      linearGradient.addColorStop(1.0, fill.getColor2());
+
+      ctx.fillStyle = linearGradient;
+      element.draw(ctx);
+      ctx.fill();
+    }
+  }
+
+  var stroke = element.getStroke();
+  if (stroke) {
+    element.draw(ctx);
+    ctx.strokeStyle = stroke.getColor();
+
+    var width = stroke.getWidth();
+    if (goog.isString(width) && width.indexOf('px') != -1) {
+      width = parseFloat(width) / this.getPixelScaleX();
+    }
+    ctx.lineWidth = width;
+
+    ctx.stroke();
+  }
+
+  this.popElementTransform();
+};
+
+
+/**
+ * Append an element.
+ *
+ * @param {goog.graphics.Element} element The element to draw.
+ * @param {goog.graphics.GroupElement|undefined} group The group to draw
+ *     it in. If null or undefined, defaults to the root group.
+ * @protected
+ */
+goog.graphics.CanvasGraphics.prototype.append = function(element, group) {
+  group = group || this.canvasElement;
+  group.appendChild(element);
+
+  if (this.isDrawable(group)) {
+    this.drawElement(element);
+  }
+};
+
+
+/**
+ * Draw an ellipse.
+ *
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @param {number} rx Radius length for the x-axis.
+ * @param {number} ry Radius length for the y-axis.
+ * @param {goog.graphics.Stroke} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper
+ *     element to append to.  If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.EllipseElement} The newly created element.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.drawEllipse = function(cx, cy, rx, ry,
+    stroke, fill, opt_group) {
+  var element = new goog.graphics.CanvasEllipseElement(null, this,
+      cx, cy, rx, ry, stroke, fill);
+  this.append(element, opt_group);
+  return element;
+};
+
+
+/**
+ * Draw a rectangle.
+ *
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @param {goog.graphics.Stroke} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper
+ *     element to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.RectElement} The newly created element.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.drawRect = function(x, y, width, height,
+    stroke, fill, opt_group) {
+  var element = new goog.graphics.CanvasRectElement(null, this,
+      x, y, width, height, stroke, fill);
+  this.append(element, opt_group);
+  return element;
+};
+
+
+/**
+ * Draw an image.
+ *
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} width Width of image.
+ * @param {number} height Height of image.
+ * @param {string} src Source of the image.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper
+ *     element to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.ImageElement} The newly created element.
+ */
+goog.graphics.CanvasGraphics.prototype.drawImage = function(x, y, width, height,
+    src, opt_group) {
+  var element = new goog.graphics.CanvasImageElement(null, this, x, y, width,
+      height, src);
+  this.append(element, opt_group);
+  return element;
+};
+
+
+/**
+ * Draw a text string vertically centered on a given line.
+ *
+ * @param {string} text The text to draw.
+ * @param {number} x1 X coordinate of start of line.
+ * @param {number} y1 Y coordinate of start of line.
+ * @param {number} x2 X coordinate of end of line.
+ * @param {number} y2 Y coordinate of end of line.
+ * @param {?string} align Horizontal alignment: left (default), center, right.
+ * @param {goog.graphics.Font} font Font describing the font properties.
+ * @param {goog.graphics.Stroke} stroke Stroke object describing the stroke.
+ * @param {goog.graphics.Fill} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper
+ *     element to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.TextElement} The newly created element.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.drawTextOnLine = function(
+    text, x1, y1, x2, y2, align, font, stroke, fill, opt_group) {
+  var element = new goog.graphics.CanvasTextElement(this,
+      text, x1, y1, x2, y2, align, /** @type {!goog.graphics.Font} */ (font),
+      stroke, fill);
+  this.append(element, opt_group);
+  return element;
+};
+
+
+/**
+ * Draw a path.
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @param {goog.graphics.Stroke} stroke Stroke object describing the stroke.
+ * @param {goog.graphics.Fill} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper
+ *     element to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.PathElement} The newly created element.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.drawPath = function(path, stroke, fill,
+    opt_group) {
+  var element = new goog.graphics.CanvasPathElement(null, this,
+      path, stroke, fill);
+  this.append(element, opt_group);
+  return element;
+};
+
+
+/**
+ * @param {goog.graphics.GroupElement} group The group to possibly
+ *     draw to.
+ * @return {boolean} Whether drawing can occur now.
+ */
+goog.graphics.CanvasGraphics.prototype.isDrawable = function(group) {
+  return this.isInDocument() && !this.redrawTimeout_ &&
+      !this.isRedrawRequired(group);
+};
+
+
+/**
+ * Returns true if drawing to the given group means a redraw is required.
+ * @param {goog.graphics.GroupElement} group The group to draw to.
+ * @return {boolean} Whether drawing to this group should force a redraw.
+ */
+goog.graphics.CanvasGraphics.prototype.isRedrawRequired = function(group) {
+  // TODO(robbyw): Moving up to any parent of lastGroup should not force redraw.
+  return group != this.canvasElement && group != this.lastGroup_;
+};
+
+
+/**
+ * Create an empty group of drawing elements.
+ *
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper
+ *     element to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.CanvasGroupElement} The newly created group.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.createGroup = function(opt_group) {
+  var group = new goog.graphics.CanvasGroupElement(this);
+
+  opt_group = opt_group || this.canvasElement;
+
+  // TODO(robbyw): Moving up to any parent group should not force redraw.
+  if (opt_group == this.canvasElement || opt_group == this.lastGroup_) {
+    this.lastGroup_ = group;
+  }
+
+  this.append(group, opt_group);
+
+  return group;
+};
+
+
+/**
+ * Measure and return the width (in pixels) of a given text string.
+ * Text measurement is needed to make sure a text can fit in the allocated
+ * area. The way text length is measured is by writing it into a div that is
+ * after the visible area, measure the div width, and immediatly erase the
+ * written value.
+ *
+ * @param {string} text The text string to measure.
+ * @param {goog.graphics.Font} font The font object describing the font style.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.getTextWidth = goog.abstractMethod;
+
+
+/**
+ * Disposes of the component by removing event handlers, detacing DOM nodes from
+ * the document body, and removing references to them.
+ * @override
+ * @protected
+ */
+goog.graphics.CanvasGraphics.prototype.disposeInternal = function() {
+  this.context_ = null;
+  goog.graphics.CanvasGraphics.superClass_.disposeInternal.call(this);
+};
+
+
+/** @override */
+goog.graphics.CanvasGraphics.prototype.enterDocument = function() {
+  var oldPixelSize = this.getPixelSize();
+  goog.graphics.CanvasGraphics.superClass_.enterDocument.call(this);
+  if (!oldPixelSize) {
+    this.updateSize();
+    this.dispatchEvent(goog.events.EventType.RESIZE);
+  }
+  this.redraw();
+};
+
+
+/**
+ * Start preventing redraws - useful for chaining large numbers of changes
+ * together.  Not guaranteed to do anything - i.e. only use this for
+ * optimization of a single code path.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.suspend = function() {
+  this.preventRedraw_ = true;
+};
+
+
+/**
+ * Stop preventing redraws.  If any redraws had been prevented, a redraw will
+ * be done now.
+ * @override
+ */
+goog.graphics.CanvasGraphics.prototype.resume = function() {
+  this.preventRedraw_ = false;
+
+  if (this.needsRedraw_) {
+    this.redraw();
+    this.needsRedraw_ = false;
+  }
+};


[49/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/a11y/aria/attributes.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/a11y/aria/attributes.js b/externs/GCL/externs/goog/a11y/aria/attributes.js
new file mode 100644
index 0000000..f4e0a3d
--- /dev/null
+++ b/externs/GCL/externs/goog/a11y/aria/attributes.js
@@ -0,0 +1,389 @@
+// Copyright 2013 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 The file contains generated enumerations for ARIA states
+ * and properties as defined by W3C ARIA standard:
+ * http://www.w3.org/TR/wai-aria/.
+ *
+ * This is auto-generated code. Do not manually edit! For more details
+ * about how to edit it via the generator check go/closure-ariagen.
+ */
+
+goog.provide('goog.a11y.aria.AutoCompleteValues');
+goog.provide('goog.a11y.aria.CheckedValues');
+goog.provide('goog.a11y.aria.DropEffectValues');
+goog.provide('goog.a11y.aria.ExpandedValues');
+goog.provide('goog.a11y.aria.GrabbedValues');
+goog.provide('goog.a11y.aria.InvalidValues');
+goog.provide('goog.a11y.aria.LivePriority');
+goog.provide('goog.a11y.aria.OrientationValues');
+goog.provide('goog.a11y.aria.PressedValues');
+goog.provide('goog.a11y.aria.RelevantValues');
+goog.provide('goog.a11y.aria.SelectedValues');
+goog.provide('goog.a11y.aria.SortValues');
+goog.provide('goog.a11y.aria.State');
+
+
+/**
+ * ARIA states and properties.
+ * @enum {string}
+ */
+goog.a11y.aria.State = {
+  // ARIA property for setting the currently active descendant of an element,
+  // for example the selected item in a list box. Value: ID of an element.
+  ACTIVEDESCENDANT: 'activedescendant',
+
+  // ARIA property that, if true, indicates that all of a changed region should
+  // be presented, instead of only parts. Value: one of {true, false}.
+  ATOMIC: 'atomic',
+
+  // ARIA property to specify that input completion is provided. Value:
+  // one of {'inline', 'list', 'both', 'none'}.
+  AUTOCOMPLETE: 'autocomplete',
+
+  // ARIA state to indicate that an element and its subtree are being updated.
+  // Value: one of {true, false}.
+  BUSY: 'busy',
+
+  // ARIA state for a checked item. Value: one of {'true', 'false', 'mixed',
+  // undefined}.
+  CHECKED: 'checked',
+
+  // ARIA property that identifies the element or elements whose contents or
+  // presence are controlled by this element.
+  // Value: space-separated IDs of other elements.
+  CONTROLS: 'controls',
+
+  // ARIA property that identifies the element or elements that describe
+  // this element. Value: space-separated IDs of other elements.
+  DESCRIBEDBY: 'describedby',
+
+  // ARIA state for a disabled item. Value: one of {true, false}.
+  DISABLED: 'disabled',
+
+  // ARIA property that indicates what functions can be performed when a
+  // dragged object is released on the drop target.  Value: one of
+  // {'copy', 'move', 'link', 'execute', 'popup', 'none'}.
+  DROPEFFECT: 'dropeffect',
+
+  // ARIA state for setting whether the element like a tree node is expanded.
+  // Value: one of {true, false, undefined}.
+  EXPANDED: 'expanded',
+
+  // ARIA property that identifies the next element (or elements) in the
+  // recommended reading order of content. Value: space-separated ids of
+  // elements to flow to.
+  FLOWTO: 'flowto',
+
+  // ARIA state that indicates an element's "grabbed" state in drag-and-drop.
+  // Value: one of {true, false, undefined}.
+  GRABBED: 'grabbed',
+
+  // ARIA property indicating whether the element has a popup.
+  // Value: one of {true, false}.
+  HASPOPUP: 'haspopup',
+
+  // ARIA state indicating that the element is not visible or perceivable
+  // to any user. Value: one of {true, false}.
+  HIDDEN: 'hidden',
+
+  // ARIA state indicating that the entered value does not conform. Value:
+  // one of {false, true, 'grammar', 'spelling'}
+  INVALID: 'invalid',
+
+  // ARIA property that provides a label to override any other text, value, or
+  // contents used to describe this element. Value: string.
+  LABEL: 'label',
+
+  // ARIA property for setting the element which labels another element.
+  // Value: space-separated IDs of elements.
+  LABELLEDBY: 'labelledby',
+
+  // ARIA property for setting the level of an element in the hierarchy.
+  // Value: integer.
+  LEVEL: 'level',
+
+  // ARIA property indicating that an element will be updated, and
+  // describes the types of updates the user agents, assistive technologies,
+  // and user can expect from the live region. Value: one of {'off', 'polite',
+  // 'assertive'}.
+  LIVE: 'live',
+
+  // ARIA property indicating whether a text box can accept multiline input.
+  // Value: one of {true, false}.
+  MULTILINE: 'multiline',
+
+  // ARIA property indicating if the user may select more than one item.
+  // Value: one of {true, false}.
+  MULTISELECTABLE: 'multiselectable',
+
+  // ARIA property indicating if the element is horizontal or vertical.
+  // Value: one of {'vertical', 'horizontal'}.
+  ORIENTATION: 'orientation',
+
+  // ARIA property creating a visual, functional, or contextual parent/child
+  // relationship when the DOM hierarchy can't be used to represent it.
+  // Value: Space-separated IDs of elements.
+  OWNS: 'owns',
+
+  // ARIA property that defines an element's number of position in a list.
+  // Value: integer.
+  POSINSET: 'posinset',
+
+  // ARIA state for a pressed item.
+  // Value: one of {true, false, undefined, 'mixed'}.
+  PRESSED: 'pressed',
+
+  // ARIA property indicating that an element is not editable.
+  // Value: one of {true, false}.
+  READONLY: 'readonly',
+
+  // ARIA property indicating that change notifications within this subtree
+  // of a live region should be announced. Value: one of {'additions',
+  // 'removals', 'text', 'all', 'additions text'}.
+  RELEVANT: 'relevant',
+
+  // ARIA property indicating that user input is required on this element
+  // before a form may be submitted. Value: one of {true, false}.
+  REQUIRED: 'required',
+
+  // ARIA state for setting the currently selected item in the list.
+  // Value: one of {true, false, undefined}.
+  SELECTED: 'selected',
+
+  // ARIA property defining the number of items in a list. Value: integer.
+  SETSIZE: 'setsize',
+
+  // ARIA property indicating if items are sorted. Value: one of {'ascending',
+  // 'descending', 'none', 'other'}.
+  SORT: 'sort',
+
+  // ARIA property for slider maximum value. Value: number.
+  VALUEMAX: 'valuemax',
+
+  // ARIA property for slider minimum value. Value: number.
+  VALUEMIN: 'valuemin',
+
+  // ARIA property for slider active value. Value: number.
+  VALUENOW: 'valuenow',
+
+  // ARIA property for slider active value represented as text.
+  // Value: string.
+  VALUETEXT: 'valuetext'
+};
+
+
+/**
+ * ARIA state values for AutoCompleteValues.
+ * @enum {string}
+ */
+goog.a11y.aria.AutoCompleteValues = {
+  // The system provides text after the caret as a suggestion
+  // for how to complete the field.
+  INLINE: 'inline',
+  // A list of choices appears from which the user can choose,
+  // but the edit box retains focus.
+  LIST: 'list',
+  // A list of choices appears and the currently selected suggestion
+  // also appears inline.
+  BOTH: 'both',
+  // No input completion suggestions are provided.
+  NONE: 'none'
+};
+
+
+/**
+ * ARIA state values for DropEffectValues.
+ * @enum {string}
+ */
+goog.a11y.aria.DropEffectValues = {
+  // A duplicate of the source object will be dropped into the target.
+  COPY: 'copy',
+  // The source object will be removed from its current location
+  // and dropped into the target.
+  MOVE: 'move',
+  // A reference or shortcut to the dragged object
+  // will be created in the target object.
+  LINK: 'link',
+  // A function supported by the drop target is
+  // executed, using the drag source as an input.
+  EXECUTE: 'execute',
+  // There is a popup menu or dialog that allows the user to choose
+  // one of the drag operations (copy, move, link, execute) and any other
+  // drag functionality, such as cancel.
+  POPUP: 'popup',
+  // No operation can be performed; effectively
+  // cancels the drag operation if an attempt is made to drop on this object.
+  NONE: 'none'
+};
+
+
+/**
+ * ARIA state values for LivePriority.
+ * @enum {string}
+ */
+goog.a11y.aria.LivePriority = {
+  // Updates to the region will not be presented to the user
+  // unless the assitive technology is currently focused on that region.
+  OFF: 'off',
+  // (Background change) Assistive technologies SHOULD announce
+  // updates at the next graceful opportunity, such as at the end of
+  // speaking the current sentence or when the user pauses typing.
+  POLITE: 'polite',
+  // This information has the highest priority and assistive
+  // technologies SHOULD notify the user immediately.
+  // Because an interruption may disorient users or cause them to not complete
+  // their current task, authors SHOULD NOT use the assertive value unless the
+  // interruption is imperative.
+  ASSERTIVE: 'assertive'
+};
+
+
+/**
+ * ARIA state values for OrientationValues.
+ * @enum {string}
+ */
+goog.a11y.aria.OrientationValues = {
+  // The element is oriented vertically.
+  VERTICAL: 'vertical',
+  // The element is oriented horizontally.
+  HORIZONTAL: 'horizontal'
+};
+
+
+/**
+ * ARIA state values for RelevantValues.
+ * @enum {string}
+ */
+goog.a11y.aria.RelevantValues = {
+  // Element nodes are added to the DOM within the live region.
+  ADDITIONS: 'additions',
+  // Text or element nodes within the live region are removed from the DOM.
+  REMOVALS: 'removals',
+  // Text is added to any DOM descendant nodes of the live region.
+  TEXT: 'text',
+  // Equivalent to the combination of all values, "additions removals text".
+  ALL: 'all'
+};
+
+
+/**
+ * ARIA state values for SortValues.
+ * @enum {string}
+ */
+goog.a11y.aria.SortValues = {
+  // Items are sorted in ascending order by this column.
+  ASCENDING: 'ascending',
+  // Items are sorted in descending order by this column.
+  DESCENDING: 'descending',
+  // There is no defined sort applied to the column.
+  NONE: 'none',
+  // A sort algorithm other than ascending or descending has been applied.
+  OTHER: 'other'
+};
+
+
+/**
+ * ARIA state values for CheckedValues.
+ * @enum {string}
+ */
+goog.a11y.aria.CheckedValues = {
+  // The selectable element is checked.
+  TRUE: 'true',
+  // The selectable element is not checked.
+  FALSE: 'false',
+  // Indicates a mixed mode value for a tri-state
+  // checkbox or menuitemcheckbox.
+  MIXED: 'mixed',
+  // The element does not support being checked.
+  UNDEFINED: 'undefined'
+};
+
+
+/**
+ * ARIA state values for ExpandedValues.
+ * @enum {string}
+ */
+goog.a11y.aria.ExpandedValues = {
+  // The element, or another grouping element it controls, is expanded.
+  TRUE: 'true',
+  // The element, or another grouping element it controls, is collapsed.
+  FALSE: 'false',
+  // The element, or another grouping element
+  // it controls, is neither expandable nor collapsible; all its
+  // child elements are shown or there are no child elements.
+  UNDEFINED: 'undefined'
+};
+
+
+/**
+ * ARIA state values for GrabbedValues.
+ * @enum {string}
+ */
+goog.a11y.aria.GrabbedValues = {
+  // Indicates that the element has been "grabbed" for dragging.
+  TRUE: 'true',
+  // Indicates that the element supports being dragged.
+  FALSE: 'false',
+  // Indicates that the element does not support being dragged.
+  UNDEFINED: 'undefined'
+};
+
+
+/**
+ * ARIA state values for InvalidValues.
+ * @enum {string}
+ */
+goog.a11y.aria.InvalidValues = {
+  // There are no detected errors in the value.
+  FALSE: 'false',
+  // The value entered by the user has failed validation.
+  TRUE: 'true',
+  // A grammatical error was detected.
+  GRAMMAR: 'grammar',
+  // A spelling error was detected.
+  SPELLING: 'spelling'
+};
+
+
+/**
+ * ARIA state values for PressedValues.
+ * @enum {string}
+ */
+goog.a11y.aria.PressedValues = {
+  // The element is pressed.
+  TRUE: 'true',
+  // The element supports being pressed but is not currently pressed.
+  FALSE: 'false',
+  // Indicates a mixed mode value for a tri-state toggle button.
+  MIXED: 'mixed',
+  // The element does not support being pressed.
+  UNDEFINED: 'undefined'
+};
+
+
+/**
+ * ARIA state values for SelectedValues.
+ * @enum {string}
+ */
+goog.a11y.aria.SelectedValues = {
+  // The selectable element is selected.
+  TRUE: 'true',
+  // The selectable element is not selected.
+  FALSE: 'false',
+  // The element is not selectable.
+  UNDEFINED: 'undefined'
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/a11y/aria/datatables.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/a11y/aria/datatables.js b/externs/GCL/externs/goog/a11y/aria/datatables.js
new file mode 100644
index 0000000..f1ba566
--- /dev/null
+++ b/externs/GCL/externs/goog/a11y/aria/datatables.js
@@ -0,0 +1,68 @@
+// Copyright 2013 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 The file contains data tables generated from the ARIA
+ * standard schema http://www.w3.org/TR/wai-aria/.
+ *
+ * This is auto-generated code. Do not manually edit!
+ */
+
+goog.provide('goog.a11y.aria.datatables');
+
+goog.require('goog.a11y.aria.State');
+goog.require('goog.object');
+
+
+/**
+ * A map that contains mapping between an ARIA state and the default value
+ * for it. Note that not all ARIA states have default values.
+ *
+ * @type {Object<!(goog.a11y.aria.State|string), (string|boolean|number)>}
+ */
+goog.a11y.aria.DefaultStateValueMap_;
+
+
+/**
+ * A method that creates a map that contains mapping between an ARIA state and
+ * the default value for it. Note that not all ARIA states have default values.
+ *
+ * @return {!Object<!(goog.a11y.aria.State|string), (string|boolean|number)>}
+ *      The names for each of the notification methods.
+ */
+goog.a11y.aria.datatables.getDefaultValuesMap = function() {
+  if (!goog.a11y.aria.DefaultStateValueMap_) {
+    goog.a11y.aria.DefaultStateValueMap_ = goog.object.create(
+        goog.a11y.aria.State.ATOMIC, false,
+        goog.a11y.aria.State.AUTOCOMPLETE, 'none',
+        goog.a11y.aria.State.DROPEFFECT, 'none',
+        goog.a11y.aria.State.HASPOPUP, false,
+        goog.a11y.aria.State.LIVE, 'off',
+        goog.a11y.aria.State.MULTILINE, false,
+        goog.a11y.aria.State.MULTISELECTABLE, false,
+        goog.a11y.aria.State.ORIENTATION, 'vertical',
+        goog.a11y.aria.State.READONLY, false,
+        goog.a11y.aria.State.RELEVANT, 'additions text',
+        goog.a11y.aria.State.REQUIRED, false,
+        goog.a11y.aria.State.SORT, 'none',
+        goog.a11y.aria.State.BUSY, false,
+        goog.a11y.aria.State.DISABLED, false,
+        goog.a11y.aria.State.HIDDEN, false,
+        goog.a11y.aria.State.INVALID, 'false');
+  }
+
+  return goog.a11y.aria.DefaultStateValueMap_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/a11y/aria/roles.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/a11y/aria/roles.js b/externs/GCL/externs/goog/a11y/aria/roles.js
new file mode 100644
index 0000000..a282cc2
--- /dev/null
+++ b/externs/GCL/externs/goog/a11y/aria/roles.js
@@ -0,0 +1,216 @@
+// Copyright 2013 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 The file contains generated enumerations for ARIA roles
+ * as defined by W3C ARIA standard: http://www.w3.org/TR/wai-aria/.
+ *
+ * This is auto-generated code. Do not manually edit! For more details
+ * about how to edit it via the generator check go/closure-ariagen.
+ */
+
+goog.provide('goog.a11y.aria.Role');
+
+
+/**
+ * ARIA role values.
+ * @enum {string}
+ */
+goog.a11y.aria.Role = {
+  // ARIA role for an alert element that doesn't need to be explicitly closed.
+  ALERT: 'alert',
+
+  // ARIA role for an alert dialog element that takes focus and must be closed.
+  ALERTDIALOG: 'alertdialog',
+
+  // ARIA role for an application that implements its own keyboard navigation.
+  APPLICATION: 'application',
+
+  // ARIA role for an article.
+  ARTICLE: 'article',
+
+  // ARIA role for a banner containing mostly site content, not page content.
+  BANNER: 'banner',
+
+  // ARIA role for a button element.
+  BUTTON: 'button',
+
+  // ARIA role for a checkbox button element; use with the CHECKED state.
+  CHECKBOX: 'checkbox',
+
+  // ARIA role for a column header of a table or grid.
+  COLUMNHEADER: 'columnheader',
+
+  // ARIA role for a combo box element.
+  COMBOBOX: 'combobox',
+
+  // ARIA role for a supporting section of the document.
+  COMPLEMENTARY: 'complementary',
+
+  // ARIA role for a large perceivable region that contains information
+  // about the parent document.
+  CONTENTINFO: 'contentinfo',
+
+  // ARIA role for a definition of a term or concept.
+  DEFINITION: 'definition',
+
+  // ARIA role for a dialog, some descendant must take initial focus.
+  DIALOG: 'dialog',
+
+  // ARIA role for a directory, like a table of contents.
+  DIRECTORY: 'directory',
+
+  // ARIA role for a part of a page that's a document, not a web application.
+  DOCUMENT: 'document',
+
+  // ARIA role for a landmark region logically considered one form.
+  FORM: 'form',
+
+  // ARIA role for an interactive control of tabular data.
+  GRID: 'grid',
+
+  // ARIA role for a cell in a grid.
+  GRIDCELL: 'gridcell',
+
+  // ARIA role for a group of related elements like tree item siblings.
+  GROUP: 'group',
+
+  // ARIA role for a heading element.
+  HEADING: 'heading',
+
+  // ARIA role for a container of elements that together comprise one image.
+  IMG: 'img',
+
+  // ARIA role for a link.
+  LINK: 'link',
+
+  // ARIA role for a list of non-interactive list items.
+  LIST: 'list',
+
+  // ARIA role for a listbox.
+  LISTBOX: 'listbox',
+
+  // ARIA role for a list item.
+  LISTITEM: 'listitem',
+
+  // ARIA role for a live region where new information is added.
+  LOG: 'log',
+
+  // ARIA landmark role for the main content in a document. Use only once.
+  MAIN: 'main',
+
+  // ARIA role for a live region of non-essential information that changes.
+  MARQUEE: 'marquee',
+
+  // ARIA role for a mathematical expression.
+  MATH: 'math',
+
+  // ARIA role for a popup menu.
+  MENU: 'menu',
+
+  // ARIA role for a menubar element containing menu elements.
+  MENUBAR: 'menubar',
+
+  // ARIA role for menu item elements.
+  MENU_ITEM: 'menuitem',
+
+  // ARIA role for a checkbox box element inside a menu.
+  MENU_ITEM_CHECKBOX: 'menuitemcheckbox',
+
+  // ARIA role for a radio button element inside a menu.
+  MENU_ITEM_RADIO: 'menuitemradio',
+
+  // ARIA landmark role for a collection of navigation links.
+  NAVIGATION: 'navigation',
+
+  // ARIA role for a section ancillary to the main content.
+  NOTE: 'note',
+
+  // ARIA role for option items that are  children of combobox, listbox, menu,
+  // radiogroup, or tree elements.
+  OPTION: 'option',
+
+  // ARIA role for ignorable cosmetic elements with no semantic significance.
+  PRESENTATION: 'presentation',
+
+  // ARIA role for a progress bar element.
+  PROGRESSBAR: 'progressbar',
+
+  // ARIA role for a radio button element.
+  RADIO: 'radio',
+
+  // ARIA role for a group of connected radio button elements.
+  RADIOGROUP: 'radiogroup',
+
+  // ARIA role for an important region of the page.
+  REGION: 'region',
+
+  // ARIA role for a row of cells in a grid.
+  ROW: 'row',
+
+  // ARIA role for a group of one or more rows in a grid.
+  ROWGROUP: 'rowgroup',
+
+  // ARIA role for a row header of a table or grid.
+  ROWHEADER: 'rowheader',
+
+  // ARIA role for a scrollbar element.
+  SCROLLBAR: 'scrollbar',
+
+  // ARIA landmark role for a part of the page providing search functionality.
+  SEARCH: 'search',
+
+  // ARIA role for a menu separator.
+  SEPARATOR: 'separator',
+
+  // ARIA role for a slider.
+  SLIDER: 'slider',
+
+  // ARIA role for a spin button.
+  SPINBUTTON: 'spinbutton',
+
+  // ARIA role for a live region with advisory info less severe than an alert.
+  STATUS: 'status',
+
+  // ARIA role for a tab button.
+  TAB: 'tab',
+
+  // ARIA role for a tab bar (i.e. a list of tab buttons).
+  TAB_LIST: 'tablist',
+
+  // ARIA role for a tab page (i.e. the element holding tab contents).
+  TAB_PANEL: 'tabpanel',
+
+  // ARIA role for a textbox element.
+  TEXTBOX: 'textbox',
+
+  // ARIA role for an element displaying elapsed time or time remaining.
+  TIMER: 'timer',
+
+  // ARIA role for a toolbar element.
+  TOOLBAR: 'toolbar',
+
+  // ARIA role for a tooltip element.
+  TOOLTIP: 'tooltip',
+
+  // ARIA role for a tree.
+  TREE: 'tree',
+
+  // ARIA role for a grid whose rows can be expanded and collapsed like a tree.
+  TREEGRID: 'treegrid',
+
+  // ARIA role for a tree item that sometimes may be expanded or collapsed.
+  TREEITEM: 'treeitem'
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/array/array.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/array/array.js b/externs/GCL/externs/goog/array/array.js
new file mode 100644
index 0000000..bd99626
--- /dev/null
+++ b/externs/GCL/externs/goog/array/array.js
@@ -0,0 +1,1655 @@
+// 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 manipulating arrays.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.array');
+goog.provide('goog.array.ArrayLike');
+
+goog.require('goog.asserts');
+
+
+/**
+ * @define {boolean} NATIVE_ARRAY_PROTOTYPES indicates whether the code should
+ * rely on Array.prototype functions, if available.
+ *
+ * The Array.prototype functions can be defined by external libraries like
+ * Prototype and setting this flag to false forces closure to use its own
+ * goog.array implementation.
+ *
+ * If your javascript can be loaded by a third party site and you are wary about
+ * relying on the prototype functions, specify
+ * "--define goog.NATIVE_ARRAY_PROTOTYPES=false" to the JSCompiler.
+ *
+ * Setting goog.TRUSTED_SITE to false will automatically set
+ * NATIVE_ARRAY_PROTOTYPES to false.
+ */
+goog.define('goog.NATIVE_ARRAY_PROTOTYPES', goog.TRUSTED_SITE);
+
+
+/**
+ * @define {boolean} If true, JSCompiler will use the native implementation of
+ * array functions where appropriate (e.g., {@code Array#filter}) and remove the
+ * unused pure JS implementation.
+ */
+goog.define('goog.array.ASSUME_NATIVE_FUNCTIONS', false);
+
+
+/**
+ * @typedef {Array|NodeList|Arguments|{length: number}}
+ */
+goog.array.ArrayLike;
+
+
+/**
+ * Returns the last element in an array without removing it.
+ * Same as goog.array.last.
+ * @param {Array<T>|goog.array.ArrayLike} array The array.
+ * @return {T} Last item in array.
+ * @template T
+ */
+goog.array.peek = function(array) {
+  return array[array.length - 1];
+};
+
+
+/**
+ * Returns the last element in an array without removing it.
+ * Same as goog.array.peek.
+ * @param {Array<T>|goog.array.ArrayLike} array The array.
+ * @return {T} Last item in array.
+ * @template T
+ */
+goog.array.last = goog.array.peek;
+
+
+/**
+ * Reference to the original {@code Array.prototype}.
+ * @private
+ */
+goog.array.ARRAY_PROTOTYPE_ = Array.prototype;
+
+
+// NOTE(arv): Since most of the array functions are generic it allows you to
+// pass an array-like object. Strings have a length and are considered array-
+// like. However, the 'in' operator does not work on strings so we cannot just
+// use the array path even if the browser supports indexing into strings. We
+// therefore end up splitting the string.
+
+
+/**
+ * Returns the index of the first element of an array with a specified value, or
+ * -1 if the element is not present in the array.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-indexof}
+ *
+ * @param {Array<T>|goog.array.ArrayLike} arr The array to be searched.
+ * @param {T} obj The object for which we are searching.
+ * @param {number=} opt_fromIndex The index at which to start the search. If
+ *     omitted the search starts at index 0.
+ * @return {number} The index of the first matching array element.
+ * @template T
+ */
+goog.array.indexOf = goog.NATIVE_ARRAY_PROTOTYPES &&
+                     (goog.array.ASSUME_NATIVE_FUNCTIONS ||
+                      goog.array.ARRAY_PROTOTYPE_.indexOf) ?
+    function(arr, obj, opt_fromIndex) {
+      goog.asserts.assert(arr.length != null);
+
+      return goog.array.ARRAY_PROTOTYPE_.indexOf.call(arr, obj, opt_fromIndex);
+    } :
+    function(arr, obj, opt_fromIndex) {
+      var fromIndex = opt_fromIndex == null ?
+          0 : (opt_fromIndex < 0 ?
+               Math.max(0, arr.length + opt_fromIndex) : opt_fromIndex);
+
+      if (goog.isString(arr)) {
+        // Array.prototype.indexOf uses === so only strings should be found.
+        if (!goog.isString(obj) || obj.length != 1) {
+          return -1;
+        }
+        return arr.indexOf(obj, fromIndex);
+      }
+
+      for (var i = fromIndex; i < arr.length; i++) {
+        if (i in arr && arr[i] === obj)
+          return i;
+      }
+      return -1;
+    };
+
+
+/**
+ * Returns the index of the last element of an array with a specified value, or
+ * -1 if the element is not present in the array.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-lastindexof}
+ *
+ * @param {!Array<T>|!goog.array.ArrayLike} arr The array to be searched.
+ * @param {T} obj The object for which we are searching.
+ * @param {?number=} opt_fromIndex The index at which to start the search. If
+ *     omitted the search starts at the end of the array.
+ * @return {number} The index of the last matching array element.
+ * @template T
+ */
+goog.array.lastIndexOf = goog.NATIVE_ARRAY_PROTOTYPES &&
+                         (goog.array.ASSUME_NATIVE_FUNCTIONS ||
+                          goog.array.ARRAY_PROTOTYPE_.lastIndexOf) ?
+    function(arr, obj, opt_fromIndex) {
+      goog.asserts.assert(arr.length != null);
+
+      // Firefox treats undefined and null as 0 in the fromIndex argument which
+      // leads it to always return -1
+      var fromIndex = opt_fromIndex == null ? arr.length - 1 : opt_fromIndex;
+      return goog.array.ARRAY_PROTOTYPE_.lastIndexOf.call(arr, obj, fromIndex);
+    } :
+    function(arr, obj, opt_fromIndex) {
+      var fromIndex = opt_fromIndex == null ? arr.length - 1 : opt_fromIndex;
+
+      if (fromIndex < 0) {
+        fromIndex = Math.max(0, arr.length + fromIndex);
+      }
+
+      if (goog.isString(arr)) {
+        // Array.prototype.lastIndexOf uses === so only strings should be found.
+        if (!goog.isString(obj) || obj.length != 1) {
+          return -1;
+        }
+        return arr.lastIndexOf(obj, fromIndex);
+      }
+
+      for (var i = fromIndex; i >= 0; i--) {
+        if (i in arr && arr[i] === obj)
+          return i;
+      }
+      return -1;
+    };
+
+
+/**
+ * Calls a function for each element in an array. Skips holes in the array.
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-foreach}
+ *
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array like object over
+ *     which to iterate.
+ * @param {?function(this: S, T, number, ?): ?} f The function to call for every
+ *     element. This function takes 3 arguments (the element, the index and the
+ *     array). The return value is ignored.
+ * @param {S=} opt_obj The object to be used as the value of 'this' within f.
+ * @template T,S
+ */
+goog.array.forEach = goog.NATIVE_ARRAY_PROTOTYPES &&
+                     (goog.array.ASSUME_NATIVE_FUNCTIONS ||
+                      goog.array.ARRAY_PROTOTYPE_.forEach) ?
+    function(arr, f, opt_obj) {
+      goog.asserts.assert(arr.length != null);
+
+      goog.array.ARRAY_PROTOTYPE_.forEach.call(arr, f, opt_obj);
+    } :
+    function(arr, f, opt_obj) {
+      var l = arr.length;  // must be fixed during loop... see docs
+      var arr2 = goog.isString(arr) ? arr.split('') : arr;
+      for (var i = 0; i < l; i++) {
+        if (i in arr2) {
+          f.call(opt_obj, arr2[i], i, arr);
+        }
+      }
+    };
+
+
+/**
+ * Calls a function for each element in an array, starting from the last
+ * element rather than the first.
+ *
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array
+ *     like object over which to iterate.
+ * @param {?function(this: S, T, number, ?): ?} f The function to call for every
+ *     element. This function
+ *     takes 3 arguments (the element, the index and the array). The return
+ *     value is ignored.
+ * @param {S=} opt_obj The object to be used as the value of 'this'
+ *     within f.
+ * @template T,S
+ */
+goog.array.forEachRight = function(arr, f, opt_obj) {
+  var l = arr.length;  // must be fixed during loop... see docs
+  var arr2 = goog.isString(arr) ? arr.split('') : arr;
+  for (var i = l - 1; i >= 0; --i) {
+    if (i in arr2) {
+      f.call(opt_obj, arr2[i], i, arr);
+    }
+  }
+};
+
+
+/**
+ * Calls a function for each element in an array, and if the function returns
+ * true adds the element to a new array.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-filter}
+ *
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array
+ *     like object over which to iterate.
+ * @param {?function(this:S, T, number, ?):boolean} f The function to call for
+ *     every element. This function
+ *     takes 3 arguments (the element, the index and the array) and must
+ *     return a Boolean. If the return value is true the element is added to the
+ *     result array. If it is false the element is not included.
+ * @param {S=} opt_obj The object to be used as the value of 'this'
+ *     within f.
+ * @return {!Array<T>} a new array in which only elements that passed the test
+ *     are present.
+ * @template T,S
+ */
+goog.array.filter = goog.NATIVE_ARRAY_PROTOTYPES &&
+                    (goog.array.ASSUME_NATIVE_FUNCTIONS ||
+                     goog.array.ARRAY_PROTOTYPE_.filter) ?
+    function(arr, f, opt_obj) {
+      goog.asserts.assert(arr.length != null);
+
+      return goog.array.ARRAY_PROTOTYPE_.filter.call(arr, f, opt_obj);
+    } :
+    function(arr, f, opt_obj) {
+      var l = arr.length;  // must be fixed during loop... see docs
+      var res = [];
+      var resLength = 0;
+      var arr2 = goog.isString(arr) ? arr.split('') : arr;
+      for (var i = 0; i < l; i++) {
+        if (i in arr2) {
+          var val = arr2[i];  // in case f mutates arr2
+          if (f.call(opt_obj, val, i, arr)) {
+            res[resLength++] = val;
+          }
+        }
+      }
+      return res;
+    };
+
+
+/**
+ * Calls a function for each element in an array and inserts the result into a
+ * new array.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-map}
+ *
+ * @param {Array<VALUE>|goog.array.ArrayLike} arr Array or array like object
+ *     over which to iterate.
+ * @param {function(this:THIS, VALUE, number, ?): RESULT} f The function to call
+ *     for every element. This function takes 3 arguments (the element,
+ *     the index and the array) and should return something. The result will be
+ *     inserted into a new array.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this' within f.
+ * @return {!Array<RESULT>} a new array with the results from f.
+ * @template THIS, VALUE, RESULT
+ */
+goog.array.map = goog.NATIVE_ARRAY_PROTOTYPES &&
+                 (goog.array.ASSUME_NATIVE_FUNCTIONS ||
+                  goog.array.ARRAY_PROTOTYPE_.map) ?
+    function(arr, f, opt_obj) {
+      goog.asserts.assert(arr.length != null);
+
+      return goog.array.ARRAY_PROTOTYPE_.map.call(arr, f, opt_obj);
+    } :
+    function(arr, f, opt_obj) {
+      var l = arr.length;  // must be fixed during loop... see docs
+      var res = new Array(l);
+      var arr2 = goog.isString(arr) ? arr.split('') : arr;
+      for (var i = 0; i < l; i++) {
+        if (i in arr2) {
+          res[i] = f.call(opt_obj, arr2[i], i, arr);
+        }
+      }
+      return res;
+    };
+
+
+/**
+ * Passes every element of an array into a function and accumulates the result.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-reduce}
+ *
+ * For example:
+ * var a = [1, 2, 3, 4];
+ * goog.array.reduce(a, function(r, v, i, arr) {return r + v;}, 0);
+ * returns 10
+ *
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array
+ *     like object over which to iterate.
+ * @param {function(this:S, R, T, number, ?) : R} f The function to call for
+ *     every element. This function
+ *     takes 4 arguments (the function's previous result or the initial value,
+ *     the value of the current array element, the current array index, and the
+ *     array itself)
+ *     function(previousValue, currentValue, index, array).
+ * @param {?} val The initial value to pass into the function on the first call.
+ * @param {S=} opt_obj  The object to be used as the value of 'this'
+ *     within f.
+ * @return {R} Result of evaluating f repeatedly across the values of the array.
+ * @template T,S,R
+ */
+goog.array.reduce = goog.NATIVE_ARRAY_PROTOTYPES &&
+                    (goog.array.ASSUME_NATIVE_FUNCTIONS ||
+                     goog.array.ARRAY_PROTOTYPE_.reduce) ?
+    function(arr, f, val, opt_obj) {
+      goog.asserts.assert(arr.length != null);
+      if (opt_obj) {
+        f = goog.bind(f, opt_obj);
+      }
+      return goog.array.ARRAY_PROTOTYPE_.reduce.call(arr, f, val);
+    } :
+    function(arr, f, val, opt_obj) {
+      var rval = val;
+      goog.array.forEach(arr, function(val, index) {
+        rval = f.call(opt_obj, rval, val, index, arr);
+      });
+      return rval;
+    };
+
+
+/**
+ * Passes every element of an array into a function and accumulates the result,
+ * starting from the last element and working towards the first.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-reduceright}
+ *
+ * For example:
+ * var a = ['a', 'b', 'c'];
+ * goog.array.reduceRight(a, function(r, v, i, arr) {return r + v;}, '');
+ * returns 'cba'
+ *
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array
+ *     like object over which to iterate.
+ * @param {?function(this:S, R, T, number, ?) : R} f The function to call for
+ *     every element. This function
+ *     takes 4 arguments (the function's previous result or the initial value,
+ *     the value of the current array element, the current array index, and the
+ *     array itself)
+ *     function(previousValue, currentValue, index, array).
+ * @param {?} val The initial value to pass into the function on the first call.
+ * @param {S=} opt_obj The object to be used as the value of 'this'
+ *     within f.
+ * @return {R} Object returned as a result of evaluating f repeatedly across the
+ *     values of the array.
+ * @template T,S,R
+ */
+goog.array.reduceRight = goog.NATIVE_ARRAY_PROTOTYPES &&
+                         (goog.array.ASSUME_NATIVE_FUNCTIONS ||
+                          goog.array.ARRAY_PROTOTYPE_.reduceRight) ?
+    function(arr, f, val, opt_obj) {
+      goog.asserts.assert(arr.length != null);
+      if (opt_obj) {
+        f = goog.bind(f, opt_obj);
+      }
+      return goog.array.ARRAY_PROTOTYPE_.reduceRight.call(arr, f, val);
+    } :
+    function(arr, f, val, opt_obj) {
+      var rval = val;
+      goog.array.forEachRight(arr, function(val, index) {
+        rval = f.call(opt_obj, rval, val, index, arr);
+      });
+      return rval;
+    };
+
+
+/**
+ * Calls f for each element of an array. If any call returns true, some()
+ * returns true (without checking the remaining elements). If all calls
+ * return false, some() returns false.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-some}
+ *
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array
+ *     like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call for
+ *     for every element. This function takes 3 arguments (the element, the
+ *     index and the array) and should return a boolean.
+ * @param {S=} opt_obj  The object to be used as the value of 'this'
+ *     within f.
+ * @return {boolean} true if any element passes the test.
+ * @template T,S
+ */
+goog.array.some = goog.NATIVE_ARRAY_PROTOTYPES &&
+                  (goog.array.ASSUME_NATIVE_FUNCTIONS ||
+                   goog.array.ARRAY_PROTOTYPE_.some) ?
+    function(arr, f, opt_obj) {
+      goog.asserts.assert(arr.length != null);
+
+      return goog.array.ARRAY_PROTOTYPE_.some.call(arr, f, opt_obj);
+    } :
+    function(arr, f, opt_obj) {
+      var l = arr.length;  // must be fixed during loop... see docs
+      var arr2 = goog.isString(arr) ? arr.split('') : arr;
+      for (var i = 0; i < l; i++) {
+        if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) {
+          return true;
+        }
+      }
+      return false;
+    };
+
+
+/**
+ * Call f for each element of an array. If all calls return true, every()
+ * returns true. If any call returns false, every() returns false and
+ * does not continue to check the remaining elements.
+ *
+ * See {@link http://tinyurl.com/developer-mozilla-org-array-every}
+ *
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array
+ *     like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call for
+ *     for every element. This function takes 3 arguments (the element, the
+ *     index and the array) and should return a boolean.
+ * @param {S=} opt_obj The object to be used as the value of 'this'
+ *     within f.
+ * @return {boolean} false if any element fails the test.
+ * @template T,S
+ */
+goog.array.every = goog.NATIVE_ARRAY_PROTOTYPES &&
+                   (goog.array.ASSUME_NATIVE_FUNCTIONS ||
+                    goog.array.ARRAY_PROTOTYPE_.every) ?
+    function(arr, f, opt_obj) {
+      goog.asserts.assert(arr.length != null);
+
+      return goog.array.ARRAY_PROTOTYPE_.every.call(arr, f, opt_obj);
+    } :
+    function(arr, f, opt_obj) {
+      var l = arr.length;  // must be fixed during loop... see docs
+      var arr2 = goog.isString(arr) ? arr.split('') : arr;
+      for (var i = 0; i < l; i++) {
+        if (i in arr2 && !f.call(opt_obj, arr2[i], i, arr)) {
+          return false;
+        }
+      }
+      return true;
+    };
+
+
+/**
+ * Counts the array elements that fulfill the predicate, i.e. for which the
+ * callback function returns true. Skips holes in the array.
+ *
+ * @param {!(Array<T>|goog.array.ArrayLike)} arr Array or array like object
+ *     over which to iterate.
+ * @param {function(this: S, T, number, ?): boolean} f The function to call for
+ *     every element. Takes 3 arguments (the element, the index and the array).
+ * @param {S=} opt_obj The object to be used as the value of 'this' within f.
+ * @return {number} The number of the matching elements.
+ * @template T,S
+ */
+goog.array.count = function(arr, f, opt_obj) {
+  var count = 0;
+  goog.array.forEach(arr, function(element, index, arr) {
+    if (f.call(opt_obj, element, index, arr)) {
+      ++count;
+    }
+  }, opt_obj);
+  return count;
+};
+
+
+/**
+ * Search an array for the first element that satisfies a given condition and
+ * return that element.
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array
+ *     like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call
+ *     for every element. This function takes 3 arguments (the element, the
+ *     index and the array) and should return a boolean.
+ * @param {S=} opt_obj An optional "this" context for the function.
+ * @return {T|null} The first array element that passes the test, or null if no
+ *     element is found.
+ * @template T,S
+ */
+goog.array.find = function(arr, f, opt_obj) {
+  var i = goog.array.findIndex(arr, f, opt_obj);
+  return i < 0 ? null : goog.isString(arr) ? arr.charAt(i) : arr[i];
+};
+
+
+/**
+ * Search an array for the first element that satisfies a given condition and
+ * return its index.
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array
+ *     like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call for
+ *     every element. This function
+ *     takes 3 arguments (the element, the index and the array) and should
+ *     return a boolean.
+ * @param {S=} opt_obj An optional "this" context for the function.
+ * @return {number} The index of the first array element that passes the test,
+ *     or -1 if no element is found.
+ * @template T,S
+ */
+goog.array.findIndex = function(arr, f, opt_obj) {
+  var l = arr.length;  // must be fixed during loop... see docs
+  var arr2 = goog.isString(arr) ? arr.split('') : arr;
+  for (var i = 0; i < l; i++) {
+    if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) {
+      return i;
+    }
+  }
+  return -1;
+};
+
+
+/**
+ * Search an array (in reverse order) for the last element that satisfies a
+ * given condition and return that element.
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array
+ *     like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call
+ *     for every element. This function
+ *     takes 3 arguments (the element, the index and the array) and should
+ *     return a boolean.
+ * @param {S=} opt_obj An optional "this" context for the function.
+ * @return {T|null} The last array element that passes the test, or null if no
+ *     element is found.
+ * @template T,S
+ */
+goog.array.findRight = function(arr, f, opt_obj) {
+  var i = goog.array.findIndexRight(arr, f, opt_obj);
+  return i < 0 ? null : goog.isString(arr) ? arr.charAt(i) : arr[i];
+};
+
+
+/**
+ * Search an array (in reverse order) for the last element that satisfies a
+ * given condition and return its index.
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array
+ *     like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call
+ *     for every element. This function
+ *     takes 3 arguments (the element, the index and the array) and should
+ *     return a boolean.
+ * @param {S=} opt_obj An optional "this" context for the function.
+ * @return {number} The index of the last array element that passes the test,
+ *     or -1 if no element is found.
+ * @template T,S
+ */
+goog.array.findIndexRight = function(arr, f, opt_obj) {
+  var l = arr.length;  // must be fixed during loop... see docs
+  var arr2 = goog.isString(arr) ? arr.split('') : arr;
+  for (var i = l - 1; i >= 0; i--) {
+    if (i in arr2 && f.call(opt_obj, arr2[i], i, arr)) {
+      return i;
+    }
+  }
+  return -1;
+};
+
+
+/**
+ * Whether the array contains the given object.
+ * @param {goog.array.ArrayLike} arr The array to test for the presence of the
+ *     element.
+ * @param {*} obj The object for which to test.
+ * @return {boolean} true if obj is present.
+ */
+goog.array.contains = function(arr, obj) {
+  return goog.array.indexOf(arr, obj) >= 0;
+};
+
+
+/**
+ * Whether the array is empty.
+ * @param {goog.array.ArrayLike} arr The array to test.
+ * @return {boolean} true if empty.
+ */
+goog.array.isEmpty = function(arr) {
+  return arr.length == 0;
+};
+
+
+/**
+ * Clears the array.
+ * @param {goog.array.ArrayLike} arr Array or array like object to clear.
+ */
+goog.array.clear = function(arr) {
+  // For non real arrays we don't have the magic length so we delete the
+  // indices.
+  if (!goog.isArray(arr)) {
+    for (var i = arr.length - 1; i >= 0; i--) {
+      delete arr[i];
+    }
+  }
+  arr.length = 0;
+};
+
+
+/**
+ * Pushes an item into an array, if it's not already in the array.
+ * @param {Array<T>} arr Array into which to insert the item.
+ * @param {T} obj Value to add.
+ * @template T
+ */
+goog.array.insert = function(arr, obj) {
+  if (!goog.array.contains(arr, obj)) {
+    arr.push(obj);
+  }
+};
+
+
+/**
+ * Inserts an object at the given index of the array.
+ * @param {goog.array.ArrayLike} arr The array to modify.
+ * @param {*} obj The object to insert.
+ * @param {number=} opt_i The index at which to insert the object. If omitted,
+ *      treated as 0. A negative index is counted from the end of the array.
+ */
+goog.array.insertAt = function(arr, obj, opt_i) {
+  goog.array.splice(arr, opt_i, 0, obj);
+};
+
+
+/**
+ * Inserts at the given index of the array, all elements of another array.
+ * @param {goog.array.ArrayLike} arr The array to modify.
+ * @param {goog.array.ArrayLike} elementsToAdd The array of elements to add.
+ * @param {number=} opt_i The index at which to insert the object. If omitted,
+ *      treated as 0. A negative index is counted from the end of the array.
+ */
+goog.array.insertArrayAt = function(arr, elementsToAdd, opt_i) {
+  goog.partial(goog.array.splice, arr, opt_i, 0).apply(null, elementsToAdd);
+};
+
+
+/**
+ * Inserts an object into an array before a specified object.
+ * @param {Array<T>} arr The array to modify.
+ * @param {T} obj The object to insert.
+ * @param {T=} opt_obj2 The object before which obj should be inserted. If obj2
+ *     is omitted or not found, obj is inserted at the end of the array.
+ * @template T
+ */
+goog.array.insertBefore = function(arr, obj, opt_obj2) {
+  var i;
+  if (arguments.length == 2 || (i = goog.array.indexOf(arr, opt_obj2)) < 0) {
+    arr.push(obj);
+  } else {
+    goog.array.insertAt(arr, obj, i);
+  }
+};
+
+
+/**
+ * Removes the first occurrence of a particular value from an array.
+ * @param {Array<T>|goog.array.ArrayLike} arr Array from which to remove
+ *     value.
+ * @param {T} obj Object to remove.
+ * @return {boolean} True if an element was removed.
+ * @template T
+ */
+goog.array.remove = function(arr, obj) {
+  var i = goog.array.indexOf(arr, obj);
+  var rv;
+  if ((rv = i >= 0)) {
+    goog.array.removeAt(arr, i);
+  }
+  return rv;
+};
+
+
+/**
+ * Removes from an array the element at index i
+ * @param {goog.array.ArrayLike} arr Array or array like object from which to
+ *     remove value.
+ * @param {number} i The index to remove.
+ * @return {boolean} True if an element was removed.
+ */
+goog.array.removeAt = function(arr, i) {
+  goog.asserts.assert(arr.length != null);
+
+  // use generic form of splice
+  // splice returns the removed items and if successful the length of that
+  // will be 1
+  return goog.array.ARRAY_PROTOTYPE_.splice.call(arr, i, 1).length == 1;
+};
+
+
+/**
+ * Removes the first value that satisfies the given condition.
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array
+ *     like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call
+ *     for every element. This function
+ *     takes 3 arguments (the element, the index and the array) and should
+ *     return a boolean.
+ * @param {S=} opt_obj An optional "this" context for the function.
+ * @return {boolean} True if an element was removed.
+ * @template T,S
+ */
+goog.array.removeIf = function(arr, f, opt_obj) {
+  var i = goog.array.findIndex(arr, f, opt_obj);
+  if (i >= 0) {
+    goog.array.removeAt(arr, i);
+    return true;
+  }
+  return false;
+};
+
+
+/**
+ * Removes all values that satisfy the given condition.
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array
+ *     like object over which to iterate.
+ * @param {?function(this:S, T, number, ?) : boolean} f The function to call
+ *     for every element. This function
+ *     takes 3 arguments (the element, the index and the array) and should
+ *     return a boolean.
+ * @param {S=} opt_obj An optional "this" context for the function.
+ * @return {number} The number of items removed
+ * @template T,S
+ */
+goog.array.removeAllIf = function(arr, f, opt_obj) {
+  var removedCount = 0;
+  goog.array.forEachRight(arr, function(val, index) {
+    if (f.call(opt_obj, val, index, arr)) {
+      if (goog.array.removeAt(arr, index)) {
+        removedCount++;
+      }
+    }
+  });
+  return removedCount;
+};
+
+
+/**
+ * Returns a new array that is the result of joining the arguments.  If arrays
+ * are passed then their items are added, however, if non-arrays are passed they
+ * will be added to the return array as is.
+ *
+ * Note that ArrayLike objects will be added as is, rather than having their
+ * items added.
+ *
+ * goog.array.concat([1, 2], [3, 4]) -> [1, 2, 3, 4]
+ * goog.array.concat(0, [1, 2]) -> [0, 1, 2]
+ * goog.array.concat([1, 2], null) -> [1, 2, null]
+ *
+ * There is bug in all current versions of IE (6, 7 and 8) where arrays created
+ * in an iframe become corrupted soon (not immediately) after the iframe is
+ * destroyed. This is common if loading data via goog.net.IframeIo, for example.
+ * This corruption only affects the concat method which will start throwing
+ * Catastrophic Errors (#-2147418113).
+ *
+ * See http://endoflow.com/scratch/corrupted-arrays.html for a test case.
+ *
+ * Internally goog.array should use this, so that all methods will continue to
+ * work on these broken array objects.
+ *
+ * @param {...*} var_args Items to concatenate.  Arrays will have each item
+ *     added, while primitives and objects will be added as is.
+ * @return {!Array<?>} The new resultant array.
+ */
+goog.array.concat = function(var_args) {
+  return goog.array.ARRAY_PROTOTYPE_.concat.apply(
+      goog.array.ARRAY_PROTOTYPE_, arguments);
+};
+
+
+/**
+ * Returns a new array that contains the contents of all the arrays passed.
+ * @param {...!Array<T>} var_args
+ * @return {!Array<T>}
+ * @template T
+ */
+goog.array.join = function(var_args) {
+  return goog.array.ARRAY_PROTOTYPE_.concat.apply(
+      goog.array.ARRAY_PROTOTYPE_, arguments);
+};
+
+
+/**
+ * Converts an object to an array.
+ * @param {Array<T>|goog.array.ArrayLike} object  The object to convert to an
+ *     array.
+ * @return {!Array<T>} The object converted into an array. If object has a
+ *     length property, every property indexed with a non-negative number
+ *     less than length will be included in the result. If object does not
+ *     have a length property, an empty array will be returned.
+ * @template T
+ */
+goog.array.toArray = function(object) {
+  var length = object.length;
+
+  // If length is not a number the following it false. This case is kept for
+  // backwards compatibility since there are callers that pass objects that are
+  // not array like.
+  if (length > 0) {
+    var rv = new Array(length);
+    for (var i = 0; i < length; i++) {
+      rv[i] = object[i];
+    }
+    return rv;
+  }
+  return [];
+};
+
+
+/**
+ * Does a shallow copy of an array.
+ * @param {Array<T>|goog.array.ArrayLike} arr  Array or array-like object to
+ *     clone.
+ * @return {!Array<T>} Clone of the input array.
+ * @template T
+ */
+goog.array.clone = goog.array.toArray;
+
+
+/**
+ * Extends an array with another array, element, or "array like" object.
+ * This function operates 'in-place', it does not create a new Array.
+ *
+ * Example:
+ * var a = [];
+ * goog.array.extend(a, [0, 1]);
+ * a; // [0, 1]
+ * goog.array.extend(a, 2);
+ * a; // [0, 1, 2]
+ *
+ * @param {Array<VALUE>} arr1  The array to modify.
+ * @param {...(Array<VALUE>|VALUE)} var_args The elements or arrays of elements
+ *     to add to arr1.
+ * @template VALUE
+ */
+goog.array.extend = function(arr1, var_args) {
+  for (var i = 1; i < arguments.length; i++) {
+    var arr2 = arguments[i];
+    if (goog.isArrayLike(arr2)) {
+      var len1 = arr1.length || 0;
+      var len2 = arr2.length || 0;
+      arr1.length = len1 + len2;
+      for (var j = 0; j < len2; j++) {
+        arr1[len1 + j] = arr2[j];
+      }
+    } else {
+      arr1.push(arr2);
+    }
+  }
+};
+
+
+/**
+ * Adds or removes elements from an array. This is a generic version of Array
+ * splice. This means that it might work on other objects similar to arrays,
+ * such as the arguments object.
+ *
+ * @param {Array<T>|goog.array.ArrayLike} arr The array to modify.
+ * @param {number|undefined} index The index at which to start changing the
+ *     array. If not defined, treated as 0.
+ * @param {number} howMany How many elements to remove (0 means no removal. A
+ *     value below 0 is treated as zero and so is any other non number. Numbers
+ *     are floored).
+ * @param {...T} var_args Optional, additional elements to insert into the
+ *     array.
+ * @return {!Array<T>} the removed elements.
+ * @template T
+ */
+goog.array.splice = function(arr, index, howMany, var_args) {
+  goog.asserts.assert(arr.length != null);
+
+  return goog.array.ARRAY_PROTOTYPE_.splice.apply(
+      arr, goog.array.slice(arguments, 1));
+};
+
+
+/**
+ * Returns a new array from a segment of an array. This is a generic version of
+ * Array slice. This means that it might work on other objects similar to
+ * arrays, such as the arguments object.
+ *
+ * @param {Array<T>|goog.array.ArrayLike} arr The array from
+ * which to copy a segment.
+ * @param {number} start The index of the first element to copy.
+ * @param {number=} opt_end The index after the last element to copy.
+ * @return {!Array<T>} A new array containing the specified segment of the
+ *     original array.
+ * @template T
+ */
+goog.array.slice = function(arr, start, opt_end) {
+  goog.asserts.assert(arr.length != null);
+
+  // passing 1 arg to slice is not the same as passing 2 where the second is
+  // null or undefined (in that case the second argument is treated as 0).
+  // we could use slice on the arguments object and then use apply instead of
+  // testing the length
+  if (arguments.length <= 2) {
+    return goog.array.ARRAY_PROTOTYPE_.slice.call(arr, start);
+  } else {
+    return goog.array.ARRAY_PROTOTYPE_.slice.call(arr, start, opt_end);
+  }
+};
+
+
+/**
+ * Removes all duplicates from an array (retaining only the first
+ * occurrence of each array element).  This function modifies the
+ * array in place and doesn't change the order of the non-duplicate items.
+ *
+ * For objects, duplicates are identified as having the same unique ID as
+ * defined by {@link goog.getUid}.
+ *
+ * Alternatively you can specify a custom hash function that returns a unique
+ * value for each item in the array it should consider unique.
+ *
+ * Runtime: N,
+ * Worstcase space: 2N (no dupes)
+ *
+ * @param {Array<T>|goog.array.ArrayLike} arr The array from which to remove
+ *     duplicates.
+ * @param {Array=} opt_rv An optional array in which to return the results,
+ *     instead of performing the removal inplace.  If specified, the original
+ *     array will remain unchanged.
+ * @param {function(T):string=} opt_hashFn An optional function to use to
+ *     apply to every item in the array. This function should return a unique
+ *     value for each item in the array it should consider unique.
+ * @template T
+ */
+goog.array.removeDuplicates = function(arr, opt_rv, opt_hashFn) {
+  var returnArray = opt_rv || arr;
+  var defaultHashFn = function(item) {
+    // Prefix each type with a single character representing the type to
+    // prevent conflicting keys (e.g. true and 'true').
+    return goog.isObject(current) ? 'o' + goog.getUid(current) :
+        (typeof current).charAt(0) + current;
+  };
+  var hashFn = opt_hashFn || defaultHashFn;
+
+  var seen = {}, cursorInsert = 0, cursorRead = 0;
+  while (cursorRead < arr.length) {
+    var current = arr[cursorRead++];
+    var key = hashFn(current);
+    if (!Object.prototype.hasOwnProperty.call(seen, key)) {
+      seen[key] = true;
+      returnArray[cursorInsert++] = current;
+    }
+  }
+  returnArray.length = cursorInsert;
+};
+
+
+/**
+ * Searches the specified array for the specified target using the binary
+ * search algorithm.  If no opt_compareFn is specified, elements are compared
+ * using <code>goog.array.defaultCompare</code>, which compares the elements
+ * using the built in < and > operators.  This will produce the expected
+ * behavior for homogeneous arrays of String(s) and Number(s). The array
+ * specified <b>must</b> be sorted in ascending order (as defined by the
+ * comparison function).  If the array is not sorted, results are undefined.
+ * If the array contains multiple instances of the specified target value, any
+ * of these instances may be found.
+ *
+ * Runtime: O(log n)
+ *
+ * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to be searched.
+ * @param {TARGET} target The sought value.
+ * @param {function(TARGET, VALUE): number=} opt_compareFn Optional comparison
+ *     function by which the array is ordered. Should take 2 arguments to
+ *     compare, and return a negative number, zero, or a positive number
+ *     depending on whether the first argument is less than, equal to, or
+ *     greater than the second.
+ * @return {number} Lowest index of the target value if found, otherwise
+ *     (-(insertion point) - 1). The insertion point is where the value should
+ *     be inserted into arr to preserve the sorted property.  Return value >= 0
+ *     iff target is found.
+ * @template TARGET, VALUE
+ */
+goog.array.binarySearch = function(arr, target, opt_compareFn) {
+  return goog.array.binarySearch_(arr,
+      opt_compareFn || goog.array.defaultCompare, false /* isEvaluator */,
+      target);
+};
+
+
+/**
+ * Selects an index in the specified array using the binary search algorithm.
+ * The evaluator receives an element and determines whether the desired index
+ * is before, at, or after it.  The evaluator must be consistent (formally,
+ * goog.array.map(goog.array.map(arr, evaluator, opt_obj), goog.math.sign)
+ * must be monotonically non-increasing).
+ *
+ * Runtime: O(log n)
+ *
+ * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to be searched.
+ * @param {function(this:THIS, VALUE, number, ?): number} evaluator
+ *     Evaluator function that receives 3 arguments (the element, the index and
+ *     the array). Should return a negative number, zero, or a positive number
+ *     depending on whether the desired index is before, at, or after the
+ *     element passed to it.
+ * @param {THIS=} opt_obj The object to be used as the value of 'this'
+ *     within evaluator.
+ * @return {number} Index of the leftmost element matched by the evaluator, if
+ *     such exists; otherwise (-(insertion point) - 1). The insertion point is
+ *     the index of the first element for which the evaluator returns negative,
+ *     or arr.length if no such element exists. The return value is non-negative
+ *     iff a match is found.
+ * @template THIS, VALUE
+ */
+goog.array.binarySelect = function(arr, evaluator, opt_obj) {
+  return goog.array.binarySearch_(arr, evaluator, true /* isEvaluator */,
+      undefined /* opt_target */, opt_obj);
+};
+
+
+/**
+ * Implementation of a binary search algorithm which knows how to use both
+ * comparison functions and evaluators. If an evaluator is provided, will call
+ * the evaluator with the given optional data object, conforming to the
+ * interface defined in binarySelect. Otherwise, if a comparison function is
+ * provided, will call the comparison function against the given data object.
+ *
+ * This implementation purposefully does not use goog.bind or goog.partial for
+ * performance reasons.
+ *
+ * Runtime: O(log n)
+ *
+ * @param {Array<VALUE>|goog.array.ArrayLike} arr The array to be searched.
+ * @param {function(TARGET, VALUE): number|
+ *         function(this:THIS, VALUE, number, ?): number} compareFn Either an
+ *     evaluator or a comparison function, as defined by binarySearch
+ *     and binarySelect above.
+ * @param {boolean} isEvaluator Whether the function is an evaluator or a
+ *     comparison function.
+ * @param {TARGET=} opt_target If the function is a comparison function, then
+ *     this is the target to binary search for.
+ * @param {THIS=} opt_selfObj If the function is an evaluator, this is an
+  *    optional this object for the evaluator.
+ * @return {number} Lowest index of the target value if found, otherwise
+ *     (-(insertion point) - 1). The insertion point is where the value should
+ *     be inserted into arr to preserve the sorted property.  Return value >= 0
+ *     iff target is found.
+ * @template THIS, VALUE, TARGET
+ * @private
+ */
+goog.array.binarySearch_ = function(arr, compareFn, isEvaluator, opt_target,
+    opt_selfObj) {
+  var left = 0;  // inclusive
+  var right = arr.length;  // exclusive
+  var found;
+  while (left < right) {
+    var middle = (left + right) >> 1;
+    var compareResult;
+    if (isEvaluator) {
+      compareResult = compareFn.call(opt_selfObj, arr[middle], middle, arr);
+    } else {
+      compareResult = compareFn(opt_target, arr[middle]);
+    }
+    if (compareResult > 0) {
+      left = middle + 1;
+    } else {
+      right = middle;
+      // We are looking for the lowest index so we can't return immediately.
+      found = !compareResult;
+    }
+  }
+  // left is the index if found, or the insertion point otherwise.
+  // ~left is a shorthand for -left - 1.
+  return found ? left : ~left;
+};
+
+
+/**
+ * Sorts the specified array into ascending order.  If no opt_compareFn is
+ * specified, elements are compared using
+ * <code>goog.array.defaultCompare</code>, which compares the elements using
+ * the built in < and > operators.  This will produce the expected behavior
+ * for homogeneous arrays of String(s) and Number(s), unlike the native sort,
+ * but will give unpredictable results for heterogenous lists of strings and
+ * numbers with different numbers of digits.
+ *
+ * This sort is not guaranteed to be stable.
+ *
+ * Runtime: Same as <code>Array.prototype.sort</code>
+ *
+ * @param {Array<T>} arr The array to be sorted.
+ * @param {?function(T,T):number=} opt_compareFn Optional comparison
+ *     function by which the
+ *     array is to be ordered. Should take 2 arguments to compare, and return a
+ *     negative number, zero, or a positive number depending on whether the
+ *     first argument is less than, equal to, or greater than the second.
+ * @template T
+ */
+goog.array.sort = function(arr, opt_compareFn) {
+  // TODO(arv): Update type annotation since null is not accepted.
+  arr.sort(opt_compareFn || goog.array.defaultCompare);
+};
+
+
+/**
+ * Sorts the specified array into ascending order in a stable way.  If no
+ * opt_compareFn is specified, elements are compared using
+ * <code>goog.array.defaultCompare</code>, which compares the elements using
+ * the built in < and > operators.  This will produce the expected behavior
+ * for homogeneous arrays of String(s) and Number(s).
+ *
+ * Runtime: Same as <code>Array.prototype.sort</code>, plus an additional
+ * O(n) overhead of copying the array twice.
+ *
+ * @param {Array<T>} arr The array to be sorted.
+ * @param {?function(T, T): number=} opt_compareFn Optional comparison function
+ *     by which the array is to be ordered. Should take 2 arguments to compare,
+ *     and return a negative number, zero, or a positive number depending on
+ *     whether the first argument is less than, equal to, or greater than the
+ *     second.
+ * @template T
+ */
+goog.array.stableSort = function(arr, opt_compareFn) {
+  for (var i = 0; i < arr.length; i++) {
+    arr[i] = {index: i, value: arr[i]};
+  }
+  var valueCompareFn = opt_compareFn || goog.array.defaultCompare;
+  function stableCompareFn(obj1, obj2) {
+    return valueCompareFn(obj1.value, obj2.value) || obj1.index - obj2.index;
+  };
+  goog.array.sort(arr, stableCompareFn);
+  for (var i = 0; i < arr.length; i++) {
+    arr[i] = arr[i].value;
+  }
+};
+
+
+/**
+ * Sort the specified array into ascending order based on item keys
+ * returned by the specified key function.
+ * If no opt_compareFn is specified, the keys are compared in ascending order
+ * using <code>goog.array.defaultCompare</code>.
+ *
+ * Runtime: O(S(f(n)), where S is runtime of <code>goog.array.sort</code>
+ * and f(n) is runtime of the key function.
+ *
+ * @param {Array<T>} arr The array to be sorted.
+ * @param {function(T): K} keyFn Function taking array element and returning
+ *     a key used for sorting this element.
+ * @param {?function(K, K): number=} opt_compareFn Optional comparison function
+ *     by which the keys are to be ordered. Should take 2 arguments to compare,
+ *     and return a negative number, zero, or a positive number depending on
+ *     whether the first argument is less than, equal to, or greater than the
+ *     second.
+ * @template T
+ * @template K
+ */
+goog.array.sortByKey = function(arr, keyFn, opt_compareFn) {
+  var keyCompareFn = opt_compareFn || goog.array.defaultCompare;
+  goog.array.sort(arr, function(a, b) {
+    return keyCompareFn(keyFn(a), keyFn(b));
+  });
+};
+
+
+/**
+ * Sorts an array of objects by the specified object key and compare
+ * function. If no compare function is provided, the key values are
+ * compared in ascending order using <code>goog.array.defaultCompare</code>.
+ * This won't work for keys that get renamed by the compiler. So use
+ * {'foo': 1, 'bar': 2} rather than {foo: 1, bar: 2}.
+ * @param {Array<Object>} arr An array of objects to sort.
+ * @param {string} key The object key to sort by.
+ * @param {Function=} opt_compareFn The function to use to compare key
+ *     values.
+ */
+goog.array.sortObjectsByKey = function(arr, key, opt_compareFn) {
+  goog.array.sortByKey(arr,
+      function(obj) { return obj[key]; },
+      opt_compareFn);
+};
+
+
+/**
+ * Tells if the array is sorted.
+ * @param {!Array<T>} arr The array.
+ * @param {?function(T,T):number=} opt_compareFn Function to compare the
+ *     array elements.
+ *     Should take 2 arguments to compare, and return a negative number, zero,
+ *     or a positive number depending on whether the first argument is less
+ *     than, equal to, or greater than the second.
+ * @param {boolean=} opt_strict If true no equal elements are allowed.
+ * @return {boolean} Whether the array is sorted.
+ * @template T
+ */
+goog.array.isSorted = function(arr, opt_compareFn, opt_strict) {
+  var compare = opt_compareFn || goog.array.defaultCompare;
+  for (var i = 1; i < arr.length; i++) {
+    var compareResult = compare(arr[i - 1], arr[i]);
+    if (compareResult > 0 || compareResult == 0 && opt_strict) {
+      return false;
+    }
+  }
+  return true;
+};
+
+
+/**
+ * Compares two arrays for equality. Two arrays are considered equal if they
+ * have the same length and their corresponding elements are equal according to
+ * the comparison function.
+ *
+ * @param {goog.array.ArrayLike} arr1 The first array to compare.
+ * @param {goog.array.ArrayLike} arr2 The second array to compare.
+ * @param {Function=} opt_equalsFn Optional comparison function.
+ *     Should take 2 arguments to compare, and return true if the arguments
+ *     are equal. Defaults to {@link goog.array.defaultCompareEquality} which
+ *     compares the elements using the built-in '===' operator.
+ * @return {boolean} Whether the two arrays are equal.
+ */
+goog.array.equals = function(arr1, arr2, opt_equalsFn) {
+  if (!goog.isArrayLike(arr1) || !goog.isArrayLike(arr2) ||
+      arr1.length != arr2.length) {
+    return false;
+  }
+  var l = arr1.length;
+  var equalsFn = opt_equalsFn || goog.array.defaultCompareEquality;
+  for (var i = 0; i < l; i++) {
+    if (!equalsFn(arr1[i], arr2[i])) {
+      return false;
+    }
+  }
+  return true;
+};
+
+
+/**
+ * 3-way array compare function.
+ * @param {!Array<VALUE>|!goog.array.ArrayLike} arr1 The first array to
+ *     compare.
+ * @param {!Array<VALUE>|!goog.array.ArrayLike} arr2 The second array to
+ *     compare.
+ * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison
+ *     function by which the array is to be ordered. Should take 2 arguments to
+ *     compare, and return a negative number, zero, or a positive number
+ *     depending on whether the first argument is less than, equal to, or
+ *     greater than the second.
+ * @return {number} Negative number, zero, or a positive number depending on
+ *     whether the first argument is less than, equal to, or greater than the
+ *     second.
+ * @template VALUE
+ */
+goog.array.compare3 = function(arr1, arr2, opt_compareFn) {
+  var compare = opt_compareFn || goog.array.defaultCompare;
+  var l = Math.min(arr1.length, arr2.length);
+  for (var i = 0; i < l; i++) {
+    var result = compare(arr1[i], arr2[i]);
+    if (result != 0) {
+      return result;
+    }
+  }
+  return goog.array.defaultCompare(arr1.length, arr2.length);
+};
+
+
+/**
+ * Compares its two arguments for order, using the built in < and >
+ * operators.
+ * @param {VALUE} a The first object to be compared.
+ * @param {VALUE} b The second object to be compared.
+ * @return {number} A negative number, zero, or a positive number as the first
+ *     argument is less than, equal to, or greater than the second,
+ *     respectively.
+ * @template VALUE
+ */
+goog.array.defaultCompare = function(a, b) {
+  return a > b ? 1 : a < b ? -1 : 0;
+};
+
+
+/**
+ * Compares its two arguments for inverse order, using the built in < and >
+ * operators.
+ * @param {VALUE} a The first object to be compared.
+ * @param {VALUE} b The second object to be compared.
+ * @return {number} A negative number, zero, or a positive number as the first
+ *     argument is greater than, equal to, or less than the second,
+ *     respectively.
+ * @template VALUE
+ */
+goog.array.inverseDefaultCompare = function(a, b) {
+  return -goog.array.defaultCompare(a, b);
+};
+
+
+/**
+ * Compares its two arguments for equality, using the built in === operator.
+ * @param {*} a The first object to compare.
+ * @param {*} b The second object to compare.
+ * @return {boolean} True if the two arguments are equal, false otherwise.
+ */
+goog.array.defaultCompareEquality = function(a, b) {
+  return a === b;
+};
+
+
+/**
+ * Inserts a value into a sorted array. The array is not modified if the
+ * value is already present.
+ * @param {Array<VALUE>|goog.array.ArrayLike} array The array to modify.
+ * @param {VALUE} value The object to insert.
+ * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison
+ *     function by which the array is ordered. Should take 2 arguments to
+ *     compare, and return a negative number, zero, or a positive number
+ *     depending on whether the first argument is less than, equal to, or
+ *     greater than the second.
+ * @return {boolean} True if an element was inserted.
+ * @template VALUE
+ */
+goog.array.binaryInsert = function(array, value, opt_compareFn) {
+  var index = goog.array.binarySearch(array, value, opt_compareFn);
+  if (index < 0) {
+    goog.array.insertAt(array, value, -(index + 1));
+    return true;
+  }
+  return false;
+};
+
+
+/**
+ * Removes a value from a sorted array.
+ * @param {!Array<VALUE>|!goog.array.ArrayLike} array The array to modify.
+ * @param {VALUE} value The object to remove.
+ * @param {function(VALUE, VALUE): number=} opt_compareFn Optional comparison
+ *     function by which the array is ordered. Should take 2 arguments to
+ *     compare, and return a negative number, zero, or a positive number
+ *     depending on whether the first argument is less than, equal to, or
+ *     greater than the second.
+ * @return {boolean} True if an element was removed.
+ * @template VALUE
+ */
+goog.array.binaryRemove = function(array, value, opt_compareFn) {
+  var index = goog.array.binarySearch(array, value, opt_compareFn);
+  return (index >= 0) ? goog.array.removeAt(array, index) : false;
+};
+
+
+/**
+ * Splits an array into disjoint buckets according to a splitting function.
+ * @param {Array<T>} array The array.
+ * @param {function(this:S, T,number,Array<T>):?} sorter Function to call for
+ *     every element.  This takes 3 arguments (the element, the index and the
+ *     array) and must return a valid object key (a string, number, etc), or
+ *     undefined, if that object should not be placed in a bucket.
+ * @param {S=} opt_obj The object to be used as the value of 'this' within
+ *     sorter.
+ * @return {!Object} An object, with keys being all of the unique return values
+ *     of sorter, and values being arrays containing the items for
+ *     which the splitter returned that key.
+ * @template T,S
+ */
+goog.array.bucket = function(array, sorter, opt_obj) {
+  var buckets = {};
+
+  for (var i = 0; i < array.length; i++) {
+    var value = array[i];
+    var key = sorter.call(opt_obj, value, i, array);
+    if (goog.isDef(key)) {
+      // Push the value to the right bucket, creating it if necessary.
+      var bucket = buckets[key] || (buckets[key] = []);
+      bucket.push(value);
+    }
+  }
+
+  return buckets;
+};
+
+
+/**
+ * Creates a new object built from the provided array and the key-generation
+ * function.
+ * @param {Array<T>|goog.array.ArrayLike} arr Array or array like object over
+ *     which to iterate whose elements will be the values in the new object.
+ * @param {?function(this:S, T, number, ?) : string} keyFunc The function to
+ *     call for every element. This function takes 3 arguments (the element, the
+ *     index and the array) and should return a string that will be used as the
+ *     key for the element in the new object. If the function returns the same
+ *     key for more than one element, the value for that key is
+ *     implementation-defined.
+ * @param {S=} opt_obj The object to be used as the value of 'this'
+ *     within keyFunc.
+ * @return {!Object<T>} The new object.
+ * @template T,S
+ */
+goog.array.toObject = function(arr, keyFunc, opt_obj) {
+  var ret = {};
+  goog.array.forEach(arr, function(element, index) {
+    ret[keyFunc.call(opt_obj, element, index, arr)] = element;
+  });
+  return ret;
+};
+
+
+/**
+ * Creates a range of numbers in an arithmetic progression.
+ *
+ * Range takes 1, 2, or 3 arguments:
+ * <pre>
+ * range(5) is the same as range(0, 5, 1) and produces [0, 1, 2, 3, 4]
+ * range(2, 5) is the same as range(2, 5, 1) and produces [2, 3, 4]
+ * range(-2, -5, -1) produces [-2, -3, -4]
+ * range(-2, -5, 1) produces [], since stepping by 1 wouldn't ever reach -5.
+ * </pre>
+ *
+ * @param {number} startOrEnd The starting value of the range if an end argument
+ *     is provided. Otherwise, the start value is 0, and this is the end value.
+ * @param {number=} opt_end The optional end value of the range.
+ * @param {number=} opt_step The step size between range values. Defaults to 1
+ *     if opt_step is undefined or 0.
+ * @return {!Array<number>} An array of numbers for the requested range. May be
+ *     an empty array if adding the step would not converge toward the end
+ *     value.
+ */
+goog.array.range = function(startOrEnd, opt_end, opt_step) {
+  var array = [];
+  var start = 0;
+  var end = startOrEnd;
+  var step = opt_step || 1;
+  if (opt_end !== undefined) {
+    start = startOrEnd;
+    end = opt_end;
+  }
+
+  if (step * (end - start) < 0) {
+    // Sign mismatch: start + step will never reach the end value.
+    return [];
+  }
+
+  if (step > 0) {
+    for (var i = start; i < end; i += step) {
+      array.push(i);
+    }
+  } else {
+    for (var i = start; i > end; i += step) {
+      array.push(i);
+    }
+  }
+  return array;
+};
+
+
+/**
+ * Returns an array consisting of the given value repeated N times.
+ *
+ * @param {VALUE} value The value to repeat.
+ * @param {number} n The repeat count.
+ * @return {!Array<VALUE>} An array with the repeated value.
+ * @template VALUE
+ */
+goog.array.repeat = function(value, n) {
+  var array = [];
+  for (var i = 0; i < n; i++) {
+    array[i] = value;
+  }
+  return array;
+};
+
+
+/**
+ * Returns an array consisting of every argument with all arrays
+ * expanded in-place recursively.
+ *
+ * @param {...*} var_args The values to flatten.
+ * @return {!Array<?>} An array containing the flattened values.
+ */
+goog.array.flatten = function(var_args) {
+  var CHUNK_SIZE = 8192;
+
+  var result = [];
+  for (var i = 0; i < arguments.length; i++) {
+    var element = arguments[i];
+    if (goog.isArray(element)) {
+      for (var c = 0; c < element.length; c += CHUNK_SIZE) {
+        var chunk = goog.array.slice(element, c, c + CHUNK_SIZE);
+        var recurseResult = goog.array.flatten.apply(null, chunk);
+        for (var r = 0; r < recurseResult.length; r++) {
+          result.push(recurseResult[r]);
+        }
+      }
+    } else {
+      result.push(element);
+    }
+  }
+  return result;
+};
+
+
+/**
+ * Rotates an array in-place. After calling this method, the element at
+ * index i will be the element previously at index (i - n) %
+ * array.length, for all values of i between 0 and array.length - 1,
+ * inclusive.
+ *
+ * For example, suppose list comprises [t, a, n, k, s]. After invoking
+ * rotate(array, 1) (or rotate(array, -4)), array will comprise [s, t, a, n, k].
+ *
+ * @param {!Array<T>} array The array to rotate.
+ * @param {number} n The amount to rotate.
+ * @return {!Array<T>} The array.
+ * @template T
+ */
+goog.array.rotate = function(array, n) {
+  goog.asserts.assert(array.length != null);
+
+  if (array.length) {
+    n %= array.length;
+    if (n > 0) {
+      goog.array.ARRAY_PROTOTYPE_.unshift.apply(array, array.splice(-n, n));
+    } else if (n < 0) {
+      goog.array.ARRAY_PROTOTYPE_.push.apply(array, array.splice(0, -n));
+    }
+  }
+  return array;
+};
+
+
+/**
+ * Moves one item of an array to a new position keeping the order of the rest
+ * of the items. Example use case: keeping a list of JavaScript objects
+ * synchronized with the corresponding list of DOM elements after one of the
+ * elements has been dragged to a new position.
+ * @param {!(Array|Arguments|{length:number})} arr The array to modify.
+ * @param {number} fromIndex Index of the item to move between 0 and
+ *     {@code arr.length - 1}.
+ * @param {number} toIndex Target index between 0 and {@code arr.length - 1}.
+ */
+goog.array.moveItem = function(arr, fromIndex, toIndex) {
+  goog.asserts.assert(fromIndex >= 0 && fromIndex < arr.length);
+  goog.asserts.assert(toIndex >= 0 && toIndex < arr.length);
+  // Remove 1 item at fromIndex.
+  var removedItems = goog.array.ARRAY_PROTOTYPE_.splice.call(arr, fromIndex, 1);
+  // Insert the removed item at toIndex.
+  goog.array.ARRAY_PROTOTYPE_.splice.call(arr, toIndex, 0, removedItems[0]);
+  // We don't use goog.array.insertAt and goog.array.removeAt, because they're
+  // significantly slower than splice.
+};
+
+
+/**
+ * Creates a new array for which the element at position i is an array of the
+ * ith element of the provided arrays.  The returned array will only be as long
+ * as the shortest array provided; additional values are ignored.  For example,
+ * the result of zipping [1, 2] and [3, 4, 5] is [[1,3], [2, 4]].
+ *
+ * This is similar to the zip() function in Python.  See {@link
+ * http://docs.python.org/library/functions.html#zip}
+ *
+ * @param {...!goog.array.ArrayLike} var_args Arrays to be combined.
+ * @return {!Array<!Array<?>>} A new array of arrays created from
+ *     provided arrays.
+ */
+goog.array.zip = function(var_args) {
+  if (!arguments.length) {
+    return [];
+  }
+  var result = [];
+  for (var i = 0; true; i++) {
+    var value = [];
+    for (var j = 0; j < arguments.length; j++) {
+      var arr = arguments[j];
+      // If i is larger than the array length, this is the shortest array.
+      if (i >= arr.length) {
+        return result;
+      }
+      value.push(arr[i]);
+    }
+    result.push(value);
+  }
+};
+
+
+/**
+ * Shuffles the values in the specified array using the Fisher-Yates in-place
+ * shuffle (also known as the Knuth Shuffle). By default, calls Math.random()
+ * and so resets the state of that random number generator. Similarly, may reset
+ * the state of the any other specified random number generator.
+ *
+ * Runtime: O(n)
+ *
+ * @param {!Array<?>} arr The array to be shuffled.
+ * @param {function():number=} opt_randFn Optional random function to use for
+ *     shuffling.
+ *     Takes no arguments, and returns a random number on the interval [0, 1).
+ *     Defaults to Math.random() using JavaScript's built-in Math library.
+ */
+goog.array.shuffle = function(arr, opt_randFn) {
+  var randFn = opt_randFn || Math.random;
+
+  for (var i = arr.length - 1; i > 0; i--) {
+    // Choose a random array index in [0, i] (inclusive with i).
+    var j = Math.floor(randFn() * (i + 1));
+
+    var tmp = arr[i];
+    arr[i] = arr[j];
+    arr[j] = tmp;
+  }
+};
+
+
+/**
+ * Returns a new array of elements from arr, based on the indexes of elements
+ * provided by index_arr. For example, the result of index copying
+ * ['a', 'b', 'c'] with index_arr [1,0,0,2] is ['b', 'a', 'a', 'c'].
+ *
+ * @param {!Array<T>} arr The array to get a indexed copy from.
+ * @param {!Array<number>} index_arr An array of indexes to get from arr.
+ * @return {!Array<T>} A new array of elements from arr in index_arr order.
+ * @template T
+ */
+goog.array.copyByIndex = function(arr, index_arr) {
+  var result = [];
+  goog.array.forEach(index_arr, function(index) {
+    result.push(arr[index]);
+  });
+  return result;
+};


[20/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/range.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/range.js b/externs/GCL/externs/goog/editor/range.js
new file mode 100644
index 0000000..ec1a6a7
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/range.js
@@ -0,0 +1,632 @@
+// Copyright 2008 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 Utilties for working with ranges.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.editor.range');
+goog.provide('goog.editor.range.Point');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.Range');
+goog.require('goog.dom.RangeEndpoint');
+goog.require('goog.dom.SavedCaretRange');
+goog.require('goog.editor.node');
+goog.require('goog.editor.style');
+goog.require('goog.iter');
+goog.require('goog.userAgent');
+
+
+/**
+ * Given a range and an element, create a narrower range that is limited to the
+ * boundaries of the element. If the range starts (or ends) outside the
+ * element, the narrowed range's start point (or end point) will be the
+ * leftmost (or rightmost) leaf of the element.
+ * @param {goog.dom.AbstractRange} range The range.
+ * @param {Element} el The element to limit the range to.
+ * @return {goog.dom.AbstractRange} A new narrowed range, or null if the
+ *     element does not contain any part of the given range.
+ */
+goog.editor.range.narrow = function(range, el) {
+  var startContainer = range.getStartNode();
+  var endContainer = range.getEndNode();
+
+  if (startContainer && endContainer) {
+    var isElement = function(node) {
+      return node == el;
+    };
+    var hasStart = goog.dom.getAncestor(startContainer, isElement, true);
+    var hasEnd = goog.dom.getAncestor(endContainer, isElement, true);
+
+    if (hasStart && hasEnd) {
+      // The range is contained entirely within this element.
+      return range.clone();
+    } else if (hasStart) {
+      // The range starts inside the element, but ends outside it.
+      var leaf = goog.editor.node.getRightMostLeaf(el);
+      return goog.dom.Range.createFromNodes(
+          range.getStartNode(), range.getStartOffset(),
+          leaf, goog.editor.node.getLength(leaf));
+    } else if (hasEnd) {
+      // The range starts outside the element, but ends inside it.
+      return goog.dom.Range.createFromNodes(
+          goog.editor.node.getLeftMostLeaf(el), 0,
+          range.getEndNode(), range.getEndOffset());
+    }
+  }
+
+  // The selection starts and ends outside the element.
+  return null;
+};
+
+
+/**
+ * Given a range, expand the range to include outer tags if the full contents of
+ * those tags are entirely selected.  This essentially changes the dom position,
+ * but not the visible position of the range.
+ * Ex. <li>foo</li> if "foo" is selected, instead of returning start and end
+ * nodes as the foo text node, return the li.
+ * @param {goog.dom.AbstractRange} range The range.
+ * @param {Node=} opt_stopNode Optional node to stop expanding past.
+ * @return {!goog.dom.AbstractRange} The expanded range.
+ */
+goog.editor.range.expand = function(range, opt_stopNode) {
+  // Expand the start out to the common container.
+  var expandedRange = goog.editor.range.expandEndPointToContainer_(
+      range, goog.dom.RangeEndpoint.START, opt_stopNode);
+  // Expand the end out to the common container.
+  expandedRange = goog.editor.range.expandEndPointToContainer_(
+      expandedRange, goog.dom.RangeEndpoint.END, opt_stopNode);
+
+  var startNode = expandedRange.getStartNode();
+  var endNode = expandedRange.getEndNode();
+  var startOffset = expandedRange.getStartOffset();
+  var endOffset = expandedRange.getEndOffset();
+
+  // If we have reached a common container, now expand out.
+  if (startNode == endNode) {
+    while (endNode != opt_stopNode &&
+           startOffset == 0 &&
+           endOffset == goog.editor.node.getLength(endNode)) {
+      // Select the parent instead.
+      var parentNode = endNode.parentNode;
+      startOffset = goog.array.indexOf(parentNode.childNodes, endNode);
+      endOffset = startOffset + 1;
+      endNode = parentNode;
+    }
+    startNode = endNode;
+  }
+
+  return goog.dom.Range.createFromNodes(startNode, startOffset,
+      endNode, endOffset);
+};
+
+
+/**
+ * Given a range, expands the start or end points as far out towards the
+ * range's common container (or stopNode, if provided) as possible, while
+ * perserving the same visible position.
+ *
+ * @param {goog.dom.AbstractRange} range The range to expand.
+ * @param {goog.dom.RangeEndpoint} endpoint The endpoint to expand.
+ * @param {Node=} opt_stopNode Optional node to stop expanding past.
+ * @return {!goog.dom.AbstractRange} The expanded range.
+ * @private
+ */
+goog.editor.range.expandEndPointToContainer_ = function(range, endpoint,
+                                                        opt_stopNode) {
+  var expandStart = endpoint == goog.dom.RangeEndpoint.START;
+  var node = expandStart ? range.getStartNode() : range.getEndNode();
+  var offset = expandStart ? range.getStartOffset() : range.getEndOffset();
+  var container = range.getContainerElement();
+
+  // Expand the node out until we reach the container or the stop node.
+  while (node != container && node != opt_stopNode) {
+    // It is only valid to expand the start if we are at the start of a node
+    // (offset 0) or expand the end if we are at the end of a node
+    // (offset length).
+    if (expandStart && offset != 0 ||
+        !expandStart && offset != goog.editor.node.getLength(node)) {
+      break;
+    }
+
+    var parentNode = node.parentNode;
+    var index = goog.array.indexOf(parentNode.childNodes, node);
+    offset = expandStart ? index : index + 1;
+    node = parentNode;
+  }
+
+  return goog.dom.Range.createFromNodes(
+      expandStart ? node : range.getStartNode(),
+      expandStart ? offset : range.getStartOffset(),
+      expandStart ? range.getEndNode() : node,
+      expandStart ? range.getEndOffset() : offset);
+};
+
+
+/**
+ * Cause the window's selection to be the start of this node.
+ * @param {Node} node The node to select the start of.
+ */
+goog.editor.range.selectNodeStart = function(node) {
+  goog.dom.Range.createCaret(goog.editor.node.getLeftMostLeaf(node), 0).
+      select();
+};
+
+
+/**
+ * Position the cursor immediately to the left or right of "node".
+ * In Firefox, the selection parent is outside of "node", so the cursor can
+ * effectively be moved to the end of a link node, without being considered
+ * inside of it.
+ * Note: This does not always work in WebKit. In particular, if you try to
+ * place a cursor to the right of a link, typing still puts you in the link.
+ * Bug: http://bugs.webkit.org/show_bug.cgi?id=17697
+ * @param {Node} node The node to position the cursor relative to.
+ * @param {boolean} toLeft True to place it to the left, false to the right.
+ * @return {!goog.dom.AbstractRange} The newly selected range.
+ */
+goog.editor.range.placeCursorNextTo = function(node, toLeft) {
+  var parent = node.parentNode;
+  var offset = goog.array.indexOf(parent.childNodes, node) +
+      (toLeft ? 0 : 1);
+  var point = goog.editor.range.Point.createDeepestPoint(
+      parent, offset, toLeft, true);
+  var range = goog.dom.Range.createCaret(point.node, point.offset);
+  range.select();
+  return range;
+};
+
+
+/**
+ * Normalizes the node, preserving the selection of the document.
+ *
+ * May also normalize things outside the node, if it is more efficient to do so.
+ *
+ * @param {Node} node The node to normalize.
+ */
+goog.editor.range.selectionPreservingNormalize = function(node) {
+  var doc = goog.dom.getOwnerDocument(node);
+  var selection = goog.dom.Range.createFromWindow(goog.dom.getWindow(doc));
+  var normalizedRange =
+      goog.editor.range.rangePreservingNormalize(node, selection);
+  if (normalizedRange) {
+    normalizedRange.select();
+  }
+};
+
+
+/**
+ * Manually normalizes the node in IE, since native normalize in IE causes
+ * transient problems.
+ * @param {Node} node The node to normalize.
+ * @private
+ */
+goog.editor.range.normalizeNodeIe_ = function(node) {
+  var lastText = null;
+  var child = node.firstChild;
+  while (child) {
+    var next = child.nextSibling;
+    if (child.nodeType == goog.dom.NodeType.TEXT) {
+      if (child.nodeValue == '') {
+        node.removeChild(child);
+      } else if (lastText) {
+        lastText.nodeValue += child.nodeValue;
+        node.removeChild(child);
+      } else {
+        lastText = child;
+      }
+    } else {
+      goog.editor.range.normalizeNodeIe_(child);
+      lastText = null;
+    }
+    child = next;
+  }
+};
+
+
+/**
+ * Normalizes the given node.
+ * @param {Node} node The node to normalize.
+ */
+goog.editor.range.normalizeNode = function(node) {
+  if (goog.userAgent.IE) {
+    goog.editor.range.normalizeNodeIe_(node);
+  } else {
+    node.normalize();
+  }
+};
+
+
+/**
+ * Normalizes the node, preserving a range of the document.
+ *
+ * May also normalize things outside the node, if it is more efficient to do so.
+ *
+ * @param {Node} node The node to normalize.
+ * @param {goog.dom.AbstractRange?} range The range to normalize.
+ * @return {goog.dom.AbstractRange?} The range, adjusted for normalization.
+ */
+goog.editor.range.rangePreservingNormalize = function(node, range) {
+  if (range) {
+    var rangeFactory = goog.editor.range.normalize(range);
+    // WebKit has broken selection affinity, so carets tend to jump out of the
+    // beginning of inline elements. This means that if we're doing the
+    // normalize as the result of a range that will later become the selection,
+    // we might not normalize something in the range after it is read back from
+    // the selection. We can't just normalize the parentNode here because WebKit
+    // can move the selection range out of multiple inline parents.
+    var container = goog.editor.style.getContainer(range.getContainerElement());
+  }
+
+  if (container) {
+    goog.editor.range.normalizeNode(
+        goog.dom.findCommonAncestor(container, node));
+  } else if (node) {
+    goog.editor.range.normalizeNode(node);
+  }
+
+  if (rangeFactory) {
+    return rangeFactory();
+  } else {
+    return null;
+  }
+};
+
+
+/**
+ * Get the deepest point in the DOM that's equivalent to the endpoint of the
+ * given range.
+ *
+ * @param {goog.dom.AbstractRange} range A range.
+ * @param {boolean} atStart True for the start point, false for the end point.
+ * @return {!goog.editor.range.Point} The end point, expressed as a node
+ *    and an offset.
+ */
+goog.editor.range.getDeepEndPoint = function(range, atStart) {
+  return atStart ?
+      goog.editor.range.Point.createDeepestPoint(
+          range.getStartNode(), range.getStartOffset()) :
+      goog.editor.range.Point.createDeepestPoint(
+          range.getEndNode(), range.getEndOffset());
+};
+
+
+/**
+ * Given a range in the current DOM, create a factory for a range that
+ * represents the same selection in a normalized DOM. The factory function
+ * should be invoked after the DOM is normalized.
+ *
+ * All browsers do a bad job preserving ranges across DOM normalization.
+ * The issue is best described in this 5-year-old bug report:
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=191864
+ * For most applications, this isn't a problem. The browsers do a good job
+ * handling un-normalized text, so there's usually no reason to normalize.
+ *
+ * The exception to this rule is the rich text editing commands
+ * execCommand and queryCommandValue, which will fail often if there are
+ * un-normalized text nodes.
+ *
+ * The factory function creates new ranges so that we can normalize the DOM
+ * without problems. It must be created before any normalization happens,
+ * and invoked after normalization happens.
+ *
+ * @param {goog.dom.AbstractRange} range The range to normalize. It may
+ *    become invalid after body.normalize() is called.
+ * @return {function(): goog.dom.AbstractRange} A factory for a normalized
+ *    range. Should be called after body.normalize() is called.
+ */
+goog.editor.range.normalize = function(range) {
+  var isReversed = range.isReversed();
+  var anchorPoint = goog.editor.range.normalizePoint_(
+      goog.editor.range.getDeepEndPoint(range, !isReversed));
+  var anchorParent = anchorPoint.getParentPoint();
+  var anchorPreviousSibling = anchorPoint.node.previousSibling;
+  if (anchorPoint.node.nodeType == goog.dom.NodeType.TEXT) {
+    anchorPoint.node = null;
+  }
+
+  var focusPoint = goog.editor.range.normalizePoint_(
+      goog.editor.range.getDeepEndPoint(range, isReversed));
+  var focusParent = focusPoint.getParentPoint();
+  var focusPreviousSibling = focusPoint.node.previousSibling;
+  if (focusPoint.node.nodeType == goog.dom.NodeType.TEXT) {
+    focusPoint.node = null;
+  }
+
+  return function() {
+    if (!anchorPoint.node && anchorPreviousSibling) {
+      // If anchorPoint.node was previously an empty text node with no siblings,
+      // anchorPreviousSibling may not have a nextSibling since that node will
+      // no longer exist.  Do our best and point to the end of the previous
+      // element.
+      anchorPoint.node = anchorPreviousSibling.nextSibling;
+      if (!anchorPoint.node) {
+        anchorPoint = goog.editor.range.Point.getPointAtEndOfNode(
+            anchorPreviousSibling);
+      }
+    }
+
+    if (!focusPoint.node && focusPreviousSibling) {
+      // If focusPoint.node was previously an empty text node with no siblings,
+      // focusPreviousSibling may not have a nextSibling since that node will no
+      // longer exist.  Do our best and point to the end of the previous
+      // element.
+      focusPoint.node = focusPreviousSibling.nextSibling;
+      if (!focusPoint.node) {
+        focusPoint = goog.editor.range.Point.getPointAtEndOfNode(
+            focusPreviousSibling);
+      }
+    }
+
+    return goog.dom.Range.createFromNodes(
+        anchorPoint.node || anchorParent.node.firstChild || anchorParent.node,
+        anchorPoint.offset,
+        focusPoint.node || focusParent.node.firstChild || focusParent.node,
+        focusPoint.offset);
+  };
+};
+
+
+/**
+ * Given a point in the current DOM, adjust it to represent the same point in
+ * a normalized DOM.
+ *
+ * See the comments on goog.editor.range.normalize for more context.
+ *
+ * @param {goog.editor.range.Point} point A point in the document.
+ * @return {!goog.editor.range.Point} The same point, for easy chaining.
+ * @private
+ */
+goog.editor.range.normalizePoint_ = function(point) {
+  var previous;
+  if (point.node.nodeType == goog.dom.NodeType.TEXT) {
+    // If the cursor position is in a text node,
+    // look at all the previous text siblings of the text node,
+    // and set the offset relative to the earliest text sibling.
+    for (var current = point.node.previousSibling;
+         current && current.nodeType == goog.dom.NodeType.TEXT;
+         current = current.previousSibling) {
+      point.offset += goog.editor.node.getLength(current);
+    }
+
+    previous = current;
+  } else {
+    previous = point.node.previousSibling;
+  }
+
+  var parent = point.node.parentNode;
+  point.node = previous ? previous.nextSibling : parent.firstChild;
+  return point;
+};
+
+
+/**
+ * Checks if a range is completely inside an editable region.
+ * @param {goog.dom.AbstractRange} range The range to test.
+ * @return {boolean} Whether the range is completely inside an editable region.
+ */
+goog.editor.range.isEditable = function(range) {
+  var rangeContainer = range.getContainerElement();
+
+  // Closure's implementation of getContainerElement() is a little too
+  // smart in IE when exactly one element is contained in the range.
+  // It assumes that there's a user whose intent was actually to select
+  // all that element's children, so it returns the element itself as its
+  // own containing element.
+  // This little sanity check detects this condition so we can account for it.
+  var rangeContainerIsOutsideRange =
+      range.getStartNode() != rangeContainer.parentElement;
+
+  return (rangeContainerIsOutsideRange &&
+          goog.editor.node.isEditableContainer(rangeContainer)) ||
+      goog.editor.node.isEditable(rangeContainer);
+};
+
+
+/**
+ * Returns whether the given range intersects with any instance of the given
+ * tag.
+ * @param {goog.dom.AbstractRange} range The range to check.
+ * @param {goog.dom.TagName} tagName The name of the tag.
+ * @return {boolean} Whether the given range intersects with any instance of
+ *     the given tag.
+ */
+goog.editor.range.intersectsTag = function(range, tagName) {
+  if (goog.dom.getAncestorByTagNameAndClass(range.getContainerElement(),
+                                            tagName)) {
+    return true;
+  }
+
+  return goog.iter.some(range, function(node) {
+    return node.tagName == tagName;
+  });
+};
+
+
+
+/**
+ * One endpoint of a range, represented as a Node and and offset.
+ * @param {Node} node The node containing the point.
+ * @param {number} offset The offset of the point into the node.
+ * @constructor
+ * @final
+ */
+goog.editor.range.Point = function(node, offset) {
+  /**
+   * The node containing the point.
+   * @type {Node}
+   */
+  this.node = node;
+
+  /**
+   * The offset of the point into the node.
+   * @type {number}
+   */
+  this.offset = offset;
+};
+
+
+/**
+ * Gets the point of this point's node in the DOM.
+ * @return {!goog.editor.range.Point} The node's point.
+ */
+goog.editor.range.Point.prototype.getParentPoint = function() {
+  var parent = this.node.parentNode;
+  return new goog.editor.range.Point(
+      parent, goog.array.indexOf(parent.childNodes, this.node));
+};
+
+
+/**
+ * Construct the deepest possible point in the DOM that's equivalent
+ * to the given point, expressed as a node and an offset.
+ * @param {Node} node The node containing the point.
+ * @param {number} offset The offset of the point from the node.
+ * @param {boolean=} opt_trendLeft Notice that a (node, offset) pair may be
+ *     equivalent to more than one descendent (node, offset) pair in the DOM.
+ *     By default, we trend rightward. If this parameter is true, then we
+ *     trend leftward. The tendency to fall rightward by default is for
+ *     consistency with other range APIs (like placeCursorNextTo).
+ * @param {boolean=} opt_stopOnChildlessElement If true, and we encounter
+ *     a Node which is an Element that cannot have children, we return a Point
+ *     based on its parent rather than that Node itself.
+ * @return {!goog.editor.range.Point} A new point.
+ */
+goog.editor.range.Point.createDeepestPoint =
+    function(node, offset, opt_trendLeft, opt_stopOnChildlessElement) {
+  while (node.nodeType == goog.dom.NodeType.ELEMENT) {
+    var child = node.childNodes[offset];
+    if (!child && !node.lastChild) {
+      break;
+    } else if (child) {
+      var prevSibling = child.previousSibling;
+      if (opt_trendLeft && prevSibling) {
+        if (opt_stopOnChildlessElement &&
+            goog.editor.range.Point.isTerminalElement_(prevSibling)) {
+          break;
+        }
+        node = prevSibling;
+        offset = goog.editor.node.getLength(node);
+      } else {
+        if (opt_stopOnChildlessElement &&
+            goog.editor.range.Point.isTerminalElement_(child)) {
+          break;
+        }
+        node = child;
+        offset = 0;
+      }
+    } else {
+      if (opt_stopOnChildlessElement &&
+          goog.editor.range.Point.isTerminalElement_(node.lastChild)) {
+        break;
+      }
+      node = node.lastChild;
+      offset = goog.editor.node.getLength(node);
+    }
+  }
+
+  return new goog.editor.range.Point(node, offset);
+};
+
+
+/**
+ * Return true if the specified node is an Element that is not expected to have
+ * children. The createDeepestPoint() method should not traverse into
+ * such elements.
+ * @param {Node} node .
+ * @return {boolean} True if the node is an Element that does not contain
+ *     child nodes (e.g. BR, IMG).
+ * @private
+ */
+goog.editor.range.Point.isTerminalElement_ = function(node) {
+  return (node.nodeType == goog.dom.NodeType.ELEMENT &&
+          !goog.dom.canHaveChildren(node));
+};
+
+
+/**
+ * Construct a point at the very end of the given node.
+ * @param {Node} node The node to create a point for.
+ * @return {!goog.editor.range.Point} A new point.
+ */
+goog.editor.range.Point.getPointAtEndOfNode = function(node) {
+  return new goog.editor.range.Point(node, goog.editor.node.getLength(node));
+};
+
+
+/**
+ * Saves the range by inserting carets into the HTML.
+ *
+ * Unlike the regular saveUsingCarets, this SavedRange normalizes text nodes.
+ * Browsers have other bugs where they don't handle split text nodes in
+ * contentEditable regions right.
+ *
+ * @param {goog.dom.AbstractRange} range The abstract range object.
+ * @return {!goog.dom.SavedCaretRange} A saved caret range that normalizes
+ *     text nodes.
+ */
+goog.editor.range.saveUsingNormalizedCarets = function(range) {
+  return new goog.editor.range.NormalizedCaretRange_(range);
+};
+
+
+
+/**
+ * Saves the range using carets, but normalizes text nodes when carets
+ * are removed.
+ * @see goog.editor.range.saveUsingNormalizedCarets
+ * @param {goog.dom.AbstractRange} range The range being saved.
+ * @constructor
+ * @extends {goog.dom.SavedCaretRange}
+ * @private
+ */
+goog.editor.range.NormalizedCaretRange_ = function(range) {
+  goog.dom.SavedCaretRange.call(this, range);
+};
+goog.inherits(goog.editor.range.NormalizedCaretRange_,
+    goog.dom.SavedCaretRange);
+
+
+/**
+ * Normalizes text nodes whenever carets are removed from the document.
+ * @param {goog.dom.AbstractRange=} opt_range A range whose offsets have already
+ *     been adjusted for caret removal; it will be adjusted and returned if it
+ *     is also affected by post-removal operations, such as text node
+ *     normalization.
+ * @return {goog.dom.AbstractRange|undefined} The adjusted range, if opt_range
+ *     was provided.
+ * @override
+ */
+goog.editor.range.NormalizedCaretRange_.prototype.removeCarets =
+    function(opt_range) {
+  var startCaret = this.getCaret(true);
+  var endCaret = this.getCaret(false);
+  var node = startCaret && endCaret ?
+      goog.dom.findCommonAncestor(startCaret, endCaret) :
+      startCaret || endCaret;
+
+  goog.editor.range.NormalizedCaretRange_.superClass_.removeCarets.call(this);
+
+  if (opt_range) {
+    return goog.editor.range.rangePreservingNormalize(node, opt_range);
+  } else if (node) {
+    goog.editor.range.selectionPreservingNormalize(node);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/seamlessfield.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/seamlessfield.js b/externs/GCL/externs/goog/editor/seamlessfield.js
new file mode 100644
index 0000000..7d84533
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/seamlessfield.js
@@ -0,0 +1,746 @@
+// 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 Class to encapsulate an editable field that blends in with
+ * the style of the page. The field can be fixed height, grow with its
+ * contents, or have a min height after which it grows to its contents.
+ * This is a goog.editor.Field, but with blending and sizing capabilities,
+ * and avoids using an iframe whenever possible.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ * @see ../demos/editor/seamlessfield.html
+ */
+
+
+goog.provide('goog.editor.SeamlessField');
+
+goog.require('goog.cssom.iframe.style');
+goog.require('goog.dom');
+goog.require('goog.dom.Range');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.safe');
+goog.require('goog.editor.BrowserFeature');
+goog.require('goog.editor.Field');
+goog.require('goog.editor.icontent');
+goog.require('goog.editor.icontent.FieldFormatInfo');
+goog.require('goog.editor.icontent.FieldStyleInfo');
+goog.require('goog.editor.node');
+goog.require('goog.events');
+goog.require('goog.events.EventType');
+goog.require('goog.html.uncheckedconversions');
+goog.require('goog.log');
+goog.require('goog.string.Const');
+goog.require('goog.style');
+
+
+
+/**
+ * This class encapsulates an editable field that blends in with the
+ * surrounding page.
+ * To see events fired by this object, please see the base class.
+ *
+ * @param {string} id An identifer for the field. This is used to find the
+ *     field and the element associated with this field.
+ * @param {Document=} opt_doc The document that the element with the given
+ *     id can be found it.
+ * @constructor
+ * @extends {goog.editor.Field}
+ */
+goog.editor.SeamlessField = function(id, opt_doc) {
+  goog.editor.Field.call(this, id, opt_doc);
+};
+goog.inherits(goog.editor.SeamlessField, goog.editor.Field);
+
+
+/**
+ * @override
+ */
+goog.editor.SeamlessField.prototype.logger =
+    goog.log.getLogger('goog.editor.SeamlessField');
+
+// Functions dealing with field sizing.
+
+
+/**
+ * The key used for listening for the "dragover" event.
+ * @type {goog.events.Key}
+ * @private
+ */
+goog.editor.SeamlessField.prototype.listenForDragOverEventKey_;
+
+
+/**
+ * The key used for listening for the iframe "load" event.
+ * @type {goog.events.Key}
+ * @private
+ */
+goog.editor.SeamlessField.prototype.listenForIframeLoadEventKey_;
+
+
+/**
+ * Sets the min height of this editable field's iframe. Only used in growing
+ * mode when an iframe is used. This will cause an immediate field sizing to
+ * update the field if necessary based on the new min height.
+ * @param {number} height The min height specified as a number of pixels,
+ *    e.g., 75.
+ */
+goog.editor.SeamlessField.prototype.setMinHeight = function(height) {
+  if (height == this.minHeight_) {
+    // Do nothing if the min height isn't changing.
+    return;
+  }
+  this.minHeight_ = height;
+  if (this.usesIframe()) {
+    this.doFieldSizingGecko();
+  }
+};
+
+
+/**
+ * Whether the field should be rendered with a fixed height, or should expand
+ * to fit its contents.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.SeamlessField.prototype.isFixedHeight_ = false;
+
+
+/**
+ * Whether the fixed-height handling has been overridden manually.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.SeamlessField.prototype.isFixedHeightOverridden_ = false;
+
+
+/**
+ * @return {boolean} Whether the field should be rendered with a fixed
+ *    height, or should expand to fit its contents.
+ * @override
+ */
+goog.editor.SeamlessField.prototype.isFixedHeight = function() {
+  return this.isFixedHeight_;
+};
+
+
+/**
+ * @param {boolean} newVal Explicitly set whether the field should be
+ *    of a fixed-height. This overrides auto-detection.
+ */
+goog.editor.SeamlessField.prototype.overrideFixedHeight = function(newVal) {
+  this.isFixedHeight_ = newVal;
+  this.isFixedHeightOverridden_ = true;
+};
+
+
+/**
+ * Auto-detect whether the current field should have a fixed height.
+ * @private
+ */
+goog.editor.SeamlessField.prototype.autoDetectFixedHeight_ = function() {
+  if (!this.isFixedHeightOverridden_) {
+    var originalElement = this.getOriginalElement();
+    if (originalElement) {
+      this.isFixedHeight_ =
+          goog.style.getComputedOverflowY(originalElement) == 'auto';
+    }
+  }
+};
+
+
+/**
+ * Resize the iframe in response to the wrapper div changing size.
+ * @private
+ */
+goog.editor.SeamlessField.prototype.handleOuterDocChange_ = function() {
+  if (this.isEventStopped(goog.editor.Field.EventType.CHANGE)) {
+    return;
+  }
+  this.sizeIframeToWrapperGecko_();
+};
+
+
+/**
+ * Sizes the iframe to its body's height.
+ * @private
+ */
+goog.editor.SeamlessField.prototype.sizeIframeToBodyHeightGecko_ = function() {
+  if (this.acquireSizeIframeLockGecko_()) {
+    var resized = false;
+    var ifr = this.getEditableIframe();
+    if (ifr) {
+      var fieldHeight = this.getIframeBodyHeightGecko_();
+
+      if (this.minHeight_) {
+        fieldHeight = Math.max(fieldHeight, this.minHeight_);
+      }
+      if (parseInt(goog.style.getStyle(ifr, 'height'), 10) != fieldHeight) {
+        ifr.style.height = fieldHeight + 'px';
+        resized = true;
+      }
+    }
+    this.releaseSizeIframeLockGecko_();
+    if (resized) {
+      this.dispatchEvent(goog.editor.Field.EventType.IFRAME_RESIZED);
+    }
+  }
+};
+
+
+/**
+ * @return {number} The height of the editable iframe's body.
+ * @private
+ */
+goog.editor.SeamlessField.prototype.getIframeBodyHeightGecko_ = function() {
+  var ifr = this.getEditableIframe();
+  var body = ifr.contentDocument.body;
+  var htmlElement = body.parentNode;
+
+
+  // If the iframe's height is 0, then the offsetHeight/scrollHeight of the
+  // HTML element in the iframe can be totally wack (i.e. too large
+  // by 50-500px). Also, in standard's mode the clientHeight is 0.
+  if (parseInt(goog.style.getStyle(ifr, 'height'), 10) === 0) {
+    goog.style.setStyle(ifr, 'height', 1 + 'px');
+  }
+
+  var fieldHeight;
+  if (goog.editor.node.isStandardsMode(body)) {
+
+    // If in standards-mode,
+    // grab the HTML element as it will contain all the field's
+    // contents. The body's height, for example, will not include that of
+    // floated images at the bottom in standards mode.
+    // Note that this value include all scrollbars *except* for scrollbars
+    // on the HTML element itself.
+    fieldHeight = htmlElement.offsetHeight;
+  } else {
+    // In quirks-mode, the body-element always seems
+    // to size to the containing window.  The html-element however,
+    // sizes to the content, and can thus end up with a value smaller
+    // than its child body-element if the content is shrinking.
+    // We want to make the iframe shrink too when the content shrinks,
+    // so rather than size the iframe to the body-element, size it to
+    // the html-element.
+    fieldHeight = htmlElement.scrollHeight;
+
+    // If there is a horizontal scroll, add in the thickness of the
+    // scrollbar.
+    if (htmlElement.clientHeight != htmlElement.offsetHeight) {
+      fieldHeight += goog.editor.SeamlessField.getScrollbarWidth_();
+    }
+  }
+
+  return fieldHeight;
+};
+
+
+/**
+ * Grabs the width of a scrollbar from the browser and caches the result.
+ * @return {number} The scrollbar width in pixels.
+ * @private
+ */
+goog.editor.SeamlessField.getScrollbarWidth_ = function() {
+  return goog.editor.SeamlessField.scrollbarWidth_ ||
+      (goog.editor.SeamlessField.scrollbarWidth_ =
+          goog.style.getScrollbarWidth());
+};
+
+
+/**
+ * Sizes the iframe to its container div's width. The width of the div
+ * is controlled by its containing context, not by its contents.
+ * if it extends outside of it's contents, then it gets a horizontal scroll.
+ * @private
+ */
+goog.editor.SeamlessField.prototype.sizeIframeToWrapperGecko_ = function() {
+  if (this.acquireSizeIframeLockGecko_()) {
+    var ifr = this.getEditableIframe();
+    var field = this.getElement();
+    var resized = false;
+    if (ifr && field) {
+      var fieldPaddingBox;
+      var widthDiv = ifr.parentNode;
+
+      var width = widthDiv.offsetWidth;
+      if (parseInt(goog.style.getStyle(ifr, 'width'), 10) != width) {
+        fieldPaddingBox = goog.style.getPaddingBox(field);
+        ifr.style.width = width + 'px';
+        field.style.width =
+            width - fieldPaddingBox.left - fieldPaddingBox.right + 'px';
+        resized = true;
+      }
+
+      var height = widthDiv.offsetHeight;
+      if (this.isFixedHeight() &&
+          parseInt(goog.style.getStyle(ifr, 'height'), 10) != height) {
+        if (!fieldPaddingBox) {
+          fieldPaddingBox = goog.style.getPaddingBox(field);
+        }
+        ifr.style.height = height + 'px';
+        field.style.height =
+            height - fieldPaddingBox.top - fieldPaddingBox.bottom + 'px';
+        resized = true;
+      }
+
+    }
+    this.releaseSizeIframeLockGecko_();
+    if (resized) {
+      this.dispatchEvent(goog.editor.Field.EventType.IFRAME_RESIZED);
+    }
+  }
+};
+
+
+/**
+ * Perform all the sizing immediately.
+ */
+goog.editor.SeamlessField.prototype.doFieldSizingGecko = function() {
+  // Because doFieldSizingGecko can be called after a setTimeout
+  // it is possible that the field has been destroyed before this call
+  // to do the sizing is executed. Check for field existence and do nothing
+  // if it has already been destroyed.
+  if (this.getElement()) {
+    // The order of operations is important here.  Sizing the iframe to the
+    // wrapper could cause the width to change, which could change the line
+    // wrapping, which could change the body height.  So we need to do that
+    // first, then size the iframe to fit the body height.
+    this.sizeIframeToWrapperGecko_();
+    if (!this.isFixedHeight()) {
+      this.sizeIframeToBodyHeightGecko_();
+    }
+  }
+};
+
+
+/**
+ * Acquires a lock on resizing the field iframe. This is used to ensure that
+ * modifications we make while in a mutation event handler don't cause
+ * infinite loops.
+ * @return {boolean} False if the lock is already acquired.
+ * @private
+ */
+goog.editor.SeamlessField.prototype.acquireSizeIframeLockGecko_ = function() {
+  if (this.sizeIframeLock_) {
+    return false;
+  }
+  return this.sizeIframeLock_ = true;
+};
+
+
+/**
+ * Releases a lock on resizing the field iframe. This is used to ensure that
+ * modifications we make while in a mutation event handler don't cause
+ * infinite loops.
+ * @private
+ */
+goog.editor.SeamlessField.prototype.releaseSizeIframeLockGecko_ = function() {
+  this.sizeIframeLock_ = false;
+};
+
+
+// Functions dealing with blending in with the surrounding page.
+
+
+/**
+ * String containing the css rules that, if applied to a document's body,
+ * would style that body as if it were the original element we made editable.
+ * See goog.cssom.iframe.style.getElementContext for more details.
+ * @type {string}
+ * @private
+ */
+goog.editor.SeamlessField.prototype.iframeableCss_ = '';
+
+
+/**
+ * Gets the css rules that should be used to style an iframe's body as if it
+ * were the original element that we made editable.
+ * @param {boolean=} opt_forceRegeneration Set to true to not read the cached
+ * copy and instead completely regenerate the css rules.
+ * @return {string} The string containing the css rules to use.
+ */
+goog.editor.SeamlessField.prototype.getIframeableCss = function(
+    opt_forceRegeneration) {
+  if (!this.iframeableCss_ || opt_forceRegeneration) {
+    var originalElement = this.getOriginalElement();
+    if (originalElement) {
+      this.iframeableCss_ =
+          goog.cssom.iframe.style.getElementContext(originalElement,
+          opt_forceRegeneration);
+    }
+  }
+  return this.iframeableCss_;
+};
+
+
+/**
+ * Sets the css rules that should be used inside the editable iframe.
+ * Note: to clear the css cache between makeNotEditable/makeEditable,
+ * call this with "" as iframeableCss.
+ * TODO(user): Unify all these css setting methods + Nick's open
+ * CL.  This is getting ridiculous.
+ * @param {string} iframeableCss String containing the css rules to use.
+ */
+goog.editor.SeamlessField.prototype.setIframeableCss = function(iframeableCss) {
+  this.iframeableCss_ = iframeableCss;
+};
+
+
+/**
+ * Used to ensure that CSS stylings are only installed once for none
+ * iframe seamless mode.
+ * TODO(user): Make it a formal part of the API that you can only
+ * set one set of styles globally.
+ * In seamless, non-iframe mode, all the stylings would go in the
+ * same document and conflict.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.SeamlessField.haveInstalledCss_ = false;
+
+
+/**
+ * Applies CSS from the wrapper-div to the field iframe.
+ */
+goog.editor.SeamlessField.prototype.inheritBlendedCSS = function() {
+  // No-op if the field isn't using an iframe.
+  if (!this.usesIframe()) {
+    return;
+  }
+  var field = this.getElement();
+  var head = goog.dom.getDomHelper(field).getElementsByTagNameAndClass(
+      goog.dom.TagName.HEAD)[0];
+  if (head) {
+    // We created this <head>, and we know the only thing we put in there
+    // is a <style> block.  So it's safe to blow away all the children
+    // as part of rewriting the styles.
+    goog.dom.removeChildren(head);
+  }
+
+  // Force a cache-clearing in CssUtil - this function was called because
+  // we're applying the 'blend' for the first time, or because we
+  // *need* to recompute the blend.
+  var newCSS = this.getIframeableCss(true);
+  goog.style.installStyles(newCSS, field);
+};
+
+
+// Overridden methods.
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.usesIframe = function() {
+  // TODO(user): Switch Firefox to using contentEditable
+  // rather than designMode iframe once contentEditable support
+  // is less buggy.
+  return !goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE;
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.setupMutationEventHandlersGecko =
+    function() {
+  goog.editor.SeamlessField.superClass_.setupMutationEventHandlersGecko.call(
+      this);
+
+  if (this.usesIframe()) {
+    var iframe = this.getEditableIframe();
+    var outerDoc = iframe.ownerDocument;
+    this.eventRegister.listen(outerDoc,
+        goog.editor.Field.MUTATION_EVENTS_GECKO,
+        this.handleOuterDocChange_, true);
+
+    // If the images load after we do the initial sizing, then this will
+    // force a field resize.
+    this.listenForIframeLoadEventKey_ = goog.events.listenOnce(
+        this.getEditableDomHelper().getWindow(),
+        goog.events.EventType.LOAD, this.sizeIframeToBodyHeightGecko_,
+        true, this);
+
+    this.eventRegister.listen(outerDoc,
+        'DOMAttrModified',
+        goog.bind(this.handleDomAttrChange, this, this.handleOuterDocChange_),
+        true);
+  }
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.handleChange = function() {
+  if (this.isEventStopped(goog.editor.Field.EventType.CHANGE)) {
+    return;
+  }
+
+  goog.editor.SeamlessField.superClass_.handleChange.call(this);
+
+  if (this.usesIframe()) {
+    this.sizeIframeToBodyHeightGecko_();
+  }
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.dispatchBlur = function() {
+  if (this.isEventStopped(goog.editor.Field.EventType.BLUR)) {
+    return;
+  }
+
+  goog.editor.SeamlessField.superClass_.dispatchBlur.call(this);
+
+  // Clear the selection and restore the current range back after collapsing
+  // it. The ideal solution would have been to just leave the range intact; but
+  // when there are multiple fields present on the page, its important that
+  // the selection isn't retained when we switch between the fields. We also
+  // have to make sure that the cursor position is retained when we tab in and
+  // out of a field and our approach addresses both these issues.
+  // Another point to note is that we do it on a setTimeout to allow for
+  // DOM modifications on blur. Otherwise, something like setLoremIpsum will
+  // leave a blinking cursor in the field even though it's blurred.
+  if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE &&
+      !goog.editor.BrowserFeature.CLEARS_SELECTION_WHEN_FOCUS_LEAVES) {
+    var win = this.getEditableDomHelper().getWindow();
+    var dragging = false;
+    goog.events.unlistenByKey(this.listenForDragOverEventKey_);
+    this.listenForDragOverEventKey_ = goog.events.listenOnce(
+        win.document.body, 'dragover',
+        function() {
+          dragging = true;
+        });
+    goog.global.setTimeout(goog.bind(function() {
+      // Do not clear the selection if we're only dragging text.
+      // This addresses a bug on FF1.5/linux where dragging fires a blur,
+      // but clearing the selection confuses Firefox's drag-and-drop
+      // implementation. For more info, see http://b/1061064
+      if (!dragging) {
+        if (this.editableDomHelper) {
+          var rng = this.getRange();
+
+          // If there are multiple fields on a page, we need to make sure that
+          // the selection isn't retained when we switch between fields. We
+          // could have collapsed the range but there is a bug in GECKO where
+          // the selection stays highlighted even though its backing range is
+          // collapsed (http://b/1390115). To get around this, we clear the
+          // selection and restore the collapsed range back in. Restoring the
+          // range is important so that the cursor stays intact when we tab out
+          // and into a field (See http://b/1790301 for additional details on
+          // this).
+          var iframeWindow = this.editableDomHelper.getWindow();
+          goog.dom.Range.clearSelection(iframeWindow);
+
+          if (rng) {
+            rng.collapse(true);
+            rng.select();
+          }
+        }
+      }
+    }, this), 0);
+  }
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.turnOnDesignModeGecko = function() {
+  goog.editor.SeamlessField.superClass_.turnOnDesignModeGecko.call(this);
+  var doc = this.getEditableDomHelper().getDocument();
+
+  doc.execCommand('enableInlineTableEditing', false, 'false');
+  doc.execCommand('enableObjectResizing', false, 'false');
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.installStyles = function() {
+  if (!this.usesIframe()) {
+    if (!goog.editor.SeamlessField.haveInstalledCss_) {
+      if (this.cssStyles) {
+        goog.style.installStyles(this.cssStyles, this.getElement());
+      }
+
+      // TODO(user): this should be reset to false when the editor is quit.
+      // In non-iframe mode, CSS styles should only be instaled once.
+      goog.editor.SeamlessField.haveInstalledCss_ = true;
+    }
+  }
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.makeEditableInternal = function(
+    opt_iframeSrc) {
+  if (this.usesIframe()) {
+    goog.editor.SeamlessField.superClass_.makeEditableInternal.call(this,
+        opt_iframeSrc);
+  } else {
+    var field = this.getOriginalElement();
+    if (field) {
+      this.setupFieldObject(field);
+      field.contentEditable = true;
+
+      this.injectContents(field.innerHTML, field);
+
+      this.handleFieldLoad();
+    }
+  }
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.handleFieldLoad = function() {
+  if (this.usesIframe()) {
+    // If the CSS inheriting code screws up (e.g. makes fonts too large) and
+    // the field is sized off in goog.editor.Field.makeIframeField, then we need
+    // to size it correctly, but it needs to be visible for the browser
+    // to have fully rendered it. We need to put this on a timeout to give
+    // the browser time to render.
+    var self = this;
+    goog.global.setTimeout(function() {
+      self.doFieldSizingGecko();
+    }, 0);
+  }
+  goog.editor.SeamlessField.superClass_.handleFieldLoad.call(this);
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.getIframeAttributes = function() {
+  return { 'frameBorder': 0, 'style': 'padding:0;' };
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.attachIframe = function(iframe) {
+  this.autoDetectFixedHeight_();
+  var field = this.getOriginalElement();
+  var dh = goog.dom.getDomHelper(field);
+
+  // Grab the width/height values of the field before modifying any CSS
+  // as some of the modifications affect its size (e.g. innerHTML='')
+  // Here, we set the size of the field to fixed so there's not too much
+  // jiggling when we set the innerHTML of the field.
+  var oldWidth = field.style.width;
+  var oldHeight = field.style.height;
+  goog.style.setStyle(field, 'visibility', 'hidden');
+
+  // If there is a floated element at the bottom of the field,
+  // then it needs a clearing div at the end to cause the clientHeight
+  // to contain the entire field.
+  // Also, with css re-writing, the margins of the first/last
+  // paragraph don't seem to get included in the clientHeight. Specifically,
+  // the extra divs below force the field's clientHeight to include the
+  // margins on the first and last elements contained within it.
+  var startDiv = dh.createDom(goog.dom.TagName.DIV,
+      {'style': 'height:0;clear:both', 'innerHTML': '&nbsp;'});
+  var endDiv = startDiv.cloneNode(true);
+  field.insertBefore(startDiv, field.firstChild);
+  goog.dom.appendChild(field, endDiv);
+
+  var contentBox = goog.style.getContentBoxSize(field);
+  var width = contentBox.width;
+  var height = contentBox.height;
+
+  var html = '';
+  if (this.isFixedHeight()) {
+    html = '&nbsp;';
+
+    goog.style.setStyle(field, 'position', 'relative');
+    goog.style.setStyle(field, 'overflow', 'visible');
+
+    goog.style.setStyle(iframe, 'position', 'absolute');
+    goog.style.setStyle(iframe, 'top', '0');
+    goog.style.setStyle(iframe, 'left', '0');
+  }
+  goog.style.setSize(field, width, height);
+
+  // In strict mode, browsers put blank space at the bottom and right
+  // if a field when it has an iframe child, to fill up the remaining line
+  // height. So make the line height = 0.
+  if (goog.editor.node.isStandardsMode(field)) {
+    this.originalFieldLineHeight_ = field.style.lineHeight;
+    goog.style.setStyle(field, 'lineHeight', '0');
+  }
+
+  goog.editor.node.replaceInnerHtml(field, html);
+  // Set the initial size
+  goog.style.setSize(iframe, width, height);
+  goog.style.setSize(field, oldWidth, oldHeight);
+  goog.style.setStyle(field, 'visibility', '');
+  goog.dom.appendChild(field, iframe);
+
+  // Only write if its not IE HTTPS in which case we're waiting for load.
+  if (!this.shouldLoadAsynchronously()) {
+    var doc = iframe.contentWindow.document;
+    if (goog.editor.node.isStandardsMode(iframe.ownerDocument)) {
+      doc.open();
+      var emptyHtml = goog.html.uncheckedconversions
+          .safeHtmlFromStringKnownToSatisfyTypeContract(
+              goog.string.Const.from('HTML from constant string'),
+              '<!DOCTYPE HTML><html></html>');
+      goog.dom.safe.documentWrite(doc, emptyHtml);
+      doc.close();
+    }
+  }
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.getFieldFormatInfo = function(
+    extraStyles) {
+  var originalElement = this.getOriginalElement();
+  if (originalElement) {
+    return new goog.editor.icontent.FieldFormatInfo(
+        this.id,
+        goog.editor.node.isStandardsMode(originalElement),
+        true,
+        this.isFixedHeight(),
+        extraStyles);
+  }
+  throw Error('no field');
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.writeIframeContent = function(
+    iframe, innerHtml, extraStyles) {
+  // For seamless iframes, hide the iframe while we're laying it out to
+  // prevent the flicker.
+  goog.style.setStyle(iframe, 'visibility', 'hidden');
+  var formatInfo = this.getFieldFormatInfo(extraStyles);
+  var styleInfo = new goog.editor.icontent.FieldStyleInfo(
+      this.getOriginalElement(),
+      this.cssStyles + this.getIframeableCss());
+  goog.editor.icontent.writeNormalInitialBlendedIframe(
+      formatInfo, innerHtml, styleInfo, iframe);
+  this.doFieldSizingGecko();
+  goog.style.setStyle(iframe, 'visibility', 'visible');
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.restoreDom = function() {
+  // TODO(user): Consider only removing the iframe if we are
+  // restoring the original node.
+  if (this.usesIframe()) {
+    goog.dom.removeNode(this.getEditableIframe());
+  }
+};
+
+
+/** @override */
+goog.editor.SeamlessField.prototype.clearListeners = function() {
+  goog.events.unlistenByKey(this.listenForDragOverEventKey_);
+  goog.events.unlistenByKey(this.listenForIframeLoadEventKey_);
+
+  goog.editor.SeamlessField.base(this, 'clearListeners');
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/style.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/style.js b/externs/GCL/externs/goog/editor/style.js
new file mode 100644
index 0000000..55b703b
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/style.js
@@ -0,0 +1,225 @@
+// 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 Utilties for working with the styles of DOM nodes, and
+ * related to rich text editing.
+ *
+ * Many of these are not general enough to go into goog.style, and use
+ * constructs (like "isContainer") that only really make sense inside
+ * of an HTML editor.
+ *
+ * The API has been optimized for iterating over large, irregular DOM
+ * structures (with lots of text nodes), and so the API tends to be a bit
+ * more permissive than the goog.style API should be. For example,
+ * goog.style.getComputedStyle will throw an exception if you give it a
+ * text node.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.editor.style');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.BrowserFeature');
+goog.require('goog.events.EventType');
+goog.require('goog.object');
+goog.require('goog.style');
+goog.require('goog.userAgent');
+
+
+/**
+ * Gets the computed or cascaded style.
+ *
+ * This is different than goog.style.getStyle_ because it returns null
+ * for text nodes (instead of throwing an exception), and never reads
+ * inline style. These two functions may need to be reconciled.
+ *
+ * @param {!Node} node Node to get style of.
+ * @param {string} stylePropertyName Property to get (must be camelCase,
+ *     not css-style).
+ * @return {?string} Style value, or null if this is not an element node.
+ * @private
+ */
+goog.editor.style.getComputedOrCascadedStyle_ = function(
+    node, stylePropertyName) {
+  if (node.nodeType != goog.dom.NodeType.ELEMENT) {
+    // Only element nodes have style.
+    return null;
+  }
+  return goog.userAgent.IE ?
+      goog.style.getCascadedStyle(/** @type {!Element} */ (node),
+          stylePropertyName) :
+      goog.style.getComputedStyle(/** @type {!Element} */ (node),
+          stylePropertyName);
+};
+
+
+/**
+ * Checks whether the given element inherits display: block.
+ * @param {!Node} node The Node to check.
+ * @return {boolean} Whether the element inherits CSS display: block.
+ */
+goog.editor.style.isDisplayBlock = function(node) {
+  return goog.editor.style.getComputedOrCascadedStyle_(
+      node, 'display') == 'block';
+};
+
+
+/**
+ * Returns true if the element is a container of other non-inline HTML
+ * Note that span, strong and em tags, being inline can only contain
+ * other inline elements and are thus, not containers. Containers are elements
+ * that should not be broken up when wrapping selections with a node of an
+ * inline block styling.
+ * @param {Node} element The element to check.
+ * @return {boolean} Whether the element is a container.
+ */
+goog.editor.style.isContainer = function(element) {
+  var nodeName = element && element.nodeName;
+  return !!(element &&
+            (goog.editor.style.isDisplayBlock(element) ||
+             nodeName == goog.dom.TagName.TD ||
+             nodeName == goog.dom.TagName.TABLE ||
+             nodeName == goog.dom.TagName.LI));
+};
+
+
+/**
+ * Return the first ancestor of this node that is a container, inclusive.
+ * @see isContainer
+ * @param {Node} node Node to find the container of.
+ * @return {Element} The element which contains node.
+ */
+goog.editor.style.getContainer = function(node) {
+  // We assume that every node must have a container.
+  return /** @type {Element} */ (
+      goog.dom.getAncestor(node, goog.editor.style.isContainer, true));
+};
+
+
+/**
+ * Set of input types that should be kept selectable even when their ancestors
+ * are made unselectable.
+ * @type {Object}
+ * @private
+ */
+goog.editor.style.SELECTABLE_INPUT_TYPES_ = goog.object.createSet(
+    'text', 'file', 'url');
+
+
+/**
+ * Prevent the default action on mousedown events.
+ * @param {goog.events.Event} e The mouse down event.
+ * @private
+ */
+goog.editor.style.cancelMouseDownHelper_ = function(e) {
+  var targetTagName = e.target.tagName;
+  if (targetTagName != goog.dom.TagName.TEXTAREA &&
+      targetTagName != goog.dom.TagName.INPUT) {
+    e.preventDefault();
+  }
+};
+
+
+/**
+ * Makes the given element unselectable, as well as all of its children, except
+ * for text areas, text, file and url inputs.
+ * @param {Element} element The element to make unselectable.
+ * @param {goog.events.EventHandler} eventHandler An EventHandler to register
+ *     the event with. Assumes when the node is destroyed, the eventHandler's
+ *     listeners are destroyed as well.
+ */
+goog.editor.style.makeUnselectable = function(element, eventHandler) {
+  if (goog.editor.BrowserFeature.HAS_UNSELECTABLE_STYLE) {
+    // The mousing down on a node should not blur the focused node.
+    // This is consistent with how IE works.
+    // TODO: Consider using just the mousedown handler and not the css property.
+    eventHandler.listen(element, goog.events.EventType.MOUSEDOWN,
+        goog.editor.style.cancelMouseDownHelper_, true);
+  }
+
+  goog.style.setUnselectable(element, true);
+
+  // Make inputs and text areas selectable.
+  var inputs = element.getElementsByTagName(goog.dom.TagName.INPUT);
+  for (var i = 0, len = inputs.length; i < len; i++) {
+    var input = inputs[i];
+    if (input.type in goog.editor.style.SELECTABLE_INPUT_TYPES_) {
+      goog.editor.style.makeSelectable(input);
+    }
+  }
+  goog.array.forEach(element.getElementsByTagName(goog.dom.TagName.TEXTAREA),
+      goog.editor.style.makeSelectable);
+};
+
+
+/**
+ * Make the given element selectable.
+ *
+ * For IE this simply turns off the "unselectable" property.
+ *
+ * Under FF no descendent of an unselectable node can be selectable:
+ *
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=203291
+ *
+ * So we make each ancestor of node selectable, while trying to preserve the
+ * unselectability of other nodes along that path
+ *
+ * This may cause certain text nodes which should be unselectable, to become
+ * selectable. For example:
+ *
+ * <div id=div1 style="-moz-user-select: none">
+ *   Text1
+ *   <span id=span1>Text2</span>
+ * </div>
+ *
+ * If we call makeSelectable on span1, then it will cause "Text1" to become
+ * selectable, since it had to make div1 selectable in order for span1 to be
+ * selectable.
+ *
+ * If "Text1" were enclosed within a <p> or <span>, then this problem would
+ * not arise.  Text nodes do not have styles, so its style can't be set to
+ * unselectable.
+ *
+ * @param {Element} element The element to make selectable.
+ */
+goog.editor.style.makeSelectable = function(element) {
+  goog.style.setUnselectable(element, false);
+  if (goog.editor.BrowserFeature.HAS_UNSELECTABLE_STYLE) {
+    // Go up ancestor chain, searching for nodes that are unselectable.
+    // If such a node exists, mark it as selectable but mark its other children
+    // as unselectable so the minimum set of nodes is changed.
+    var child = element;
+    var current = /** @type {Element} */ (element.parentNode);
+    while (current && current.tagName != goog.dom.TagName.HTML) {
+      if (goog.style.isUnselectable(current)) {
+        goog.style.setUnselectable(current, false, true);
+
+        for (var i = 0, len = current.childNodes.length; i < len; i++) {
+          var node = current.childNodes[i];
+          if (node != child && node.nodeType == goog.dom.NodeType.ELEMENT) {
+            goog.style.setUnselectable(current.childNodes[i], true);
+          }
+        }
+      }
+
+      child = current;
+      current = /** @type {Element} */ (current.parentNode);
+    }
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/table.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/table.js b/externs/GCL/externs/goog/editor/table.js
new file mode 100644
index 0000000..1bddc6d
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/table.js
@@ -0,0 +1,570 @@
+// Copyright 2008 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 Table editing support.
+ * This file provides the class goog.editor.Table and two
+ * supporting classes, goog.editor.TableRow and
+ * goog.editor.TableCell. Together these provide support for
+ * high level table modifications: Adding and deleting rows and columns,
+ * and merging and splitting cells.
+ *
+ * @supported IE6+, WebKit 525+, Firefox 2+.
+ */
+
+goog.provide('goog.editor.Table');
+goog.provide('goog.editor.TableCell');
+goog.provide('goog.editor.TableRow');
+
+goog.require('goog.dom');
+goog.require('goog.dom.DomHelper');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.TagName');
+goog.require('goog.log');
+goog.require('goog.string.Unicode');
+goog.require('goog.style');
+
+
+
+/**
+ * Class providing high level table editing functions.
+ * @param {Element} node Element that is a table or descendant of a table.
+ * @constructor
+ * @final
+ */
+goog.editor.Table = function(node) {
+  this.element = goog.dom.getAncestorByTagNameAndClass(node,
+      goog.dom.TagName.TABLE);
+  if (!this.element) {
+    goog.log.error(this.logger_,
+        "Can't create Table based on a node " +
+        "that isn't a table, or descended from a table.");
+  }
+  this.dom_ = goog.dom.getDomHelper(this.element);
+  this.refresh();
+};
+
+
+/**
+ * Logger object for debugging and error messages.
+ * @type {goog.log.Logger}
+ * @private
+ */
+goog.editor.Table.prototype.logger_ =
+    goog.log.getLogger('goog.editor.Table');
+
+
+/**
+ * Walks the dom structure of this object's table element and populates
+ * this.rows with goog.editor.TableRow objects. This is done initially
+ * to populate the internal data structures, and also after each time the
+ * DOM structure is modified. Currently this means that the all existing
+ * information is discarded and re-read from the DOM.
+ */
+// TODO(user): support partial refresh to save cost of full update
+// every time there is a change to the DOM.
+goog.editor.Table.prototype.refresh = function() {
+  var rows = this.rows = [];
+  var tbody = this.element.getElementsByTagName(goog.dom.TagName.TBODY)[0];
+  if (!tbody) {
+    return;
+  }
+  var trs = [];
+  for (var child = tbody.firstChild; child; child = child.nextSibling) {
+    if (child.nodeName == goog.dom.TagName.TR) {
+      trs.push(child);
+    }
+  }
+
+  for (var rowNum = 0, tr; tr = trs[rowNum]; rowNum++) {
+    var existingRow = rows[rowNum];
+    var tds = goog.editor.Table.getChildCellElements(tr);
+    var columnNum = 0;
+    // A note on cellNum vs. columnNum: A cell is a td/th element. Cells may
+    // use colspan/rowspan to extend over multiple rows/columns. cellNum
+    // is the dom element number, columnNum is the logical column number.
+    for (var cellNum = 0, td; td = tds[cellNum]; cellNum++) {
+      // If there's already a cell extending into this column
+      // (due to that cell's colspan/rowspan), increment the column counter.
+      while (existingRow && existingRow.columns[columnNum]) {
+        columnNum++;
+      }
+      var cell = new goog.editor.TableCell(td, rowNum, columnNum);
+      // Place this cell in every row and column into which it extends.
+      for (var i = 0; i < cell.rowSpan; i++) {
+        var cellRowNum = rowNum + i;
+        // Create TableRow objects in this.rows as needed.
+        var cellRow = rows[cellRowNum];
+        if (!cellRow) {
+          // TODO(user): try to avoid second trs[] lookup.
+          rows.push(
+              cellRow = new goog.editor.TableRow(trs[cellRowNum], cellRowNum));
+        }
+        // Extend length of column array to make room for this cell.
+        var minimumColumnLength = columnNum + cell.colSpan;
+        if (cellRow.columns.length < minimumColumnLength) {
+          cellRow.columns.length = minimumColumnLength;
+        }
+        for (var j = 0; j < cell.colSpan; j++) {
+          var cellColumnNum = columnNum + j;
+          cellRow.columns[cellColumnNum] = cell;
+        }
+      }
+      columnNum += cell.colSpan;
+    }
+  }
+};
+
+
+/**
+ * Returns all child elements of a TR element that are of type TD or TH.
+ * @param {Element} tr TR element in which to find children.
+ * @return {!Array<Element>} array of child cell elements.
+ */
+goog.editor.Table.getChildCellElements = function(tr) {
+  var cells = [];
+  for (var i = 0, cell; cell = tr.childNodes[i]; i++) {
+    if (cell.nodeName == goog.dom.TagName.TD ||
+        cell.nodeName == goog.dom.TagName.TH) {
+      cells.push(cell);
+    }
+  }
+  return cells;
+};
+
+
+/**
+ * Inserts a new row in the table. The row will be populated with new
+ * cells, and existing rowspanned cells that overlap the new row will
+ * be extended.
+ * @param {number=} opt_rowIndex Index at which to insert the row. If
+ *     this is omitted the row will be appended to the end of the table.
+ * @return {!Element} The new row.
+ */
+goog.editor.Table.prototype.insertRow = function(opt_rowIndex) {
+  var rowIndex = goog.isDefAndNotNull(opt_rowIndex) ?
+      opt_rowIndex : this.rows.length;
+  var refRow;
+  var insertAfter;
+  if (rowIndex == 0) {
+    refRow = this.rows[0];
+    insertAfter = false;
+  } else {
+    refRow = this.rows[rowIndex - 1];
+    insertAfter = true;
+  }
+  var newTr = this.dom_.createElement(goog.dom.TagName.TR);
+  for (var i = 0, cell; cell = refRow.columns[i]; i += 1) {
+    // Check whether the existing cell will span this new row.
+    // If so, instead of creating a new cell, extend
+    // the rowspan of the existing cell.
+    if ((insertAfter && cell.endRow > rowIndex) ||
+        (!insertAfter && cell.startRow < rowIndex)) {
+      cell.setRowSpan(cell.rowSpan + 1);
+      if (cell.colSpan > 1) {
+        i += cell.colSpan - 1;
+      }
+    } else {
+      newTr.appendChild(this.createEmptyTd());
+    }
+    if (insertAfter) {
+      goog.dom.insertSiblingAfter(newTr, refRow.element);
+    } else {
+      goog.dom.insertSiblingBefore(newTr, refRow.element);
+    }
+  }
+  this.refresh();
+  return newTr;
+};
+
+
+/**
+ * Inserts a new column in the table. The column will be created by
+ * inserting new TD elements in each row, or extending the colspan
+ * of existing TD elements.
+ * @param {number=} opt_colIndex Index at which to insert the column. If
+ *     this is omitted the column will be appended to the right side of
+ *     the table.
+ * @return {!Array<Element>} Array of new cell elements that were created
+ *     to populate the new column.
+ */
+goog.editor.Table.prototype.insertColumn = function(opt_colIndex) {
+  // TODO(user): set column widths in a way that makes sense.
+  var colIndex = goog.isDefAndNotNull(opt_colIndex) ?
+      opt_colIndex :
+      (this.rows[0] && this.rows[0].columns.length) || 0;
+  var newTds = [];
+  for (var rowNum = 0, row; row = this.rows[rowNum]; rowNum++) {
+    var existingCell = row.columns[colIndex];
+    if (existingCell && existingCell.endCol >= colIndex &&
+        existingCell.startCol < colIndex) {
+      existingCell.setColSpan(existingCell.colSpan + 1);
+      rowNum += existingCell.rowSpan - 1;
+    } else {
+      var newTd = this.createEmptyTd();
+      // TODO(user): figure out a way to intelligently size new columns.
+      newTd.style.width = goog.editor.Table.OPTIMUM_EMPTY_CELL_WIDTH + 'px';
+      this.insertCellElement(newTd, rowNum, colIndex);
+      newTds.push(newTd);
+    }
+  }
+  this.refresh();
+  return newTds;
+};
+
+
+/**
+ * Removes a row from the table, removing the TR element and
+ * decrementing the rowspan of any cells in other rows that overlap the row.
+ * @param {number} rowIndex Index of the row to delete.
+ */
+goog.editor.Table.prototype.removeRow = function(rowIndex) {
+  var row = this.rows[rowIndex];
+  if (!row) {
+    goog.log.warning(this.logger_,
+        "Can't remove row at position " + rowIndex + ': no such row.');
+  }
+  for (var i = 0, cell; cell = row.columns[i]; i += cell.colSpan) {
+    if (cell.rowSpan > 1) {
+      cell.setRowSpan(cell.rowSpan - 1);
+      if (cell.startRow == rowIndex) {
+        // Rowspanned cell started in this row - move it down to the next row.
+        this.insertCellElement(cell.element, rowIndex + 1, cell.startCol);
+      }
+    }
+  }
+  row.element.parentNode.removeChild(row.element);
+  this.refresh();
+};
+
+
+/**
+ * Removes a column from the table. This is done by removing cell elements,
+ * or shrinking the colspan of elements that span multiple columns.
+ * @param {number} colIndex Index of the column to delete.
+ */
+goog.editor.Table.prototype.removeColumn = function(colIndex) {
+  for (var i = 0, row; row = this.rows[i]; i++) {
+    var cell = row.columns[colIndex];
+    if (!cell) {
+      goog.log.error(this.logger_,
+          "Can't remove cell at position " + i + ', ' + colIndex +
+          ': no such cell.');
+    }
+    if (cell.colSpan > 1) {
+      cell.setColSpan(cell.colSpan - 1);
+    } else {
+      cell.element.parentNode.removeChild(cell.element);
+    }
+    // Skip over following rows that contain this same cell.
+    i += cell.rowSpan - 1;
+  }
+  this.refresh();
+};
+
+
+/**
+ * Merges multiple cells into a single cell, and sets the rowSpan and colSpan
+ * attributes of the cell to take up the same space as the original cells.
+ * @param {number} startRowIndex Top coordinate of the cells to merge.
+ * @param {number} startColIndex Left coordinate of the cells to merge.
+ * @param {number} endRowIndex Bottom coordinate of the cells to merge.
+ * @param {number} endColIndex Right coordinate of the cells to merge.
+ * @return {boolean} Whether or not the merge was possible. If the cells
+ *     in the supplied coordinates can't be merged this will return false.
+ */
+goog.editor.Table.prototype.mergeCells = function(
+    startRowIndex, startColIndex, endRowIndex, endColIndex) {
+  // TODO(user): take a single goog.math.Rect parameter instead?
+  var cells = [];
+  var cell;
+  if (startRowIndex == endRowIndex && startColIndex == endColIndex) {
+    goog.log.warning(this.logger_, "Can't merge single cell");
+    return false;
+  }
+  // Gather cells and do sanity check.
+  for (var i = startRowIndex; i <= endRowIndex; i++) {
+    for (var j = startColIndex; j <= endColIndex; j++) {
+      cell = this.rows[i].columns[j];
+      if (cell.startRow < startRowIndex ||
+          cell.endRow > endRowIndex ||
+          cell.startCol < startColIndex ||
+          cell.endCol > endColIndex) {
+        goog.log.warning(this.logger_,
+            "Can't merge cells: the cell in row " + i + ', column ' + j +
+            'extends outside the supplied rectangle.');
+        return false;
+      }
+      // TODO(user): this is somewhat inefficient, as we will add
+      // a reference for a cell for each position, even if it's a single
+      // cell with row/colspan.
+      cells.push(cell);
+    }
+  }
+  var targetCell = cells[0];
+  var targetTd = targetCell.element;
+  var doc = this.dom_.getDocument();
+
+  // Merge cell contents and discard other cells.
+  for (var i = 1; cell = cells[i]; i++) {
+    var td = cell.element;
+    if (!td.parentNode || td == targetTd) {
+      // We've already handled this cell at one of its previous positions.
+      continue;
+    }
+    // Add a space if needed, to keep merged content from getting squished
+    // together.
+    if (targetTd.lastChild &&
+        targetTd.lastChild.nodeType == goog.dom.NodeType.TEXT) {
+      targetTd.appendChild(doc.createTextNode(' '));
+    }
+    var childNode;
+    while ((childNode = td.firstChild)) {
+      targetTd.appendChild(childNode);
+    }
+    td.parentNode.removeChild(td);
+  }
+  targetCell.setColSpan((endColIndex - startColIndex) + 1);
+  targetCell.setRowSpan((endRowIndex - startRowIndex) + 1);
+  if (endColIndex > startColIndex) {
+    // Clear width on target cell.
+    // TODO(user): instead of clearing width, calculate width
+    // based on width of input cells
+    targetTd.removeAttribute('width');
+    targetTd.style.width = null;
+  }
+  this.refresh();
+
+  return true;
+};
+
+
+/**
+ * Splits a cell with colspans or rowspans into multiple descrete cells.
+ * @param {number} rowIndex y coordinate of the cell to split.
+ * @param {number} colIndex x coordinate of the cell to split.
+ * @return {!Array<Element>} Array of new cell elements created by splitting
+ *     the cell.
+ */
+// TODO(user): support splitting only horizontally or vertically,
+// support splitting cells that aren't already row/colspanned.
+goog.editor.Table.prototype.splitCell = function(rowIndex, colIndex) {
+  var row = this.rows[rowIndex];
+  var cell = row.columns[colIndex];
+  var newTds = [];
+  for (var i = 0; i < cell.rowSpan; i++) {
+    for (var j = 0; j < cell.colSpan; j++) {
+      if (i > 0 || j > 0) {
+        var newTd = this.createEmptyTd();
+        this.insertCellElement(newTd, rowIndex + i, colIndex + j);
+        newTds.push(newTd);
+      }
+    }
+  }
+  cell.setColSpan(1);
+  cell.setRowSpan(1);
+  this.refresh();
+  return newTds;
+};
+
+
+/**
+ * Inserts a cell element at the given position. The colIndex is the logical
+ * column index, not the position in the dom. This takes into consideration
+ * that cells in a given logical  row may actually be children of a previous
+ * DOM row that have used rowSpan to extend into the row.
+ * @param {Element} td The new cell element to insert.
+ * @param {number} rowIndex Row in which to insert the element.
+ * @param {number} colIndex Column in which to insert the element.
+ */
+goog.editor.Table.prototype.insertCellElement = function(
+    td, rowIndex, colIndex) {
+  var row = this.rows[rowIndex];
+  var nextSiblingElement = null;
+  for (var i = colIndex, cell; cell = row.columns[i]; i += cell.colSpan) {
+    if (cell.startRow == rowIndex) {
+      nextSiblingElement = cell.element;
+      break;
+    }
+  }
+  row.element.insertBefore(td, nextSiblingElement);
+};
+
+
+/**
+ * Creates an empty TD element and fill it with some empty content so it will
+ * show up with borders even in IE pre-7 or if empty-cells is set to 'hide'
+ * @return {!Element} a new TD element.
+ */
+goog.editor.Table.prototype.createEmptyTd = function() {
+  // TODO(user): more cross-browser testing to determine best
+  // and least annoying filler content.
+  return this.dom_.createDom(goog.dom.TagName.TD, {}, goog.string.Unicode.NBSP);
+};
+
+
+
+/**
+ * Class representing a logical table row: a tr element and any cells
+ * that appear in that row.
+ * @param {Element} trElement This rows's underlying TR element.
+ * @param {number} rowIndex This row's index in its parent table.
+ * @constructor
+ * @final
+ */
+goog.editor.TableRow = function(trElement, rowIndex) {
+  this.index = rowIndex;
+  this.element = trElement;
+  this.columns = [];
+};
+
+
+
+/**
+ * Class representing a table cell, which may span across multiple
+ * rows and columns
+ * @param {Element} td This cell's underlying TD or TH element.
+ * @param {number} startRow Index of the row where this cell begins.
+ * @param {number} startCol Index of the column where this cell begins.
+ * @constructor
+ * @final
+ */
+goog.editor.TableCell = function(td, startRow, startCol) {
+  this.element = td;
+  this.colSpan = parseInt(td.colSpan, 10) || 1;
+  this.rowSpan = parseInt(td.rowSpan, 10) || 1;
+  this.startRow = startRow;
+  this.startCol = startCol;
+  this.updateCoordinates_();
+};
+
+
+/**
+ * Calculates this cell's endRow/endCol coordinates based on rowSpan/colSpan
+ * @private
+ */
+goog.editor.TableCell.prototype.updateCoordinates_ = function() {
+  this.endCol = this.startCol + this.colSpan - 1;
+  this.endRow = this.startRow + this.rowSpan - 1;
+};
+
+
+/**
+ * Set this cell's colSpan, updating both its colSpan property and the
+ * underlying element's colSpan attribute.
+ * @param {number} colSpan The new colSpan.
+ */
+goog.editor.TableCell.prototype.setColSpan = function(colSpan) {
+  if (colSpan != this.colSpan) {
+    if (colSpan > 1) {
+      this.element.colSpan = colSpan;
+    } else {
+      this.element.colSpan = 1,
+      this.element.removeAttribute('colSpan');
+    }
+    this.colSpan = colSpan;
+    this.updateCoordinates_();
+  }
+};
+
+
+/**
+ * Set this cell's rowSpan, updating both its rowSpan property and the
+ * underlying element's rowSpan attribute.
+ * @param {number} rowSpan The new rowSpan.
+ */
+goog.editor.TableCell.prototype.setRowSpan = function(rowSpan) {
+  if (rowSpan != this.rowSpan) {
+    if (rowSpan > 1) {
+      this.element.rowSpan = rowSpan.toString();
+    } else {
+      this.element.rowSpan = '1';
+      this.element.removeAttribute('rowSpan');
+    }
+    this.rowSpan = rowSpan;
+    this.updateCoordinates_();
+  }
+};
+
+
+/**
+ * Optimum size of empty cells (in pixels), if possible.
+ * @type {number}
+ */
+goog.editor.Table.OPTIMUM_EMPTY_CELL_WIDTH = 60;
+
+
+/**
+ * Maximum width for new tables.
+ * @type {number}
+ */
+goog.editor.Table.OPTIMUM_MAX_NEW_TABLE_WIDTH = 600;
+
+
+/**
+ * Default color for table borders.
+ * @type {string}
+ */
+goog.editor.Table.DEFAULT_BORDER_COLOR = '#888';
+
+
+/**
+ * Creates a new table element, populated with cells and formatted.
+ * @param {Document} doc Document in which to create the table element.
+ * @param {number} columns Number of columns in the table.
+ * @param {number} rows Number of rows in the table.
+ * @param {Object=} opt_tableStyle Object containing borderWidth and borderColor
+ *    properties, used to set the inital style of the table.
+ * @return {!Element} a table element.
+ */
+goog.editor.Table.createDomTable = function(
+    doc, columns, rows, opt_tableStyle) {
+  // TODO(user): define formatting properties as constants,
+  // make separate formatTable() function
+  var style = {
+    borderWidth: '1',
+    borderColor: goog.editor.Table.DEFAULT_BORDER_COLOR
+  };
+  for (var prop in opt_tableStyle) {
+    style[prop] = opt_tableStyle[prop];
+  }
+  var dom = new goog.dom.DomHelper(doc);
+  var tableElement = dom.createTable(rows, columns, true);
+
+  var minimumCellWidth = 10;
+  // Calculate a good cell width.
+  var cellWidth = Math.max(
+      minimumCellWidth,
+      Math.min(goog.editor.Table.OPTIMUM_EMPTY_CELL_WIDTH,
+               goog.editor.Table.OPTIMUM_MAX_NEW_TABLE_WIDTH / columns));
+
+  var tds = tableElement.getElementsByTagName(goog.dom.TagName.TD);
+  for (var i = 0, td; td = tds[i]; i++) {
+    td.style.width = cellWidth + 'px';
+  }
+
+  // Set border somewhat redundantly to make sure they show
+  // up correctly in all browsers.
+  goog.style.setStyle(
+      tableElement, {
+        'borderCollapse': 'collapse',
+        'borderColor': style.borderColor,
+        'borderWidth': style.borderWidth + 'px'
+      });
+  tableElement.border = style.borderWidth;
+  tableElement.setAttribute('bordercolor', style.borderColor);
+  tableElement.setAttribute('cellspacing', '0');
+
+  return tableElement;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/actioneventwrapper.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/actioneventwrapper.js b/externs/GCL/externs/goog/events/actioneventwrapper.js
new file mode 100644
index 0000000..779150f
--- /dev/null
+++ b/externs/GCL/externs/goog/events/actioneventwrapper.js
@@ -0,0 +1,151 @@
+// 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 Action event wrapper implementation.
+ * @author eae@google.com (Emil A Eklund)
+ */
+
+goog.provide('goog.events.actionEventWrapper');
+
+goog.require('goog.a11y.aria');
+goog.require('goog.a11y.aria.Role');
+goog.require('goog.dom');
+goog.require('goog.events');
+/** @suppress {extraRequire} */
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventType');
+goog.require('goog.events.EventWrapper');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Event wrapper for action handling. Fires when an element is activated either
+ * by clicking it or by focusing it and pressing Enter.
+ *
+ * @constructor
+ * @implements {goog.events.EventWrapper}
+ * @private
+ */
+goog.events.ActionEventWrapper_ = function() {
+};
+
+
+/**
+ * Singleton instance of ActionEventWrapper_.
+ * @type {goog.events.ActionEventWrapper_}
+ */
+goog.events.actionEventWrapper = new goog.events.ActionEventWrapper_();
+
+
+/**
+ * Event types used by the wrapper.
+ *
+ * @type {Array<goog.events.EventType>}
+ * @private
+ */
+goog.events.ActionEventWrapper_.EVENT_TYPES_ = [
+  goog.events.EventType.CLICK,
+  goog.userAgent.GECKO ?
+      goog.events.EventType.KEYPRESS : goog.events.EventType.KEYDOWN,
+  goog.events.EventType.KEYUP
+];
+
+
+/**
+ * Adds an event listener using the wrapper on a DOM Node or an object that has
+ * implemented {@link goog.events.EventTarget}. A listener can only be added
+ * once to an object.
+ *
+ * @param {goog.events.ListenableType} target The target to listen to events on.
+ * @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
+ *     method, or an object with a handleEvent function.
+ * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
+ *     false).
+ * @param {Object=} opt_scope Element in whose scope to call the listener.
+ * @param {goog.events.EventHandler=} opt_eventHandler Event handler to add
+ *     listener to.
+ * @override
+ */
+goog.events.ActionEventWrapper_.prototype.listen = function(target, listener,
+    opt_capt, opt_scope, opt_eventHandler) {
+  var callback = function(e) {
+    var listenerFn = goog.events.wrapListener(listener);
+    var role = goog.dom.isElement(e.target) ?
+        goog.a11y.aria.getRole(/** @type {!Element} */ (e.target)) : null;
+    if (e.type == goog.events.EventType.CLICK && e.isMouseActionButton()) {
+      listenerFn.call(opt_scope, e);
+    } else if ((e.keyCode == goog.events.KeyCodes.ENTER ||
+        e.keyCode == goog.events.KeyCodes.MAC_ENTER) &&
+        e.type != goog.events.EventType.KEYUP) {
+      // convert keydown to keypress for backward compatibility.
+      e.type = goog.events.EventType.KEYPRESS;
+      listenerFn.call(opt_scope, e);
+    } else if (e.keyCode == goog.events.KeyCodes.SPACE &&
+        e.type == goog.events.EventType.KEYUP &&
+        (role == goog.a11y.aria.Role.BUTTON ||
+            role == goog.a11y.aria.Role.TAB)) {
+      listenerFn.call(opt_scope, e);
+      e.preventDefault();
+    }
+  };
+  callback.listener_ = listener;
+  callback.scope_ = opt_scope;
+
+  if (opt_eventHandler) {
+    opt_eventHandler.listen(target,
+        goog.events.ActionEventWrapper_.EVENT_TYPES_,
+        callback, opt_capt);
+  } else {
+    goog.events.listen(target,
+        goog.events.ActionEventWrapper_.EVENT_TYPES_,
+        callback, opt_capt);
+  }
+};
+
+
+/**
+ * Removes an event listener added using goog.events.EventWrapper.listen.
+ *
+ * @param {goog.events.ListenableType} target The node to remove listener from.
+ * @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
+ *     method, or an object with a handleEvent function.
+ * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
+ *     false).
+ * @param {Object=} opt_scope Element in whose scope to call the listener.
+ * @param {goog.events.EventHandler=} opt_eventHandler Event handler to remove
+ *     listener from.
+ * @override
+ */
+goog.events.ActionEventWrapper_.prototype.unlisten = function(target, listener,
+    opt_capt, opt_scope, opt_eventHandler) {
+  for (var type, j = 0; type = goog.events.ActionEventWrapper_.EVENT_TYPES_[j];
+      j++) {
+    var listeners = goog.events.getListeners(target, type, !!opt_capt);
+    for (var obj, i = 0; obj = listeners[i]; i++) {
+      if (obj.listener.listener_ == listener &&
+          obj.listener.scope_ == opt_scope) {
+        if (opt_eventHandler) {
+          opt_eventHandler.unlisten(target, type, obj.listener, opt_capt,
+              opt_scope);
+        } else {
+          goog.events.unlisten(target, type, obj.listener, opt_capt, opt_scope);
+        }
+        break;
+      }
+    }
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/actionhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/actionhandler.js b/externs/GCL/externs/goog/events/actionhandler.js
new file mode 100644
index 0000000..190cc26
--- /dev/null
+++ b/externs/GCL/externs/goog/events/actionhandler.js
@@ -0,0 +1,184 @@
+// 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 This file contains a class to provide a unified mechanism for
+ * CLICK and enter KEYDOWN events. This provides better accessibility by
+ * providing the given functionality to a keyboard user which is otherwise
+ * would be available only via a mouse click.
+ *
+ * If there is an existing CLICK listener or planning to be added as below -
+ *
+ * <code>this.eventHandler_.listen(el, CLICK, this.onClick_);<code>
+ *
+ * it can be replaced with an ACTION listener as follows:
+ *
+ * <code>this.eventHandler_.listen(
+ *    new goog.events.ActionHandler(el),
+ *    ACTION,
+ *    this.onAction_);<code>
+ *
+ */
+
+goog.provide('goog.events.ActionEvent');
+goog.provide('goog.events.ActionHandler');
+goog.provide('goog.events.ActionHandler.EventType');
+goog.provide('goog.events.BeforeActionEvent');
+
+goog.require('goog.events');
+goog.require('goog.events.BrowserEvent');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * A wrapper around an element that you want to listen to ACTION events on.
+ * @param {Element|Document} element The element or document to listen on.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @final
+ */
+goog.events.ActionHandler = function(element) {
+  goog.events.EventTarget.call(this);
+
+  /**
+   * This is the element that we will listen to events on.
+   * @type {Element|Document}
+   * @private
+   */
+  this.element_ = element;
+
+  goog.events.listen(element, goog.events.ActionHandler.KEY_EVENT_TYPE_,
+      this.handleKeyDown_, false, this);
+  goog.events.listen(element, goog.events.EventType.CLICK,
+      this.handleClick_, false, this);
+};
+goog.inherits(goog.events.ActionHandler, goog.events.EventTarget);
+
+
+/**
+ * Enum type for the events fired by the action handler
+ * @enum {string}
+ */
+goog.events.ActionHandler.EventType = {
+  ACTION: 'action',
+  BEFOREACTION: 'beforeaction'
+};
+
+
+/**
+ * Key event type to listen for.
+ * @type {string}
+ * @private
+ */
+goog.events.ActionHandler.KEY_EVENT_TYPE_ = goog.userAgent.GECKO ?
+    goog.events.EventType.KEYPRESS :
+    goog.events.EventType.KEYDOWN;
+
+
+/**
+ * Handles key press events.
+ * @param {!goog.events.BrowserEvent} e The key press event.
+ * @private
+ */
+goog.events.ActionHandler.prototype.handleKeyDown_ = function(e) {
+  if (e.keyCode == goog.events.KeyCodes.ENTER ||
+      goog.userAgent.WEBKIT && e.keyCode == goog.events.KeyCodes.MAC_ENTER) {
+    this.dispatchEvents_(e);
+  }
+};
+
+
+/**
+ * Handles mouse events.
+ * @param {!goog.events.BrowserEvent} e The click event.
+ * @private
+ */
+goog.events.ActionHandler.prototype.handleClick_ = function(e) {
+  this.dispatchEvents_(e);
+};
+
+
+/**
+ * Dispatches BeforeAction and Action events to the element
+ * @param {!goog.events.BrowserEvent} e The event causing dispatches.
+ * @private
+ */
+goog.events.ActionHandler.prototype.dispatchEvents_ = function(e) {
+  var beforeActionEvent = new goog.events.BeforeActionEvent(e);
+
+  // Allow application specific logic here before the ACTION event.
+  // For example, Gmail uses this event to restore keyboard focus
+  if (!this.dispatchEvent(beforeActionEvent)) {
+    // If the listener swallowed the BEFOREACTION event, don't dispatch the
+    // ACTION event.
+    return;
+  }
+
+
+  // Wrap up original event and send it off
+  var actionEvent = new goog.events.ActionEvent(e);
+  try {
+    this.dispatchEvent(actionEvent);
+  } finally {
+    // Stop propagating the event
+    e.stopPropagation();
+  }
+};
+
+
+/** @override */
+goog.events.ActionHandler.prototype.disposeInternal = function() {
+  goog.events.ActionHandler.superClass_.disposeInternal.call(this);
+  goog.events.unlisten(this.element_, goog.events.ActionHandler.KEY_EVENT_TYPE_,
+      this.handleKeyDown_, false, this);
+  goog.events.unlisten(this.element_, goog.events.EventType.CLICK,
+      this.handleClick_, false, this);
+  delete this.element_;
+};
+
+
+
+/**
+ * This class is used for the goog.events.ActionHandler.EventType.ACTION event.
+ * @param {!goog.events.BrowserEvent} browserEvent Browser event object.
+ * @constructor
+ * @extends {goog.events.BrowserEvent}
+ * @final
+ */
+goog.events.ActionEvent = function(browserEvent) {
+  goog.events.BrowserEvent.call(this, browserEvent.getBrowserEvent());
+  this.type = goog.events.ActionHandler.EventType.ACTION;
+};
+goog.inherits(goog.events.ActionEvent, goog.events.BrowserEvent);
+
+
+
+/**
+ * This class is used for the goog.events.ActionHandler.EventType.BEFOREACTION
+ * event. BEFOREACTION gives a chance to the application so the keyboard focus
+ * can be restored back, if required.
+ * @param {!goog.events.BrowserEvent} browserEvent Browser event object.
+ * @constructor
+ * @extends {goog.events.BrowserEvent}
+ * @final
+ */
+goog.events.BeforeActionEvent = function(browserEvent) {
+  goog.events.BrowserEvent.call(this, browserEvent.getBrowserEvent());
+  this.type = goog.events.ActionHandler.EventType.BEFOREACTION;
+};
+goog.inherits(goog.events.BeforeActionEvent, goog.events.BrowserEvent);


[36/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/logrecordserializer.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/logrecordserializer.js b/externs/GCL/externs/goog/debug/logrecordserializer.js
new file mode 100644
index 0000000..9b09d56
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/logrecordserializer.js
@@ -0,0 +1,121 @@
+// Copyright 2011 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 Static methods for serializing and deserializing log
+ * messages.  These methods are deliberately kept separate from logrecord.js
+ * and logger.js because they add dependencies on goog.json and goog.object.
+ *
+ */
+
+goog.provide('goog.debug.logRecordSerializer');
+
+goog.require('goog.debug.LogRecord');
+goog.require('goog.debug.Logger');
+goog.require('goog.json');
+goog.require('goog.object');
+
+
+/**
+ * Enumeration of object keys used when serializing a log message.
+ * @enum {string}
+ * @private
+ */
+goog.debug.logRecordSerializer.Param_ = {
+  TIME: 't',
+  LEVEL_NAME: 'ln',
+  LEVEL_VALUE: 'lv',
+  MSG: 'm',
+  LOGGER_NAME: 'n',
+  SEQUENCE_NUMBER: 's',
+  EXCEPTION: 'e'
+};
+
+
+/**
+ * Serializes a LogRecord to a JSON string.  Note that any associated
+ * exception is likely to be lost.
+ * @param {goog.debug.LogRecord} record The record to serialize.
+ * @return {string} Serialized JSON string of the log message.
+ */
+goog.debug.logRecordSerializer.serialize = function(record) {
+  var param = goog.debug.logRecordSerializer.Param_;
+  return goog.json.serialize(goog.object.create(
+      param.TIME, record.getMillis(),
+      param.LEVEL_NAME, record.getLevel().name,
+      param.LEVEL_VALUE, record.getLevel().value,
+      param.MSG, record.getMessage(),
+      param.LOGGER_NAME, record.getLoggerName(),
+      param.SEQUENCE_NUMBER, record.getSequenceNumber(),
+      param.EXCEPTION, record.getException() && record.getException().message));
+};
+
+
+/**
+ * Deserializes a JSON-serialized LogRecord.
+ * @param {string} s The JSON serialized record.
+ * @return {!goog.debug.LogRecord} The deserialized record.
+ */
+goog.debug.logRecordSerializer.parse = function(s) {
+  return goog.debug.logRecordSerializer.reconstitute_(goog.json.parse(s));
+};
+
+
+/**
+ * Deserializes a JSON-serialized LogRecord.  Use this only if you're
+ * naive enough to blindly trust any JSON formatted input that comes
+ * your way.
+ * @param {string} s The JSON serialized record.
+ * @return {!goog.debug.LogRecord} The deserialized record.
+ */
+goog.debug.logRecordSerializer.unsafeParse = function(s) {
+  return goog.debug.logRecordSerializer.reconstitute_(goog.json.unsafeParse(s));
+};
+
+
+/**
+ * Common reconsitution method for for parse and unsafeParse.
+ * @param {Object} o The JSON object.
+ * @return {!goog.debug.LogRecord} The reconstituted record.
+ * @private
+ */
+goog.debug.logRecordSerializer.reconstitute_ = function(o) {
+  var param = goog.debug.logRecordSerializer.Param_;
+  var level = goog.debug.logRecordSerializer.getLevel_(
+      o[param.LEVEL_NAME], o[param.LEVEL_VALUE]);
+
+  var ret = new goog.debug.LogRecord(level, o[param.MSG],
+      o[param.LOGGER_NAME], o[param.TIME], o[param.SEQUENCE_NUMBER]);
+  var exceptionMessage = o[param.EXCEPTION];
+  if (goog.isDefAndNotNull(exceptionMessage)) {
+    ret.setException(new Error(exceptionMessage));
+  }
+  return ret;
+};
+
+
+/**
+ * @param {string} name The name of the log level to return.
+ * @param {number} value The numeric value of the log level to return.
+ * @return {!goog.debug.Logger.Level} Returns a goog.debug.Logger.Level with
+ *     the specified name and value.  If the name and value match a predefined
+ *     log level, that instance will be returned, otherwise a new one will be
+ *     created.
+ * @private
+ */
+goog.debug.logRecordSerializer.getLevel_ = function(name, value) {
+  var level = goog.debug.Logger.Level.getPredefinedLevel(name);
+  return level && level.value == value ?
+      level : new goog.debug.Logger.Level(name, value);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/relativetimeprovider.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/relativetimeprovider.js b/externs/GCL/externs/goog/debug/relativetimeprovider.js
new file mode 100644
index 0000000..1201147
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/relativetimeprovider.js
@@ -0,0 +1,84 @@
+// 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 the goog.debug.RelativeTimeProvider class.
+ *
+ */
+
+goog.provide('goog.debug.RelativeTimeProvider');
+
+
+
+/**
+ * A simple object to keep track of a timestamp considered the start of
+ * something. The main use is for the logger system to maintain a start time
+ * that is occasionally reset. For example, in Gmail, we reset this relative
+ * time at the start of a user action so that timings are offset from the
+ * beginning of the action. This class also provides a singleton as the default
+ * behavior for most use cases is to share the same start time.
+ *
+ * @constructor
+ * @final
+ */
+goog.debug.RelativeTimeProvider = function() {
+  /**
+   * The start time.
+   * @type {number}
+   * @private
+   */
+  this.relativeTimeStart_ = goog.now();
+};
+
+
+/**
+ * Default instance.
+ * @type {goog.debug.RelativeTimeProvider}
+ * @private
+ */
+goog.debug.RelativeTimeProvider.defaultInstance_ =
+    new goog.debug.RelativeTimeProvider();
+
+
+/**
+ * Sets the start time to the specified time.
+ * @param {number} timeStamp The start time.
+ */
+goog.debug.RelativeTimeProvider.prototype.set = function(timeStamp) {
+  this.relativeTimeStart_ = timeStamp;
+};
+
+
+/**
+ * Resets the start time to now.
+ */
+goog.debug.RelativeTimeProvider.prototype.reset = function() {
+  this.set(goog.now());
+};
+
+
+/**
+ * @return {number} The start time.
+ */
+goog.debug.RelativeTimeProvider.prototype.get = function() {
+  return this.relativeTimeStart_;
+};
+
+
+/**
+ * @return {goog.debug.RelativeTimeProvider} The default instance.
+ */
+goog.debug.RelativeTimeProvider.getDefaultInstance = function() {
+  return goog.debug.RelativeTimeProvider.defaultInstance_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/tracer.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/tracer.js b/externs/GCL/externs/goog/debug/tracer.js
new file mode 100644
index 0000000..b56a324
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/tracer.js
@@ -0,0 +1,725 @@
+// 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 Definition of the Tracer class and associated classes.
+ *
+ * @see ../demos/tracer.html
+ */
+
+goog.provide('goog.debug.Trace');
+
+goog.require('goog.array');
+goog.require('goog.debug.Logger');
+goog.require('goog.iter');
+goog.require('goog.log');
+goog.require('goog.structs.Map');
+goog.require('goog.structs.SimplePool');
+
+
+
+/**
+ * Class used for singleton goog.debug.Trace.  Used for timing slow points in
+ * the code. Based on the java Tracer class but optimized for javascript.
+ * See com.google.common.tracing.Tracer.
+ * @constructor
+ * @private
+ */
+goog.debug.Trace_ = function() {
+
+  /**
+   * Events in order.
+   * @type {Array<goog.debug.Trace_.Event_>}
+   * @private
+   */
+  this.events_ = [];
+
+  /**
+   * Outstanding events that have started but haven't yet ended. The keys are
+   * numeric ids and the values are goog.debug.Trace_.Event_ objects.
+   * @type {goog.structs.Map}
+   * @private
+   */
+  this.outstandingEvents_ = new goog.structs.Map();
+
+  /**
+   * Start time of the event trace
+   * @type {number}
+   * @private
+   */
+  this.startTime_ = 0;
+
+  /**
+   * Cummulative overhead of calls to startTracer
+   * @type {number}
+   * @private
+   */
+  this.tracerOverheadStart_ = 0;
+
+  /**
+   * Cummulative overhead of calls to endTracer
+   * @type {number}
+   * @private
+   */
+  this.tracerOverheadEnd_ = 0;
+
+  /**
+   * Cummulative overhead of calls to addComment
+   * @type {number}
+   * @private
+   */
+  this.tracerOverheadComment_ = 0;
+
+  /**
+   * Keeps stats on different types of tracers. The keys are strings and the
+   * values are goog.debug.Stat
+   * @type {goog.structs.Map}
+   * @private
+   */
+  this.stats_ = new goog.structs.Map();
+
+  /**
+   * Total number of traces created in the trace.
+   * @type {number}
+   * @private
+   */
+  this.tracerCount_ = 0;
+
+  /**
+   * Total number of comments created in the trace.
+   * @type {number}
+   * @private
+   */
+  this.commentCount_ = 0;
+
+  /**
+   * Next id to use for the trace.
+   * @type {number}
+   * @private
+   */
+  this.nextId_ = 1;
+
+  /**
+   * A pool for goog.debug.Trace_.Event_ objects so we don't keep creating and
+   * garbage collecting these (which is very expensive in IE6).
+   * @private {!goog.structs.SimplePool}
+   */
+  this.eventPool_ = new goog.structs.SimplePool(0, 4000);
+  this.eventPool_.createObject = function() {
+    return new goog.debug.Trace_.Event_();
+  };
+
+
+  /**
+   * A pool for goog.debug.Trace_.Stat_ objects so we don't keep creating and
+   * garbage collecting these (which is very expensive in IE6).
+   * @private {!goog.structs.SimplePool}
+   */
+  this.statPool_ = new goog.structs.SimplePool(0, 50);
+  this.statPool_.createObject = function() {
+    return new goog.debug.Trace_.Stat_();
+  };
+
+  var self = this;
+
+  /** @private {!goog.structs.SimplePool} */
+  this.idPool_ = new goog.structs.SimplePool(0, 2000);
+
+  // TODO(nicksantos): SimplePool is supposed to only return objects.
+  // Reconcile this so that we don't have to cast to number below.
+  this.idPool_.createObject = function() {
+    return String(self.nextId_++);
+  };
+  this.idPool_.disposeObject = function(obj) {};
+
+  /**
+   * Default threshold below which a tracer shouldn't be reported
+   * @type {number}
+   * @private
+   */
+  this.defaultThreshold_ = 3;
+};
+
+
+/**
+ * Logger for the tracer
+ * @type {goog.log.Logger}
+ * @private
+ */
+goog.debug.Trace_.prototype.logger_ =
+    goog.log.getLogger('goog.debug.Trace');
+
+
+/**
+ * Maximum size of the trace before we discard events
+ * @type {number}
+ */
+goog.debug.Trace_.prototype.MAX_TRACE_SIZE = 1000;
+
+
+/**
+ * Event type supported by tracer
+ * @enum {number}
+ */
+goog.debug.Trace_.EventType = {
+  /**
+   * Start event type
+   */
+  START: 0,
+
+  /**
+   * Stop event type
+   */
+  STOP: 1,
+
+  /**
+   * Comment event type
+   */
+  COMMENT: 2
+};
+
+
+
+/**
+ * Class to keep track of a stat of a single tracer type. Stores the count
+ * and cumulative time.
+ * @constructor
+ * @private
+ */
+goog.debug.Trace_.Stat_ = function() {
+  /**
+   * Number of tracers
+   * @type {number}
+   */
+  this.count = 0;
+
+  /**
+   * Cumulative time of traces
+   * @type {number}
+   */
+  this.time = 0;
+
+  /**
+   * Total number of allocations for this tracer type
+   * @type {number}
+   */
+  this.varAlloc = 0;
+};
+
+
+/**
+ * @type {string|null|undefined}
+ */
+goog.debug.Trace_.Stat_.prototype.type;
+
+
+/**
+ * @return {string} A string describing the tracer stat.
+ * @override
+ */
+goog.debug.Trace_.Stat_.prototype.toString = function() {
+  var sb = [];
+  sb.push(this.type, ' ', this.count, ' (', Math.round(this.time * 10) / 10,
+      ' ms)');
+  if (this.varAlloc) {
+    sb.push(' [VarAlloc = ', this.varAlloc, ']');
+  }
+  return sb.join('');
+};
+
+
+
+/**
+ * Private class used to encapsulate a single event, either the start or stop
+ * of a tracer.
+ * @constructor
+ * @private
+ */
+goog.debug.Trace_.Event_ = function() {
+  // the fields are different for different events - see usage in code
+};
+
+
+/**
+ * @type {string|null|undefined}
+ */
+goog.debug.Trace_.Event_.prototype.type;
+
+
+/**
+ * Returns a formatted string for the event.
+ * @param {number} startTime The start time of the trace to generate relative
+ * times.
+ * @param {number} prevTime The completion time of the previous event or -1.
+ * @param {string} indent Extra indent for the message
+ *     if there was no previous event.
+ * @return {string} The formatted tracer string.
+ */
+goog.debug.Trace_.Event_.prototype.toTraceString = function(startTime, prevTime,
+    indent) {
+  var sb = [];
+
+  if (prevTime == -1) {
+    sb.push('    ');
+  } else {
+    sb.push(goog.debug.Trace_.longToPaddedString_(this.eventTime - prevTime));
+  }
+
+  sb.push(' ', goog.debug.Trace_.formatTime_(this.eventTime - startTime));
+  if (this.eventType == goog.debug.Trace_.EventType.START) {
+    sb.push(' Start        ');
+  } else if (this.eventType == goog.debug.Trace_.EventType.STOP) {
+    sb.push(' Done ');
+    var delta = this.stopTime - this.startTime;
+    sb.push(goog.debug.Trace_.longToPaddedString_(delta), ' ms ');
+  } else {
+    sb.push(' Comment      ');
+  }
+
+  sb.push(indent, this);
+  if (this.totalVarAlloc > 0) {
+    sb.push('[VarAlloc ', this.totalVarAlloc, '] ');
+  }
+  return sb.join('');
+};
+
+
+/**
+ * @return {string} A string describing the tracer event.
+ * @override
+ */
+goog.debug.Trace_.Event_.prototype.toString = function() {
+  if (this.type == null) {
+    return this.comment;
+  } else {
+    return '[' + this.type + '] ' + this.comment;
+  }
+};
+
+
+/**
+ * Add the ability to explicitly set the start time. This is useful for example
+ * for measuring initial load time where you can set a variable as soon as the
+ * main page of the app is loaded and then later call this function when the
+ * Tracer code has been loaded.
+ * @param {number} startTime The start time to set.
+ */
+goog.debug.Trace_.prototype.setStartTime = function(startTime) {
+  this.startTime_ = startTime;
+};
+
+
+/**
+ * Initializes and resets the current trace
+ * @param {number} defaultThreshold The default threshold below which the
+ * tracer output will be supressed. Can be overridden on a per-Tracer basis.
+ */
+goog.debug.Trace_.prototype.initCurrentTrace = function(defaultThreshold) {
+  this.reset(defaultThreshold);
+};
+
+
+/**
+ * Clears the current trace
+ */
+goog.debug.Trace_.prototype.clearCurrentTrace = function() {
+  this.reset(0);
+};
+
+
+/**
+ * Resets the trace.
+ * @param {number} defaultThreshold The default threshold below which the
+ * tracer output will be supressed. Can be overridden on a per-Tracer basis.
+ */
+goog.debug.Trace_.prototype.reset = function(defaultThreshold) {
+  this.defaultThreshold_ = defaultThreshold;
+
+  for (var i = 0; i < this.events_.length; i++) {
+    var id = /** @type {Object} */ (this.eventPool_).id;
+    if (id) {
+      this.idPool_.releaseObject(id);
+    }
+    this.eventPool_.releaseObject(this.events_[i]);
+  }
+
+  this.events_.length = 0;
+  this.outstandingEvents_.clear();
+  this.startTime_ = goog.debug.Trace_.now();
+  this.tracerOverheadStart_ = 0;
+  this.tracerOverheadEnd_ = 0;
+  this.tracerOverheadComment_ = 0;
+  this.tracerCount_ = 0;
+  this.commentCount_ = 0;
+
+  var keys = this.stats_.getKeys();
+  for (var i = 0; i < keys.length; i++) {
+    var key = keys[i];
+    var stat = this.stats_.get(key);
+    stat.count = 0;
+    stat.time = 0;
+    stat.varAlloc = 0;
+    this.statPool_.releaseObject(/** @type {Object} */ (stat));
+  }
+  this.stats_.clear();
+};
+
+
+/**
+ * Starts a tracer
+ * @param {string} comment A comment used to identify the tracer. Does not
+ *     need to be unique.
+ * @param {string=} opt_type Type used to identify the tracer. If a Trace is
+ *     given a type (the first argument to the constructor) and multiple Traces
+ *     are done on that type then a "TOTAL line will be produced showing the
+ *     total number of traces and the sum of the time
+ *     ("TOTAL Database 2 (37 ms)" in our example). These traces should be
+ *     mutually exclusive or else the sum won't make sense (the time will
+ *     be double counted if the second starts before the first ends).
+ * @return {number} The identifier for the tracer that should be passed to the
+ *     the stopTracer method.
+ */
+goog.debug.Trace_.prototype.startTracer = function(comment, opt_type) {
+  var tracerStartTime = goog.debug.Trace_.now();
+  var varAlloc = this.getTotalVarAlloc();
+  var outstandingEventCount = this.outstandingEvents_.getCount();
+  if (this.events_.length + outstandingEventCount > this.MAX_TRACE_SIZE) {
+    goog.log.warning(this.logger_,
+        'Giant thread trace. Clearing to avoid memory leak.');
+    // This is the more likely case. This usually means that we
+    // either forgot to clear the trace or else we are performing a
+    // very large number of events
+    if (this.events_.length > this.MAX_TRACE_SIZE / 2) {
+      for (var i = 0; i < this.events_.length; i++) {
+        var event = this.events_[i];
+        if (event.id) {
+          this.idPool_.releaseObject(event.id);
+        }
+        this.eventPool_.releaseObject(event);
+      }
+      this.events_.length = 0;
+    }
+
+    // This is less likely and probably indicates that a lot of traces
+    // aren't being closed. We want to avoid unnecessarily clearing
+    // this though in case the events do eventually finish.
+    if (outstandingEventCount > this.MAX_TRACE_SIZE / 2) {
+      this.outstandingEvents_.clear();
+    }
+  }
+
+  goog.debug.Logger.logToProfilers('Start : ' + comment);
+
+  var event = /** @type {goog.debug.Trace_.Event_} */ (
+      this.eventPool_.getObject());
+  event.totalVarAlloc = varAlloc;
+  event.eventType = goog.debug.Trace_.EventType.START;
+  event.id = Number(this.idPool_.getObject());
+  event.comment = comment;
+  event.type = opt_type;
+  this.events_.push(event);
+  this.outstandingEvents_.set(String(event.id), event);
+  this.tracerCount_++;
+  var now = goog.debug.Trace_.now();
+  event.startTime = event.eventTime = now;
+  this.tracerOverheadStart_ += now - tracerStartTime;
+  return event.id;
+};
+
+
+/**
+ * Stops a tracer
+ * @param {number|undefined|null} id The id of the tracer that is ending.
+ * @param {number=} opt_silenceThreshold Threshold below which the tracer is
+ *    silenced.
+ * @return {?number} The elapsed time for the tracer or null if the tracer
+ *    identitifer was not recognized.
+ */
+goog.debug.Trace_.prototype.stopTracer = function(id, opt_silenceThreshold) {
+  // this used to call goog.isDef(opt_silenceThreshold) but that causes an
+  // object allocation in IE for some reason (doh!). The following code doesn't
+  // cause an allocation
+  var now = goog.debug.Trace_.now();
+  var silenceThreshold;
+  if (opt_silenceThreshold === 0) {
+    silenceThreshold = 0;
+  } else if (opt_silenceThreshold) {
+    silenceThreshold = opt_silenceThreshold;
+  } else {
+    silenceThreshold = this.defaultThreshold_;
+  }
+
+  var startEvent = this.outstandingEvents_.get(String(id));
+  if (startEvent == null) {
+    return null;
+  }
+
+  this.outstandingEvents_.remove(String(id));
+
+  var stopEvent;
+  var elapsed = now - startEvent.startTime;
+  if (elapsed < silenceThreshold) {
+    var count = this.events_.length;
+    for (var i = count - 1; i >= 0; i--) {
+      var nextEvent = this.events_[i];
+      if (nextEvent == startEvent) {
+        this.events_.splice(i, 1);
+        this.idPool_.releaseObject(startEvent.id);
+        this.eventPool_.releaseObject(/** @type {Object} */ (startEvent));
+        break;
+      }
+    }
+
+  } else {
+    stopEvent = /** @type {goog.debug.Trace_.Event_} */ (
+        this.eventPool_.getObject());
+    stopEvent.eventType = goog.debug.Trace_.EventType.STOP;
+    stopEvent.startTime = startEvent.startTime;
+    stopEvent.comment = startEvent.comment;
+    stopEvent.type = startEvent.type;
+    stopEvent.stopTime = stopEvent.eventTime = now;
+
+    this.events_.push(stopEvent);
+  }
+
+  var type = startEvent.type;
+  var stat = null;
+  if (type) {
+    stat = this.getStat_(type);
+    stat.count++;
+    stat.time += elapsed;
+  }
+  if (stopEvent) {
+    goog.debug.Logger.logToProfilers('Stop : ' + stopEvent.comment);
+
+    stopEvent.totalVarAlloc = this.getTotalVarAlloc();
+
+    if (stat) {
+      stat.varAlloc += (stopEvent.totalVarAlloc - startEvent.totalVarAlloc);
+    }
+  }
+  var tracerFinishTime = goog.debug.Trace_.now();
+  this.tracerOverheadEnd_ += tracerFinishTime - now;
+  return elapsed;
+};
+
+
+/**
+ * Sets the ActiveX object that can be used to get GC tracing in IE6.
+ * @param {Object} gcTracer GCTracer ActiveX object.
+ */
+goog.debug.Trace_.prototype.setGcTracer = function(gcTracer) {
+  this.gcTracer_ = gcTracer;
+};
+
+
+/**
+ * Returns the total number of allocations since the GC stats were reset. Only
+ * works in IE.
+ * @return {number} The number of allocaitons or -1 if not supported.
+ */
+goog.debug.Trace_.prototype.getTotalVarAlloc = function() {
+  var gcTracer = this.gcTracer_;
+  // isTracing is defined on the ActiveX object.
+  if (gcTracer && gcTracer['isTracing']()) {
+    return gcTracer['totalVarAlloc'];
+  }
+  return -1;
+};
+
+
+/**
+ * Adds a comment to the trace. Makes it possible to see when a specific event
+ * happened in relation to the traces.
+ * @param {string} comment A comment that is inserted into the trace.
+ * @param {?string=} opt_type Type used to identify the tracer. If a comment is
+ *     given a type and multiple comments are done on that type then a "TOTAL
+ *     line will be produced showing the total number of comments of that type.
+ * @param {?number=} opt_timeStamp The timestamp to insert the comment. If not
+ *    specified, the current time wil be used.
+ */
+goog.debug.Trace_.prototype.addComment = function(comment, opt_type,
+                                                  opt_timeStamp) {
+  var now = goog.debug.Trace_.now();
+  var timeStamp = opt_timeStamp ? opt_timeStamp : now;
+
+  var eventComment = /** @type {goog.debug.Trace_.Event_} */ (
+      this.eventPool_.getObject());
+  eventComment.eventType = goog.debug.Trace_.EventType.COMMENT;
+  eventComment.eventTime = timeStamp;
+  eventComment.type = opt_type;
+  eventComment.comment = comment;
+  eventComment.totalVarAlloc = this.getTotalVarAlloc();
+  this.commentCount_++;
+
+  if (opt_timeStamp) {
+    var numEvents = this.events_.length;
+    for (var i = 0; i < numEvents; i++) {
+      var event = this.events_[i];
+      var eventTime = event.eventTime;
+
+      if (eventTime > timeStamp) {
+        goog.array.insertAt(this.events_, eventComment, i);
+        break;
+      }
+    }
+    if (i == numEvents) {
+      this.events_.push(eventComment);
+    }
+  } else {
+    this.events_.push(eventComment);
+  }
+
+  var type = eventComment.type;
+  if (type) {
+    var stat = this.getStat_(type);
+    stat.count++;
+  }
+
+  this.tracerOverheadComment_ += goog.debug.Trace_.now() - now;
+};
+
+
+/**
+ * Gets a stat object for a particular type. The stat object is created if it
+ * hasn't yet been.
+ * @param {string} type The type of stat.
+ * @return {goog.debug.Trace_.Stat_} The stat object.
+ * @private
+ */
+goog.debug.Trace_.prototype.getStat_ = function(type) {
+  var stat = this.stats_.get(type);
+  if (!stat) {
+    stat = /** @type {goog.debug.Trace_.Event_} */ (
+        this.statPool_.getObject());
+    stat.type = type;
+    this.stats_.set(type, stat);
+  }
+  return /** @type {goog.debug.Trace_.Stat_} */(stat);
+};
+
+
+/**
+ * Returns a formatted string for the current trace
+ * @return {string} A formatted string that shows the timings of the current
+ *     trace.
+ */
+goog.debug.Trace_.prototype.getFormattedTrace = function() {
+  return this.toString();
+};
+
+
+/**
+ * Returns a formatted string that describes the thread trace.
+ * @return {string} A formatted string.
+ * @override
+ */
+goog.debug.Trace_.prototype.toString = function() {
+  var sb = [];
+  var etime = -1;
+  var indent = [];
+  for (var i = 0; i < this.events_.length; i++) {
+    var e = this.events_[i];
+    if (e.eventType == goog.debug.Trace_.EventType.STOP) {
+      indent.pop();
+    }
+    sb.push(' ', e.toTraceString(this.startTime_, etime, indent.join('')));
+    etime = e.eventTime;
+    sb.push('\n');
+    if (e.eventType == goog.debug.Trace_.EventType.START) {
+      indent.push('|  ');
+    }
+  }
+
+  if (this.outstandingEvents_.getCount() != 0) {
+    var now = goog.debug.Trace_.now();
+
+    sb.push(' Unstopped timers:\n');
+    goog.iter.forEach(this.outstandingEvents_, function(startEvent) {
+      sb.push('  ', startEvent, ' (', now - startEvent.startTime,
+          ' ms, started at ',
+          goog.debug.Trace_.formatTime_(startEvent.startTime),
+          ')\n');
+    });
+  }
+
+  var statKeys = this.stats_.getKeys();
+  for (var i = 0; i < statKeys.length; i++) {
+    var stat = this.stats_.get(statKeys[i]);
+    if (stat.count > 1) {
+      sb.push(' TOTAL ', stat, '\n');
+    }
+  }
+
+  sb.push('Total tracers created ', this.tracerCount_, '\n',
+      'Total comments created ', this.commentCount_, '\n',
+      'Overhead start: ', this.tracerOverheadStart_, ' ms\n',
+      'Overhead end: ', this.tracerOverheadEnd_, ' ms\n',
+      'Overhead comment: ', this.tracerOverheadComment_, ' ms\n');
+
+  return sb.join('');
+};
+
+
+/**
+ * Converts 'v' to a string and pads it with up to 3 spaces for
+ * improved alignment. TODO there must be a better way
+ * @param {number} v A number.
+ * @return {string} A padded string.
+ * @private
+ */
+goog.debug.Trace_.longToPaddedString_ = function(v) {
+  v = Math.round(v);
+  // todo (pupius) - there should be a generic string in goog.string for this
+  var space = '';
+  if (v < 1000) space = ' ';
+  if (v < 100) space = '  ';
+  if (v < 10) space = '   ';
+  return space + v;
+};
+
+
+/**
+ * Return the sec.ms part of time (if time = "20:06:11.566",  "11.566
+ * @param {number} time The time in MS.
+ * @return {string} A formatted string as sec.ms'.
+ * @private
+ */
+goog.debug.Trace_.formatTime_ = function(time) {
+  time = Math.round(time);
+  var sec = (time / 1000) % 60;
+  var ms = time % 1000;
+
+  // TODO their must be a nicer way to get zero padded integers
+  return String(100 + sec).substring(1, 3) + '.' +
+         String(1000 + ms).substring(1, 4);
+};
+
+
+/**
+ * Returns the current time. Done through a wrapper function so it can be
+ * overridden by application code. Gmail has an ActiveX extension that provides
+ * higher precision timing info.
+ * @return {number} The current time in milliseconds.
+ */
+goog.debug.Trace_.now = function() {
+  return goog.now();
+};
+
+
+/**
+ * Singleton trace object
+ * @type {goog.debug.Trace_}
+ */
+goog.debug.Trace = new goog.debug.Trace_();

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/autocompleteremotedata.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/autocompleteremotedata.js b/externs/GCL/externs/goog/demos/autocompleteremotedata.js
new file mode 100644
index 0000000..ff55f67
--- /dev/null
+++ b/externs/GCL/externs/goog/demos/autocompleteremotedata.js
@@ -0,0 +1,18 @@
+// Copyright 2010 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.
+
+/** @nocompile */
+
+['Big Table', 'Googlebot', 'Instant Indexing', 'Mustang', 'Page Rank',
+    'Proto Buffer']

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/autocompleterichremotedata.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/autocompleterichremotedata.js b/externs/GCL/externs/goog/demos/autocompleterichremotedata.js
new file mode 100644
index 0000000..0fad7db
--- /dev/null
+++ b/externs/GCL/externs/goog/demos/autocompleterichremotedata.js
@@ -0,0 +1,33 @@
+// Copyright 2010 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.
+
+/** @nocompile */
+
+[
+ ['apple',
+  {name: 'Fuji', url: 'http://www.google.com/images?q=fuji+apple'},
+  {name: 'Gala', url: 'http://www.google.com/images?q=gala+apple'},
+  {name: 'Golden Delicious',
+   url: 'http://www.google.com/images?q=golden delicious+apple'}
+ ],
+ ['citrus',
+  {name: 'Lemon', url: 'http://www.google.com/images?q=lemon+fruit'},
+  {name: 'Orange', url: 'http://www.google.com/images?q=orange+fruit'}
+  ],
+ ['berry',
+  {name: 'Strawberry', url: 'http://www.google.com/images?q=strawberry+fruit'},
+  {name: 'Blueberry', url: 'http://www.google.com/images?q=blueberry+fruit'},
+  {name: 'Blackberry', url: 'http://www.google.com/images?q=blackberry+fruit'}
+ ]
+]

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/css/demo.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/css/demo.css b/externs/GCL/externs/goog/demos/css/demo.css
new file mode 100644
index 0000000..6eb82e8
--- /dev/null
+++ b/externs/GCL/externs/goog/demos/css/demo.css
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2007 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: attila@google.com (Attila Bodis) */
+
+
+@import url(../../css/common.css);
+
+
+body {
+  background-color: #ffe;
+  font: normal 10pt Arial, sans-serif;
+}
+
+
+/* Misc. styles used for logging and debugging. */
+fieldset {
+  padding: 4px 8px;
+  margin-bottom: 1em;
+}
+
+fieldset legend {
+  font-weight: bold;
+  color: #036;
+}
+
+label, input {
+  vertical-align: middle;
+}
+
+.hint {
+  font-size: 90%;
+  color: #369;
+}
+
+.goog-debug-panel {
+  border: 1px solid #369;
+}
+
+.goog-debug-panel .logdiv {
+  position: relative;
+  width: 100%;
+  height: 8em;
+  overflow: scroll;
+  overflow-x: hidden;
+  overflow-y: scroll;
+}
+
+.goog-debug-panel .logdiv .logmsg {
+  font: normal 10px "Lucida Sans Typewriter", "Courier New", Courier, fixed;
+}
+
+.perf {
+  margin: 0;
+  border: 0;
+  padding: 4px;
+  font: italic 95% Arial, sans-serif;
+  color: #999;
+}
+
+#perf {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  text-align: right;
+  margin: 0;
+  border: 0;
+  padding: 4px;
+  font: italic 95% Arial, sans-serif;
+  color: #999;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/css/emojipicker.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/css/emojipicker.css b/externs/GCL/externs/goog/demos/css/emojipicker.css
new file mode 100644
index 0000000..826d5bd
--- /dev/null
+++ b/externs/GCL/externs/goog/demos/css/emojipicker.css
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2007 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: dalewis@google.com (Darren Lewis) */
+
+/* Styles used in the emojipicker demo */
+.goog-ui-popupemojipicker {
+  position: absolute;
+  -moz-outline: 0;
+  outline: 0;
+  visibility: hidden;
+}
+
+.goog-palette-cell {
+  padding: 2px;
+  background: white;
+}
+
+.goog-palette-cell div {
+  vertical-align: middle;
+  text-align: center;
+  margin: auto;
+}
+
+.goog-palette-cell-wrapper {
+  width: 25px;
+  height: 25px;
+}
+
+.goog-palette-cell-hover {
+  background: lightblue;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/css/emojisprite.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/css/emojisprite.css b/externs/GCL/externs/goog/demos/css/emojisprite.css
new file mode 100644
index 0000000..fe1a2cc
--- /dev/null
+++ b/externs/GCL/externs/goog/demos/css/emojisprite.css
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2010 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* This file is autogenerated. To regenerate, do:
+cd google3/javascript/closure/demos/emoji
+/home/build/static/projects/sitespeed optisprite *.gif
+
+This will generate an optimal sprite in /usr/local/google/tmp/bestsprite.tar.gz.
+
+Rename the optimal sprite to "sprite.png" (from sprite_XX.png), rename the css
+to "sprite.css" (from sprite_XX.css), then change all the URLs in sprite.css to
+point to sprite.png in google3/javascript/closure/demos/emoji, and cp the
+sprite.png into that directory.
+*/
+
+.SPRITE_200{background:no-repeat url(../emoji/sprite.png) -18px 0;width:18px;height:18px}
+.SPRITE_201{background:no-repeat url(../emoji/sprite.png) 0 -234px;width:18px;height:18px}
+.SPRITE_202{background:no-repeat url(../emoji/sprite.png) -18px -338px;width:18px;height:18px}
+.SPRITE_203{background:no-repeat url(../emoji/sprite.png) -36px 0;width:18px;height:18px}
+.SPRITE_204{background:no-repeat url(../emoji/sprite.png) 0 -305px;width:18px;height:19px}
+.SPRITE_205{background:no-repeat url(../emoji/sprite.png) -36px -126px;width:18px;height:18px}
+.SPRITE_206{background:no-repeat url(../emoji/sprite.png) -36px -36px;width:18px;height:18px}
+.SPRITE_2BC{background:no-repeat url(../emoji/sprite.png) -18px -144px;width:18px;height:18px}
+.SPRITE_2BD{background:no-repeat url(../emoji/sprite.png) 0 -18px;width:18px;height:18px}
+.SPRITE_2BE{background:no-repeat url(../emoji/sprite.png) -36px -54px;width:18px;height:18px}
+.SPRITE_2BF{background:no-repeat url(../emoji/sprite.png) 0 -126px;width:18px;height:18px}
+.SPRITE_2C0{background:no-repeat url(../emoji/sprite.png) -18px -305px;width:18px;height:18px}
+.SPRITE_2C1{background:no-repeat url(../emoji/sprite.png) 0 -287px;width:18px;height:18px}
+.SPRITE_2C2{background:no-repeat url(../emoji/sprite.png) -18px -126px;width:18px;height:18px}
+.SPRITE_2C3{background:no-repeat url(../emoji/sprite.png) -36px -234px;width:18px;height:20px}
+.SPRITE_2C4{background:no-repeat url(../emoji/sprite.png) -36px -72px;width:18px;height:18px}
+.SPRITE_2C5{background:no-repeat url(../emoji/sprite.png) -54px -54px;width:18px;height:18px}
+.SPRITE_2C6{background:no-repeat url(../emoji/sprite.png) 0 -72px;width:18px;height:18px}
+.SPRITE_2C7{background:no-repeat url(../emoji/sprite.png) -18px -180px;width:18px;height:18px}
+.SPRITE_2C8{background:no-repeat url(../emoji/sprite.png) -36px -198px;width:18px;height:18px}
+.SPRITE_2C9{background:no-repeat url(../emoji/sprite.png) -36px -287px;width:18px;height:18px}
+.SPRITE_2CB{background:no-repeat url(../emoji/sprite.png) -54px -252px;width:18px;height:18px}
+.SPRITE_2CC{background:no-repeat url(../emoji/sprite.png) -54px -288px;width:18px;height:16px}
+.SPRITE_2CD{background:no-repeat url(../emoji/sprite.png) -36px -162px;width:18px;height:18px}
+.SPRITE_2CE{background:no-repeat url(../emoji/sprite.png) 0 -269px;width:18px;height:18px}
+.SPRITE_2CF{background:no-repeat url(../emoji/sprite.png) -36px -108px;width:18px;height:18px}
+.SPRITE_2D0{background:no-repeat url(../emoji/sprite.png) -36px -338px;width:18px;height:18px}
+.SPRITE_2D1{background:no-repeat url(../emoji/sprite.png) 0 -338px;width:18px;height:18px}
+.SPRITE_2D2{background:no-repeat url(../emoji/sprite.png) -54px -36px;width:18px;height:16px}
+.SPRITE_2D3{background:no-repeat url(../emoji/sprite.png) -36px -305px;width:18px;height:18px}
+.SPRITE_2D4{background:no-repeat url(../emoji/sprite.png) -36px -18px;width:18px;height:18px}
+.SPRITE_2D5{background:no-repeat url(../emoji/sprite.png) -18px -108px;width:18px;height:18px}
+.SPRITE_2D6{background:no-repeat url(../emoji/sprite.png) -36px -144px;width:18px;height:18px}
+.SPRITE_2D7{background:no-repeat url(../emoji/sprite.png) 0 -36px;width:18px;height:18px}
+.SPRITE_2D8{background:no-repeat url(../emoji/sprite.png) -54px -126px;width:18px;height:18px}
+.SPRITE_2D9{background:no-repeat url(../emoji/sprite.png) -18px -287px;width:18px;height:18px}
+.SPRITE_2DA{background:no-repeat url(../emoji/sprite.png) -54px -216px;width:18px;height:18px}
+.SPRITE_2DB{background:no-repeat url(../emoji/sprite.png) -36px -180px;width:18px;height:18px}
+.SPRITE_2DC{background:no-repeat url(../emoji/sprite.png) 0 -54px;width:18px;height:18px}
+.SPRITE_2DD{background:no-repeat url(../emoji/sprite.png) -18px -72px;width:18px;height:18px}
+.SPRITE_2DE{background:no-repeat url(../emoji/sprite.png) -36px -90px;width:18px;height:18px}
+.SPRITE_2DF{background:no-repeat url(../emoji/sprite.png) -54px -108px;width:18px;height:18px}
+.SPRITE_2E0{background:no-repeat url(../emoji/sprite.png) -18px -198px;width:18px;height:18px}
+.SPRITE_2E1{background:no-repeat url(../emoji/sprite.png) 0 -180px;width:18px;height:18px}
+.SPRITE_2E2{background:no-repeat url(../emoji/sprite.png) -54px -338px;width:18px;height:18px}
+.SPRITE_2E4{background:no-repeat url(../emoji/sprite.png) -54px -198px;width:18px;height:18px}
+.SPRITE_2E5{background:no-repeat url(../emoji/sprite.png) 0 -162px;width:18px;height:18px}
+.SPRITE_2E6{background:no-repeat url(../emoji/sprite.png) -54px -270px;width:18px;height:18px}
+.SPRITE_2E7{background:no-repeat url(../emoji/sprite.png) 0 -108px;width:18px;height:18px}
+.SPRITE_2E8{background:no-repeat url(../emoji/sprite.png) 0 -198px;width:18px;height:18px}
+.SPRITE_2E9{background:no-repeat url(../emoji/sprite.png) -54px 0;width:18px;height:18px}
+.SPRITE_2EA{background:no-repeat url(../emoji/sprite.png) -54px -144px;width:18px;height:18px}
+.SPRITE_2EB{background:no-repeat url(../emoji/sprite.png) -18px -36px;width:18px;height:18px}
+.SPRITE_2EC{background:no-repeat url(../emoji/sprite.png) -18px -18px;width:18px;height:18px}
+.SPRITE_2ED{background:no-repeat url(../emoji/sprite.png) -36px -269px;width:18px;height:18px}
+.SPRITE_2EE{background:no-repeat url(../emoji/sprite.png) -18px -90px;width:18px;height:18px}
+.SPRITE_2F0{background:no-repeat url(../emoji/sprite.png) 0 0;width:18px;height:18px}
+.SPRITE_2F2{background:no-repeat url(../emoji/sprite.png) -54px -234px;width:18px;height:18px}
+.SPRITE_2F3{background:no-repeat url(../emoji/sprite.png) 0 -144px;width:18px;height:18px}
+.SPRITE_2F4{background:no-repeat url(../emoji/sprite.png) 0 -252px;width:18px;height:17px}
+.SPRITE_2F5{background:no-repeat url(../emoji/sprite.png) -54px -321px;width:18px;height:14px}
+.SPRITE_2F6{background:no-repeat url(../emoji/sprite.png) -36px -254px;width:18px;height:15px}
+.SPRITE_2F7{background:no-repeat url(../emoji/sprite.png) -18px -54px;width:18px;height:18px}
+.SPRITE_2F8{background:no-repeat url(../emoji/sprite.png) 0 -216px;width:18px;height:18px}
+.SPRITE_2F9{background:no-repeat url(../emoji/sprite.png) -18px -234px;width:18px;height:18px}
+.SPRITE_2FA{background:no-repeat url(../emoji/sprite.png) -18px -216px;width:18px;height:18px}
+.SPRITE_2FB{background:no-repeat url(../emoji/sprite.png) -36px -216px;width:18px;height:18px}
+.SPRITE_2FC{background:no-repeat url(../emoji/sprite.png) -54px -162px;width:18px;height:18px}
+.SPRITE_2FD{background:no-repeat url(../emoji/sprite.png) 0 -90px;width:18px;height:18px}
+.SPRITE_2FE{background:no-repeat url(../emoji/sprite.png) -54px -305px;width:18px;height:16px}
+.SPRITE_2FF{background:no-repeat url(../emoji/sprite.png) -54px -72px;width:18px;height:16px}
+.SPRITE_none{background:no-repeat url(../emoji/sprite.png) -54px -180px;width:18px;height:18px}
+.SPRITE_unknown{background:no-repeat url(../emoji/sprite.png) -36px -323px;width:14px;height:15px}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/editor/deps.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/editor/deps.js b/externs/GCL/externs/goog/demos/editor/deps.js
new file mode 100644
index 0000000..70b0973
--- /dev/null
+++ b/externs/GCL/externs/goog/demos/editor/deps.js
@@ -0,0 +1,21 @@
+// 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.
+//
+// This file has been auto-generated by GenJsDeps, please do not edit.
+
+goog.addDependency('demos/editor/equationeditor.js', ['goog.demos.editor.EquationEditor'], ['goog.ui.equation.EquationEditorDialog']);
+goog.addDependency('demos/editor/helloworld.js', ['goog.demos.editor.HelloWorld'], ['goog.dom', 'goog.dom.TagName', 'goog.editor.Plugin']);
+goog.addDependency('demos/editor/helloworlddialog.js', ['goog.demos.editor.HelloWorldDialog', 'goog.demos.editor.HelloWorldDialog.OkEvent'], ['goog.dom.TagName', 'goog.events.Event', 'goog.string', 'goog.ui.editor.AbstractDialog', 'goog.ui.editor.AbstractDialog.Builder', 'goog.ui.editor.AbstractDialog.EventType']);
+goog.addDependency('demos/editor/helloworlddialogplugin.js', ['goog.demos.editor.HelloWorldDialogPlugin', 'goog.demos.editor.HelloWorldDialogPlugin.Command'], ['goog.demos.editor.HelloWorldDialog', 'goog.dom.TagName', 'goog.editor.plugins.AbstractDialogPlugin', 'goog.editor.range', 'goog.functions', 'goog.ui.editor.AbstractDialog.EventType']);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/editor/helloworld.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/editor/helloworld.js b/externs/GCL/externs/goog/demos/editor/helloworld.js
new file mode 100644
index 0000000..4b2f0c7
--- /dev/null
+++ b/externs/GCL/externs/goog/demos/editor/helloworld.js
@@ -0,0 +1,82 @@
+// Copyright 2008 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 simple plugin that inserts 'Hello World!' on command. This
+ * plugin is intended to be an example of a very simple plugin for plugin
+ * developers.
+ *
+ * @author gak@google.com (Gregory Kick)
+ * @see helloworld.html
+ */
+
+goog.provide('goog.demos.editor.HelloWorld');
+
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.Plugin');
+
+
+
+/**
+ * Plugin to insert 'Hello World!' into an editable field.
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ * @final
+ */
+goog.demos.editor.HelloWorld = function() {
+  goog.editor.Plugin.call(this);
+};
+goog.inherits(goog.demos.editor.HelloWorld, goog.editor.Plugin);
+
+
+/** @override */
+goog.demos.editor.HelloWorld.prototype.getTrogClassId = function() {
+  return 'HelloWorld';
+};
+
+
+/**
+ * Commands implemented by this plugin.
+ * @enum {string}
+ */
+goog.demos.editor.HelloWorld.COMMAND = {
+  HELLO_WORLD: '+helloWorld'
+};
+
+
+/** @override */
+goog.demos.editor.HelloWorld.prototype.isSupportedCommand = function(
+    command) {
+  return command == goog.demos.editor.HelloWorld.COMMAND.HELLO_WORLD;
+};
+
+
+/**
+ * Executes a command. Does not fire any BEFORECHANGE, CHANGE, or
+ * SELECTIONCHANGE events (these are handled by the super class implementation
+ * of {@code execCommand}.
+ * @param {string} command Command to execute.
+ * @override
+ * @protected
+ */
+goog.demos.editor.HelloWorld.prototype.execCommandInternal = function(
+    command) {
+  var domHelper = this.getFieldObject().getEditableDomHelper();
+  var range = this.getFieldObject().getRange();
+  range.removeContents();
+  var newNode =
+      domHelper.createDom(goog.dom.TagName.SPAN, null, 'Hello World!');
+  range.insertNode(newNode, false);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/editor/helloworlddialog.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/editor/helloworlddialog.js b/externs/GCL/externs/goog/demos/editor/helloworlddialog.js
new file mode 100644
index 0000000..5ab271e
--- /dev/null
+++ b/externs/GCL/externs/goog/demos/editor/helloworlddialog.js
@@ -0,0 +1,173 @@
+// Copyright 2008 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 An example of how to write a dialog to be opened by a plugin.
+ *
+ */
+
+goog.provide('goog.demos.editor.HelloWorldDialog');
+goog.provide('goog.demos.editor.HelloWorldDialog.OkEvent');
+
+goog.require('goog.dom.TagName');
+goog.require('goog.events.Event');
+goog.require('goog.string');
+goog.require('goog.ui.editor.AbstractDialog');
+
+
+// *** Public interface ***************************************************** //
+
+
+
+/**
+ * Creates a dialog to let the user enter a customized hello world message.
+ * @param {goog.dom.DomHelper} domHelper DomHelper to be used to create the
+ * dialog's dom structure.
+ * @constructor
+ * @extends {goog.ui.editor.AbstractDialog}
+ * @final
+ */
+goog.demos.editor.HelloWorldDialog = function(domHelper) {
+  goog.ui.editor.AbstractDialog.call(this, domHelper);
+};
+goog.inherits(goog.demos.editor.HelloWorldDialog,
+              goog.ui.editor.AbstractDialog);
+
+
+// *** Event **************************************************************** //
+
+
+
+/**
+ * OK event object for the hello world dialog.
+ * @param {string} message Customized hello world message chosen by the user.
+ * @constructor
+ * @extends {goog.events.Event}
+ * @final
+ */
+goog.demos.editor.HelloWorldDialog.OkEvent = function(message) {
+  this.message = message;
+};
+goog.inherits(goog.demos.editor.HelloWorldDialog.OkEvent, goog.events.Event);
+
+
+/**
+ * Event type.
+ * @type {goog.ui.editor.AbstractDialog.EventType}
+ * @override
+ */
+goog.demos.editor.HelloWorldDialog.OkEvent.prototype.type =
+    goog.ui.editor.AbstractDialog.EventType.OK;
+
+
+/**
+ * Customized hello world message chosen by the user.
+ * @type {string}
+ */
+goog.demos.editor.HelloWorldDialog.OkEvent.prototype.message;
+
+
+// *** Protected interface ************************************************** //
+
+
+/** @override */
+goog.demos.editor.HelloWorldDialog.prototype.createDialogControl = function() {
+  var builder = new goog.ui.editor.AbstractDialog.Builder(this);
+  /** @desc Title of the hello world dialog. */
+  var MSG_HELLO_WORLD_DIALOG_TITLE = goog.getMsg('Add a Hello World message');
+  builder.setTitle(MSG_HELLO_WORLD_DIALOG_TITLE).
+      setContent(this.createContent_());
+  return builder.build();
+};
+
+
+/**
+ * Creates and returns the event object to be used when dispatching the OK
+ * event to listeners, or returns null to prevent the dialog from closing.
+ * @param {goog.events.Event} e The event object dispatched by the wrapped
+ *     dialog.
+ * @return {goog.demos.editor.HelloWorldDialog.OkEvent} The event object to be
+ *     used when dispatching the OK event to listeners.
+ * @protected
+ * @override
+ */
+goog.demos.editor.HelloWorldDialog.prototype.createOkEvent = function(e) {
+  var message = this.getMessage_();
+  if (message &&
+      goog.demos.editor.HelloWorldDialog.isValidHelloWorld_(message)) {
+    return new goog.demos.editor.HelloWorldDialog.OkEvent(message);
+  } else {
+    /** @desc Error message telling the user why their message was rejected. */
+    var MSG_HELLO_WORLD_DIALOG_ERROR =
+        goog.getMsg('Your message must contain the words "hello" and "world".');
+    this.dom.getWindow().alert(MSG_HELLO_WORLD_DIALOG_ERROR);
+    return null; // Prevents the dialog from closing.
+  }
+};
+
+
+// *** Private implementation *********************************************** //
+
+
+/**
+ * Input element where the user will type their hello world message.
+ * @type {Element}
+ * @private
+ */
+goog.demos.editor.HelloWorldDialog.prototype.input_;
+
+
+/**
+ * Creates the DOM structure that makes up the dialog's content area.
+ * @return {Element} The DOM structure that makes up the dialog's content area.
+ * @private
+ */
+goog.demos.editor.HelloWorldDialog.prototype.createContent_ = function() {
+  /** @desc Sample hello world message to prepopulate the dialog with. */
+  var MSG_HELLO_WORLD_DIALOG_SAMPLE = goog.getMsg('Hello, world!');
+  this.input_ = this.dom.createDom(goog.dom.TagName.INPUT,
+      {size: 25, value: MSG_HELLO_WORLD_DIALOG_SAMPLE});
+  /** @desc Prompt telling the user to enter a hello world message. */
+  var MSG_HELLO_WORLD_DIALOG_PROMPT =
+      goog.getMsg('Enter your Hello World message');
+  return this.dom.createDom(goog.dom.TagName.DIV,
+                            null,
+                            [MSG_HELLO_WORLD_DIALOG_PROMPT, this.input_]);
+};
+
+
+/**
+ * Returns the hello world message currently typed into the dialog's input.
+ * @return {?string} The hello world message currently typed into the dialog's
+ *     input, or null if called before the input is created.
+ * @private
+ */
+goog.demos.editor.HelloWorldDialog.prototype.getMessage_ = function() {
+  return this.input_ && this.input_.value;
+};
+
+
+/**
+ * Returns whether or not the given message contains the strings "hello" and
+ * "world". Case-insensitive and order doesn't matter.
+ * @param {string} message The message to be checked.
+ * @return {boolean} Whether or not the given message contains the strings
+ *     "hello" and "world".
+ * @private
+ */
+goog.demos.editor.HelloWorldDialog.isValidHelloWorld_ = function(message) {
+  message = message.toLowerCase();
+  return goog.string.contains(message, 'hello') &&
+         goog.string.contains(message, 'world');
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/editor/helloworlddialogplugin.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/editor/helloworlddialogplugin.js b/externs/GCL/externs/goog/demos/editor/helloworlddialogplugin.js
new file mode 100644
index 0000000..56a65b6
--- /dev/null
+++ b/externs/GCL/externs/goog/demos/editor/helloworlddialogplugin.js
@@ -0,0 +1,117 @@
+// Copyright 2008 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 An example of how to write a dialog plugin.
+ *
+ */
+
+goog.provide('goog.demos.editor.HelloWorldDialogPlugin');
+goog.provide('goog.demos.editor.HelloWorldDialogPlugin.Command');
+
+goog.require('goog.demos.editor.HelloWorldDialog');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.plugins.AbstractDialogPlugin');
+goog.require('goog.editor.range');
+goog.require('goog.functions');
+goog.require('goog.ui.editor.AbstractDialog');
+
+
+// *** Public interface ***************************************************** //
+
+
+
+/**
+ * A plugin that opens the hello world dialog.
+ * @constructor
+ * @extends {goog.editor.plugins.AbstractDialogPlugin}
+ * @final
+ */
+goog.demos.editor.HelloWorldDialogPlugin = function() {
+  goog.editor.plugins.AbstractDialogPlugin.call(this,
+      goog.demos.editor.HelloWorldDialogPlugin.Command.HELLO_WORLD_DIALOG);
+};
+goog.inherits(goog.demos.editor.HelloWorldDialogPlugin,
+              goog.editor.plugins.AbstractDialogPlugin);
+
+
+/**
+ * Commands implemented by this plugin.
+ * @enum {string}
+ */
+goog.demos.editor.HelloWorldDialogPlugin.Command = {
+  HELLO_WORLD_DIALOG: 'helloWorldDialog'
+};
+
+
+/** @override */
+goog.demos.editor.HelloWorldDialogPlugin.prototype.getTrogClassId =
+    goog.functions.constant('HelloWorldDialog');
+
+
+// *** Protected interface ************************************************** //
+
+
+/**
+ * Creates a new instance of the dialog and registers for the relevant events.
+ * @param {goog.dom.DomHelper} dialogDomHelper The dom helper to be used to
+ *     create the dialog.
+ * @return {goog.demos.editor.HelloWorldDialog} The dialog.
+ * @override
+ * @protected
+ */
+goog.demos.editor.HelloWorldDialogPlugin.prototype.createDialog = function(
+    dialogDomHelper) {
+  var dialog = new goog.demos.editor.HelloWorldDialog(dialogDomHelper);
+  dialog.addEventListener(goog.ui.editor.AbstractDialog.EventType.OK,
+                          this.handleOk_,
+                          false,
+                          this);
+  return dialog;
+};
+
+
+// *** Private implementation *********************************************** //
+
+
+/**
+ * Handles the OK event from the dialog by inserting the hello world message
+ * into the field.
+ * @param {goog.demos.editor.HelloWorldDialog.OkEvent} e OK event object.
+ * @private
+ */
+goog.demos.editor.HelloWorldDialogPlugin.prototype.handleOk_ = function(e) {
+  // First restore the selection so we can manipulate the field's content
+  // according to what was selected.
+  this.restoreOriginalSelection();
+
+  // Notify listeners that the field's contents are about to change.
+  this.getFieldObject().dispatchBeforeChange();
+
+  // Now we can clear out what was previously selected (if anything).
+  var range = this.getFieldObject().getRange();
+  range.removeContents();
+  // And replace it with a span containing our hello world message.
+  var createdNode = this.getFieldDomHelper().createDom(goog.dom.TagName.SPAN,
+                                                       null,
+                                                       e.message);
+  createdNode = range.insertNode(createdNode, false);
+  // Place the cursor at the end of the new text node (false == to the right).
+  goog.editor.range.placeCursorNextTo(createdNode, false);
+
+  // Notify listeners that the field's selection has changed.
+  this.getFieldObject().dispatchSelectionChangeEvent();
+  // Notify listeners that the field's contents have changed.
+  this.getFieldObject().dispatchChange();
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/200.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/200.gif b/externs/GCL/externs/goog/demos/emoji/200.gif
new file mode 100644
index 0000000..6245f69
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/200.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/201.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/201.gif b/externs/GCL/externs/goog/demos/emoji/201.gif
new file mode 100644
index 0000000..b740d39
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/201.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/202.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/202.gif b/externs/GCL/externs/goog/demos/emoji/202.gif
new file mode 100644
index 0000000..2bc9be6
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/202.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/203.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/203.gif b/externs/GCL/externs/goog/demos/emoji/203.gif
new file mode 100644
index 0000000..1ce3f56
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/203.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/204.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/204.gif b/externs/GCL/externs/goog/demos/emoji/204.gif
new file mode 100644
index 0000000..2166ce8
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/204.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/205.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/205.gif b/externs/GCL/externs/goog/demos/emoji/205.gif
new file mode 100644
index 0000000..363e045
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/205.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/206.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/206.gif b/externs/GCL/externs/goog/demos/emoji/206.gif
new file mode 100644
index 0000000..5b95f44
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/206.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2BC.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2BC.gif b/externs/GCL/externs/goog/demos/emoji/2BC.gif
new file mode 100644
index 0000000..aecbdc0
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2BC.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2BD.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2BD.gif b/externs/GCL/externs/goog/demos/emoji/2BD.gif
new file mode 100644
index 0000000..0b352dd
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2BD.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2BE.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2BE.gif b/externs/GCL/externs/goog/demos/emoji/2BE.gif
new file mode 100644
index 0000000..282c361
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2BE.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2BF.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2BF.gif b/externs/GCL/externs/goog/demos/emoji/2BF.gif
new file mode 100644
index 0000000..5b88ee7
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2BF.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2C0.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2C0.gif b/externs/GCL/externs/goog/demos/emoji/2C0.gif
new file mode 100644
index 0000000..17fa1a3
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2C0.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2C1.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2C1.gif b/externs/GCL/externs/goog/demos/emoji/2C1.gif
new file mode 100644
index 0000000..a1f294a
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2C1.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2C2.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2C2.gif b/externs/GCL/externs/goog/demos/emoji/2C2.gif
new file mode 100644
index 0000000..01dadbe
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2C2.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2C3.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2C3.gif b/externs/GCL/externs/goog/demos/emoji/2C3.gif
new file mode 100644
index 0000000..69a6126
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2C3.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2C4.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2C4.gif b/externs/GCL/externs/goog/demos/emoji/2C4.gif
new file mode 100644
index 0000000..224527b
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2C4.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2C5.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2C5.gif b/externs/GCL/externs/goog/demos/emoji/2C5.gif
new file mode 100644
index 0000000..2fe94b3
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2C5.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2C6.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2C6.gif b/externs/GCL/externs/goog/demos/emoji/2C6.gif
new file mode 100644
index 0000000..8b1e731
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2C6.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2C7.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2C7.gif b/externs/GCL/externs/goog/demos/emoji/2C7.gif
new file mode 100644
index 0000000..3d7c63a
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2C7.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2C8.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2C8.gif b/externs/GCL/externs/goog/demos/emoji/2C8.gif
new file mode 100644
index 0000000..cb44d16
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2C8.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2C9.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2C9.gif b/externs/GCL/externs/goog/demos/emoji/2C9.gif
new file mode 100644
index 0000000..69fe427
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2C9.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2CA.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2CA.gif b/externs/GCL/externs/goog/demos/emoji/2CA.gif
new file mode 100644
index 0000000..cba4c24
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2CA.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2CB.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2CB.gif b/externs/GCL/externs/goog/demos/emoji/2CB.gif
new file mode 100644
index 0000000..c1f035e
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2CB.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2CC.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2CC.gif b/externs/GCL/externs/goog/demos/emoji/2CC.gif
new file mode 100644
index 0000000..bd757fa
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2CC.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2CD.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2CD.gif b/externs/GCL/externs/goog/demos/emoji/2CD.gif
new file mode 100644
index 0000000..f42f5a1
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2CD.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2CE.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2CE.gif b/externs/GCL/externs/goog/demos/emoji/2CE.gif
new file mode 100644
index 0000000..3f6eff3
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2CE.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2CF.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2CF.gif b/externs/GCL/externs/goog/demos/emoji/2CF.gif
new file mode 100644
index 0000000..2f7d407
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2CF.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2D0.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2D0.gif b/externs/GCL/externs/goog/demos/emoji/2D0.gif
new file mode 100644
index 0000000..37da48e
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2D0.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2D1.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2D1.gif b/externs/GCL/externs/goog/demos/emoji/2D1.gif
new file mode 100644
index 0000000..2bc951d
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2D1.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2D2.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2D2.gif b/externs/GCL/externs/goog/demos/emoji/2D2.gif
new file mode 100644
index 0000000..a7c50db
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2D2.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2D3.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2D3.gif b/externs/GCL/externs/goog/demos/emoji/2D3.gif
new file mode 100644
index 0000000..22ceddf
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2D3.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2D4.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2D4.gif b/externs/GCL/externs/goog/demos/emoji/2D4.gif
new file mode 100644
index 0000000..8e99652
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2D4.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2D5.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2D5.gif b/externs/GCL/externs/goog/demos/emoji/2D5.gif
new file mode 100644
index 0000000..4837a48
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2D5.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2D6.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2D6.gif b/externs/GCL/externs/goog/demos/emoji/2D6.gif
new file mode 100644
index 0000000..bd7230f
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2D6.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2D7.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2D7.gif b/externs/GCL/externs/goog/demos/emoji/2D7.gif
new file mode 100644
index 0000000..880829f
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2D7.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2D8.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2D8.gif b/externs/GCL/externs/goog/demos/emoji/2D8.gif
new file mode 100644
index 0000000..7d727db
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2D8.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2D9.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2D9.gif b/externs/GCL/externs/goog/demos/emoji/2D9.gif
new file mode 100644
index 0000000..98a0fa2
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2D9.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2DA.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2DA.gif b/externs/GCL/externs/goog/demos/emoji/2DA.gif
new file mode 100644
index 0000000..c831816
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2DA.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2DB.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2DB.gif b/externs/GCL/externs/goog/demos/emoji/2DB.gif
new file mode 100644
index 0000000..301c931
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2DB.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2DC.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2DC.gif b/externs/GCL/externs/goog/demos/emoji/2DC.gif
new file mode 100644
index 0000000..27ab408
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2DC.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2DD.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2DD.gif b/externs/GCL/externs/goog/demos/emoji/2DD.gif
new file mode 100644
index 0000000..b5e6edf
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2DD.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2DE.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2DE.gif b/externs/GCL/externs/goog/demos/emoji/2DE.gif
new file mode 100644
index 0000000..b9a7272
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2DE.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2DF.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2DF.gif b/externs/GCL/externs/goog/demos/emoji/2DF.gif
new file mode 100644
index 0000000..89fa186
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2DF.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2E0.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2E0.gif b/externs/GCL/externs/goog/demos/emoji/2E0.gif
new file mode 100644
index 0000000..7fd754a
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2E0.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2E1.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2E1.gif b/externs/GCL/externs/goog/demos/emoji/2E1.gif
new file mode 100644
index 0000000..6926e4e
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2E1.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2E2.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2E2.gif b/externs/GCL/externs/goog/demos/emoji/2E2.gif
new file mode 100644
index 0000000..1718dae
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2E2.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2E3.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2E3.gif b/externs/GCL/externs/goog/demos/emoji/2E3.gif
new file mode 100644
index 0000000..4f23b2b
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2E3.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2E4.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2E4.gif b/externs/GCL/externs/goog/demos/emoji/2E4.gif
new file mode 100644
index 0000000..ab2c9eb
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2E4.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2E5.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2E5.gif b/externs/GCL/externs/goog/demos/emoji/2E5.gif
new file mode 100644
index 0000000..ff8f45b
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2E5.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2E6.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2E6.gif b/externs/GCL/externs/goog/demos/emoji/2E6.gif
new file mode 100644
index 0000000..56e75e8
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2E6.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2E7.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2E7.gif b/externs/GCL/externs/goog/demos/emoji/2E7.gif
new file mode 100644
index 0000000..157042d
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2E7.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2E8.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2E8.gif b/externs/GCL/externs/goog/demos/emoji/2E8.gif
new file mode 100644
index 0000000..1eb1cc9
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2E8.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2E9.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2E9.gif b/externs/GCL/externs/goog/demos/emoji/2E9.gif
new file mode 100644
index 0000000..5b98149
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2E9.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2EA.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2EA.gif b/externs/GCL/externs/goog/demos/emoji/2EA.gif
new file mode 100644
index 0000000..40d60a6
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2EA.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2EB.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2EB.gif b/externs/GCL/externs/goog/demos/emoji/2EB.gif
new file mode 100644
index 0000000..8e2ca7d
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2EB.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2EC.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2EC.gif b/externs/GCL/externs/goog/demos/emoji/2EC.gif
new file mode 100644
index 0000000..884e226
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2EC.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2ED.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2ED.gif b/externs/GCL/externs/goog/demos/emoji/2ED.gif
new file mode 100644
index 0000000..b50ba96
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2ED.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2EE.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2EE.gif b/externs/GCL/externs/goog/demos/emoji/2EE.gif
new file mode 100644
index 0000000..a96fbd1
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2EE.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2EF.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2EF.gif b/externs/GCL/externs/goog/demos/emoji/2EF.gif
new file mode 100644
index 0000000..13a0d2b
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2EF.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2F0.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2F0.gif b/externs/GCL/externs/goog/demos/emoji/2F0.gif
new file mode 100644
index 0000000..1538221
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2F0.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2F1.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2F1.gif b/externs/GCL/externs/goog/demos/emoji/2F1.gif
new file mode 100644
index 0000000..d04c68d
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2F1.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2F2.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2F2.gif b/externs/GCL/externs/goog/demos/emoji/2F2.gif
new file mode 100644
index 0000000..402dfce
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2F2.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2F3.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2F3.gif b/externs/GCL/externs/goog/demos/emoji/2F3.gif
new file mode 100644
index 0000000..250271e
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2F3.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2F4.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2F4.gif b/externs/GCL/externs/goog/demos/emoji/2F4.gif
new file mode 100644
index 0000000..dec31af
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2F4.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2F5.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2F5.gif b/externs/GCL/externs/goog/demos/emoji/2F5.gif
new file mode 100644
index 0000000..bed6e71
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2F5.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2F6.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2F6.gif b/externs/GCL/externs/goog/demos/emoji/2F6.gif
new file mode 100644
index 0000000..e9b885f
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2F6.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2F7.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2F7.gif b/externs/GCL/externs/goog/demos/emoji/2F7.gif
new file mode 100644
index 0000000..5bdcb64
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2F7.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2F8.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2F8.gif b/externs/GCL/externs/goog/demos/emoji/2F8.gif
new file mode 100644
index 0000000..629016b
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2F8.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2F9.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2F9.gif b/externs/GCL/externs/goog/demos/emoji/2F9.gif
new file mode 100644
index 0000000..f8b41da
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2F9.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2FA.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2FA.gif b/externs/GCL/externs/goog/demos/emoji/2FA.gif
new file mode 100644
index 0000000..0a4a5b3
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2FA.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2FB.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2FB.gif b/externs/GCL/externs/goog/demos/emoji/2FB.gif
new file mode 100644
index 0000000..620d898
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2FB.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2FC.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2FC.gif b/externs/GCL/externs/goog/demos/emoji/2FC.gif
new file mode 100644
index 0000000..2171097
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2FC.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2FD.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2FD.gif b/externs/GCL/externs/goog/demos/emoji/2FD.gif
new file mode 100644
index 0000000..c6bcdb4
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2FD.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2FE.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2FE.gif b/externs/GCL/externs/goog/demos/emoji/2FE.gif
new file mode 100644
index 0000000..a8888c5
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2FE.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/2FF.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/2FF.gif b/externs/GCL/externs/goog/demos/emoji/2FF.gif
new file mode 100644
index 0000000..6022c4c
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/2FF.gif differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/none.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/none.gif b/externs/GCL/externs/goog/demos/emoji/none.gif
new file mode 100644
index 0000000..8e1f90e
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/none.gif differ


[14/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/anim/anim.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/anim/anim.js b/externs/GCL/externs/goog/fx/anim/anim.js
new file mode 100644
index 0000000..fdce513
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/anim/anim.js
@@ -0,0 +1,211 @@
+// 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 Basic animation controls.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ */
+goog.provide('goog.fx.anim');
+goog.provide('goog.fx.anim.Animated');
+
+goog.require('goog.async.AnimationDelay');
+goog.require('goog.async.Delay');
+goog.require('goog.object');
+
+
+
+/**
+ * An interface for programatically animated objects. I.e. rendered in
+ * javascript frame by frame.
+ *
+ * @interface
+ */
+goog.fx.anim.Animated = function() {};
+
+
+/**
+ * Function called when a frame is requested for the animation.
+ *
+ * @param {number} now Current time in milliseconds.
+ */
+goog.fx.anim.Animated.prototype.onAnimationFrame;
+
+
+/**
+ * Default wait timeout for animations (in milliseconds).  Only used for timed
+ * animation, which uses a timer (setTimeout) to schedule animation.
+ *
+ * @type {number}
+ * @const
+ */
+goog.fx.anim.TIMEOUT = goog.async.AnimationDelay.TIMEOUT;
+
+
+/**
+ * A map of animations which should be cycled on the global timer.
+ *
+ * @type {Object<number, goog.fx.anim.Animated>}
+ * @private
+ */
+goog.fx.anim.activeAnimations_ = {};
+
+
+/**
+ * An optional animation window.
+ * @type {Window}
+ * @private
+ */
+goog.fx.anim.animationWindow_ = null;
+
+
+/**
+ * An interval ID for the global timer or event handler uid.
+ * @type {goog.async.Delay|goog.async.AnimationDelay}
+ * @private
+ */
+goog.fx.anim.animationDelay_ = null;
+
+
+/**
+ * Registers an animation to be cycled on the global timer.
+ * @param {goog.fx.anim.Animated} animation The animation to register.
+ */
+goog.fx.anim.registerAnimation = function(animation) {
+  var uid = goog.getUid(animation);
+  if (!(uid in goog.fx.anim.activeAnimations_)) {
+    goog.fx.anim.activeAnimations_[uid] = animation;
+  }
+
+  // If the timer is not already started, start it now.
+  goog.fx.anim.requestAnimationFrame_();
+};
+
+
+/**
+ * Removes an animation from the list of animations which are cycled on the
+ * global timer.
+ * @param {goog.fx.anim.Animated} animation The animation to unregister.
+ */
+goog.fx.anim.unregisterAnimation = function(animation) {
+  var uid = goog.getUid(animation);
+  delete goog.fx.anim.activeAnimations_[uid];
+
+  // If a timer is running and we no longer have any active timers we stop the
+  // timers.
+  if (goog.object.isEmpty(goog.fx.anim.activeAnimations_)) {
+    goog.fx.anim.cancelAnimationFrame_();
+  }
+};
+
+
+/**
+ * Tears down this module. Useful for testing.
+ */
+// TODO(nicksantos): Wow, this api is pretty broken. This should be fixed.
+goog.fx.anim.tearDown = function() {
+  goog.fx.anim.animationWindow_ = null;
+  goog.dispose(goog.fx.anim.animationDelay_);
+  goog.fx.anim.animationDelay_ = null;
+  goog.fx.anim.activeAnimations_ = {};
+};
+
+
+/**
+ * Registers an animation window. This allows usage of the timing control API
+ * for animations. Note that this window must be visible, as non-visible
+ * windows can potentially stop animating. This window does not necessarily
+ * need to be the window inside which animation occurs, but must remain visible.
+ * See: https://developer.mozilla.org/en/DOM/window.mozRequestAnimationFrame.
+ *
+ * @param {Window} animationWindow The window in which to animate elements.
+ */
+goog.fx.anim.setAnimationWindow = function(animationWindow) {
+  // If a timer is currently running, reset it and restart with new functions
+  // after a timeout. This is to avoid mismatching timer UIDs if we change the
+  // animation window during a running animation.
+  //
+  // In practice this cannot happen before some animation window and timer
+  // control functions has already been set.
+  var hasTimer =
+      goog.fx.anim.animationDelay_ && goog.fx.anim.animationDelay_.isActive();
+
+  goog.dispose(goog.fx.anim.animationDelay_);
+  goog.fx.anim.animationDelay_ = null;
+  goog.fx.anim.animationWindow_ = animationWindow;
+
+  // If the timer was running, start it again.
+  if (hasTimer) {
+    goog.fx.anim.requestAnimationFrame_();
+  }
+};
+
+
+/**
+ * Requests an animation frame based on the requestAnimationFrame and
+ * cancelRequestAnimationFrame function pair.
+ * @private
+ */
+goog.fx.anim.requestAnimationFrame_ = function() {
+  if (!goog.fx.anim.animationDelay_) {
+    // We cannot guarantee that the global window will be one that fires
+    // requestAnimationFrame events (consider off-screen chrome extension
+    // windows). Default to use goog.async.Delay, unless
+    // the client has explicitly set an animation window.
+    if (goog.fx.anim.animationWindow_) {
+      // requestAnimationFrame will call cycleAnimations_ with the current
+      // time in ms, as returned from goog.now().
+      goog.fx.anim.animationDelay_ = new goog.async.AnimationDelay(
+          function(now) {
+            goog.fx.anim.cycleAnimations_(now);
+          }, goog.fx.anim.animationWindow_);
+    } else {
+      goog.fx.anim.animationDelay_ = new goog.async.Delay(function() {
+        goog.fx.anim.cycleAnimations_(goog.now());
+      }, goog.fx.anim.TIMEOUT);
+    }
+  }
+
+  var delay = goog.fx.anim.animationDelay_;
+  if (!delay.isActive()) {
+    delay.start();
+  }
+};
+
+
+/**
+ * Cancels an animation frame created by requestAnimationFrame_().
+ * @private
+ */
+goog.fx.anim.cancelAnimationFrame_ = function() {
+  if (goog.fx.anim.animationDelay_) {
+    goog.fx.anim.animationDelay_.stop();
+  }
+};
+
+
+/**
+ * Cycles through all registered animations.
+ * @param {number} now Current time in milliseconds.
+ * @private
+ */
+goog.fx.anim.cycleAnimations_ = function(now) {
+  goog.object.forEach(goog.fx.anim.activeAnimations_, function(anim) {
+    anim.onAnimationFrame(now);
+  });
+
+  if (!goog.object.isEmpty(goog.fx.anim.activeAnimations_)) {
+    goog.fx.anim.requestAnimationFrame_();
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/animation.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/animation.js b/externs/GCL/externs/goog/fx/animation.js
new file mode 100644
index 0000000..0a4401b
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/animation.js
@@ -0,0 +1,524 @@
+// 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 Classes for doing animations and visual effects.
+ *
+ * (Based loosly on my animation code for 13thparallel.org, with extra
+ * inspiration from the DojoToolkit's modifications to my code)
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+goog.provide('goog.fx.Animation');
+goog.provide('goog.fx.Animation.EventType');
+goog.provide('goog.fx.Animation.State');
+goog.provide('goog.fx.AnimationEvent');
+
+goog.require('goog.array');
+goog.require('goog.events.Event');
+goog.require('goog.fx.Transition');  // Unreferenced: interface
+goog.require('goog.fx.TransitionBase');
+goog.require('goog.fx.anim');
+goog.require('goog.fx.anim.Animated');  // Unreferenced: interface
+
+
+
+/**
+ * Constructor for an animation object.
+ * @param {Array<number>} start Array for start coordinates.
+ * @param {Array<number>} end Array for end coordinates.
+ * @param {number} duration Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @constructor
+ * @implements {goog.fx.anim.Animated}
+ * @implements {goog.fx.Transition}
+ * @extends {goog.fx.TransitionBase}
+ */
+goog.fx.Animation = function(start, end, duration, opt_acc) {
+  goog.fx.Animation.base(this, 'constructor');
+
+  if (!goog.isArray(start) || !goog.isArray(end)) {
+    throw Error('Start and end parameters must be arrays');
+  }
+
+  if (start.length != end.length) {
+    throw Error('Start and end points must be the same length');
+  }
+
+  /**
+   * Start point.
+   * @type {Array<number>}
+   * @protected
+   */
+  this.startPoint = start;
+
+  /**
+   * End point.
+   * @type {Array<number>}
+   * @protected
+   */
+  this.endPoint = end;
+
+  /**
+   * Duration of animation in milliseconds.
+   * @type {number}
+   * @protected
+   */
+  this.duration = duration;
+
+  /**
+   * Acceleration function, which must return a number between 0 and 1 for
+   * inputs between 0 and 1.
+   * @type {Function|undefined}
+   * @private
+   */
+  this.accel_ = opt_acc;
+
+  /**
+   * Current coordinate for animation.
+   * @type {Array<number>}
+   * @protected
+   */
+  this.coords = [];
+
+  /**
+   * Whether the animation should use "right" rather than "left" to position
+   * elements in RTL.  This is a temporary flag to allow clients to transition
+   * to the new behavior at their convenience.  At some point it will be the
+   * default.
+   * @type {boolean}
+   * @private
+   */
+  this.useRightPositioningForRtl_ = false;
+
+  /**
+   * Current frame rate.
+   * @private {number}
+   */
+  this.fps_ = 0;
+
+  /**
+   * Percent of the way through the animation.
+   * @protected {number}
+   */
+  this.progress = 0;
+
+  /**
+   * Timestamp for when last frame was run.
+   * @protected {?number}
+   */
+  this.lastFrame = null;
+};
+goog.inherits(goog.fx.Animation, goog.fx.TransitionBase);
+
+
+/**
+ * Sets whether the animation should use "right" rather than "left" to position
+ * elements.  This is a temporary flag to allow clients to transition
+ * to the new component at their convenience.  At some point "right" will be
+ * used for RTL elements by default.
+ * @param {boolean} useRightPositioningForRtl True if "right" should be used for
+ *     positioning, false if "left" should be used for positioning.
+ */
+goog.fx.Animation.prototype.enableRightPositioningForRtl =
+    function(useRightPositioningForRtl) {
+  this.useRightPositioningForRtl_ = useRightPositioningForRtl;
+};
+
+
+/**
+ * Whether the animation should use "right" rather than "left" to position
+ * elements.  This is a temporary flag to allow clients to transition
+ * to the new component at their convenience.  At some point "right" will be
+ * used for RTL elements by default.
+ * @return {boolean} True if "right" should be used for positioning, false if
+ *     "left" should be used for positioning.
+ */
+goog.fx.Animation.prototype.isRightPositioningForRtlEnabled = function() {
+  return this.useRightPositioningForRtl_;
+};
+
+
+/**
+ * Events fired by the animation.
+ * @enum {string}
+ */
+goog.fx.Animation.EventType = {
+  /**
+   * Dispatched when played for the first time OR when it is resumed.
+   * @deprecated Use goog.fx.Transition.EventType.PLAY.
+   */
+  PLAY: goog.fx.Transition.EventType.PLAY,
+
+  /**
+   * Dispatched only when the animation starts from the beginning.
+   * @deprecated Use goog.fx.Transition.EventType.BEGIN.
+   */
+  BEGIN: goog.fx.Transition.EventType.BEGIN,
+
+  /**
+   * Dispatched only when animation is restarted after a pause.
+   * @deprecated Use goog.fx.Transition.EventType.RESUME.
+   */
+  RESUME: goog.fx.Transition.EventType.RESUME,
+
+  /**
+   * Dispatched when animation comes to the end of its duration OR stop
+   * is called.
+   * @deprecated Use goog.fx.Transition.EventType.END.
+   */
+  END: goog.fx.Transition.EventType.END,
+
+  /**
+   * Dispatched only when stop is called.
+   * @deprecated Use goog.fx.Transition.EventType.STOP.
+   */
+  STOP: goog.fx.Transition.EventType.STOP,
+
+  /**
+   * Dispatched only when animation comes to its end naturally.
+   * @deprecated Use goog.fx.Transition.EventType.FINISH.
+   */
+  FINISH: goog.fx.Transition.EventType.FINISH,
+
+  /**
+   * Dispatched when an animation is paused.
+   * @deprecated Use goog.fx.Transition.EventType.PAUSE.
+   */
+  PAUSE: goog.fx.Transition.EventType.PAUSE,
+
+  /**
+   * Dispatched each frame of the animation.  This is where the actual animator
+   * will listen.
+   */
+  ANIMATE: 'animate',
+
+  /**
+   * Dispatched when the animation is destroyed.
+   */
+  DESTROY: 'destroy'
+};
+
+
+/**
+ * @deprecated Use goog.fx.anim.TIMEOUT.
+ */
+goog.fx.Animation.TIMEOUT = goog.fx.anim.TIMEOUT;
+
+
+/**
+ * Enum for the possible states of an animation.
+ * @deprecated Use goog.fx.Transition.State instead.
+ * @enum {number}
+ */
+goog.fx.Animation.State = goog.fx.TransitionBase.State;
+
+
+/**
+ * @deprecated Use goog.fx.anim.setAnimationWindow.
+ * @param {Window} animationWindow The window in which to animate elements.
+ */
+goog.fx.Animation.setAnimationWindow = function(animationWindow) {
+  goog.fx.anim.setAnimationWindow(animationWindow);
+};
+
+
+/**
+ * Starts or resumes an animation.
+ * @param {boolean=} opt_restart Whether to restart the
+ *     animation from the beginning if it has been paused.
+ * @return {boolean} Whether animation was started.
+ * @override
+ */
+goog.fx.Animation.prototype.play = function(opt_restart) {
+  if (opt_restart || this.isStopped()) {
+    this.progress = 0;
+    this.coords = this.startPoint;
+  } else if (this.isPlaying()) {
+    return false;
+  }
+
+  goog.fx.anim.unregisterAnimation(this);
+
+  var now = /** @type {number} */ (goog.now());
+
+  this.startTime = now;
+  if (this.isPaused()) {
+    this.startTime -= this.duration * this.progress;
+  }
+
+  this.endTime = this.startTime + this.duration;
+  this.lastFrame = this.startTime;
+
+  if (!this.progress) {
+    this.onBegin();
+  }
+
+  this.onPlay();
+
+  if (this.isPaused()) {
+    this.onResume();
+  }
+
+  this.setStatePlaying();
+
+  goog.fx.anim.registerAnimation(this);
+  this.cycle(now);
+
+  return true;
+};
+
+
+/**
+ * Stops the animation.
+ * @param {boolean=} opt_gotoEnd If true the animation will move to the
+ *     end coords.
+ * @override
+ */
+goog.fx.Animation.prototype.stop = function(opt_gotoEnd) {
+  goog.fx.anim.unregisterAnimation(this);
+  this.setStateStopped();
+
+  if (!!opt_gotoEnd) {
+    this.progress = 1;
+  }
+
+  this.updateCoords_(this.progress);
+
+  this.onStop();
+  this.onEnd();
+};
+
+
+/**
+ * Pauses the animation (iff it's playing).
+ * @override
+ */
+goog.fx.Animation.prototype.pause = function() {
+  if (this.isPlaying()) {
+    goog.fx.anim.unregisterAnimation(this);
+    this.setStatePaused();
+    this.onPause();
+  }
+};
+
+
+/**
+ * @return {number} The current progress of the animation, the number
+ *     is between 0 and 1 inclusive.
+ */
+goog.fx.Animation.prototype.getProgress = function() {
+  return this.progress;
+};
+
+
+/**
+ * Sets the progress of the animation.
+ * @param {number} progress The new progress of the animation.
+ */
+goog.fx.Animation.prototype.setProgress = function(progress) {
+  this.progress = progress;
+  if (this.isPlaying()) {
+    var now = goog.now();
+    // If the animation is already playing, we recompute startTime and endTime
+    // such that the animation plays consistently, that is:
+    // now = startTime + progress * duration.
+    this.startTime = now - this.duration * this.progress;
+    this.endTime = this.startTime + this.duration;
+  }
+};
+
+
+/**
+ * Disposes of the animation.  Stops an animation, fires a 'destroy' event and
+ * then removes all the event handlers to clean up memory.
+ * @override
+ * @protected
+ */
+goog.fx.Animation.prototype.disposeInternal = function() {
+  if (!this.isStopped()) {
+    this.stop(false);
+  }
+  this.onDestroy();
+  goog.fx.Animation.base(this, 'disposeInternal');
+};
+
+
+/**
+ * Stops an animation, fires a 'destroy' event and then removes all the event
+ * handlers to clean up memory.
+ * @deprecated Use dispose() instead.
+ */
+goog.fx.Animation.prototype.destroy = function() {
+  this.dispose();
+};
+
+
+/** @override */
+goog.fx.Animation.prototype.onAnimationFrame = function(now) {
+  this.cycle(now);
+};
+
+
+/**
+ * Handles the actual iteration of the animation in a timeout
+ * @param {number} now The current time.
+ */
+goog.fx.Animation.prototype.cycle = function(now) {
+  this.progress = (now - this.startTime) / (this.endTime - this.startTime);
+
+  if (this.progress >= 1) {
+    this.progress = 1;
+  }
+
+  this.fps_ = 1000 / (now - this.lastFrame);
+  this.lastFrame = now;
+
+  this.updateCoords_(this.progress);
+
+  // Animation has finished.
+  if (this.progress == 1) {
+    this.setStateStopped();
+    goog.fx.anim.unregisterAnimation(this);
+
+    this.onFinish();
+    this.onEnd();
+
+  // Animation is still under way.
+  } else if (this.isPlaying()) {
+    this.onAnimate();
+  }
+};
+
+
+/**
+ * Calculates current coordinates, based on the current state.  Applies
+ * the accelleration function if it exists.
+ * @param {number} t Percentage of the way through the animation as a decimal.
+ * @private
+ */
+goog.fx.Animation.prototype.updateCoords_ = function(t) {
+  if (goog.isFunction(this.accel_)) {
+    t = this.accel_(t);
+  }
+  this.coords = new Array(this.startPoint.length);
+  for (var i = 0; i < this.startPoint.length; i++) {
+    this.coords[i] = (this.endPoint[i] - this.startPoint[i]) * t +
+        this.startPoint[i];
+  }
+};
+
+
+/**
+ * Dispatches the ANIMATE event. Sub classes should override this instead
+ * of listening to the event.
+ * @protected
+ */
+goog.fx.Animation.prototype.onAnimate = function() {
+  this.dispatchAnimationEvent(goog.fx.Animation.EventType.ANIMATE);
+};
+
+
+/**
+ * Dispatches the DESTROY event. Sub classes should override this instead
+ * of listening to the event.
+ * @protected
+ */
+goog.fx.Animation.prototype.onDestroy = function() {
+  this.dispatchAnimationEvent(goog.fx.Animation.EventType.DESTROY);
+};
+
+
+/** @override */
+goog.fx.Animation.prototype.dispatchAnimationEvent = function(type) {
+  this.dispatchEvent(new goog.fx.AnimationEvent(type, this));
+};
+
+
+
+/**
+ * Class for an animation event object.
+ * @param {string} type Event type.
+ * @param {goog.fx.Animation} anim An animation object.
+ * @constructor
+ * @extends {goog.events.Event}
+ */
+goog.fx.AnimationEvent = function(type, anim) {
+  goog.fx.AnimationEvent.base(this, 'constructor', type);
+
+  /**
+   * The current coordinates.
+   * @type {Array<number>}
+   */
+  this.coords = anim.coords;
+
+  /**
+   * The x coordinate.
+   * @type {number}
+   */
+  this.x = anim.coords[0];
+
+  /**
+   * The y coordinate.
+   * @type {number}
+   */
+  this.y = anim.coords[1];
+
+  /**
+   * The z coordinate.
+   * @type {number}
+   */
+  this.z = anim.coords[2];
+
+  /**
+   * The current duration.
+   * @type {number}
+   */
+  this.duration = anim.duration;
+
+  /**
+   * The current progress.
+   * @type {number}
+   */
+  this.progress = anim.getProgress();
+
+  /**
+   * Frames per second so far.
+   */
+  this.fps = anim.fps_;
+
+  /**
+   * The state of the animation.
+   * @type {number}
+   */
+  this.state = anim.getStateInternal();
+
+  /**
+   * The animation object.
+   * @type {goog.fx.Animation}
+   */
+  // TODO(arv): This can be removed as this is the same as the target
+  this.anim = anim;
+};
+goog.inherits(goog.fx.AnimationEvent, goog.events.Event);
+
+
+/**
+ * Returns the coordinates as integers (rounded to nearest integer).
+ * @return {!Array<number>} An array of the coordinates rounded to
+ *     the nearest integer.
+ */
+goog.fx.AnimationEvent.prototype.coordsAsInts = function() {
+  return goog.array.map(this.coords, Math.round);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/animationqueue.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/animationqueue.js b/externs/GCL/externs/goog/fx/animationqueue.js
new file mode 100644
index 0000000..2ad74ab
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/animationqueue.js
@@ -0,0 +1,310 @@
+// 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 A class which automatically plays through a queue of
+ * animations.  AnimationParallelQueue and AnimationSerialQueue provide
+ * specific implementations of the abstract class AnimationQueue.
+ *
+ * @see ../demos/animationqueue.html
+ */
+
+goog.provide('goog.fx.AnimationParallelQueue');
+goog.provide('goog.fx.AnimationQueue');
+goog.provide('goog.fx.AnimationSerialQueue');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.events');
+goog.require('goog.fx.Transition');
+goog.require('goog.fx.TransitionBase');
+
+
+
+/**
+ * Constructor for AnimationQueue object.
+ *
+ * @constructor
+ * @extends {goog.fx.TransitionBase}
+ * @struct
+ * @suppress {checkStructDictInheritance}
+ */
+goog.fx.AnimationQueue = function() {
+  goog.fx.AnimationQueue.base(this, 'constructor');
+
+  /**
+   * An array holding all animations in the queue.
+   * @type {Array<goog.fx.TransitionBase>}
+   * @protected
+   */
+  this.queue = [];
+};
+goog.inherits(goog.fx.AnimationQueue, goog.fx.TransitionBase);
+
+
+/**
+ * Pushes an Animation to the end of the queue.
+ * @param {goog.fx.TransitionBase} animation The animation to add to the queue.
+ */
+goog.fx.AnimationQueue.prototype.add = function(animation) {
+  goog.asserts.assert(this.isStopped(),
+      'Not allowed to add animations to a running animation queue.');
+
+  if (goog.array.contains(this.queue, animation)) {
+    return;
+  }
+
+  this.queue.push(animation);
+  goog.events.listen(animation, goog.fx.Transition.EventType.FINISH,
+                     this.onAnimationFinish, false, this);
+};
+
+
+/**
+ * Removes an Animation from the queue.
+ * @param {goog.fx.Animation} animation The animation to remove.
+ */
+goog.fx.AnimationQueue.prototype.remove = function(animation) {
+  goog.asserts.assert(this.isStopped(),
+      'Not allowed to remove animations from a running animation queue.');
+
+  if (goog.array.remove(this.queue, animation)) {
+    goog.events.unlisten(animation, goog.fx.Transition.EventType.FINISH,
+                         this.onAnimationFinish, false, this);
+  }
+};
+
+
+/**
+ * Handles the event that an animation has finished.
+ * @param {goog.events.Event} e The finishing event.
+ * @protected
+ */
+goog.fx.AnimationQueue.prototype.onAnimationFinish = goog.abstractMethod;
+
+
+/**
+ * Disposes of the animations.
+ * @override
+ */
+goog.fx.AnimationQueue.prototype.disposeInternal = function() {
+  goog.array.forEach(this.queue, function(animation) {
+    animation.dispose();
+  });
+  this.queue.length = 0;
+
+  goog.fx.AnimationQueue.base(this, 'disposeInternal');
+};
+
+
+
+/**
+ * Constructor for AnimationParallelQueue object.
+ * @constructor
+ * @extends {goog.fx.AnimationQueue}
+ * @struct
+ */
+goog.fx.AnimationParallelQueue = function() {
+  goog.fx.AnimationParallelQueue.base(this, 'constructor');
+
+  /**
+   * Number of finished animations.
+   * @type {number}
+   * @private
+   */
+  this.finishedCounter_ = 0;
+};
+goog.inherits(goog.fx.AnimationParallelQueue, goog.fx.AnimationQueue);
+
+
+/** @override */
+goog.fx.AnimationParallelQueue.prototype.play = function(opt_restart) {
+  if (this.queue.length == 0) {
+    return false;
+  }
+
+  if (opt_restart || this.isStopped()) {
+    this.finishedCounter_ = 0;
+    this.onBegin();
+  } else if (this.isPlaying()) {
+    return false;
+  }
+
+  this.onPlay();
+  if (this.isPaused()) {
+    this.onResume();
+  }
+  var resuming = this.isPaused() && !opt_restart;
+
+  this.startTime = goog.now();
+  this.endTime = null;
+  this.setStatePlaying();
+
+  goog.array.forEach(this.queue, function(anim) {
+    if (!resuming || anim.isPaused()) {
+      anim.play(opt_restart);
+    }
+  });
+
+  return true;
+};
+
+
+/** @override */
+goog.fx.AnimationParallelQueue.prototype.pause = function() {
+  if (this.isPlaying()) {
+    goog.array.forEach(this.queue, function(anim) {
+      if (anim.isPlaying()) {
+        anim.pause();
+      }
+    });
+
+    this.setStatePaused();
+    this.onPause();
+  }
+};
+
+
+/** @override */
+goog.fx.AnimationParallelQueue.prototype.stop = function(opt_gotoEnd) {
+  goog.array.forEach(this.queue, function(anim) {
+    if (!anim.isStopped()) {
+      anim.stop(opt_gotoEnd);
+    }
+  });
+
+  this.setStateStopped();
+  this.endTime = goog.now();
+
+  this.onStop();
+  this.onEnd();
+};
+
+
+/** @override */
+goog.fx.AnimationParallelQueue.prototype.onAnimationFinish = function(e) {
+  this.finishedCounter_++;
+  if (this.finishedCounter_ == this.queue.length) {
+    this.endTime = goog.now();
+
+    this.setStateStopped();
+
+    this.onFinish();
+    this.onEnd();
+  }
+};
+
+
+
+/**
+ * Constructor for AnimationSerialQueue object.
+ * @constructor
+ * @extends {goog.fx.AnimationQueue}
+ * @struct
+ */
+goog.fx.AnimationSerialQueue = function() {
+  goog.fx.AnimationSerialQueue.base(this, 'constructor');
+
+  /**
+   * Current animation in queue currently active.
+   * @type {number}
+   * @private
+   */
+  this.current_ = 0;
+};
+goog.inherits(goog.fx.AnimationSerialQueue, goog.fx.AnimationQueue);
+
+
+/** @override */
+goog.fx.AnimationSerialQueue.prototype.play = function(opt_restart) {
+  if (this.queue.length == 0) {
+    return false;
+  }
+
+  if (opt_restart || this.isStopped()) {
+    if (this.current_ < this.queue.length &&
+        !this.queue[this.current_].isStopped()) {
+      this.queue[this.current_].stop(false);
+    }
+
+    this.current_ = 0;
+    this.onBegin();
+  } else if (this.isPlaying()) {
+    return false;
+  }
+
+  this.onPlay();
+  if (this.isPaused()) {
+    this.onResume();
+  }
+
+  this.startTime = goog.now();
+  this.endTime = null;
+  this.setStatePlaying();
+
+  this.queue[this.current_].play(opt_restart);
+
+  return true;
+};
+
+
+/** @override */
+goog.fx.AnimationSerialQueue.prototype.pause = function() {
+  if (this.isPlaying()) {
+    this.queue[this.current_].pause();
+    this.setStatePaused();
+    this.onPause();
+  }
+};
+
+
+/** @override */
+goog.fx.AnimationSerialQueue.prototype.stop = function(opt_gotoEnd) {
+  this.setStateStopped();
+  this.endTime = goog.now();
+
+  if (opt_gotoEnd) {
+    for (var i = this.current_; i < this.queue.length; ++i) {
+      var anim = this.queue[i];
+      // If the animation is stopped, start it to initiate rendering.  This
+      // might be needed to make the next line work.
+      if (anim.isStopped()) anim.play();
+      // If the animation is not done, stop it and go to the end state of the
+      // animation.
+      if (!anim.isStopped()) anim.stop(true);
+    }
+  } else if (this.current_ < this.queue.length) {
+    this.queue[this.current_].stop(false);
+  }
+
+  this.onStop();
+  this.onEnd();
+};
+
+
+/** @override */
+goog.fx.AnimationSerialQueue.prototype.onAnimationFinish = function(e) {
+  if (this.isPlaying()) {
+    this.current_++;
+    if (this.current_ < this.queue.length) {
+      this.queue[this.current_].play();
+    } else {
+      this.endTime = goog.now();
+      this.setStateStopped();
+
+      this.onFinish();
+      this.onEnd();
+    }
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/css3/fx.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/css3/fx.js b/externs/GCL/externs/goog/fx/css3/fx.js
new file mode 100644
index 0000000..267c78a
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/css3/fx.js
@@ -0,0 +1,63 @@
+// Copyright 2011 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 collection of CSS3 targeted animation, based on
+ * {@code goog.fx.css3.Transition}.
+ *
+ * @author chrishenry@google.com (Chris Henry)
+ */
+
+goog.provide('goog.fx.css3');
+
+goog.require('goog.fx.css3.Transition');
+
+
+/**
+ * Creates a transition to fade the element.
+ * @param {Element} element The element to fade.
+ * @param {number} duration Duration in seconds.
+ * @param {string} timing The CSS3 timing function.
+ * @param {number} startOpacity Starting opacity.
+ * @param {number} endOpacity Ending opacity.
+ * @return {!goog.fx.css3.Transition} The transition object.
+ */
+goog.fx.css3.fade = function(
+    element, duration, timing,  startOpacity, endOpacity) {
+  return new goog.fx.css3.Transition(
+      element, duration, {'opacity': startOpacity}, {'opacity': endOpacity},
+      {property: 'opacity', duration: duration, timing: timing, delay: 0});
+};
+
+
+/**
+ * Creates a transition to fade in the element.
+ * @param {Element} element The element to fade in.
+ * @param {number} duration Duration in seconds.
+ * @return {!goog.fx.css3.Transition} The transition object.
+ */
+goog.fx.css3.fadeIn = function(element, duration) {
+  return goog.fx.css3.fade(element, duration, 'ease-out', 0, 1);
+};
+
+
+/**
+ * Creates a transition to fade out the element.
+ * @param {Element} element The element to fade out.
+ * @param {number} duration Duration in seconds.
+ * @return {!goog.fx.css3.Transition} The transition object.
+ */
+goog.fx.css3.fadeOut = function(element, duration) {
+  return goog.fx.css3.fade(element, duration, 'ease-in', 1, 0);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/css3/transition.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/css3/transition.js b/externs/GCL/externs/goog/fx/css3/transition.js
new file mode 100644
index 0000000..59ec3f7
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/css3/transition.js
@@ -0,0 +1,201 @@
+// Copyright 2011 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 CSS3 transition base library.
+ *
+ * @author chrishenry@google.com (Chris Henry)
+ */
+
+goog.provide('goog.fx.css3.Transition');
+
+goog.require('goog.Timer');
+goog.require('goog.asserts');
+goog.require('goog.fx.TransitionBase');
+goog.require('goog.style');
+goog.require('goog.style.transition');
+
+
+
+/**
+ * A class to handle targeted CSS3 transition. This class
+ * handles common features required for targeted CSS3 transition.
+ *
+ * Browser that does not support CSS3 transition will still receive all
+ * the events fired by the transition object, but will not have any transition
+ * played. If the browser supports the final state as set in setFinalState
+ * method, the element will ends in the final state.
+ *
+ * Transitioning multiple properties with the same setting is possible
+ * by setting Css3Property's property to 'all'. Performing multiple
+ * transitions can be done via setting multiple initialStyle,
+ * finalStyle and transitions. Css3Property's delay can be used to
+ * delay one of the transition. Here is an example for a transition
+ * that expands on the width and then followed by the height:
+ *
+ * <pre>
+ *   initialStyle: {width: 10px, height: 10px}
+ *   finalStyle: {width: 100px, height: 100px}
+ *   transitions: [
+ *     {property: width, duration: 1, timing: 'ease-in', delay: 0},
+ *     {property: height, duration: 1, timing: 'ease-in', delay: 1}
+ *   ]
+ * </pre>
+ *
+ * @param {Element} element The element to be transitioned.
+ * @param {number} duration The duration of the transition in seconds.
+ *     This should be the longest of all transitions.
+ * @param {Object} initialStyle Initial style properties of the element before
+ *     animating. Set using {@code goog.style.setStyle}.
+ * @param {Object} finalStyle Final style properties of the element after
+ *     animating. Set using {@code goog.style.setStyle}.
+ * @param {goog.style.transition.Css3Property|
+ *     Array<goog.style.transition.Css3Property>} transitions A single CSS3
+ *     transition property or an array of it.
+ * @extends {goog.fx.TransitionBase}
+ * @constructor
+ */
+goog.fx.css3.Transition = function(
+    element, duration, initialStyle, finalStyle, transitions) {
+  goog.fx.css3.Transition.base(this, 'constructor');
+
+  /**
+   * @type {Element}
+   * @private
+   */
+  this.element_ = element;
+
+  /**
+   * @type {number}
+   * @private
+   */
+  this.duration_ = duration;
+
+  /**
+   * @type {Object}
+   * @private
+   */
+  this.initialStyle_ = initialStyle;
+
+  /**
+   * @type {Object}
+   * @private
+   */
+  this.finalStyle_ = finalStyle;
+
+  /**
+   * @type {Array<goog.style.transition.Css3Property>}
+   * @private
+   */
+  this.transitions_ = goog.isArray(transitions) ? transitions : [transitions];
+};
+goog.inherits(goog.fx.css3.Transition, goog.fx.TransitionBase);
+
+
+/**
+ * Timer id to be used to cancel animation part-way.
+ * @type {number}
+ * @private
+ */
+goog.fx.css3.Transition.prototype.timerId_;
+
+
+/** @override */
+goog.fx.css3.Transition.prototype.play = function() {
+  if (this.isPlaying()) {
+    return false;
+  }
+
+  this.onBegin();
+  this.onPlay();
+
+  this.startTime = goog.now();
+  this.setStatePlaying();
+
+  if (goog.style.transition.isSupported()) {
+    goog.style.setStyle(this.element_, this.initialStyle_);
+    // Allow element to get updated to its initial state before installing
+    // CSS3 transition.
+    this.timerId_ = goog.Timer.callOnce(this.play_, undefined, this);
+    return true;
+  } else {
+    this.stop_(false);
+    return false;
+  }
+};
+
+
+/**
+ * Helper method for play method. This needs to be executed on a timer.
+ * @private
+ */
+goog.fx.css3.Transition.prototype.play_ = function() {
+  // This measurement of the DOM element causes the browser to recalculate its
+  // initial state before the transition starts.
+  goog.style.getSize(this.element_);
+  goog.style.transition.set(this.element_, this.transitions_);
+  goog.style.setStyle(this.element_, this.finalStyle_);
+  this.timerId_ = goog.Timer.callOnce(
+      goog.bind(this.stop_, this, false), this.duration_ * 1000);
+};
+
+
+/** @override */
+goog.fx.css3.Transition.prototype.stop = function() {
+  if (!this.isPlaying()) return;
+
+  this.stop_(true);
+};
+
+
+/**
+ * Helper method for stop method.
+ * @param {boolean} stopped If the transition was stopped.
+ * @private
+ */
+goog.fx.css3.Transition.prototype.stop_ = function(stopped) {
+  goog.style.transition.removeAll(this.element_);
+
+  // Clear the timer.
+  goog.Timer.clear(this.timerId_);
+
+  // Make sure that we have reached the final style.
+  goog.style.setStyle(this.element_, this.finalStyle_);
+
+  this.endTime = goog.now();
+  this.setStateStopped();
+
+  if (stopped) {
+    this.onStop();
+  } else {
+    this.onFinish();
+  }
+  this.onEnd();
+};
+
+
+/** @override */
+goog.fx.css3.Transition.prototype.disposeInternal = function() {
+  this.stop();
+  goog.fx.css3.Transition.base(this, 'disposeInternal');
+};
+
+
+/**
+ * Pausing CSS3 Transitions in not supported.
+ * @override
+ */
+goog.fx.css3.Transition.prototype.pause = function() {
+  goog.asserts.assert(false, 'Css3 transitions does not support pause action.');
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/cssspriteanimation.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/cssspriteanimation.js b/externs/GCL/externs/goog/fx/cssspriteanimation.js
new file mode 100644
index 0000000..9813f7d
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/cssspriteanimation.js
@@ -0,0 +1,130 @@
+// Copyright 2008 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 An animation class that animates CSS sprites by changing the
+ * CSS background-position.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/cssspriteanimation.html
+ */
+
+goog.provide('goog.fx.CssSpriteAnimation');
+
+goog.require('goog.fx.Animation');
+
+
+
+/**
+ * This animation class is used to animate a CSS sprite (moving a background
+ * image).  This moves through a series of images in a single image sprite. By
+ * default, the animation loops when done.  Looping can be disabled by setting
+ * {@code opt_disableLoop} and results in the animation stopping on the last
+ * image in the image sprite.  You should set up the {@code background-image}
+ * and size in a CSS rule for the relevant element.
+ *
+ * @param {Element} element The HTML element to animate the background for.
+ * @param {goog.math.Size} size The size of one image in the image sprite.
+ * @param {goog.math.Box} box The box describing the layout of the sprites to
+ *     use in the large image.  The sprites can be position horizontally or
+ *     vertically and using a box here allows the implementation to know which
+ *     way to go.
+ * @param {number} time The duration in milliseconds for one iteration of the
+ *     animation.  For example, if the sprite contains 4 images and the duration
+ *     is set to 400ms then each sprite will be displayed for 100ms.
+ * @param {function(number) : number=} opt_acc Acceleration function,
+ *    returns 0-1 for inputs 0-1.  This can be used to make certain frames be
+ *    shown for a longer period of time.
+ * @param {boolean=} opt_disableLoop Whether the animation should be halted
+ *    after a single loop of the images in the sprite.
+ *
+ * @constructor
+ * @extends {goog.fx.Animation}
+ * @final
+ */
+goog.fx.CssSpriteAnimation = function(element, size, box, time, opt_acc,
+    opt_disableLoop) {
+  var start = [box.left, box.top];
+  // We never draw for the end so we do not need to subtract for the size
+  var end = [box.right, box.bottom];
+  goog.fx.CssSpriteAnimation.base(
+      this, 'constructor', start, end, time, opt_acc);
+
+  /**
+   * HTML element that will be used in the animation.
+   * @type {Element}
+   * @private
+   */
+  this.element_ = element;
+
+  /**
+   * The size of an individual sprite in the image sprite.
+   * @type {goog.math.Size}
+   * @private
+   */
+  this.size_ = size;
+
+  /**
+   * Whether the animation should be halted after a single loop of the images
+   * in the sprite.
+   * @type {boolean}
+   * @private
+   */
+  this.disableLoop_ = !!opt_disableLoop;
+};
+goog.inherits(goog.fx.CssSpriteAnimation, goog.fx.Animation);
+
+
+/** @override */
+goog.fx.CssSpriteAnimation.prototype.onAnimate = function() {
+  // Round to nearest sprite.
+  var x = -Math.floor(this.coords[0] / this.size_.width) * this.size_.width;
+  var y = -Math.floor(this.coords[1] / this.size_.height) * this.size_.height;
+  this.element_.style.backgroundPosition = x + 'px ' + y + 'px';
+
+  goog.fx.CssSpriteAnimation.base(this, 'onAnimate');
+};
+
+
+/** @override */
+goog.fx.CssSpriteAnimation.prototype.onFinish = function() {
+  if (!this.disableLoop_) {
+    this.play(true);
+  }
+  goog.fx.CssSpriteAnimation.base(this, 'onFinish');
+};
+
+
+/**
+ * Clears the background position style set directly on the element
+ * by the animation. Allows to apply CSS styling for background position on the
+ * same element when the sprite animation is not runniing.
+ */
+goog.fx.CssSpriteAnimation.prototype.clearSpritePosition = function() {
+  var style = this.element_.style;
+  style.backgroundPosition = '';
+
+  if (typeof style.backgroundPositionX != 'undefined') {
+    // IE needs to clear x and y to actually clear the position
+    style.backgroundPositionX = '';
+    style.backgroundPositionY = '';
+  }
+};
+
+
+/** @override */
+goog.fx.CssSpriteAnimation.prototype.disposeInternal = function() {
+  goog.fx.CssSpriteAnimation.superClass_.disposeInternal.call(this);
+  this.element_ = null;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/dom.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/dom.js b/externs/GCL/externs/goog/fx/dom.js
new file mode 100644
index 0000000..8430fba
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/dom.js
@@ -0,0 +1,686 @@
+// Copyright 2005 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 Predefined DHTML animations such as slide, resize and fade.
+ *
+ * @see ../demos/effects.html
+ */
+
+goog.provide('goog.fx.dom');
+goog.provide('goog.fx.dom.BgColorTransform');
+goog.provide('goog.fx.dom.ColorTransform');
+goog.provide('goog.fx.dom.Fade');
+goog.provide('goog.fx.dom.FadeIn');
+goog.provide('goog.fx.dom.FadeInAndShow');
+goog.provide('goog.fx.dom.FadeOut');
+goog.provide('goog.fx.dom.FadeOutAndHide');
+goog.provide('goog.fx.dom.PredefinedEffect');
+goog.provide('goog.fx.dom.Resize');
+goog.provide('goog.fx.dom.ResizeHeight');
+goog.provide('goog.fx.dom.ResizeWidth');
+goog.provide('goog.fx.dom.Scroll');
+goog.provide('goog.fx.dom.Slide');
+goog.provide('goog.fx.dom.SlideFrom');
+goog.provide('goog.fx.dom.Swipe');
+
+goog.require('goog.color');
+goog.require('goog.events');
+goog.require('goog.fx.Animation');
+goog.require('goog.fx.Transition');
+goog.require('goog.style');
+goog.require('goog.style.bidi');
+
+
+
+/**
+ * Abstract class that provides reusable functionality for predefined animations
+ * that manipulate a single DOM element
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {Array<number>} start Array for start coordinates.
+ * @param {Array<number>} end Array for end coordinates.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.Animation}
+ * @constructor
+ */
+goog.fx.dom.PredefinedEffect = function(element, start, end, time, opt_acc) {
+  goog.fx.Animation.call(this, start, end, time, opt_acc);
+
+  /**
+   * DOM Node that will be used in the animation
+   * @type {Element}
+   */
+  this.element = element;
+
+  /**
+   * Whether the element is rendered right-to-left. We cache this here for
+   * efficiency.
+   * @private {boolean|undefined}
+   */
+  this.rightToLeft_;
+};
+goog.inherits(goog.fx.dom.PredefinedEffect, goog.fx.Animation);
+
+
+/**
+ * Called to update the style of the element.
+ * @protected
+ */
+goog.fx.dom.PredefinedEffect.prototype.updateStyle = goog.nullFunction;
+
+
+/**
+ * Whether the DOM element being manipulated is rendered right-to-left.
+ * @return {boolean} True if the DOM element is rendered right-to-left, false
+ *     otherwise.
+ */
+goog.fx.dom.PredefinedEffect.prototype.isRightToLeft = function() {
+  if (!goog.isDef(this.rightToLeft_)) {
+    this.rightToLeft_ = goog.style.isRightToLeft(this.element);
+  }
+  return this.rightToLeft_;
+};
+
+
+/** @override */
+goog.fx.dom.PredefinedEffect.prototype.onAnimate = function() {
+  this.updateStyle();
+  goog.fx.dom.PredefinedEffect.superClass_.onAnimate.call(this);
+};
+
+
+/** @override */
+goog.fx.dom.PredefinedEffect.prototype.onEnd = function() {
+  this.updateStyle();
+  goog.fx.dom.PredefinedEffect.superClass_.onEnd.call(this);
+};
+
+
+/** @override */
+goog.fx.dom.PredefinedEffect.prototype.onBegin = function() {
+  this.updateStyle();
+  goog.fx.dom.PredefinedEffect.superClass_.onBegin.call(this);
+};
+
+
+
+/**
+ * Creates an animation object that will slide an element from A to B.  (This
+ * in effect automatically sets up the onanimate event for an Animation object)
+ *
+ * Start and End should be 2 dimensional arrays
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {Array<number>} start 2D array for start coordinates (X, Y).
+ * @param {Array<number>} end 2D array for end coordinates (X, Y).
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.PredefinedEffect}
+ * @constructor
+ */
+goog.fx.dom.Slide = function(element, start, end, time, opt_acc) {
+  if (start.length != 2 || end.length != 2) {
+    throw Error('Start and end points must be 2D');
+  }
+  goog.fx.dom.PredefinedEffect.apply(this, arguments);
+};
+goog.inherits(goog.fx.dom.Slide, goog.fx.dom.PredefinedEffect);
+
+
+/** @override */
+goog.fx.dom.Slide.prototype.updateStyle = function() {
+  var pos = (this.isRightPositioningForRtlEnabled() && this.isRightToLeft()) ?
+      'right' : 'left';
+  this.element.style[pos] = Math.round(this.coords[0]) + 'px';
+  this.element.style.top = Math.round(this.coords[1]) + 'px';
+};
+
+
+
+/**
+ * Slides an element from its current position.
+ *
+ * @param {Element} element DOM node to be used in the animation.
+ * @param {Array<number>} end 2D array for end coordinates (X, Y).
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.Slide}
+ * @constructor
+ */
+goog.fx.dom.SlideFrom = function(element, end, time, opt_acc) {
+  var offsetLeft = this.isRightPositioningForRtlEnabled() ?
+      goog.style.bidi.getOffsetStart(element) : element.offsetLeft;
+  var start = [offsetLeft, element.offsetTop];
+  goog.fx.dom.Slide.call(this, element, start, end, time, opt_acc);
+};
+goog.inherits(goog.fx.dom.SlideFrom, goog.fx.dom.Slide);
+
+
+/** @override */
+goog.fx.dom.SlideFrom.prototype.onBegin = function() {
+  var offsetLeft = this.isRightPositioningForRtlEnabled() ?
+      goog.style.bidi.getOffsetStart(this.element) : this.element.offsetLeft;
+  this.startPoint = [offsetLeft, this.element.offsetTop];
+  goog.fx.dom.SlideFrom.superClass_.onBegin.call(this);
+};
+
+
+
+/**
+ * Creates an animation object that will slide an element into its final size.
+ * Requires that the element is absolutely positioned.
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {Array<number>} start 2D array for start size (W, H).
+ * @param {Array<number>} end 2D array for end size (W, H).
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.PredefinedEffect}
+ * @constructor
+ */
+goog.fx.dom.Swipe = function(element, start, end, time, opt_acc) {
+  if (start.length != 2 || end.length != 2) {
+    throw Error('Start and end points must be 2D');
+  }
+  goog.fx.dom.PredefinedEffect.apply(this, arguments);
+
+  /**
+   * Maximum width for element.
+   * @type {number}
+   * @private
+   */
+  this.maxWidth_ = Math.max(this.endPoint[0], this.startPoint[0]);
+
+  /**
+   * Maximum height for element.
+   * @type {number}
+   * @private
+   */
+  this.maxHeight_ = Math.max(this.endPoint[1], this.startPoint[1]);
+};
+goog.inherits(goog.fx.dom.Swipe, goog.fx.dom.PredefinedEffect);
+
+
+/**
+ * Animation event handler that will resize an element by setting its width,
+ * height and clipping.
+ * @protected
+ * @override
+ */
+goog.fx.dom.Swipe.prototype.updateStyle = function() {
+  var x = this.coords[0];
+  var y = this.coords[1];
+  this.clip_(Math.round(x), Math.round(y), this.maxWidth_, this.maxHeight_);
+  this.element.style.width = Math.round(x) + 'px';
+  var marginX = (this.isRightPositioningForRtlEnabled() &&
+      this.isRightToLeft()) ? 'marginRight' : 'marginLeft';
+
+  this.element.style[marginX] = Math.round(x) - this.maxWidth_ + 'px';
+  this.element.style.marginTop = Math.round(y) - this.maxHeight_ + 'px';
+};
+
+
+/**
+ * Helper function for setting element clipping.
+ * @param {number} x Current element width.
+ * @param {number} y Current element height.
+ * @param {number} w Maximum element width.
+ * @param {number} h Maximum element height.
+ * @private
+ */
+goog.fx.dom.Swipe.prototype.clip_ = function(x, y, w, h) {
+  this.element.style.clip =
+      'rect(' + (h - y) + 'px ' + w + 'px ' + h + 'px ' + (w - x) + 'px)';
+};
+
+
+
+/**
+ * Creates an animation object that will scroll an element from A to B.
+ *
+ * Start and End should be 2 dimensional arrays
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {Array<number>} start 2D array for start scroll left and top.
+ * @param {Array<number>} end 2D array for end scroll left and top.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.PredefinedEffect}
+ * @constructor
+ */
+goog.fx.dom.Scroll = function(element, start, end, time, opt_acc) {
+  if (start.length != 2 || end.length != 2) {
+    throw Error('Start and end points must be 2D');
+  }
+  goog.fx.dom.PredefinedEffect.apply(this, arguments);
+};
+goog.inherits(goog.fx.dom.Scroll, goog.fx.dom.PredefinedEffect);
+
+
+/**
+ * Animation event handler that will set the scroll position of an element.
+ * @protected
+ * @override
+ */
+goog.fx.dom.Scroll.prototype.updateStyle = function() {
+  if (this.isRightPositioningForRtlEnabled()) {
+    goog.style.bidi.setScrollOffset(this.element, Math.round(this.coords[0]));
+  } else {
+    this.element.scrollLeft = Math.round(this.coords[0]);
+  }
+  this.element.scrollTop = Math.round(this.coords[1]);
+};
+
+
+
+/**
+ * Creates an animation object that will resize an element between two widths
+ * and heights.
+ *
+ * Start and End should be 2 dimensional arrays
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {Array<number>} start 2D array for start width and height.
+ * @param {Array<number>} end 2D array for end width and height.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.PredefinedEffect}
+ * @constructor
+ */
+goog.fx.dom.Resize = function(element, start, end, time, opt_acc) {
+  if (start.length != 2 || end.length != 2) {
+    throw Error('Start and end points must be 2D');
+  }
+  goog.fx.dom.PredefinedEffect.apply(this, arguments);
+};
+goog.inherits(goog.fx.dom.Resize, goog.fx.dom.PredefinedEffect);
+
+
+/**
+ * Animation event handler that will resize an element by setting its width and
+ * height.
+ * @protected
+ * @override
+ */
+goog.fx.dom.Resize.prototype.updateStyle = function() {
+  this.element.style.width = Math.round(this.coords[0]) + 'px';
+  this.element.style.height = Math.round(this.coords[1]) + 'px';
+};
+
+
+
+/**
+ * Creates an animation object that will resize an element between two widths
+ *
+ * Start and End should be numbers
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {number} start Start width.
+ * @param {number} end End width.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.PredefinedEffect}
+ * @constructor
+ */
+goog.fx.dom.ResizeWidth = function(element, start, end, time, opt_acc) {
+  goog.fx.dom.PredefinedEffect.call(this, element, [start],
+                                    [end], time, opt_acc);
+};
+goog.inherits(goog.fx.dom.ResizeWidth, goog.fx.dom.PredefinedEffect);
+
+
+/**
+ * Animation event handler that will resize an element by setting its width.
+ * @protected
+ * @override
+ */
+goog.fx.dom.ResizeWidth.prototype.updateStyle = function() {
+  this.element.style.width = Math.round(this.coords[0]) + 'px';
+};
+
+
+
+/**
+ * Creates an animation object that will resize an element between two heights
+ *
+ * Start and End should be numbers
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {number} start Start height.
+ * @param {number} end End height.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.PredefinedEffect}
+ * @constructor
+ */
+goog.fx.dom.ResizeHeight = function(element, start, end, time, opt_acc) {
+  goog.fx.dom.PredefinedEffect.call(this, element, [start],
+                                    [end], time, opt_acc);
+};
+goog.inherits(goog.fx.dom.ResizeHeight, goog.fx.dom.PredefinedEffect);
+
+
+/**
+ * Animation event handler that will resize an element by setting its height.
+ * @protected
+ * @override
+ */
+goog.fx.dom.ResizeHeight.prototype.updateStyle = function() {
+  this.element.style.height = Math.round(this.coords[0]) + 'px';
+};
+
+
+
+/**
+ * Creates an animation object that fades the opacity of an element between two
+ * limits.
+ *
+ * Start and End should be floats between 0 and 1
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {Array<number>|number} start 1D Array or Number with start opacity.
+ * @param {Array<number>|number} end 1D Array or Number for end opacity.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.PredefinedEffect}
+ * @constructor
+ */
+goog.fx.dom.Fade = function(element, start, end, time, opt_acc) {
+  if (goog.isNumber(start)) start = [start];
+  if (goog.isNumber(end)) end = [end];
+
+  goog.fx.dom.Fade.base(this, 'constructor',
+      element, start, end, time, opt_acc);
+
+  if (start.length != 1 || end.length != 1) {
+    throw Error('Start and end points must be 1D');
+  }
+
+  /**
+   * The last opacity we set, or -1 for not set.
+   * @private {number}
+   */
+  this.lastOpacityUpdate_ = goog.fx.dom.Fade.OPACITY_UNSET_;
+};
+goog.inherits(goog.fx.dom.Fade, goog.fx.dom.PredefinedEffect);
+
+
+/**
+ * The quantization of opacity values to use.
+ * @private {number}
+ */
+goog.fx.dom.Fade.TOLERANCE_ = 1.0 / 0x400;  // 10-bit color
+
+
+/**
+ * Value indicating that the opacity must be set on next update.
+ * @private {number}
+ */
+goog.fx.dom.Fade.OPACITY_UNSET_ = -1;
+
+
+/**
+ * Animation event handler that will set the opacity of an element.
+ * @protected
+ * @override
+ */
+goog.fx.dom.Fade.prototype.updateStyle = function() {
+  var opacity = this.coords[0];
+  var delta = Math.abs(opacity - this.lastOpacityUpdate_);
+  // In order to keep eager browsers from over-rendering, only update
+  // on a potentially visible change in opacity.
+  if (delta >= goog.fx.dom.Fade.TOLERANCE_) {
+    goog.style.setOpacity(this.element, opacity);
+    this.lastOpacityUpdate_ = opacity;
+  }
+};
+
+
+/** @override */
+goog.fx.dom.Fade.prototype.onBegin = function() {
+  this.lastOpacityUpdate_ = goog.fx.dom.Fade.OPACITY_UNSET_;
+  goog.fx.dom.Fade.base(this, 'onBegin');
+};
+
+
+/** @override */
+goog.fx.dom.Fade.prototype.onEnd = function() {
+  this.lastOpacityUpdate_ = goog.fx.dom.Fade.OPACITY_UNSET_;
+  goog.fx.dom.Fade.base(this, 'onEnd');
+};
+
+
+/**
+ * Animation event handler that will show the element.
+ */
+goog.fx.dom.Fade.prototype.show = function() {
+  this.element.style.display = '';
+};
+
+
+/**
+ * Animation event handler that will hide the element
+ */
+goog.fx.dom.Fade.prototype.hide = function() {
+  this.element.style.display = 'none';
+};
+
+
+
+/**
+ * Fades an element out from full opacity to completely transparent.
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.Fade}
+ * @constructor
+ */
+goog.fx.dom.FadeOut = function(element, time, opt_acc) {
+  goog.fx.dom.Fade.call(this, element, 1, 0, time, opt_acc);
+};
+goog.inherits(goog.fx.dom.FadeOut, goog.fx.dom.Fade);
+
+
+
+/**
+ * Fades an element in from completely transparent to fully opacity.
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.Fade}
+ * @constructor
+ */
+goog.fx.dom.FadeIn = function(element, time, opt_acc) {
+  goog.fx.dom.Fade.call(this, element, 0, 1, time, opt_acc);
+};
+goog.inherits(goog.fx.dom.FadeIn, goog.fx.dom.Fade);
+
+
+
+/**
+ * Fades an element out from full opacity to completely transparent and then
+ * sets the display to 'none'
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.Fade}
+ * @constructor
+ */
+goog.fx.dom.FadeOutAndHide = function(element, time, opt_acc) {
+  goog.fx.dom.Fade.call(this, element, 1, 0, time, opt_acc);
+};
+goog.inherits(goog.fx.dom.FadeOutAndHide, goog.fx.dom.Fade);
+
+
+/** @override */
+goog.fx.dom.FadeOutAndHide.prototype.onBegin = function() {
+  this.show();
+  goog.fx.dom.FadeOutAndHide.superClass_.onBegin.call(this);
+};
+
+
+/** @override */
+goog.fx.dom.FadeOutAndHide.prototype.onEnd = function() {
+  this.hide();
+  goog.fx.dom.FadeOutAndHide.superClass_.onEnd.call(this);
+};
+
+
+
+/**
+ * Sets an element's display to be visible and then fades an element in from
+ * completely transparent to fully opaque.
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.Fade}
+ * @constructor
+ */
+goog.fx.dom.FadeInAndShow = function(element, time, opt_acc) {
+  goog.fx.dom.Fade.call(this, element, 0, 1, time, opt_acc);
+};
+goog.inherits(goog.fx.dom.FadeInAndShow, goog.fx.dom.Fade);
+
+
+/** @override */
+goog.fx.dom.FadeInAndShow.prototype.onBegin = function() {
+  this.show();
+  goog.fx.dom.FadeInAndShow.superClass_.onBegin.call(this);
+};
+
+
+
+/**
+ * Provides a transformation of an elements background-color.
+ *
+ * Start and End should be 3D arrays representing R,G,B
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {Array<number>} start 3D Array for RGB of start color.
+ * @param {Array<number>} end 3D Array for RGB of end color.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @extends {goog.fx.dom.PredefinedEffect}
+ * @constructor
+ */
+goog.fx.dom.BgColorTransform = function(element, start, end, time, opt_acc) {
+  if (start.length != 3 || end.length != 3) {
+    throw Error('Start and end points must be 3D');
+  }
+  goog.fx.dom.PredefinedEffect.apply(this, arguments);
+};
+goog.inherits(goog.fx.dom.BgColorTransform, goog.fx.dom.PredefinedEffect);
+
+
+/**
+ * Animation event handler that will set the background-color of an element
+ */
+goog.fx.dom.BgColorTransform.prototype.setColor = function() {
+  var coordsAsInts = [];
+  for (var i = 0; i < this.coords.length; i++) {
+    coordsAsInts[i] = Math.round(this.coords[i]);
+  }
+  var color = 'rgb(' + coordsAsInts.join(',') + ')';
+  this.element.style.backgroundColor = color;
+};
+
+
+/** @override */
+goog.fx.dom.BgColorTransform.prototype.updateStyle = function() {
+  this.setColor();
+};
+
+
+/**
+ * Fade elements background color from start color to the element's current
+ * background color.
+ *
+ * Start should be a 3D array representing R,G,B
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {Array<number>} start 3D Array for RGB of start color.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {goog.events.EventHandler=} opt_eventHandler Optional event handler
+ *     to use when listening for events.
+ */
+goog.fx.dom.bgColorFadeIn = function(element, start, time, opt_eventHandler) {
+  var initialBgColor = element.style.backgroundColor || '';
+  var computedBgColor = goog.style.getBackgroundColor(element);
+  var end;
+
+  if (computedBgColor && computedBgColor != 'transparent' &&
+      computedBgColor != 'rgba(0, 0, 0, 0)') {
+    end = goog.color.hexToRgb(goog.color.parse(computedBgColor).hex);
+  } else {
+    end = [255, 255, 255];
+  }
+
+  var anim = new goog.fx.dom.BgColorTransform(element, start, end, time);
+
+  function setBgColor() {
+    element.style.backgroundColor = initialBgColor;
+  }
+
+  if (opt_eventHandler) {
+    opt_eventHandler.listen(
+        anim, goog.fx.Transition.EventType.END, setBgColor);
+  } else {
+    goog.events.listen(
+        anim, goog.fx.Transition.EventType.END, setBgColor);
+  }
+
+  anim.play();
+};
+
+
+
+/**
+ * Provides a transformation of an elements color.
+ *
+ * @param {Element} element Dom Node to be used in the animation.
+ * @param {Array<number>} start 3D Array representing R,G,B.
+ * @param {Array<number>} end 3D Array representing R,G,B.
+ * @param {number} time Length of animation in milliseconds.
+ * @param {Function=} opt_acc Acceleration function, returns 0-1 for inputs 0-1.
+ * @constructor
+ * @extends {goog.fx.dom.PredefinedEffect}
+ */
+goog.fx.dom.ColorTransform = function(element, start, end, time, opt_acc) {
+  if (start.length != 3 || end.length != 3) {
+    throw Error('Start and end points must be 3D');
+  }
+  goog.fx.dom.PredefinedEffect.apply(this, arguments);
+};
+goog.inherits(goog.fx.dom.ColorTransform, goog.fx.dom.PredefinedEffect);
+
+
+/**
+ * Animation event handler that will set the color of an element.
+ * @protected
+ * @override
+ */
+goog.fx.dom.ColorTransform.prototype.updateStyle = function() {
+  var coordsAsInts = [];
+  for (var i = 0; i < this.coords.length; i++) {
+    coordsAsInts[i] = Math.round(this.coords[i]);
+  }
+  var color = 'rgb(' + coordsAsInts.join(',') + ')';
+  this.element.style.color = color;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/dragdrop.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/dragdrop.js b/externs/GCL/externs/goog/fx/dragdrop.js
new file mode 100644
index 0000000..7fe9545
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/dragdrop.js
@@ -0,0 +1,50 @@
+// 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 Single Element Drag and Drop.
+ *
+ * Drag and drop implementation for sources/targets consisting of a single
+ * element.
+ *
+ * @author eae@google.com (Emil A Eklund)
+ * @see ../demos/dragdrop.html
+ */
+
+goog.provide('goog.fx.DragDrop');
+
+goog.require('goog.fx.AbstractDragDrop');
+goog.require('goog.fx.DragDropItem');
+
+
+
+/**
+ * Drag/drop implementation for creating drag sources/drop targets consisting of
+ * a single HTML Element.
+ *
+ * @param {Element|string} element Dom Node, or string representation of node
+ *     id, to be used as drag source/drop target.
+ * @param {Object=} opt_data Data associated with the source/target.
+ * @throws Error If no element argument is provided or if the type is invalid
+ * @extends {goog.fx.AbstractDragDrop}
+ * @constructor
+ */
+goog.fx.DragDrop = function(element, opt_data) {
+  goog.fx.AbstractDragDrop.call(this);
+
+  var item = new goog.fx.DragDropItem(element, opt_data);
+  item.setParent(this);
+  this.items_.push(item);
+};
+goog.inherits(goog.fx.DragDrop, goog.fx.AbstractDragDrop);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/dragdropgroup.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/dragdropgroup.js b/externs/GCL/externs/goog/fx/dragdropgroup.js
new file mode 100644
index 0000000..01aab56
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/dragdropgroup.js
@@ -0,0 +1,109 @@
+// 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 Multiple Element Drag and Drop.
+ *
+ * Drag and drop implementation for sources/targets consisting of multiple
+ * elements.
+ *
+ * @author eae@google.com (Emil A Eklund)
+ * @see ../demos/dragdrop.html
+ */
+
+goog.provide('goog.fx.DragDropGroup');
+
+goog.require('goog.dom');
+goog.require('goog.fx.AbstractDragDrop');
+goog.require('goog.fx.DragDropItem');
+
+
+
+/**
+ * Drag/drop implementation for creating drag sources/drop targets consisting of
+ * multiple HTML Elements (items). All items share the same drop target(s) but
+ * can be dragged individually.
+ *
+ * @extends {goog.fx.AbstractDragDrop}
+ * @constructor
+ */
+goog.fx.DragDropGroup = function() {
+  goog.fx.AbstractDragDrop.call(this);
+};
+goog.inherits(goog.fx.DragDropGroup, goog.fx.AbstractDragDrop);
+
+
+/**
+ * Add item to drag object.
+ *
+ * @param {Element|string} element Dom Node, or string representation of node
+ *     id, to be used as drag source/drop target.
+ * @param {Object=} opt_data Data associated with the source/target.
+ * @throws Error If no element argument is provided or if the type is
+ *     invalid
+ * @override
+ */
+goog.fx.DragDropGroup.prototype.addItem = function(element, opt_data) {
+  var item = new goog.fx.DragDropItem(element, opt_data);
+  this.addDragDropItem(item);
+};
+
+
+/**
+ * Add DragDropItem to drag object.
+ *
+ * @param {goog.fx.DragDropItem} item DragDropItem being added to the
+ *     drag object.
+ * @throws Error If no element argument is provided or if the type is
+ *     invalid
+ */
+goog.fx.DragDropGroup.prototype.addDragDropItem = function(item) {
+  item.setParent(this);
+  this.items_.push(item);
+  if (this.isInitialized()) {
+    this.initItem(item);
+  }
+};
+
+
+/**
+ * Remove item from drag object.
+ *
+ * @param {Element|string} element Dom Node, or string representation of node
+ *     id, that was previously added with addItem().
+ */
+goog.fx.DragDropGroup.prototype.removeItem = function(element) {
+  element = goog.dom.getElement(element);
+  for (var item, i = 0; item = this.items_[i]; i++) {
+    if (item.element == element) {
+      this.items_.splice(i, 1);
+      this.disposeItem(item);
+      break;
+    }
+  }
+};
+
+
+/**
+ * Marks the supplied list of items as selected. A drag operation for any of the
+ * selected items will affect all of them.
+ *
+ * @param {Array<goog.fx.DragDropItem>} list List of items to select or null to
+ *     clear selection.
+ *
+ * TODO(eae): Not yet implemented.
+ */
+goog.fx.DragDropGroup.prototype.setSelection = function(list) {
+
+};


[31/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/classlist.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/classlist.js b/externs/GCL/externs/goog/dom/classlist.js
new file mode 100644
index 0000000..dcbb7ed
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/classlist.js
@@ -0,0 +1,277 @@
+// 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 Utilities for detecting, adding and removing classes.  Prefer
+ * this over goog.dom.classes for new code since it attempts to use classList
+ * (DOMTokenList: http://dom.spec.whatwg.org/#domtokenlist) which is faster
+ * and requires less code.
+ *
+ * Note: these utilities are meant to operate on HTMLElements
+ * and may have unexpected behavior on elements with differing interfaces
+ * (such as SVGElements).
+ */
+
+
+goog.provide('goog.dom.classlist');
+
+goog.require('goog.array');
+
+
+/**
+ * Override this define at build-time if you know your target supports it.
+ * @define {boolean} Whether to use the classList property (DOMTokenList).
+ */
+goog.define('goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST', false);
+
+
+/**
+ * Gets an array-like object of class names on an element.
+ * @param {Element} element DOM node to get the classes of.
+ * @return {!goog.array.ArrayLike} Class names on {@code element}.
+ */
+goog.dom.classlist.get = function(element) {
+  if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {
+    return element.classList;
+  }
+
+  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) || [];
+};
+
+
+/**
+ * Sets the entire class name of an element.
+ * @param {Element} element DOM node to set class of.
+ * @param {string} className Class name(s) to apply to element.
+ */
+goog.dom.classlist.set = function(element, className) {
+  element.className = className;
+};
+
+
+/**
+ * Returns true if an element has a class.  This method may throw a DOM
+ * exception for an invalid or empty class name if DOMTokenList is used.
+ * @param {Element} element DOM node to test.
+ * @param {string} className Class name to test for.
+ * @return {boolean} Whether element has the class.
+ */
+goog.dom.classlist.contains = function(element, className) {
+  if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {
+    return element.classList.contains(className);
+  }
+  return goog.array.contains(goog.dom.classlist.get(element), className);
+};
+
+
+/**
+ * Adds a class to an element.  Does not add multiples of class names.  This
+ * method may throw a DOM exception for an invalid or empty class name if
+ * DOMTokenList is used.
+ * @param {Element} element DOM node to add class to.
+ * @param {string} className Class name to add.
+ */
+goog.dom.classlist.add = function(element, className) {
+  if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {
+    element.classList.add(className);
+    return;
+  }
+
+  if (!goog.dom.classlist.contains(element, className)) {
+    // Ensure we add a space if this is not the first class name added.
+    element.className += element.className.length > 0 ?
+        (' ' + className) : className;
+  }
+};
+
+
+/**
+ * Convenience method to add a number of class names at once.
+ * @param {Element} element The element to which to add classes.
+ * @param {goog.array.ArrayLike<string>} classesToAdd An array-like object
+ * containing a collection of class names to add to the element.
+ * This method may throw a DOM exception if classesToAdd contains invalid
+ * or empty class names.
+ */
+goog.dom.classlist.addAll = function(element, classesToAdd) {
+  if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {
+    goog.array.forEach(classesToAdd, function(className) {
+      goog.dom.classlist.add(element, className);
+    });
+    return;
+  }
+
+  var classMap = {};
+
+  // Get all current class names into a map.
+  goog.array.forEach(goog.dom.classlist.get(element),
+      function(className) {
+        classMap[className] = true;
+      });
+
+  // Add new class names to the map.
+  goog.array.forEach(classesToAdd,
+      function(className) {
+        classMap[className] = true;
+      });
+
+  // Flatten the keys of the map into the className.
+  element.className = '';
+  for (var className in classMap) {
+    element.className += element.className.length > 0 ?
+        (' ' + className) : className;
+  }
+};
+
+
+/**
+ * Removes a class from an element.  This method may throw a DOM exception
+ * for an invalid or empty class name if DOMTokenList is used.
+ * @param {Element} element DOM node to remove class from.
+ * @param {string} className Class name to remove.
+ */
+goog.dom.classlist.remove = function(element, className) {
+  if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {
+    element.classList.remove(className);
+    return;
+  }
+
+  if (goog.dom.classlist.contains(element, className)) {
+    // Filter out the class name.
+    element.className = goog.array.filter(
+        goog.dom.classlist.get(element),
+        function(c) {
+          return c != className;
+        }).join(' ');
+  }
+};
+
+
+/**
+ * Removes a set of classes from an element.  Prefer this call to
+ * repeatedly calling {@code goog.dom.classlist.remove} if you want to remove
+ * a large set of class names at once.
+ * @param {Element} element The element from which to remove classes.
+ * @param {goog.array.ArrayLike<string>} classesToRemove An array-like object
+ * containing a collection of class names to remove from the element.
+ * This method may throw a DOM exception if classesToRemove contains invalid
+ * or empty class names.
+ */
+goog.dom.classlist.removeAll = function(element, classesToRemove) {
+  if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {
+    goog.array.forEach(classesToRemove, function(className) {
+      goog.dom.classlist.remove(element, className);
+    });
+    return;
+  }
+  // Filter out those classes in classesToRemove.
+  element.className = goog.array.filter(
+      goog.dom.classlist.get(element),
+      function(className) {
+        // If this class is not one we are trying to remove,
+        // add it to the array of new class names.
+        return !goog.array.contains(classesToRemove, className);
+      }).join(' ');
+};
+
+
+/**
+ * Adds or removes a class depending on the enabled argument.  This method
+ * may throw a DOM exception for an invalid or empty class name if DOMTokenList
+ * is used.
+ * @param {Element} 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).
+ */
+goog.dom.classlist.enable = function(element, className, enabled) {
+  if (enabled) {
+    goog.dom.classlist.add(element, className);
+  } else {
+    goog.dom.classlist.remove(element, className);
+  }
+};
+
+
+/**
+ * Adds or removes a set of classes depending on the enabled argument.  This
+ * method may throw a DOM exception for an invalid or empty class name if
+ * DOMTokenList is used.
+ * @param {!Element} element DOM node to add or remove the class on.
+ * @param {goog.array.ArrayLike<string>} classesToEnable An array-like object
+ *     containing a collection of class names to add or remove from the element.
+ * @param {boolean} enabled Whether to add or remove the classes (true adds,
+ *     false removes).
+ */
+goog.dom.classlist.enableAll = function(element, classesToEnable, enabled) {
+  var f = enabled ? goog.dom.classlist.addAll :
+      goog.dom.classlist.removeAll;
+  f(element, classesToEnable);
+};
+
+
+/**
+ * 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.  This
+ * method may throw a DOM exception if the class names are empty or invalid.
+ * @param {Element} 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.
+ */
+goog.dom.classlist.swap = function(element, fromClass, toClass) {
+  if (goog.dom.classlist.contains(element, fromClass)) {
+    goog.dom.classlist.remove(element, fromClass);
+    goog.dom.classlist.add(element, toClass);
+    return true;
+  }
+  return false;
+};
+
+
+/**
+ * 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.  This method may throw a DOM
+ * exception if the class name is empty or invalid.
+ * @param {Element} 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).
+ */
+goog.dom.classlist.toggle = function(element, className) {
+  var add = !goog.dom.classlist.contains(element, className);
+  goog.dom.classlist.enable(element, className, add);
+  return add;
+};
+
+
+/**
+ * Adds and removes a class of an element.  Unlike
+ * {@link goog.dom.classlist.swap}, this method adds the classToAdd regardless
+ * of whether the classToRemove was present and had been removed.  This method
+ * may throw a DOM exception if the class names are empty or invalid.
+ *
+ * @param {Element} element DOM node to swap classes on.
+ * @param {string} classToRemove Class to remove.
+ * @param {string} classToAdd Class to add.
+ */
+goog.dom.classlist.addRemove = function(element, classToRemove, classToAdd) {
+  goog.dom.classlist.remove(element, classToRemove);
+  goog.dom.classlist.add(element, classToAdd);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/controlrange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/controlrange.js b/externs/GCL/externs/goog/dom/controlrange.js
new file mode 100644
index 0000000..61df59a
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/controlrange.js
@@ -0,0 +1,494 @@
+// Copyright 2008 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 working with IE control ranges.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.ControlRange');
+goog.provide('goog.dom.ControlRangeIterator');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.AbstractMultiRange');
+goog.require('goog.dom.AbstractRange');
+goog.require('goog.dom.RangeIterator');
+goog.require('goog.dom.RangeType');
+goog.require('goog.dom.SavedRange');
+goog.require('goog.dom.TagWalkType');
+goog.require('goog.dom.TextRange');
+goog.require('goog.iter.StopIteration');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Create a new control selection with no properties.  Do not use this
+ * constructor: use one of the goog.dom.Range.createFrom* methods instead.
+ * @constructor
+ * @extends {goog.dom.AbstractMultiRange}
+ * @final
+ */
+goog.dom.ControlRange = function() {
+  /**
+   * The IE control range obejct.
+   * @private {Object}
+   */
+  this.range_ = null;
+
+  /**
+   * Cached list of elements.
+   * @private {Array<Element>}
+   */
+  this.elements_ = null;
+
+  /**
+   * Cached sorted list of elements.
+   * @private {Array<Element>}
+   */
+  this.sortedElements_ = null;
+};
+goog.inherits(goog.dom.ControlRange, goog.dom.AbstractMultiRange);
+
+
+/**
+ * Create a new range wrapper from the given browser range object.  Do not use
+ * this method directly - please use goog.dom.Range.createFrom* instead.
+ * @param {Object} controlRange The browser range object.
+ * @return {!goog.dom.ControlRange} A range wrapper object.
+ */
+goog.dom.ControlRange.createFromBrowserRange = function(controlRange) {
+  var range = new goog.dom.ControlRange();
+  range.range_ = controlRange;
+  return range;
+};
+
+
+/**
+ * Create a new range wrapper that selects the given element.  Do not use
+ * this method directly - please use goog.dom.Range.createFrom* instead.
+ * @param {...Element} var_args The element(s) to select.
+ * @return {!goog.dom.ControlRange} A range wrapper object.
+ */
+goog.dom.ControlRange.createFromElements = function(var_args) {
+  var range = goog.dom.getOwnerDocument(arguments[0]).body.createControlRange();
+  for (var i = 0, len = arguments.length; i < len; i++) {
+    range.addElement(arguments[i]);
+  }
+  return goog.dom.ControlRange.createFromBrowserRange(range);
+};
+
+
+// Method implementations
+
+
+/**
+ * Clear cached values.
+ * @private
+ */
+goog.dom.ControlRange.prototype.clearCachedValues_ = function() {
+  this.elements_ = null;
+  this.sortedElements_ = null;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.clone = function() {
+  return goog.dom.ControlRange.createFromElements.apply(this,
+                                                        this.getElements());
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getType = function() {
+  return goog.dom.RangeType.CONTROL;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getBrowserRangeObject = function() {
+  return this.range_ || document.body.createControlRange();
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.setBrowserRangeObject = function(nativeRange) {
+  if (!goog.dom.AbstractRange.isNativeControlRange(nativeRange)) {
+    return false;
+  }
+  this.range_ = nativeRange;
+  return true;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getTextRangeCount = function() {
+  return this.range_ ? this.range_.length : 0;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getTextRange = function(i) {
+  return goog.dom.TextRange.createFromNodeContents(this.range_.item(i));
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getContainer = function() {
+  return goog.dom.findCommonAncestor.apply(null, this.getElements());
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getStartNode = function() {
+  return this.getSortedElements()[0];
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getStartOffset = function() {
+  return 0;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getEndNode = function() {
+  var sorted = this.getSortedElements();
+  var startsLast = /** @type {Node} */ (goog.array.peek(sorted));
+  return /** @type {Node} */ (goog.array.find(sorted, function(el) {
+    return goog.dom.contains(el, startsLast);
+  }));
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getEndOffset = function() {
+  return this.getEndNode().childNodes.length;
+};
+
+
+// TODO(robbyw): Figure out how to unify getElements with TextRange API.
+/**
+ * @return {!Array<Element>} Array of elements in the control range.
+ */
+goog.dom.ControlRange.prototype.getElements = function() {
+  if (!this.elements_) {
+    this.elements_ = [];
+    if (this.range_) {
+      for (var i = 0; i < this.range_.length; i++) {
+        this.elements_.push(this.range_.item(i));
+      }
+    }
+  }
+
+  return this.elements_;
+};
+
+
+/**
+ * @return {!Array<Element>} Array of elements comprising the control range,
+ *     sorted by document order.
+ */
+goog.dom.ControlRange.prototype.getSortedElements = function() {
+  if (!this.sortedElements_) {
+    this.sortedElements_ = this.getElements().concat();
+    this.sortedElements_.sort(function(a, b) {
+      return a.sourceIndex - b.sourceIndex;
+    });
+  }
+
+  return this.sortedElements_;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.isRangeInDocument = function() {
+  var returnValue = false;
+
+  try {
+    returnValue = goog.array.every(this.getElements(), function(element) {
+      // On IE, this throws an exception when the range is detached.
+      return goog.userAgent.IE ?
+          !!element.parentNode :
+          goog.dom.contains(element.ownerDocument.body, element);
+    });
+  } catch (e) {
+    // IE sometimes throws Invalid Argument errors for detached elements.
+    // Note: trying to return a value from the above try block can cause IE
+    // to crash.  It is necessary to use the local returnValue.
+  }
+
+  return returnValue;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.isCollapsed = function() {
+  return !this.range_ || !this.range_.length;
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getText = function() {
+  // TODO(robbyw): What about for table selections?  Should those have text?
+  return '';
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getHtmlFragment = function() {
+  return goog.array.map(this.getSortedElements(), goog.dom.getOuterHtml).
+      join('');
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getValidHtml = function() {
+  return this.getHtmlFragment();
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.getPastableHtml =
+    goog.dom.ControlRange.prototype.getValidHtml;
+
+
+/** @override */
+goog.dom.ControlRange.prototype.__iterator__ = function(opt_keys) {
+  return new goog.dom.ControlRangeIterator(this);
+};
+
+
+// RANGE ACTIONS
+
+
+/** @override */
+goog.dom.ControlRange.prototype.select = function() {
+  if (this.range_) {
+    this.range_.select();
+  }
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.removeContents = function() {
+  // TODO(robbyw): Test implementing with execCommand('Delete')
+  if (this.range_) {
+    var nodes = [];
+    for (var i = 0, len = this.range_.length; i < len; i++) {
+      nodes.push(this.range_.item(i));
+    }
+    goog.array.forEach(nodes, goog.dom.removeNode);
+
+    this.collapse(false);
+  }
+};
+
+
+/** @override */
+goog.dom.ControlRange.prototype.replaceContentsWithNode = function(node) {
+  // Control selections have to have the node inserted before removing the
+  // selection contents because a collapsed control range doesn't have start or
+  // end nodes.
+  var result = this.insertNode(node, true);
+
+  if (!this.isCollapsed()) {
+    this.removeContents();
+  }
+
+  return result;
+};
+
+
+// SAVE/RESTORE
+
+
+/** @override */
+goog.dom.ControlRange.prototype.saveUsingDom = function() {
+  return new goog.dom.DomSavedControlRange_(this);
+};
+
+
+// RANGE MODIFICATION
+
+
+/** @override */
+goog.dom.ControlRange.prototype.collapse = function(toAnchor) {
+  // TODO(robbyw): Should this return a text range?  If so, API needs to change.
+  this.range_ = null;
+  this.clearCachedValues_();
+};
+
+
+// SAVED RANGE OBJECTS
+
+
+
+/**
+ * A SavedRange implementation using DOM endpoints.
+ * @param {goog.dom.ControlRange} range The range to save.
+ * @constructor
+ * @extends {goog.dom.SavedRange}
+ * @private
+ */
+goog.dom.DomSavedControlRange_ = function(range) {
+  /**
+   * The element list.
+   * @type {Array<Element>}
+   * @private
+   */
+  this.elements_ = range.getElements();
+};
+goog.inherits(goog.dom.DomSavedControlRange_, goog.dom.SavedRange);
+
+
+/** @override */
+goog.dom.DomSavedControlRange_.prototype.restoreInternal = function() {
+  var doc = this.elements_.length ?
+      goog.dom.getOwnerDocument(this.elements_[0]) : document;
+  var controlRange = doc.body.createControlRange();
+  for (var i = 0, len = this.elements_.length; i < len; i++) {
+    controlRange.addElement(this.elements_[i]);
+  }
+  return goog.dom.ControlRange.createFromBrowserRange(controlRange);
+};
+
+
+/** @override */
+goog.dom.DomSavedControlRange_.prototype.disposeInternal = function() {
+  goog.dom.DomSavedControlRange_.superClass_.disposeInternal.call(this);
+  delete this.elements_;
+};
+
+
+// RANGE ITERATION
+
+
+
+/**
+ * Subclass of goog.dom.TagIterator that iterates over a DOM range.  It
+ * adds functions to determine the portion of each text node that is selected.
+ *
+ * @param {goog.dom.ControlRange?} range The range to traverse.
+ * @constructor
+ * @extends {goog.dom.RangeIterator}
+ * @final
+ */
+goog.dom.ControlRangeIterator = function(range) {
+  /**
+   * The first node in the selection.
+   * @private {Node}
+   */
+  this.startNode_ = null;
+
+  /**
+   * The last node in the selection.
+   * @private {Node}
+   */
+  this.endNode_ = null;
+
+  /**
+   * The list of elements left to traverse.
+   * @private {Array<Element>?}
+   */
+  this.elements_ = null;
+
+  if (range) {
+    this.elements_ = range.getSortedElements();
+    this.startNode_ = this.elements_.shift();
+    this.endNode_ = /** @type {Node} */ (goog.array.peek(this.elements_)) ||
+        this.startNode_;
+  }
+
+  goog.dom.ControlRangeIterator.base(
+      this, 'constructor', this.startNode_, false);
+};
+goog.inherits(goog.dom.ControlRangeIterator, goog.dom.RangeIterator);
+
+
+/** @override */
+goog.dom.ControlRangeIterator.prototype.getStartTextOffset = function() {
+  return 0;
+};
+
+
+/** @override */
+goog.dom.ControlRangeIterator.prototype.getEndTextOffset = function() {
+  return 0;
+};
+
+
+/** @override */
+goog.dom.ControlRangeIterator.prototype.getStartNode = function() {
+  return this.startNode_;
+};
+
+
+/** @override */
+goog.dom.ControlRangeIterator.prototype.getEndNode = function() {
+  return this.endNode_;
+};
+
+
+/** @override */
+goog.dom.ControlRangeIterator.prototype.isLast = function() {
+  return !this.depth && !this.elements_.length;
+};
+
+
+/**
+ * Move to the next position in the selection.
+ * Throws {@code goog.iter.StopIteration} when it passes the end of the range.
+ * @return {Node} The node at the next position.
+ * @override
+ */
+goog.dom.ControlRangeIterator.prototype.next = function() {
+  // Iterate over each element in the range, and all of its children.
+  if (this.isLast()) {
+    throw goog.iter.StopIteration;
+  } else if (!this.depth) {
+    var el = this.elements_.shift();
+    this.setPosition(el,
+                     goog.dom.TagWalkType.START_TAG,
+                     goog.dom.TagWalkType.START_TAG);
+    return el;
+  }
+
+  // Call the super function.
+  return goog.dom.ControlRangeIterator.superClass_.next.call(this);
+};
+
+
+/** @override */
+goog.dom.ControlRangeIterator.prototype.copyFrom = function(other) {
+  this.elements_ = other.elements_;
+  this.startNode_ = other.startNode_;
+  this.endNode_ = other.endNode_;
+
+  goog.dom.ControlRangeIterator.superClass_.copyFrom.call(this, other);
+};
+
+
+/**
+ * @return {!goog.dom.ControlRangeIterator} An identical iterator.
+ * @override
+ */
+goog.dom.ControlRangeIterator.prototype.clone = function() {
+  var copy = new goog.dom.ControlRangeIterator(null);
+  copy.copyFrom(this);
+  return copy;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/dataset.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/dataset.js b/externs/GCL/externs/goog/dom/dataset.js
new file mode 100644
index 0000000..6f24587
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/dataset.js
@@ -0,0 +1,154 @@
+// 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 Utilities for adding, removing and setting values in
+ * an Element's dataset.
+ * See {@link http://www.w3.org/TR/html5/Overview.html#dom-dataset}.
+ *
+ * @author nicksay@google.com (Alex Nicksay)
+ */
+
+goog.provide('goog.dom.dataset');
+
+goog.require('goog.string');
+goog.require('goog.userAgent.product');
+
+
+/**
+ * Whether using the dataset property is allowed.  In IE (up to and including
+ * IE 11), setting element.dataset in JS does not propagate values to CSS,
+ * breaking expressions such as `content: attr(data-content)` that would
+ * otherwise work.
+ * See {@link https://github.com/google/closure-library/issues/396}.
+ * @const
+ * @private
+ */
+goog.dom.dataset.ALLOWED_ = !goog.userAgent.product.IE;
+
+
+/**
+ * The DOM attribute name prefix that must be present for it to be considered
+ * for a dataset.
+ * @type {string}
+ * @const
+ * @private
+ */
+goog.dom.dataset.PREFIX_ = 'data-';
+
+
+/**
+ * Sets a custom data attribute on an element. The key should be
+ * in camelCase format (e.g "keyName" for the "data-key-name" attribute).
+ * @param {Element} element DOM node to set the custom data attribute on.
+ * @param {string} key Key for the custom data attribute.
+ * @param {string} value Value for the custom data attribute.
+ */
+goog.dom.dataset.set = function(element, key, value) {
+  if (goog.dom.dataset.ALLOWED_ && element.dataset) {
+    element.dataset[key] = value;
+  } else {
+    element.setAttribute(
+        goog.dom.dataset.PREFIX_ + goog.string.toSelectorCase(key),
+        value);
+  }
+};
+
+
+/**
+ * Gets a custom data attribute from an element. The key should be
+ * in camelCase format (e.g "keyName" for the "data-key-name" attribute).
+ * @param {Element} element DOM node to get the custom data attribute from.
+ * @param {string} key Key for the custom data attribute.
+ * @return {?string} The attribute value, if it exists.
+ */
+goog.dom.dataset.get = function(element, key) {
+  if (goog.dom.dataset.ALLOWED_ && element.dataset) {
+    // Android browser (non-chrome) returns the empty string for
+    // element.dataset['doesNotExist'].
+    if (!(key in element.dataset)) {
+      return null;
+    }
+    return element.dataset[key];
+  } else {
+    return element.getAttribute(goog.dom.dataset.PREFIX_ +
+                                goog.string.toSelectorCase(key));
+  }
+};
+
+
+/**
+ * Removes a custom data attribute from an element. The key should be
+  * in camelCase format (e.g "keyName" for the "data-key-name" attribute).
+ * @param {Element} element DOM node to get the custom data attribute from.
+ * @param {string} key Key for the custom data attribute.
+ */
+goog.dom.dataset.remove = function(element, key) {
+  if (goog.dom.dataset.ALLOWED_ && element.dataset) {
+    delete element.dataset[key];
+  } else {
+    element.removeAttribute(goog.dom.dataset.PREFIX_ +
+                            goog.string.toSelectorCase(key));
+  }
+};
+
+
+/**
+ * Checks whether custom data attribute exists on an element. The key should be
+ * in camelCase format (e.g "keyName" for the "data-key-name" attribute).
+ *
+ * @param {Element} element DOM node to get the custom data attribute from.
+ * @param {string} key Key for the custom data attribute.
+ * @return {boolean} Whether the attribute exists.
+ */
+goog.dom.dataset.has = function(element, key) {
+  if (goog.dom.dataset.ALLOWED_ && element.dataset) {
+    return key in element.dataset;
+  } else if (element.hasAttribute) {
+    return element.hasAttribute(goog.dom.dataset.PREFIX_ +
+                                goog.string.toSelectorCase(key));
+  } else {
+    return !!(element.getAttribute(goog.dom.dataset.PREFIX_ +
+                                   goog.string.toSelectorCase(key)));
+  }
+};
+
+
+/**
+ * Gets all custom data attributes as a string map.  The attribute names will be
+ * camel cased (e.g., data-foo-bar -> dataset['fooBar']).  This operation is not
+ * safe for attributes having camel-cased names clashing with already existing
+ * properties (e.g., data-to-string -> dataset['toString']).
+ * @param {!Element} element DOM node to get the data attributes from.
+ * @return {!Object} The string map containing data attributes and their
+ *     respective values.
+ */
+goog.dom.dataset.getAll = function(element) {
+  if (goog.dom.dataset.ALLOWED_ && element.dataset) {
+    return element.dataset;
+  } else {
+    var dataset = {};
+    var attributes = element.attributes;
+    for (var i = 0; i < attributes.length; ++i) {
+      var attribute = attributes[i];
+      if (goog.string.startsWith(attribute.name,
+                                 goog.dom.dataset.PREFIX_)) {
+        // We use substr(5), since it's faster than replacing 'data-' with ''.
+        var key = goog.string.toCamelCase(attribute.name.substr(5));
+        dataset[key] = attribute.value;
+      }
+    }
+    return dataset;
+  }
+};


[24/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/abstractdialogplugin.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/abstractdialogplugin.js b/externs/GCL/externs/goog/editor/plugins/abstractdialogplugin.js
new file mode 100644
index 0000000..278277e
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/abstractdialogplugin.js
@@ -0,0 +1,333 @@
+// Copyright 2008 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 An abstract superclass for TrogEdit dialog plugins. Each
+ * Trogedit dialog has its own plugin.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.editor.plugins.AbstractDialogPlugin');
+goog.provide('goog.editor.plugins.AbstractDialogPlugin.EventType');
+
+goog.require('goog.dom');
+goog.require('goog.dom.Range');
+goog.require('goog.editor.Field');
+goog.require('goog.editor.Plugin');
+goog.require('goog.editor.range');
+goog.require('goog.events');
+goog.require('goog.ui.editor.AbstractDialog');
+
+
+// *** Public interface ***************************************************** //
+
+
+
+/**
+ * An abstract superclass for a Trogedit plugin that creates exactly one
+ * dialog. By default dialogs are not reused -- each time execCommand is called,
+ * a new instance of the dialog object is created (and the old one disposed of).
+ * To enable reusing of the dialog object, subclasses should call
+ * setReuseDialog() after calling the superclass constructor.
+ * @param {string} command The command that this plugin handles.
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ */
+goog.editor.plugins.AbstractDialogPlugin = function(command) {
+  goog.editor.Plugin.call(this);
+  this.command_ = command;
+};
+goog.inherits(goog.editor.plugins.AbstractDialogPlugin, goog.editor.Plugin);
+
+
+/** @override */
+goog.editor.plugins.AbstractDialogPlugin.prototype.isSupportedCommand =
+    function(command) {
+  return command == this.command_;
+};
+
+
+/**
+ * Handles execCommand. Dialog plugins don't make any changes when they open a
+ * dialog, just when the dialog closes (because only modal dialogs are
+ * supported). Hence this method does not dispatch the change events that the
+ * superclass method does.
+ * @param {string} command The command to execute.
+ * @param {...*} var_args Any additional parameters needed to
+ *     execute the command.
+ * @return {*} The result of the execCommand, if any.
+ * @override
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.execCommand = function(
+    command, var_args) {
+  return this.execCommandInternal.apply(this, arguments);
+};
+
+
+// *** Events *************************************************************** //
+
+
+/**
+ * Event type constants for events the dialog plugins fire.
+ * @enum {string}
+ */
+goog.editor.plugins.AbstractDialogPlugin.EventType = {
+  // This event is fired when a dialog has been opened.
+  OPENED: 'dialogOpened',
+  // This event is fired when a dialog has been closed.
+  CLOSED: 'dialogClosed'
+};
+
+
+// *** Protected interface ************************************************** //
+
+
+/**
+ * Creates a new instance of this plugin's dialog. Must be overridden by
+ * subclasses.
+ * @param {!goog.dom.DomHelper} dialogDomHelper The dom helper to be used to
+ *     create the dialog.
+ * @param {*=} opt_arg The dialog specific argument. Concrete subclasses should
+ *     declare a specific type.
+ * @return {goog.ui.editor.AbstractDialog} The newly created dialog.
+ * @protected
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.createDialog =
+    goog.abstractMethod;
+
+
+/**
+ * Returns the current dialog that was created and opened by this plugin.
+ * @return {goog.ui.editor.AbstractDialog} The current dialog that was created
+ *     and opened by this plugin.
+ * @protected
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.getDialog = function() {
+  return this.dialog_;
+};
+
+
+/**
+ * Sets whether this plugin should reuse the same instance of the dialog each
+ * time execCommand is called or create a new one. This is intended for use by
+ * subclasses only, hence protected.
+ * @param {boolean} reuse Whether to reuse the dialog.
+ * @protected
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.setReuseDialog =
+    function(reuse) {
+  this.reuseDialog_ = reuse;
+};
+
+
+/**
+ * Handles execCommand by opening the dialog. Dispatches
+ * {@link goog.editor.plugins.AbstractDialogPlugin.EventType.OPENED} after the
+ * dialog is shown.
+ * @param {string} command The command to execute.
+ * @param {*=} opt_arg The dialog specific argument. Should be the same as
+ *     {@link createDialog}.
+ * @return {*} Always returns true, indicating the dialog was shown.
+ * @protected
+ * @override
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.execCommandInternal =
+    function(command, opt_arg) {
+  // If this plugin should not reuse dialog instances, first dispose of the
+  // previous dialog.
+  if (!this.reuseDialog_) {
+    this.disposeDialog_();
+  }
+  // If there is no dialog yet (or we aren't reusing the previous one), create
+  // one.
+  if (!this.dialog_) {
+    this.dialog_ = this.createDialog(
+        // TODO(user): Add Field.getAppDomHelper. (Note dom helper will
+        // need to be updated if setAppWindow is called by clients.)
+        goog.dom.getDomHelper(this.getFieldObject().getAppWindow()),
+        opt_arg);
+  }
+
+  // Since we're opening a dialog, we need to clear the selection because the
+  // focus will be going to the dialog, and if we leave an selection in the
+  // editor while another selection is active in the dialog as the user is
+  // typing, some browsers will screw up the original selection. But first we
+  // save it so we can restore it when the dialog closes.
+  // getRange may return null if there is no selection in the field.
+  var tempRange = this.getFieldObject().getRange();
+  // saveUsingDom() did not work as well as saveUsingNormalizedCarets(),
+  // not sure why.
+  this.savedRange_ = tempRange && goog.editor.range.saveUsingNormalizedCarets(
+      tempRange);
+  goog.dom.Range.clearSelection(
+      this.getFieldObject().getEditableDomHelper().getWindow());
+
+  // Listen for the dialog closing so we can clean up.
+  goog.events.listenOnce(this.dialog_,
+      goog.ui.editor.AbstractDialog.EventType.AFTER_HIDE,
+      this.handleAfterHide,
+      false,
+      this);
+
+  this.getFieldObject().setModalMode(true);
+  this.dialog_.show();
+  this.dispatchEvent(goog.editor.plugins.AbstractDialogPlugin.EventType.OPENED);
+
+  // Since the selection has left the document, dispatch a selection
+  // change event.
+  this.getFieldObject().dispatchSelectionChangeEvent();
+
+  return true;
+};
+
+
+/**
+ * Cleans up after the dialog has closed, including restoring the selection to
+ * what it was before the dialog was opened. If a subclass modifies the editable
+ * field's content such that the original selection is no longer valid (usually
+ * the case when the user clicks OK, and sometimes also on Cancel), it is that
+ * subclass' responsibility to place the selection in the desired place during
+ * the OK or Cancel (or other) handler. In that case, this method will leave the
+ * selection in place.
+ * @param {goog.events.Event} e The AFTER_HIDE event object.
+ * @protected
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.handleAfterHide = function(
+    e) {
+  this.getFieldObject().setModalMode(false);
+  this.restoreOriginalSelection();
+
+  if (!this.reuseDialog_) {
+    this.disposeDialog_();
+  }
+
+  this.dispatchEvent(goog.editor.plugins.AbstractDialogPlugin.EventType.CLOSED);
+
+  // Since the selection has returned to the document, dispatch a selection
+  // change event.
+  this.getFieldObject().dispatchSelectionChangeEvent();
+
+  // When the dialog closes due to pressing enter or escape, that happens on the
+  // keydown event. But the browser will still fire a keyup event after that,
+  // which is caught by the editable field and causes it to try to fire a
+  // selection change event. To avoid that, we "debounce" the selection change
+  // event, meaning the editable field will not fire that event if the keyup
+  // that caused it immediately after this dialog was hidden ("immediately"
+  // means a small number of milliseconds defined by the editable field).
+  this.getFieldObject().debounceEvent(
+      goog.editor.Field.EventType.SELECTIONCHANGE);
+};
+
+
+/**
+ * Restores the selection in the editable field to what it was before the dialog
+ * was opened. This is not guaranteed to work if the contents of the field
+ * have changed.
+ * @protected
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.restoreOriginalSelection =
+    function() {
+  this.getFieldObject().restoreSavedRange(this.savedRange_);
+  this.savedRange_ = null;
+};
+
+
+/**
+ * Cleans up the structure used to save the original selection before the dialog
+ * was opened. Should be used by subclasses that don't restore the original
+ * selection via restoreOriginalSelection.
+ * @protected
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.disposeOriginalSelection =
+    function() {
+  if (this.savedRange_) {
+    this.savedRange_.dispose();
+    this.savedRange_ = null;
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.AbstractDialogPlugin.prototype.disposeInternal =
+    function() {
+  this.disposeDialog_();
+  goog.editor.plugins.AbstractDialogPlugin.base(this, 'disposeInternal');
+};
+
+
+// *** Private implementation *********************************************** //
+
+
+/**
+ * The command that this plugin handles.
+ * @type {string}
+ * @private
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.command_;
+
+
+/**
+ * The current dialog that was created and opened by this plugin.
+ * @type {goog.ui.editor.AbstractDialog}
+ * @private
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.dialog_;
+
+
+/**
+ * Whether this plugin should reuse the same instance of the dialog each time
+ * execCommand is called or create a new one.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.reuseDialog_ = false;
+
+
+/**
+ * Mutex to prevent recursive calls to disposeDialog_.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.isDisposingDialog_ = false;
+
+
+/**
+ * SavedRange representing the selection before the dialog was opened.
+ * @type {goog.dom.SavedRange}
+ * @private
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.savedRange_;
+
+
+/**
+ * Disposes of the dialog if needed. It is this abstract class' responsibility
+ * to dispose of the dialog. The "if needed" refers to the fact this method
+ * might be called twice (nested calls, not sequential) in the dispose flow, so
+ * if the dialog was already disposed once it should not be disposed again.
+ * @private
+ */
+goog.editor.plugins.AbstractDialogPlugin.prototype.disposeDialog_ = function() {
+  // Wrap disposing the dialog in a mutex. Otherwise disposing it would cause it
+  // to get hidden (if it is still open) and fire AFTER_HIDE, which in
+  // turn would cause the dialog to be disposed again (closure only flags an
+  // object as disposed after the dispose call chain completes, so it doesn't
+  // prevent recursive dispose calls).
+  if (this.dialog_ && !this.isDisposingDialog_) {
+    this.isDisposingDialog_ = true;
+    this.dialog_.dispose();
+    this.dialog_ = null;
+    this.isDisposingDialog_ = false;
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/abstracttabhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/abstracttabhandler.js b/externs/GCL/externs/goog/editor/plugins/abstracttabhandler.js
new file mode 100644
index 0000000..de1a13a
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/abstracttabhandler.js
@@ -0,0 +1,78 @@
+// Copyright 2008 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 Abstract Editor plugin class to handle tab keys.  Has one
+ * abstract method which should be overriden to handle a tab key press.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.editor.plugins.AbstractTabHandler');
+
+goog.require('goog.editor.Plugin');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Plugin to handle tab keys. Specific tab behavior defined by subclasses.
+ *
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ */
+goog.editor.plugins.AbstractTabHandler = function() {
+  goog.editor.Plugin.call(this);
+};
+goog.inherits(goog.editor.plugins.AbstractTabHandler, goog.editor.Plugin);
+
+
+/** @override */
+goog.editor.plugins.AbstractTabHandler.prototype.getTrogClassId =
+    goog.abstractMethod;
+
+
+/** @override */
+goog.editor.plugins.AbstractTabHandler.prototype.handleKeyboardShortcut =
+    function(e, key, isModifierPressed) {
+  // If a dialog doesn't have selectable field, Moz grabs the event and
+  // performs actions in editor window. This solves that problem and allows
+  // the event to be passed on to proper handlers.
+  if (goog.userAgent.GECKO && this.getFieldObject().inModalMode()) {
+    return false;
+  }
+
+  // Don't handle Ctrl+Tab since the user is most likely trying to switch
+  // browser tabs. See bug 1305086.
+  // FF3 on Mac sends Ctrl-Tab to trogedit and we end up inserting a tab, but
+  // then it also switches the tabs. See bug 1511681. Note that we don't use
+  // isModifierPressed here since isModifierPressed is true only if metaKey
+  // is true on Mac.
+  if (e.keyCode == goog.events.KeyCodes.TAB && !e.metaKey && !e.ctrlKey) {
+    return this.handleTabKey(e);
+  }
+
+  return false;
+};
+
+
+/**
+ * Handle a tab key press.
+ * @param {goog.events.Event} e The key event.
+ * @return {boolean} Whether this event was handled by this plugin.
+ * @protected
+ */
+goog.editor.plugins.AbstractTabHandler.prototype.handleTabKey =
+    goog.abstractMethod;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/basictextformatter.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/basictextformatter.js b/externs/GCL/externs/goog/editor/plugins/basictextformatter.js
new file mode 100644
index 0000000..1cac1cd
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/basictextformatter.js
@@ -0,0 +1,1769 @@
+// 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 Functions to style text.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.editor.plugins.BasicTextFormatter');
+goog.provide('goog.editor.plugins.BasicTextFormatter.COMMAND');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.Range');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.BrowserFeature');
+goog.require('goog.editor.Command');
+goog.require('goog.editor.Link');
+goog.require('goog.editor.Plugin');
+goog.require('goog.editor.node');
+goog.require('goog.editor.range');
+goog.require('goog.editor.style');
+goog.require('goog.iter');
+goog.require('goog.iter.StopIteration');
+goog.require('goog.log');
+goog.require('goog.object');
+goog.require('goog.string');
+goog.require('goog.string.Unicode');
+goog.require('goog.style');
+goog.require('goog.ui.editor.messages');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Functions to style text (e.g. underline, make bold, etc.)
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ */
+goog.editor.plugins.BasicTextFormatter = function() {
+  goog.editor.Plugin.call(this);
+};
+goog.inherits(goog.editor.plugins.BasicTextFormatter, goog.editor.Plugin);
+
+
+/** @override */
+goog.editor.plugins.BasicTextFormatter.prototype.getTrogClassId = function() {
+  return 'BTF';
+};
+
+
+/**
+ * Logging object.
+ * @type {goog.log.Logger}
+ * @protected
+ * @override
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.logger =
+    goog.log.getLogger('goog.editor.plugins.BasicTextFormatter');
+
+
+/**
+ * Commands implemented by this plugin.
+ * @enum {string}
+ */
+goog.editor.plugins.BasicTextFormatter.COMMAND = {
+  LINK: '+link',
+  FORMAT_BLOCK: '+formatBlock',
+  INDENT: '+indent',
+  OUTDENT: '+outdent',
+  STRIKE_THROUGH: '+strikeThrough',
+  HORIZONTAL_RULE: '+insertHorizontalRule',
+  SUBSCRIPT: '+subscript',
+  SUPERSCRIPT: '+superscript',
+  UNDERLINE: '+underline',
+  BOLD: '+bold',
+  ITALIC: '+italic',
+  FONT_SIZE: '+fontSize',
+  FONT_FACE: '+fontName',
+  FONT_COLOR: '+foreColor',
+  BACKGROUND_COLOR: '+backColor',
+  ORDERED_LIST: '+insertOrderedList',
+  UNORDERED_LIST: '+insertUnorderedList',
+  JUSTIFY_CENTER: '+justifyCenter',
+  JUSTIFY_FULL: '+justifyFull',
+  JUSTIFY_RIGHT: '+justifyRight',
+  JUSTIFY_LEFT: '+justifyLeft'
+};
+
+
+/**
+ * Inverse map of execCommand strings to
+ * {@link goog.editor.plugins.BasicTextFormatter.COMMAND} constants. Used to
+ * determine whether a string corresponds to a command this plugin
+ * handles in O(1) time.
+ * @type {Object}
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.SUPPORTED_COMMANDS_ =
+    goog.object.transpose(goog.editor.plugins.BasicTextFormatter.COMMAND);
+
+
+/**
+ * Whether the string corresponds to a command this plugin handles.
+ * @param {string} command Command string to check.
+ * @return {boolean} Whether the string corresponds to a command
+ *     this plugin handles.
+ * @override
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.isSupportedCommand = function(
+    command) {
+  // TODO(user): restore this to simple check once table editing
+  // is moved out into its own plugin
+  return command in goog.editor.plugins.BasicTextFormatter.SUPPORTED_COMMANDS_;
+};
+
+
+/**
+ * @return {goog.dom.AbstractRange} The closure range object that wraps the
+ *     current user selection.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.getRange_ = function() {
+  return this.getFieldObject().getRange();
+};
+
+
+/**
+ * @return {!Document} The document object associated with the currently active
+ *     field.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.getDocument_ = function() {
+  return this.getFieldDomHelper().getDocument();
+};
+
+
+/**
+ * Execute a user-initiated command.
+ * @param {string} command Command to execute.
+ * @param {...*} var_args For color commands, this
+ *     should be the hex color (with the #). For FORMAT_BLOCK, this should be
+ *     the goog.editor.plugins.BasicTextFormatter.BLOCK_COMMAND.
+ *     It will be unused for other commands.
+ * @return {Object|undefined} The result of the command.
+ * @override
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.execCommandInternal = function(
+    command, var_args) {
+  var preserveDir, styleWithCss, needsFormatBlockDiv, hasDummySelection;
+  var result;
+  var opt_arg = arguments[1];
+
+  switch (command) {
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.BACKGROUND_COLOR:
+      // Don't bother for no color selected, color picker is resetting itself.
+      if (!goog.isNull(opt_arg)) {
+        if (goog.editor.BrowserFeature.EATS_EMPTY_BACKGROUND_COLOR) {
+          this.applyBgColorManually_(opt_arg);
+        } else if (goog.userAgent.OPERA) {
+          // backColor will color the block level element instead of
+          // the selected span of text in Opera.
+          this.execCommandHelper_('hiliteColor', opt_arg);
+        } else {
+          this.execCommandHelper_(command, opt_arg);
+        }
+      }
+      break;
+
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.LINK:
+      result = this.toggleLink_(opt_arg);
+      break;
+
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.JUSTIFY_CENTER:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.JUSTIFY_FULL:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.JUSTIFY_RIGHT:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.JUSTIFY_LEFT:
+      this.justify_(command);
+      break;
+
+    default:
+      if (goog.userAgent.IE &&
+          command ==
+              goog.editor.plugins.BasicTextFormatter.COMMAND.FORMAT_BLOCK &&
+          opt_arg) {
+        // IE requires that the argument be in the form of an opening
+        // tag, like <h1>, including angle brackets.  WebKit will accept
+        // the arguemnt with or without brackets, and Firefox pre-3 supports
+        // only a fixed subset of tags with brackets, and prefers without.
+        // So we only add them IE only.
+        opt_arg = '<' + opt_arg + '>';
+      }
+
+      if (command ==
+          goog.editor.plugins.BasicTextFormatter.COMMAND.FONT_COLOR &&
+          goog.isNull(opt_arg)) {
+        // If we don't have a color, then FONT_COLOR is a no-op.
+        break;
+      }
+
+      switch (command) {
+        case goog.editor.plugins.BasicTextFormatter.COMMAND.INDENT:
+        case goog.editor.plugins.BasicTextFormatter.COMMAND.OUTDENT:
+          if (goog.editor.BrowserFeature.HAS_STYLE_WITH_CSS) {
+            if (goog.userAgent.GECKO) {
+              styleWithCss = true;
+            }
+            if (goog.userAgent.OPERA) {
+              if (command ==
+                  goog.editor.plugins.BasicTextFormatter.COMMAND.OUTDENT) {
+                // styleWithCSS actually sets negative margins on <blockquote>
+                // to outdent them. If the command is enabled without
+                // styleWithCSS flipped on, then the caret is in a blockquote so
+                // styleWithCSS must not be used. But if the command is not
+                // enabled, styleWithCSS should be used so that elements such as
+                // a <div> with a margin-left style can still be outdented.
+                // (Opera bug: CORE-21118)
+                styleWithCss =
+                    !this.getDocument_().queryCommandEnabled('outdent');
+              } else {
+                // Always use styleWithCSS for indenting. Otherwise, Opera will
+                // make separate <blockquote>s around *each* indented line,
+                // which adds big default <blockquote> margins between each
+                // indented line.
+                styleWithCss = true;
+              }
+            }
+          }
+          // Fall through.
+
+        case goog.editor.plugins.BasicTextFormatter.COMMAND.ORDERED_LIST:
+        case goog.editor.plugins.BasicTextFormatter.COMMAND.UNORDERED_LIST:
+          if (goog.editor.BrowserFeature.LEAVES_P_WHEN_REMOVING_LISTS &&
+              this.queryCommandStateInternal_(this.getDocument_(),
+                  command)) {
+            // IE leaves behind P tags when unapplying lists.
+            // If we're not in P-mode, then we want divs
+            // So, unlistify, then convert the Ps into divs.
+            needsFormatBlockDiv = this.getFieldObject().queryCommandValue(
+                goog.editor.Command.DEFAULT_TAG) != goog.dom.TagName.P;
+          } else if (!goog.editor.BrowserFeature.CAN_LISTIFY_BR) {
+            // IE doesn't convert BRed line breaks into separate list items.
+            // So convert the BRs to divs, then do the listify.
+            this.convertBreaksToDivs_();
+          }
+
+          // This fix only works in Gecko.
+          if (goog.userAgent.GECKO &&
+              goog.editor.BrowserFeature.FORGETS_FORMATTING_WHEN_LISTIFYING &&
+              !this.queryCommandValue(command)) {
+            hasDummySelection |= this.beforeInsertListGecko_();
+          }
+          // Fall through to preserveDir block
+
+        case goog.editor.plugins.BasicTextFormatter.COMMAND.FORMAT_BLOCK:
+          // Both FF & IE may lose directionality info. Save/restore it.
+          // TODO(user): Does Safari also need this?
+          // TODO (gmark, jparent): This isn't ideal because it uses a string
+          // literal, so if the plugin name changes, it would break. We need a
+          // better solution. See also other places in code that use
+          // this.getPluginByClassId('Bidi').
+          preserveDir = !!this.getFieldObject().getPluginByClassId('Bidi');
+          break;
+
+        case goog.editor.plugins.BasicTextFormatter.COMMAND.SUBSCRIPT:
+        case goog.editor.plugins.BasicTextFormatter.COMMAND.SUPERSCRIPT:
+          if (goog.editor.BrowserFeature.NESTS_SUBSCRIPT_SUPERSCRIPT) {
+            // This browser nests subscript and superscript when both are
+            // applied, instead of canceling out the first when applying the
+            // second.
+            this.applySubscriptSuperscriptWorkarounds_(command);
+          }
+          break;
+
+        case goog.editor.plugins.BasicTextFormatter.COMMAND.UNDERLINE:
+        case goog.editor.plugins.BasicTextFormatter.COMMAND.BOLD:
+        case goog.editor.plugins.BasicTextFormatter.COMMAND.ITALIC:
+          // If we are applying the formatting, then we want to have
+          // styleWithCSS false so that we generate html tags (like <b>).  If we
+          // are unformatting something, we want to have styleWithCSS true so
+          // that we can unformat both html tags and inline styling.
+          // TODO(user): What about WebKit and Opera?
+          styleWithCss = goog.userAgent.GECKO &&
+                         goog.editor.BrowserFeature.HAS_STYLE_WITH_CSS &&
+                         this.queryCommandValue(command);
+          break;
+
+        case goog.editor.plugins.BasicTextFormatter.COMMAND.FONT_COLOR:
+        case goog.editor.plugins.BasicTextFormatter.COMMAND.FONT_FACE:
+          // It is very expensive in FF (order of magnitude difference) to use
+          // font tags instead of styled spans. Whenever possible,
+          // force FF to use spans.
+          // Font size is very expensive too, but FF always uses font tags,
+          // regardless of which styleWithCSS value you use.
+          styleWithCss = goog.editor.BrowserFeature.HAS_STYLE_WITH_CSS &&
+                         goog.userAgent.GECKO;
+      }
+
+      /**
+       * Cases where we just use the default execCommand (in addition
+       * to the above fall-throughs)
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.STRIKE_THROUGH:
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.HORIZONTAL_RULE:
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.SUBSCRIPT:
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.SUPERSCRIPT:
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.UNDERLINE:
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.BOLD:
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.ITALIC:
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.FONT_SIZE:
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.FONT_FACE:
+       */
+      this.execCommandHelper_(command, opt_arg, preserveDir, !!styleWithCss);
+
+      if (hasDummySelection) {
+        this.getDocument_().execCommand('Delete', false, true);
+      }
+
+      if (needsFormatBlockDiv) {
+        this.getDocument_().execCommand('FormatBlock', false, '<div>');
+      }
+  }
+  // FF loses focus, so we have to set the focus back to the document or the
+  // user can't type after selecting from menu.  In IE, focus is set correctly
+  // and resetting it here messes it up.
+  if (goog.userAgent.GECKO && !this.getFieldObject().inModalMode()) {
+    this.focusField_();
+  }
+  return result;
+};
+
+
+/**
+ * Focuses on the field.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.focusField_ = function() {
+  this.getFieldDomHelper().getWindow().focus();
+};
+
+
+/**
+ * Gets the command value.
+ * @param {string} command The command value to get.
+ * @return {string|boolean|null} The current value of the command in the given
+ *     selection.  NOTE: This return type list is not documented in MSDN or MDC
+ *     and has been constructed from experience.  Please update it
+ *     if necessary.
+ * @override
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.queryCommandValue = function(
+    command) {
+  var styleWithCss;
+  switch (command) {
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.LINK:
+      return this.isNodeInState_(goog.dom.TagName.A);
+
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.JUSTIFY_CENTER:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.JUSTIFY_FULL:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.JUSTIFY_RIGHT:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.JUSTIFY_LEFT:
+      return this.isJustification_(command);
+
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.FORMAT_BLOCK:
+      // TODO(nicksantos): See if we can use queryCommandValue here.
+      return goog.editor.plugins.BasicTextFormatter.getSelectionBlockState_(
+          this.getFieldObject().getRange());
+
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.INDENT:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.OUTDENT:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.HORIZONTAL_RULE:
+      // TODO: See if there are reasonable results to return for
+      // these commands.
+      return false;
+
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.FONT_SIZE:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.FONT_FACE:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.FONT_COLOR:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.BACKGROUND_COLOR:
+      // We use queryCommandValue here since we don't just want to know if a
+      // color/fontface/fontsize is applied, we want to know WHICH one it is.
+      return this.queryCommandValueInternal_(this.getDocument_(), command,
+          goog.editor.BrowserFeature.HAS_STYLE_WITH_CSS &&
+          goog.userAgent.GECKO);
+
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.UNDERLINE:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.BOLD:
+    case goog.editor.plugins.BasicTextFormatter.COMMAND.ITALIC:
+      styleWithCss = goog.editor.BrowserFeature.HAS_STYLE_WITH_CSS &&
+                     goog.userAgent.GECKO;
+
+    default:
+      /**
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.STRIKE_THROUGH
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.SUBSCRIPT
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.SUPERSCRIPT
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.UNDERLINE
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.BOLD
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.ITALIC
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.ORDERED_LIST
+       * goog.editor.plugins.BasicTextFormatter.COMMAND.UNORDERED_LIST
+       */
+      // This only works for commands that use the default execCommand
+      return this.queryCommandStateInternal_(this.getDocument_(), command,
+          styleWithCss);
+  }
+};
+
+
+/**
+ * @override
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.prepareContentsHtml =
+    function(html) {
+  // If the browser collapses empty nodes and the field has only a script
+  // tag in it, then it will collapse this node. Which will mean the user
+  // can't click into it to edit it.
+  if (goog.editor.BrowserFeature.COLLAPSES_EMPTY_NODES &&
+      html.match(/^\s*<script/i)) {
+    html = '&nbsp;' + html;
+  }
+
+  if (goog.editor.BrowserFeature.CONVERT_TO_B_AND_I_TAGS) {
+    // Some browsers (FF) can't undo strong/em in some cases, but can undo b/i!
+    html = html.replace(/<(\/?)strong([^\w])/gi, '<$1b$2');
+    html = html.replace(/<(\/?)em([^\w])/gi, '<$1i$2');
+  }
+
+  return html;
+};
+
+
+/**
+ * @override
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.cleanContentsDom =
+    function(fieldCopy) {
+  var images = fieldCopy.getElementsByTagName(goog.dom.TagName.IMG);
+  for (var i = 0, image; image = images[i]; i++) {
+    if (goog.editor.BrowserFeature.SHOWS_CUSTOM_ATTRS_IN_INNER_HTML) {
+      // Only need to remove these attributes in IE because
+      // Firefox and Safari don't show custom attributes in the innerHTML.
+      image.removeAttribute('tabIndex');
+      image.removeAttribute('tabIndexSet');
+      goog.removeUid(image);
+
+      // Declare oldTypeIndex for the compiler. The associated plugin may not be
+      // included in the compiled bundle.
+      /** @type {string} */ image.oldTabIndex;
+
+      // oldTabIndex will only be set if
+      // goog.editor.BrowserFeature.TABS_THROUGH_IMAGES is true and we're in
+      // P-on-enter mode.
+      if (image.oldTabIndex) {
+        image.tabIndex = image.oldTabIndex;
+      }
+    }
+  }
+};
+
+
+/**
+ * @override
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.cleanContentsHtml =
+    function(html) {
+  if (goog.editor.BrowserFeature.MOVES_STYLE_TO_HEAD) {
+    // Safari creates a new <head> element for <style> tags, so prepend their
+    // contents to the output.
+    var heads = this.getFieldObject().getEditableDomHelper().
+        getElementsByTagNameAndClass(goog.dom.TagName.HEAD);
+    var stylesHtmlArr = [];
+
+    // i starts at 1 so we don't copy in the original, legitimate <head>.
+    var numHeads = heads.length;
+    for (var i = 1; i < numHeads; ++i) {
+      var styles = heads[i].getElementsByTagName(goog.dom.TagName.STYLE);
+      var numStyles = styles.length;
+      for (var j = 0; j < numStyles; ++j) {
+        stylesHtmlArr.push(styles[j].outerHTML);
+      }
+    }
+    return stylesHtmlArr.join('') + html;
+  }
+
+  return html;
+};
+
+
+/**
+ * @override
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.handleKeyboardShortcut =
+    function(e, key, isModifierPressed) {
+  if (!isModifierPressed) {
+    return false;
+  }
+  var command;
+  switch (key) {
+    case 'b': // Ctrl+B
+      command = goog.editor.plugins.BasicTextFormatter.COMMAND.BOLD;
+      break;
+    case 'i': // Ctrl+I
+      command = goog.editor.plugins.BasicTextFormatter.COMMAND.ITALIC;
+      break;
+    case 'u': // Ctrl+U
+      command = goog.editor.plugins.BasicTextFormatter.COMMAND.UNDERLINE;
+      break;
+    case 's': // Ctrl+S
+      // TODO(user): This doesn't belong in here.  Clients should handle
+      // this themselves.
+      // Catching control + s prevents the annoying browser save dialog
+      // from appearing.
+      return true;
+  }
+
+  if (command) {
+    this.getFieldObject().execCommand(command);
+    return true;
+  }
+
+  return false;
+};
+
+
+// Helpers for execCommand
+
+
+/**
+ * Regular expression to match BRs in HTML. Saves the BRs' attributes in $1 for
+ * use with replace(). In non-IE browsers, does not match BRs adjacent to an
+ * opening or closing DIV or P tag, since nonrendered BR elements can occur at
+ * the end of block level containers in those browsers' editors.
+ * @type {RegExp}
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.BR_REGEXP_ =
+    goog.userAgent.IE ? /<br([^\/>]*)\/?>/gi :
+                        /<br([^\/>]*)\/?>(?!<\/(div|p)>)/gi;
+
+
+/**
+ * Convert BRs in the selection to divs.
+ * This is only intended to be used in IE and Opera.
+ * @return {boolean} Whether any BR's were converted.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.convertBreaksToDivs_ =
+    function() {
+  if (!goog.userAgent.IE && !goog.userAgent.OPERA) {
+    // This function is only supported on IE and Opera.
+    return false;
+  }
+  var range = this.getRange_();
+  var parent = range.getContainerElement();
+  var doc = this.getDocument_();
+
+  goog.editor.plugins.BasicTextFormatter.BR_REGEXP_.lastIndex = 0;
+  // Only mess with the HTML/selection if it contains a BR.
+  if (goog.editor.plugins.BasicTextFormatter.BR_REGEXP_.test(
+      parent.innerHTML)) {
+    // Insert temporary markers to remember the selection.
+    var savedRange = range.saveUsingCarets();
+
+    if (parent.tagName == goog.dom.TagName.P) {
+      // Can't append paragraphs to paragraph tags. Throws an exception in IE.
+      goog.editor.plugins.BasicTextFormatter.convertParagraphToDiv_(
+          parent, true);
+    } else {
+      // Used to do:
+      // IE: <div>foo<br>bar</div> --> <div>foo<p id="temp_br">bar</div>
+      // Opera: <div>foo<br>bar</div> --> <div>foo<p class="temp_br">bar</div>
+      // To fix bug 1939883, now does for both:
+      // <div>foo<br>bar</div> --> <div>foo<p trtempbr="temp_br">bar</div>
+      // TODO(user): Confirm if there's any way to skip this
+      // intermediate step of converting br's to p's before converting those to
+      // div's. The reason may be hidden in CLs 5332866 and 8530601.
+      var attribute = 'trtempbr';
+      var value = 'temp_br';
+      var newHtml = parent.innerHTML.replace(
+          goog.editor.plugins.BasicTextFormatter.BR_REGEXP_,
+          '<p$1 ' + attribute + '="' + value + '">');
+      goog.editor.node.replaceInnerHtml(parent, newHtml);
+
+      var paragraphs =
+          goog.array.toArray(parent.getElementsByTagName(goog.dom.TagName.P));
+      goog.iter.forEach(paragraphs, function(paragraph) {
+        if (paragraph.getAttribute(attribute) == value) {
+          paragraph.removeAttribute(attribute);
+          if (goog.string.isBreakingWhitespace(
+              goog.dom.getTextContent(paragraph))) {
+            // Prevent the empty blocks from collapsing.
+            // A <BR> is preferable because it doesn't result in any text being
+            // added to the "blank" line. In IE, however, it is possible to
+            // place the caret after the <br>, which effectively creates a
+            // visible line break. Because of this, we have to resort to using a
+            // &nbsp; in IE.
+            var child = goog.userAgent.IE ?
+                doc.createTextNode(goog.string.Unicode.NBSP) :
+                doc.createElement(goog.dom.TagName.BR);
+            paragraph.appendChild(child);
+          }
+          goog.editor.plugins.BasicTextFormatter.convertParagraphToDiv_(
+              paragraph);
+        }
+      });
+    }
+
+    // Select the previously selected text so we only listify
+    // the selected portion and maintain the user's selection.
+    savedRange.restore();
+    return true;
+  }
+
+  return false;
+};
+
+
+/**
+ * Convert the given paragraph to being a div. This clobbers the
+ * passed-in node!
+ * This is only intended to be used in IE and Opera.
+ * @param {Node} paragraph Paragragh to convert to a div.
+ * @param {boolean=} opt_convertBrs If true, also convert BRs to divs.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.convertParagraphToDiv_ =
+    function(paragraph, opt_convertBrs) {
+  if (!goog.userAgent.IE && !goog.userAgent.OPERA) {
+    // This function is only supported on IE and Opera.
+    return;
+  }
+  var outerHTML = paragraph.outerHTML.replace(/<(\/?)p/gi, '<$1div');
+  if (opt_convertBrs) {
+    // IE fills in the closing div tag if it's missing!
+    outerHTML = outerHTML.replace(
+        goog.editor.plugins.BasicTextFormatter.BR_REGEXP_,
+        '</div><div$1>');
+  }
+  if (goog.userAgent.OPERA && !/<\/div>$/i.test(outerHTML)) {
+    // Opera doesn't automatically add the closing tag, so add it if needed.
+    outerHTML += '</div>';
+  }
+  paragraph.outerHTML = outerHTML;
+};
+
+
+/**
+ * If this is a goog.editor.plugins.BasicTextFormatter.COMMAND,
+ * convert it to something that we can pass into execCommand,
+ * queryCommandState, etc.
+ *
+ * TODO(user): Consider doing away with the + and converter completely.
+ *
+ * @param {goog.editor.plugins.BasicTextFormatter.COMMAND|string}
+ *     command A command key.
+ * @return {string} The equivalent execCommand command.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.convertToRealExecCommand_ = function(
+    command) {
+  return command.indexOf('+') == 0 ? command.substring(1) : command;
+};
+
+
+/**
+ * Justify the text in the selection.
+ * @param {string} command The type of justification to perform.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.justify_ = function(command) {
+  this.execCommandHelper_(command, null, false, true);
+  // Firefox cannot justify divs.  In fact, justifying divs results in removing
+  // the divs and replacing them with brs.  So "<div>foo</div><div>bar</div>"
+  // becomes "foo<br>bar" after alignment is applied.  However, if you justify
+  // again, then you get "<div style='text-align: right'>foo<br>bar</div>",
+  // which at least looks visually correct.  Since justification is (normally)
+  // idempotent, it isn't a problem when the selection does not contain divs to
+  // apply justifcation again.
+  if (goog.userAgent.GECKO) {
+    this.execCommandHelper_(command, null, false, true);
+  }
+
+  // Convert all block elements in the selection to use CSS text-align
+  // instead of the align property. This works better because the align
+  // property is overridden by the CSS text-align property.
+  //
+  // Only for browsers that can't handle this by the styleWithCSS execCommand,
+  // which allows us to specify if we should insert align or text-align.
+  // TODO(user): What about WebKit or Opera?
+  if (!(goog.editor.BrowserFeature.HAS_STYLE_WITH_CSS &&
+        goog.userAgent.GECKO)) {
+    goog.iter.forEach(this.getFieldObject().getRange(),
+        goog.editor.plugins.BasicTextFormatter.convertContainerToTextAlign_);
+  }
+};
+
+
+/**
+ * Converts the block element containing the given node to use CSS text-align
+ * instead of the align property.
+ * @param {Node} node The node to convert the container of.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.convertContainerToTextAlign_ =
+    function(node) {
+  var container = goog.editor.style.getContainer(node);
+
+  // TODO(user): Fix this so that it doesn't screw up tables.
+  if (container.align) {
+    container.style.textAlign = container.align;
+    container.removeAttribute('align');
+  }
+};
+
+
+/**
+ * Perform an execCommand on the active document.
+ * @param {string} command The command to execute.
+ * @param {string|number|boolean|null=} opt_value Optional value.
+ * @param {boolean=} opt_preserveDir Set true to make sure that command does not
+ *     change directionality of the selected text (works only if all selected
+ *     text has the same directionality, otherwise ignored). Should not be true
+ *     if bidi plugin is not loaded.
+ * @param {boolean=} opt_styleWithCss Set to true to ask the browser to use CSS
+ *     to perform the execCommand.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.execCommandHelper_ = function(
+    command, opt_value, opt_preserveDir, opt_styleWithCss) {
+  // There is a bug in FF: some commands do not preserve attributes of the
+  // block-level elements they replace.
+  // This (among the rest) leads to loss of directionality information.
+  // For now we use a hack (when opt_preserveDir==true) to avoid this
+  // directionality problem in the simplest cases.
+  // Known affected commands: formatBlock, insertOrderedList,
+  // insertUnorderedList, indent, outdent.
+  // A similar problem occurs in IE when insertOrderedList or
+  // insertUnorderedList remove existing list.
+  var dir = null;
+  if (opt_preserveDir) {
+    dir =
+        this.getFieldObject().queryCommandValue(
+            goog.editor.Command.DIR_RTL) ? 'rtl' :
+        this.getFieldObject().queryCommandValue(
+            goog.editor.Command.DIR_LTR) ? 'ltr' :
+        null;
+  }
+
+  command = goog.editor.plugins.BasicTextFormatter.convertToRealExecCommand_(
+      command);
+
+  var endDiv, nbsp;
+  if (goog.userAgent.IE) {
+    var ret = this.applyExecCommandIEFixes_(command);
+    endDiv = ret[0];
+    nbsp = ret[1];
+  }
+
+  if (goog.userAgent.WEBKIT) {
+    endDiv = this.applyExecCommandSafariFixes_(command);
+  }
+
+  if (goog.userAgent.GECKO) {
+    this.applyExecCommandGeckoFixes_(command);
+  }
+
+  if (goog.editor.BrowserFeature.DOESNT_OVERRIDE_FONT_SIZE_IN_STYLE_ATTR &&
+      command.toLowerCase() == 'fontsize') {
+    this.removeFontSizeFromStyleAttrs_();
+  }
+
+  var doc = this.getDocument_();
+  if (opt_styleWithCss &&
+      goog.editor.BrowserFeature.HAS_STYLE_WITH_CSS) {
+    doc.execCommand('styleWithCSS', false, true);
+    if (goog.userAgent.OPERA) {
+      this.invalidateInlineCss_();
+    }
+  }
+
+  doc.execCommand(command, false, opt_value);
+  if (opt_styleWithCss &&
+      goog.editor.BrowserFeature.HAS_STYLE_WITH_CSS) {
+    // If we enabled styleWithCSS, turn it back off.
+    doc.execCommand('styleWithCSS', false, false);
+  }
+
+  if (goog.userAgent.WEBKIT &&
+      !goog.userAgent.isVersionOrHigher('526') &&
+      command.toLowerCase() == 'formatblock' &&
+      opt_value && /^[<]?h\d[>]?$/i.test(opt_value)) {
+    this.cleanUpSafariHeadings_();
+  }
+
+  if (/insert(un)?orderedlist/i.test(command)) {
+    // NOTE(user): This doesn't check queryCommandState because it seems to
+    // lie. Also, this runs for insertunorderedlist so that the the list
+    // isn't made up of an <ul> for each <li> - even though it looks the same,
+    // the markup is disgusting.
+    if (goog.userAgent.WEBKIT &&
+        !goog.userAgent.isVersionOrHigher(534)) {
+      this.fixSafariLists_();
+    }
+    if (goog.userAgent.IE) {
+      this.fixIELists_();
+
+      if (nbsp) {
+        // Remove the text node, if applicable.  Do not try to instead clobber
+        // the contents of the text node if it was added, or the same invalid
+        // node thing as above will happen.  The error won't happen here, it
+        // will happen after you hit enter and then do anything that loops
+        // through the dom and tries to read that node.
+        goog.dom.removeNode(nbsp);
+      }
+    }
+  }
+
+  if (endDiv) {
+    // Remove the dummy div.
+    goog.dom.removeNode(endDiv);
+  }
+
+  // Restore directionality if required and only when unambigous (dir!=null).
+  if (dir) {
+    this.getFieldObject().execCommand(dir);
+  }
+};
+
+
+/**
+ * Applies a background color to a selection when the browser can't do the job.
+ *
+ * NOTE(nicksantos): If you think this is hacky, you should try applying
+ * background color in Opera. It made me cry.
+ *
+ * @param {string} bgColor backgroundColor from .formatText to .execCommand.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.applyBgColorManually_ =
+    function(bgColor) {
+  var needsSpaceInTextNode = goog.userAgent.GECKO;
+  var range = this.getFieldObject().getRange();
+  var textNode;
+  var parentTag;
+  if (range && range.isCollapsed()) {
+    // Hack to handle Firefox bug:
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=279330
+    // execCommand hiliteColor in Firefox on collapsed selection creates
+    // a font tag onkeypress
+    textNode = this.getFieldDomHelper().
+        createTextNode(needsSpaceInTextNode ? ' ' : '');
+
+    var containerNode = range.getStartNode();
+    // Check if we're inside a tag that contains the cursor and nothing else;
+    // if we are, don't create a dummySpan. Just use this containing tag to
+    // hide the 1-space selection.
+    // If the user sets a background color on a collapsed selection, then sets
+    // another one immediately, we get a span tag with a single empty TextNode.
+    // If the user sets a background color, types, then backspaces, we get a
+    // span tag with nothing inside it (container is the span).
+    parentTag = containerNode.nodeType == goog.dom.NodeType.ELEMENT ?
+        containerNode : containerNode.parentNode;
+
+    if (parentTag.innerHTML == '') {
+      // There's an Element to work with
+      // make the space character invisible using a CSS indent hack
+      parentTag.style.textIndent = '-10000px';
+      parentTag.appendChild(textNode);
+    } else {
+      // No Element to work with; make one
+      // create a span with a space character inside
+      // make the space character invisible using a CSS indent hack
+      parentTag = this.getFieldDomHelper().createDom(goog.dom.TagName.SPAN,
+          {'style': 'text-indent:-10000px'}, textNode);
+      range.replaceContentsWithNode(parentTag);
+    }
+    goog.dom.Range.createFromNodeContents(textNode).select();
+  }
+
+  this.execCommandHelper_('hiliteColor', bgColor, false, true);
+
+  if (textNode) {
+    // eliminate the space if necessary.
+    if (needsSpaceInTextNode) {
+      textNode.data = '';
+    }
+
+    // eliminate the hack.
+    parentTag.style.textIndent = '';
+    // execCommand modified our span so we leave it in place.
+  }
+};
+
+
+/**
+ * Toggle link for the current selection:
+ *   If selection contains a link, unlink it, return null.
+ *   Otherwise, make selection into a link, return the link.
+ * @param {string=} opt_target Target for the link.
+ * @return {goog.editor.Link?} The resulting link, or null if a link was
+ *     removed.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.toggleLink_ = function(
+    opt_target) {
+  if (!this.getFieldObject().isSelectionEditable()) {
+    this.focusField_();
+  }
+
+  var range = this.getRange_();
+  // Since we wrap images in links, its possible that the user selected an
+  // image and clicked link, in which case we want to actually use the
+  // image as the selection.
+  var parent = range && range.getContainerElement();
+  var link = /** @type {Element} */ (
+      goog.dom.getAncestorByTagNameAndClass(parent, goog.dom.TagName.A));
+  if (link && goog.editor.node.isEditable(link)) {
+    goog.dom.flattenElement(link);
+  } else {
+    var editableLink = this.createLink_(range, '/', opt_target);
+    if (editableLink) {
+      if (!this.getFieldObject().execCommand(
+          goog.editor.Command.MODAL_LINK_EDITOR, editableLink)) {
+        var url = this.getFieldObject().getAppWindow().prompt(
+            goog.ui.editor.messages.MSG_LINK_TO, 'http://');
+        if (url) {
+          editableLink.setTextAndUrl(editableLink.getCurrentText() || url, url);
+          editableLink.placeCursorRightOf();
+        } else {
+          var savedRange = goog.editor.range.saveUsingNormalizedCarets(
+              goog.dom.Range.createFromNodeContents(editableLink.getAnchor()));
+          editableLink.removeLink();
+          savedRange.restore().select();
+          return null;
+        }
+      }
+      return editableLink;
+    }
+  }
+  return null;
+};
+
+
+/**
+ * Create a link out of the current selection.  If nothing is selected, insert
+ * a new link.  Otherwise, enclose the selection in a link.
+ * @param {goog.dom.AbstractRange} range The closure range object for the
+ *     current selection.
+ * @param {string} url The url to link to.
+ * @param {string=} opt_target Target for the link.
+ * @return {goog.editor.Link?} The newly created link, or null if the link
+ *     couldn't be created.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.createLink_ = function(range,
+    url, opt_target) {
+  var anchor = null;
+  var anchors = [];
+  var parent = range && range.getContainerElement();
+  // We do not yet support creating links around images.  Instead of throwing
+  // lots of js errors, just fail silently.
+  // TODO(user): Add support for linking images.
+  if (parent && parent.tagName == goog.dom.TagName.IMG) {
+    return null;
+  }
+  // If range is not present, the editable field doesn't have focus, abort
+  // creating a link.
+  if (!range) {
+    return null;
+  }
+
+  if (range.isCollapsed()) {
+    var textRange = range.getTextRange(0).getBrowserRangeObject();
+    if (goog.editor.BrowserFeature.HAS_W3C_RANGES) {
+      anchor = this.getFieldDomHelper().createElement(goog.dom.TagName.A);
+      textRange.insertNode(anchor);
+    } else if (goog.editor.BrowserFeature.HAS_IE_RANGES) {
+      // TODO: Use goog.dom.AbstractRange's surroundContents
+      textRange.pasteHTML("<a id='newLink'></a>");
+      anchor = this.getFieldDomHelper().getElement('newLink');
+      anchor.removeAttribute('id');
+    }
+  } else {
+    // Create a unique identifier for the link so we can retrieve it later.
+    // execCommand doesn't return the link to us, and we need a way to find
+    // the newly created link in the dom, and the url is the only property
+    // we have control over, so we set that to be unique and then find it.
+    var uniqueId = goog.string.createUniqueString();
+    this.execCommandHelper_('CreateLink', uniqueId);
+    var setHrefAndLink = function(element, index, arr) {
+      // We can't do straight comparision since the href can contain the
+      // absolute url.
+      if (goog.string.endsWith(element.href, uniqueId)) {
+        anchors.push(element);
+      }
+    };
+
+    goog.array.forEach(this.getFieldObject().getElement().getElementsByTagName(
+        goog.dom.TagName.A), setHrefAndLink);
+    if (anchors.length) {
+      anchor = anchors.pop();
+    }
+    var isLikelyUrl = function(a, i, anchors) {
+      return goog.editor.Link.isLikelyUrl(goog.dom.getRawTextContent(a));
+    };
+    if (anchors.length && goog.array.every(anchors, isLikelyUrl)) {
+      for (var i = 0, a; a = anchors[i]; i++) {
+        goog.editor.Link.createNewLinkFromText(a, opt_target);
+      }
+      anchors = null;
+    }
+  }
+
+  return goog.editor.Link.createNewLink(
+      /** @type {HTMLAnchorElement} */ (anchor), url, opt_target, anchors);
+};
+
+
+//---------------------------------------------------------------------
+// browser fixes
+
+
+/**
+ * The following execCommands are "broken" in some way - in IE they allow
+ * the nodes outside the contentEditable region to get modified (see
+ * execCommand below for more details).
+ * @const
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.brokenExecCommandsIE_ = {
+  'indent' : 1,
+  'outdent' : 1,
+  'insertOrderedList' : 1,
+  'insertUnorderedList' : 1,
+  'justifyCenter' : 1,
+  'justifyFull' : 1,
+  'justifyRight': 1,
+  'justifyLeft': 1,
+  'ltr' : 1,
+  'rtl' : 1
+};
+
+
+/**
+ * When the following commands are executed while the selection is
+ * inside a blockquote, they hose the blockquote tag in weird and
+ * unintuitive ways.
+ * @const
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.blockquoteHatingCommandsIE_ = {
+  'insertOrderedList' : 1,
+  'insertUnorderedList' : 1
+};
+
+
+/**
+ * Makes sure that superscript is removed before applying subscript, and vice
+ * versa. Fixes {@link http://buganizer/issue?id=1173491} .
+ * @param {goog.editor.plugins.BasicTextFormatter.COMMAND} command The command
+ *     being applied, either SUBSCRIPT or SUPERSCRIPT.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.
+    prototype.applySubscriptSuperscriptWorkarounds_ = function(command) {
+  if (!this.queryCommandValue(command)) {
+    // The current selection doesn't currently have the requested
+    // command, so we are applying it as opposed to removing it.
+    // (Note that queryCommandValue() will only return true if the
+    // command is applied to the whole selection, not just part of it.
+    // In this case it is fine because only if the whole selection has
+    // the command applied will we be removing it and thus skipping the
+    // removal of the opposite command.)
+    var oppositeCommand =
+        (command == goog.editor.plugins.BasicTextFormatter.COMMAND.SUBSCRIPT ?
+            goog.editor.plugins.BasicTextFormatter.COMMAND.SUPERSCRIPT :
+            goog.editor.plugins.BasicTextFormatter.COMMAND.SUBSCRIPT);
+    var oppositeExecCommand = goog.editor.plugins.BasicTextFormatter.
+        convertToRealExecCommand_(oppositeCommand);
+    // Executing the opposite command on a selection that already has it
+    // applied will cancel it out. But if the selection only has the
+    // opposite command applied to a part of it, the browser will
+    // normalize the selection to have the opposite command applied on
+    // the whole of it.
+    if (!this.queryCommandValue(oppositeCommand)) {
+      // The selection doesn't have the opposite command applied to the
+      // whole of it, so let's exec the opposite command to normalize
+      // the selection.
+      // Note: since we know both subscript and superscript commands
+      // will boil down to a simple call to the browser's execCommand(),
+      // for performance reasons we can do that directly instead of
+      // calling execCommandHelper_(). However this is a potential for
+      // bugs if the implementation of execCommandHelper_() is changed
+      // to do something more int eh case of subscript and superscript.
+      this.getDocument_().execCommand(oppositeExecCommand, false, null);
+    }
+    // Now that we know the whole selection has the opposite command
+    // applied, we exec it a second time to properly remove it.
+    this.getDocument_().execCommand(oppositeExecCommand, false, null);
+  }
+};
+
+
+/**
+ * Removes inline font-size styles from elements fully contained in the
+ * selection, so the font tags produced by execCommand work properly.
+ * See {@bug 1286408}.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.removeFontSizeFromStyleAttrs_ =
+    function() {
+  // Expand the range so that we consider surrounding tags. E.g. if only the
+  // text node inside a span is selected, the browser could wrap a font tag
+  // around the span and leave the selection such that only the text node is
+  // found when looking inside the range, not the span.
+  var range = goog.editor.range.expand(this.getFieldObject().getRange(),
+                                       this.getFieldObject().getElement());
+  goog.iter.forEach(goog.iter.filter(range, function(tag, dummy, iter) {
+    return iter.isStartTag() && range.containsNode(tag);
+  }), function(node) {
+    goog.style.setStyle(node, 'font-size', '');
+    // Gecko doesn't remove empty style tags.
+    if (goog.userAgent.GECKO &&
+        node.style.length == 0 && node.getAttribute('style') != null) {
+      node.removeAttribute('style');
+    }
+  });
+};
+
+
+/**
+ * Apply pre-execCommand fixes for IE.
+ * @param {string} command The command to execute.
+ * @return {!Array<Node>} Array of nodes to be removed after the execCommand.
+ *     Will never be longer than 2 elements.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.applyExecCommandIEFixes_ =
+    function(command) {
+  // IE has a crazy bug where executing list commands
+  // around blockquotes cause the blockquotes to get transformed
+  // into "<OL><OL>" or "<UL><UL>" tags.
+  var toRemove = [];
+  var endDiv = null;
+  var range = this.getRange_();
+  var dh = this.getFieldDomHelper();
+  if (command in
+      goog.editor.plugins.BasicTextFormatter.blockquoteHatingCommandsIE_) {
+    var parent = range && range.getContainerElement();
+    if (parent) {
+      var blockquotes = goog.dom.getElementsByTagNameAndClass(
+          goog.dom.TagName.BLOCKQUOTE, null, parent);
+
+      // If a blockquote contains the selection, the fix is easy:
+      // add a dummy div to the blockquote that isn't in the current selection.
+      //
+      // if the selection contains a blockquote,
+      // there appears to be no easy way to protect it from getting mangled.
+      // For now, we're just going to punt on this and try to
+      // adjust the selection so that IE does something reasonable.
+      //
+      // TODO(nicksantos): Find a better fix for this.
+      var bq;
+      for (var i = 0; i < blockquotes.length; i++) {
+        if (range.containsNode(blockquotes[i])) {
+          bq = blockquotes[i];
+          break;
+        }
+      }
+
+      var bqThatNeedsDummyDiv = bq || goog.dom.getAncestorByTagNameAndClass(
+          parent, goog.dom.TagName.BLOCKQUOTE);
+      if (bqThatNeedsDummyDiv) {
+        endDiv = dh.createDom(goog.dom.TagName.DIV, {style: 'height:0'});
+        goog.dom.appendChild(bqThatNeedsDummyDiv, endDiv);
+        toRemove.push(endDiv);
+
+        if (bq) {
+          range = goog.dom.Range.createFromNodes(bq, 0, endDiv, 0);
+        } else if (range.containsNode(endDiv)) {
+          // the selection might be the entire blockquote, and
+          // it's important that endDiv not be in the selection.
+          range = goog.dom.Range.createFromNodes(
+              range.getStartNode(), range.getStartOffset(),
+              endDiv, 0);
+        }
+        range.select();
+      }
+    }
+  }
+
+  // IE has a crazy bug where certain block execCommands cause it to mess with
+  // the DOM nodes above the contentEditable element if the selection contains
+  // or partially contains the last block element in the contentEditable
+  // element.
+  // Known commands: Indent, outdent, insertorderedlist, insertunorderedlist,
+  // Justify (all of them)
+
+  // Both of the above are "solved" by appending a dummy div to the field
+  // before the execCommand and removing it after, but we don't need to do this
+  // if we've alread added a dummy div somewhere else.
+  var fieldObject = this.getFieldObject();
+  if (!fieldObject.usesIframe() && !endDiv) {
+    if (command in
+        goog.editor.plugins.BasicTextFormatter.brokenExecCommandsIE_) {
+      var field = fieldObject.getElement();
+
+      // If the field is totally empty, or if the field contains only text nodes
+      // and the cursor is at the end of the field, then IE stills walks outside
+      // the contentEditable region and destroys things AND justify will not
+      // work. This is "solved" by adding a text node into the end of the
+      // field and moving the cursor before it.
+      if (range && range.isCollapsed() &&
+          !goog.dom.getFirstElementChild(field)) {
+        // The problem only occurs if the selection is at the end of the field.
+        var selection = range.getTextRange(0).getBrowserRangeObject();
+        var testRange = selection.duplicate();
+        testRange.moveToElementText(field);
+        testRange.collapse(false);
+
+        if (testRange.isEqual(selection)) {
+          // For reasons I really don't understand, if you use a breaking space
+          // here, either " " or String.fromCharCode(32), this textNode becomes
+          // corrupted, only after you hit ENTER to split it.  It exists in the
+          // dom in that its parent has it as childNode and the parent's
+          // innerText is correct, but the node itself throws invalid argument
+          // errors when you try to access its data, parentNode, nextSibling,
+          // previousSibling or most other properties.  WTF.
+          var nbsp = dh.createTextNode(goog.string.Unicode.NBSP);
+          field.appendChild(nbsp);
+          selection.move('character', 1);
+          selection.move('character', -1);
+          selection.select();
+          toRemove.push(nbsp);
+        }
+      }
+
+      endDiv = dh.createDom(goog.dom.TagName.DIV, {style: 'height:0'});
+      goog.dom.appendChild(field, endDiv);
+      toRemove.push(endDiv);
+    }
+  }
+
+  return toRemove;
+};
+
+
+/**
+ * Fix a ridiculous Safari bug: the first letters of new headings
+ * somehow retain their original font size and weight if multiple lines are
+ * selected during the execCommand that turns them into headings.
+ * The solution is to strip these styles which are normally stripped when
+ * making things headings anyway.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.cleanUpSafariHeadings_ =
+    function() {
+  goog.iter.forEach(this.getRange_(), function(node) {
+    if (node.className == 'Apple-style-span') {
+      // These shouldn't persist after creating headings via
+      // a FormatBlock execCommand.
+      node.style.fontSize = '';
+      node.style.fontWeight = '';
+    }
+  });
+};
+
+
+/**
+ * Prevent Safari from making each list item be "1" when converting from
+ * unordered to ordered lists.
+ * (see https://bugs.webkit.org/show_bug.cgi?id=19539, fixed by 2010-04-21)
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.fixSafariLists_ = function() {
+  var previousList = false;
+  goog.iter.forEach(this.getRange_(), function(node) {
+    var tagName = node.tagName;
+    if (tagName == goog.dom.TagName.UL || tagName == goog.dom.TagName.OL) {
+      // Don't disturb lists outside of the selection. If this is the first <ul>
+      // or <ol> in the range, we don't really want to merge the previous list
+      // into it, since that list isn't in the range.
+      if (!previousList) {
+        previousList = true;
+        return;
+      }
+      // The lists must be siblings to be merged; otherwise, indented sublists
+      // could be broken.
+      var previousElementSibling = goog.dom.getPreviousElementSibling(node);
+      if (!previousElementSibling) {
+        return;
+      }
+      // Make sure there isn't text between the two lists before they are merged
+      var range = node.ownerDocument.createRange();
+      range.setStartAfter(previousElementSibling);
+      range.setEndBefore(node);
+      if (!goog.string.isEmptyOrWhitespace(range.toString())) {
+        return;
+      }
+      // Make sure both are lists of the same type (ordered or unordered)
+      if (previousElementSibling.nodeName == node.nodeName) {
+        // We must merge the previous list into this one. Moving around
+        // the current node will break the iterator, so we can't merge
+        // this list into the previous one.
+        while (previousElementSibling.lastChild) {
+          node.insertBefore(previousElementSibling.lastChild, node.firstChild);
+        }
+        previousElementSibling.parentNode.removeChild(previousElementSibling);
+      }
+    }
+  });
+};
+
+
+/**
+ * Sane "type" attribute values for OL elements
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.orderedListTypes_ = {
+  '1' : 1,
+  'a' : 1,
+  'A' : 1,
+  'i' : 1,
+  'I' : 1
+};
+
+
+/**
+ * Sane "type" attribute values for UL elements
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.unorderedListTypes_ = {
+  'disc' : 1,
+  'circle' : 1,
+  'square' : 1
+};
+
+
+/**
+ * Changing an OL to a UL (or the other way around) will fail if the list
+ * has a type attribute (such as "UL type=disc" becoming "OL type=disc", which
+ * is visually identical). Most browsers will remove the type attribute
+ * automatically, but IE doesn't. This does it manually.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.fixIELists_ = function() {
+  // Find the lowest-level <ul> or <ol> that contains the entire range.
+  var range = this.getRange_();
+  var container = range && range.getContainer();
+  while (container &&
+         container.tagName != goog.dom.TagName.UL &&
+         container.tagName != goog.dom.TagName.OL) {
+    container = container.parentNode;
+  }
+  if (container) {
+    // We want the parent node of the list so that we can grab it using
+    // getElementsByTagName
+    container = container.parentNode;
+  }
+  if (!container) return;
+  var lists = goog.array.toArray(
+      container.getElementsByTagName(goog.dom.TagName.UL));
+  goog.array.extend(lists, goog.array.toArray(
+      container.getElementsByTagName(goog.dom.TagName.OL)));
+  // Fix the lists
+  goog.array.forEach(lists, function(node) {
+    var type = node.type;
+    if (type) {
+      var saneTypes =
+          (node.tagName == goog.dom.TagName.UL ?
+              goog.editor.plugins.BasicTextFormatter.unorderedListTypes_ :
+              goog.editor.plugins.BasicTextFormatter.orderedListTypes_);
+      if (!saneTypes[type]) {
+        node.type = '';
+      }
+    }
+  });
+};
+
+
+/**
+ * In WebKit, the following commands will modify the node with
+ * contentEditable=true if there are no block-level elements.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.brokenExecCommandsSafari_ = {
+  'justifyCenter' : 1,
+  'justifyFull' : 1,
+  'justifyRight': 1,
+  'justifyLeft': 1,
+  'formatBlock' : 1
+};
+
+
+/**
+ * In WebKit, the following commands can hang the browser if the selection
+ * touches the beginning of the field.
+ * https://bugs.webkit.org/show_bug.cgi?id=19735
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.hangingExecCommandWebkit_ = {
+  'insertOrderedList': 1,
+  'insertUnorderedList': 1
+};
+
+
+/**
+ * Apply pre-execCommand fixes for Safari.
+ * @param {string} command The command to execute.
+ * @return {!Element|undefined} The div added to the field.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.applyExecCommandSafariFixes_ =
+    function(command) {
+  // See the comment on brokenExecCommandsSafari_
+  var div;
+  if (goog.editor.plugins.BasicTextFormatter.
+      brokenExecCommandsSafari_[command]) {
+    // Add a new div at the end of the field.
+    // Safari knows that it would be wrong to apply text-align to the
+    // contentEditable element if there are non-empty block nodes in the field,
+    // because then it would align them too. So in this case, it will
+    // enclose the current selection in a block node.
+    div = this.getFieldDomHelper().createDom(
+        goog.dom.TagName.DIV, {'style': 'height: 0'}, 'x');
+    goog.dom.appendChild(this.getFieldObject().getElement(), div);
+  }
+
+  if (!goog.userAgent.isVersionOrHigher(534) &&
+      goog.editor.plugins.BasicTextFormatter.
+          hangingExecCommandWebkit_[command]) {
+    // Add a new div at the beginning of the field.
+    var field = this.getFieldObject().getElement();
+    div = this.getFieldDomHelper().createDom(
+        goog.dom.TagName.DIV, {'style': 'height: 0'}, 'x');
+    field.insertBefore(div, field.firstChild);
+  }
+
+  return div;
+};
+
+
+/**
+ * Apply pre-execCommand fixes for Gecko.
+ * @param {string} command The command to execute.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.applyExecCommandGeckoFixes_ =
+    function(command) {
+  if (goog.userAgent.isVersionOrHigher('1.9') &&
+      command.toLowerCase() == 'formatblock') {
+    // Firefox 3 and above throw a JS error for formatblock if the range is
+    // a child of the body node. Changing the selection to the BR fixes the
+    // problem.
+    // See https://bugzilla.mozilla.org/show_bug.cgi?id=481696
+    var range = this.getRange_();
+    var startNode = range.getStartNode();
+    if (range.isCollapsed() && startNode &&
+        startNode.tagName == goog.dom.TagName.BODY) {
+      var startOffset = range.getStartOffset();
+      var childNode = startNode.childNodes[startOffset];
+      if (childNode && childNode.tagName == goog.dom.TagName.BR) {
+        // Change the range using getBrowserRange() because goog.dom.TextRange
+        // will avoid setting <br>s directly.
+        // @see goog.dom.TextRange#createFromNodes
+        var browserRange = range.getBrowserRangeObject();
+        browserRange.setStart(childNode, 0);
+        browserRange.setEnd(childNode, 0);
+      }
+    }
+  }
+};
+
+
+/**
+ * Workaround for Opera bug CORE-23903. Opera sometimes fails to invalidate
+ * serialized CSS or innerHTML for the DOM after certain execCommands when
+ * styleWithCSS is on. Toggling an inline style on the elements fixes it.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.invalidateInlineCss_ =
+    function() {
+  var ancestors = [];
+  var ancestor = this.getFieldObject().getRange().getContainerElement();
+  do {
+    ancestors.push(ancestor);
+  } while (ancestor = ancestor.parentNode);
+  var nodesInSelection = goog.iter.chain(
+      goog.iter.toIterator(this.getFieldObject().getRange()),
+      goog.iter.toIterator(ancestors));
+  var containersInSelection =
+      goog.iter.filter(nodesInSelection, goog.editor.style.isContainer);
+  goog.iter.forEach(containersInSelection, function(element) {
+    var oldOutline = element.style.outline;
+    element.style.outline = '0px solid red';
+    element.style.outline = oldOutline;
+  });
+};
+
+
+/**
+ * Work around a Gecko bug that causes inserted lists to forget the current
+ * font. This affects WebKit in the same way and Opera in a slightly different
+ * way, but this workaround only works in Gecko.
+ * WebKit bug: https://bugs.webkit.org/show_bug.cgi?id=19653
+ * Mozilla bug: https://bugzilla.mozilla.org/show_bug.cgi?id=439966
+ * Opera bug: https://bugs.opera.com/show_bug.cgi?id=340392
+ * TODO: work around this issue in WebKit and Opera as well.
+ * @return {boolean} Whether the workaround was applied.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.beforeInsertListGecko_ =
+    function() {
+  var tag = this.getFieldObject().queryCommandValue(
+      goog.editor.Command.DEFAULT_TAG);
+  if (tag == goog.dom.TagName.P || tag == goog.dom.TagName.DIV) {
+    return false;
+  }
+
+  // Prevent Firefox from forgetting current formatting
+  // when creating a list.
+  // The bug happens with a collapsed selection, but it won't
+  // happen when text with the desired formatting is selected.
+  // So, we insert some dummy text, insert the list,
+  // then remove the dummy text (while preserving its formatting).
+  // (This formatting bug also affects WebKit, but this fix
+  // only seems to work in Firefox)
+  var range = this.getRange_();
+  if (range.isCollapsed() &&
+      (range.getContainer().nodeType != goog.dom.NodeType.TEXT)) {
+    var tempTextNode = this.getFieldDomHelper().
+        createTextNode(goog.string.Unicode.NBSP);
+    range.insertNode(tempTextNode, false);
+    goog.dom.Range.createFromNodeContents(tempTextNode).select();
+    return true;
+  }
+  return false;
+};
+
+
+// Helpers for queryCommandState
+
+
+/**
+ * Get the toolbar state for the block-level elements in the given range.
+ * @param {goog.dom.AbstractRange} range The range to get toolbar state for.
+ * @return {string?} The selection block state.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.getSelectionBlockState_ =
+    function(range) {
+  var tagName = null;
+  goog.iter.forEach(range, function(node, ignore, it) {
+    if (!it.isEndTag()) {
+      // Iterate over all containers in the range, checking if they all have the
+      // same tagName.
+      var container = goog.editor.style.getContainer(node);
+      var thisTagName = container.tagName;
+      tagName = tagName || thisTagName;
+
+      if (tagName != thisTagName) {
+        // If we find a container tag that doesn't match, exit right away.
+        tagName = null;
+        throw goog.iter.StopIteration;
+      }
+
+      // Skip the tag.
+      it.skipTag();
+    }
+  });
+
+  return tagName;
+};
+
+
+/**
+ * Hash of suppoted justifications.
+ * @type {Object}
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.SUPPORTED_JUSTIFICATIONS_ = {
+  'center': 1,
+  'justify': 1,
+  'right': 1,
+  'left': 1
+};
+
+
+/**
+ * Returns true if the current justification matches the justification
+ * command for the entire selection.
+ * @param {string} command The justification command to check for.
+ * @return {boolean} Whether the current justification matches the justification
+ *     command for the entire selection.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.isJustification_ =
+    function(command) {
+  var alignment = command.replace('+justify', '').toLowerCase();
+  if (alignment == 'full') {
+    alignment = 'justify';
+  }
+  var bidiPlugin = this.getFieldObject().getPluginByClassId('Bidi');
+  if (bidiPlugin) {
+    // BiDi aware version
+
+    // TODO: Since getComputedStyle is not used here, this version may be even
+    // faster. If profiling confirms that it would be good to use this approach
+    // in both cases. Otherwise the bidi part should be moved into an
+    // execCommand so this bidi plugin dependence isn't needed here.
+    /** @type {Function} */
+    bidiPlugin.getSelectionAlignment;
+    return alignment == bidiPlugin.getSelectionAlignment();
+  } else {
+    // BiDi unaware version
+    var range = this.getRange_();
+    if (!range) {
+      // When nothing is in the selection then no justification
+      // command matches.
+      return false;
+    }
+
+    var parent = range.getContainerElement();
+    var nodes =
+        goog.array.filter(
+            parent.childNodes,
+            function(node) {
+              return goog.editor.node.isImportant(node) &&
+                  range.containsNode(node, true);
+            });
+    nodes = nodes.length ? nodes : [parent];
+
+    for (var i = 0; i < nodes.length; i++) {
+      var current = nodes[i];
+
+      // If any node in the selection is not aligned the way we are checking,
+      // then the justification command does not match.
+      var container = goog.editor.style.getContainer(
+          /** @type {Node} */ (current));
+      if (alignment !=
+          goog.editor.plugins.BasicTextFormatter.getNodeJustification_(
+              container)) {
+        return false;
+      }
+    }
+
+    // If all nodes in the selection are aligned the way we are checking,
+    // the justification command does match.
+    return true;
+  }
+};
+
+
+/**
+ * Determines the justification for a given block-level element.
+ * @param {Element} element The node to get justification for.
+ * @return {string} The justification for a given block-level node.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.getNodeJustification_ =
+    function(element) {
+  var value = goog.style.getComputedTextAlign(element);
+  // Strip preceding -moz- or -webkit- (@bug 2472589).
+  value = value.replace(/^-(moz|webkit)-/, '');
+
+  // If there is no alignment, try the inline property,
+  // otherwise assume left aligned.
+  // TODO: for rtl languages we probably need to assume right.
+  if (!goog.editor.plugins.BasicTextFormatter.
+      SUPPORTED_JUSTIFICATIONS_[value]) {
+    value = element.align || 'left';
+  }
+  return /** @type {string} */ (value);
+};
+
+
+/**
+ * Returns true if a selection contained in the node should set the appropriate
+ * toolbar state for the given nodeName, e.g. if the node is contained in a
+ * strong element and nodeName is "strong", then it will return true.
+ * @param {string} nodeName The type of node to check for.
+ * @return {boolean} Whether the user's selection is in the given state.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.isNodeInState_ =
+    function(nodeName) {
+  var range = this.getRange_();
+  var node = range && range.getContainerElement();
+  var ancestor = goog.dom.getAncestorByTagNameAndClass(node, nodeName);
+  return !!ancestor && goog.editor.node.isEditable(ancestor);
+};
+
+
+/**
+ * Wrapper for browser's queryCommandState.
+ * @param {Document|TextRange|Range} queryObject The object to query.
+ * @param {string} command The command to check.
+ * @param {boolean=} opt_styleWithCss Set to true to enable styleWithCSS before
+ *     performing the queryCommandState.
+ * @return {boolean} The command state.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.queryCommandStateInternal_ =
+    function(queryObject, command, opt_styleWithCss) {
+  return /** @type {boolean} */ (this.queryCommandHelper_(true, queryObject,
+      command, opt_styleWithCss));
+};
+
+
+/**
+ * Wrapper for browser's queryCommandValue.
+ * @param {Document|TextRange|Range} queryObject The object to query.
+ * @param {string} command The command to check.
+ * @param {boolean=} opt_styleWithCss Set to true to enable styleWithCSS before
+ *     performing the queryCommandValue.
+ * @return {string|boolean|null} The command value.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.queryCommandValueInternal_ =
+    function(queryObject, command, opt_styleWithCss) {
+  return this.queryCommandHelper_(false, queryObject,
+      command, opt_styleWithCss);
+};
+
+
+/**
+ * Helper function to perform queryCommand(Value|State).
+ * @param {boolean} isGetQueryCommandState True to use queryCommandState, false
+ *     to use queryCommandValue.
+ * @param {Document|TextRange|Range} queryObject The object to query.
+ * @param {string} command The command to check.
+ * @param {boolean=} opt_styleWithCss Set to true to enable styleWithCSS before
+ *     performing the queryCommand(Value|State).
+ * @return {string|boolean|null} The command value.
+ * @private
+ */
+goog.editor.plugins.BasicTextFormatter.prototype.queryCommandHelper_ = function(
+    isGetQueryCommandState, queryObject, command, opt_styleWithCss) {
+  command =
+      goog.editor.plugins.BasicTextFormatter.convertToRealExecCommand_(
+          command);
+  if (opt_styleWithCss) {
+    var doc = this.getDocument_();
+    // Don't use this.execCommandHelper_ here, as it is more heavyweight
+    // and inserts a dummy div to protect against comamnds that could step
+    // outside the editable region, which would cause change event on
+    // every toolbar update.
+    doc.execCommand('styleWithCSS', false, true);
+  }
+  var ret = isGetQueryCommandState ? queryObject.queryCommandState(command) :
+      queryObject.queryCommandValue(command);
+  if (opt_styleWithCss) {
+    doc.execCommand('styleWithCSS', false, false);
+  }
+  return ret;
+};


[51/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
Added GCL extern.

The sources are not in out/as like other externs but in src because I tried to use EXTERNC first, it didn't work well on it but I used parts of what it generated, created an IntelliJ  project to build the lib, so, the Ant target doesn't work.


Project: http://git-wip-us.apache.org/repos/asf/flex-falcon/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-falcon/commit/e2cad6e6
Tree: http://git-wip-us.apache.org/repos/asf/flex-falcon/tree/e2cad6e6
Diff: http://git-wip-us.apache.org/repos/asf/flex-falcon/diff/e2cad6e6

Branch: refs/heads/JsToAs
Commit: e2cad6e69f655d8ccd6fa522eee75592778e8ff7
Parents: 21e347e
Author: Frédéric THOMAS <we...@gmail.com>
Authored: Thu Sep 17 16:25:32 2015 +0100
Committer: Frédéric THOMAS <we...@gmail.com>
Committed: Thu Sep 17 16:25:51 2015 +0100

----------------------------------------------------------------------
 externs/GCL/GCL-compile-config.xml              |   901 +
 externs/GCL/compile-config.xml                  |    99 +
 externs/GCL/externs/goog/a11y/aria/announcer.js |   123 +
 externs/GCL/externs/goog/a11y/aria/aria.js      |   386 +
 .../GCL/externs/goog/a11y/aria/attributes.js    |   389 +
 .../GCL/externs/goog/a11y/aria/datatables.js    |    68 +
 externs/GCL/externs/goog/a11y/aria/roles.js     |   216 +
 externs/GCL/externs/goog/array/array.js         |  1655 +
 externs/GCL/externs/goog/asserts/asserts.js     |   365 +
 .../GCL/externs/goog/async/animationdelay.js    |   267 +
 .../GCL/externs/goog/async/conditionaldelay.js  |   228 +
 externs/GCL/externs/goog/async/delay.js         |   182 +
 externs/GCL/externs/goog/async/freelist.js      |    88 +
 externs/GCL/externs/goog/async/nexttick.js      |   241 +
 externs/GCL/externs/goog/async/run.js           |   130 +
 externs/GCL/externs/goog/async/throttle.js      |   195 +
 externs/GCL/externs/goog/async/workqueue.js     |   139 +
 externs/GCL/externs/goog/base.js                |  2547 ++
 externs/GCL/externs/goog/bootstrap/nodejs.js    |   110 +
 .../GCL/externs/goog/bootstrap/webworkers.js    |    37 +
 externs/GCL/externs/goog/color/alpha.js         |   472 +
 externs/GCL/externs/goog/color/color.js         |   776 +
 externs/GCL/externs/goog/color/names.js         |   176 +
 externs/GCL/externs/goog/crypt/aes.js           |  1029 +
 externs/GCL/externs/goog/crypt/arc4.js          |   164 +
 externs/GCL/externs/goog/crypt/base64.js        |   286 +
 externs/GCL/externs/goog/crypt/basen.js         |   242 +
 externs/GCL/externs/goog/crypt/blobhasher.js    |   285 +
 externs/GCL/externs/goog/crypt/blockcipher.js   |    52 +
 externs/GCL/externs/goog/crypt/cbc.js           |   153 +
 externs/GCL/externs/goog/crypt/crypt.js         |   173 +
 externs/GCL/externs/goog/crypt/hash.js          |    69 +
 externs/GCL/externs/goog/crypt/hash32.js        |   184 +
 externs/GCL/externs/goog/crypt/hmac.js          |   160 +
 externs/GCL/externs/goog/crypt/md5.js           |   435 +
 externs/GCL/externs/goog/crypt/pbkdf2.js        |   128 +
 externs/GCL/externs/goog/crypt/sha1.js          |   294 +
 externs/GCL/externs/goog/crypt/sha2.js          |   338 +
 externs/GCL/externs/goog/crypt/sha224.js        |    50 +
 externs/GCL/externs/goog/crypt/sha256.js        |    49 +
 externs/GCL/externs/goog/crypt/sha2_64bit.js    |   550 +
 externs/GCL/externs/goog/crypt/sha384.js        |    59 +
 externs/GCL/externs/goog/crypt/sha512.js        |    59 +
 externs/GCL/externs/goog/crypt/sha512_256.js    |    65 +
 externs/GCL/externs/goog/css/autocomplete.css   |    43 +
 externs/GCL/externs/goog/css/bubble.css         |    84 +
 externs/GCL/externs/goog/css/button.css         |    38 +
 externs/GCL/externs/goog/css/charpicker.css     |   206 +
 externs/GCL/externs/goog/css/checkbox.css       |    38 +
 .../GCL/externs/goog/css/colormenubutton.css    |    25 +
 externs/GCL/externs/goog/css/colorpalette.css   |    54 +
 .../externs/goog/css/colorpicker-simplegrid.css |    49 +
 externs/GCL/externs/goog/css/combobox.css       |    54 +
 externs/GCL/externs/goog/css/common.css         |    41 +
 externs/GCL/externs/goog/css/css3button.css     |    77 +
 externs/GCL/externs/goog/css/css3menubutton.css |    23 +
 externs/GCL/externs/goog/css/custombutton.css   |   161 +
 externs/GCL/externs/goog/css/datepicker.css     |   154 +
 externs/GCL/externs/goog/css/dialog.css         |    72 +
 .../GCL/externs/goog/css/dimensionpicker.css    |    47 +
 .../GCL/externs/goog/css/dragdropdetector.css   |    48 +
 externs/GCL/externs/goog/css/editor/bubble.css  |    73 +
 externs/GCL/externs/goog/css/editor/dialog.css  |    66 +
 .../externs/goog/css/editor/equationeditor.css  |   113 +
 .../GCL/externs/goog/css/editor/linkdialog.css  |    36 +
 externs/GCL/externs/goog/css/editortoolbar.css  |   225 +
 externs/GCL/externs/goog/css/filteredmenu.css   |    30 +
 .../goog/css/filterobservingmenuitem.css        |    25 +
 externs/GCL/externs/goog/css/flatbutton.css     |    64 +
 externs/GCL/externs/goog/css/flatmenubutton.css |    63 +
 externs/GCL/externs/goog/css/hovercard.css      |    51 +
 externs/GCL/externs/goog/css/hsvapalette.css    |   231 +
 externs/GCL/externs/goog/css/hsvpalette.css     |   179 +
 .../GCL/externs/goog/css/imagelessbutton.css    |   160 +
 .../externs/goog/css/imagelessmenubutton.css    |    23 +
 .../GCL/externs/goog/css/inputdatepicker.css    |    12 +
 externs/GCL/externs/goog/css/linkbutton.css     |    26 +
 externs/GCL/externs/goog/css/menu.css           |    27 +
 externs/GCL/externs/goog/css/menubar.css        |    57 +
 externs/GCL/externs/goog/css/menubutton.css     |   169 +
 externs/GCL/externs/goog/css/menuitem.css       |   148 +
 externs/GCL/externs/goog/css/menuseparator.css  |    19 +
 .../GCL/externs/goog/css/multitestrunner.css    |   121 +
 externs/GCL/externs/goog/css/palette.css        |    36 +
 .../GCL/externs/goog/css/popupdatepicker.css    |    17 +
 externs/GCL/externs/goog/css/roundedpanel.css   |    29 +
 externs/GCL/externs/goog/css/roundedtab.css     |   158 +
 externs/GCL/externs/goog/css/submenu.css        |    38 +
 externs/GCL/externs/goog/css/tab.css            |   105 +
 externs/GCL/externs/goog/css/tabbar.css         |    52 +
 externs/GCL/externs/goog/css/tablesorter.css    |    14 +
 externs/GCL/externs/goog/css/toolbar.css        |   400 +
 externs/GCL/externs/goog/css/tooltip.css        |    14 +
 externs/GCL/externs/goog/css/tree.css           |   146 +
 .../GCL/externs/goog/css/tristatemenuitem.css   |    43 +
 externs/GCL/externs/goog/cssom/cssom.js         |   455 +
 .../externs/goog/cssom/cssom_test_import_1.css  |    11 +
 .../externs/goog/cssom/cssom_test_import_2.css  |    10 +
 .../externs/goog/cssom/cssom_test_link_1.css    |    10 +
 externs/GCL/externs/goog/cssom/iframe/style.js  |  1016 +
 .../goog/cssom/iframe/style_test_import.css     |    10 +
 .../GCL/externs/goog/datasource/datamanager.js  |   561 +
 .../GCL/externs/goog/datasource/datasource.js   |   658 +
 externs/GCL/externs/goog/datasource/expr.js     |   545 +
 .../GCL/externs/goog/datasource/fastdatanode.js |   814 +
 .../GCL/externs/goog/datasource/jsdatasource.js |   462 +
 .../externs/goog/datasource/jsondatasource.js   |   153 +
 .../goog/datasource/jsxmlhttpdatasource.js      |   196 +
 .../externs/goog/datasource/xmldatasource.js    |   417 +
 externs/GCL/externs/goog/date/date.js           |  1761 ++
 externs/GCL/externs/goog/date/datelike.js       |    27 +
 externs/GCL/externs/goog/date/daterange.js      |   430 +
 externs/GCL/externs/goog/date/duration.js       |   153 +
 externs/GCL/externs/goog/date/relative.js       |   490 +
 .../externs/goog/date/relativewithplurals.js    |   120 +
 externs/GCL/externs/goog/date/utcdatetime.js    |   191 +
 externs/GCL/externs/goog/db/cursor.js           |   215 +
 externs/GCL/externs/goog/db/db.js               |   185 +
 externs/GCL/externs/goog/db/error1.js           |   364 +
 externs/GCL/externs/goog/db/index.js            |   246 +
 externs/GCL/externs/goog/db/indexeddb.js        |   353 +
 externs/GCL/externs/goog/db/keyrange.js         |   118 +
 externs/GCL/externs/goog/db/objectstore.js      |   400 +
 externs/GCL/externs/goog/db/transaction.js      |   223 +
 externs/GCL/externs/goog/debug/console.js       |   207 +
 externs/GCL/externs/goog/debug/debug.js         |   653 +
 externs/GCL/externs/goog/debug/debugwindow.js   |   632 +
 externs/GCL/externs/goog/debug/devcss/devcss.js |   445 +
 .../externs/goog/debug/devcss/devcssrunner.js   |    26 +
 externs/GCL/externs/goog/debug/divconsole.js    |   150 +
 .../externs/goog/debug/entrypointregistry.js    |   158 +
 externs/GCL/externs/goog/debug/error2.js        |    63 +
 externs/GCL/externs/goog/debug/errorhandler.js  |   367 +
 .../externs/goog/debug/errorhandlerweakdep.js   |    38 +
 externs/GCL/externs/goog/debug/errorreporter.js |   434 +
 externs/GCL/externs/goog/debug/fancywindow.js   |   385 +
 externs/GCL/externs/goog/debug/formatter.js     |   387 +
 externs/GCL/externs/goog/debug/fpsdisplay.js    |   165 +
 externs/GCL/externs/goog/debug/gcdiagnostics.js |   143 +
 externs/GCL/externs/goog/debug/logbuffer.js     |   148 +
 externs/GCL/externs/goog/debug/logger.js        |   873 +
 externs/GCL/externs/goog/debug/logrecord.js     |   242 +
 .../externs/goog/debug/logrecordserializer.js   |   121 +
 .../externs/goog/debug/relativetimeprovider.js  |    84 +
 externs/GCL/externs/goog/debug/tracer.js        |   725 +
 .../goog/demos/autocompleteremotedata.js        |    18 +
 .../goog/demos/autocompleterichremotedata.js    |    33 +
 externs/GCL/externs/goog/demos/css/demo.css     |    75 +
 .../GCL/externs/goog/demos/css/emojipicker.css  |    36 +
 .../GCL/externs/goog/demos/css/emojisprite.css  |    92 +
 externs/GCL/externs/goog/demos/editor/deps.js   |    21 +
 .../GCL/externs/goog/demos/editor/helloworld.js |    82 +
 .../goog/demos/editor/helloworlddialog.js       |   173 +
 .../goog/demos/editor/helloworlddialogplugin.js |   117 +
 externs/GCL/externs/goog/demos/emoji/200.gif    |   Bin 0 -> 941 bytes
 externs/GCL/externs/goog/demos/emoji/201.gif    |   Bin 0 -> 980 bytes
 externs/GCL/externs/goog/demos/emoji/202.gif    |   Bin 0 -> 1054 bytes
 externs/GCL/externs/goog/demos/emoji/203.gif    |   Bin 0 -> 996 bytes
 externs/GCL/externs/goog/demos/emoji/204.gif    |   Bin 0 -> 1016 bytes
 externs/GCL/externs/goog/demos/emoji/205.gif    |   Bin 0 -> 1032 bytes
 externs/GCL/externs/goog/demos/emoji/206.gif    |   Bin 0 -> 990 bytes
 externs/GCL/externs/goog/demos/emoji/2BC.gif    |   Bin 0 -> 1039 bytes
 externs/GCL/externs/goog/demos/emoji/2BD.gif    |   Bin 0 -> 986 bytes
 externs/GCL/externs/goog/demos/emoji/2BE.gif    |   Bin 0 -> 1074 bytes
 externs/GCL/externs/goog/demos/emoji/2BF.gif    |   Bin 0 -> 996 bytes
 externs/GCL/externs/goog/demos/emoji/2C0.gif    |   Bin 0 -> 1036 bytes
 externs/GCL/externs/goog/demos/emoji/2C1.gif    |   Bin 0 -> 1080 bytes
 externs/GCL/externs/goog/demos/emoji/2C2.gif    |   Bin 0 -> 1049 bytes
 externs/GCL/externs/goog/demos/emoji/2C3.gif    |   Bin 0 -> 1104 bytes
 externs/GCL/externs/goog/demos/emoji/2C4.gif    |   Bin 0 -> 1072 bytes
 externs/GCL/externs/goog/demos/emoji/2C5.gif    |   Bin 0 -> 1087 bytes
 externs/GCL/externs/goog/demos/emoji/2C6.gif    |   Bin 0 -> 1041 bytes
 externs/GCL/externs/goog/demos/emoji/2C7.gif    |   Bin 0 -> 1079 bytes
 externs/GCL/externs/goog/demos/emoji/2C8.gif    |   Bin 0 -> 1049 bytes
 externs/GCL/externs/goog/demos/emoji/2C9.gif    |   Bin 0 -> 996 bytes
 externs/GCL/externs/goog/demos/emoji/2CA.gif    |   Bin 0 -> 2299 bytes
 externs/GCL/externs/goog/demos/emoji/2CB.gif    |   Bin 0 -> 992 bytes
 externs/GCL/externs/goog/demos/emoji/2CC.gif    |   Bin 0 -> 977 bytes
 externs/GCL/externs/goog/demos/emoji/2CD.gif    |   Bin 0 -> 1035 bytes
 externs/GCL/externs/goog/demos/emoji/2CE.gif    |   Bin 0 -> 1074 bytes
 externs/GCL/externs/goog/demos/emoji/2CF.gif    |   Bin 0 -> 1022 bytes
 externs/GCL/externs/goog/demos/emoji/2D0.gif    |   Bin 0 -> 987 bytes
 externs/GCL/externs/goog/demos/emoji/2D1.gif    |   Bin 0 -> 997 bytes
 externs/GCL/externs/goog/demos/emoji/2D2.gif    |   Bin 0 -> 1012 bytes
 externs/GCL/externs/goog/demos/emoji/2D3.gif    |   Bin 0 -> 1040 bytes
 externs/GCL/externs/goog/demos/emoji/2D4.gif    |   Bin 0 -> 1043 bytes
 externs/GCL/externs/goog/demos/emoji/2D5.gif    |   Bin 0 -> 1014 bytes
 externs/GCL/externs/goog/demos/emoji/2D6.gif    |   Bin 0 -> 1026 bytes
 externs/GCL/externs/goog/demos/emoji/2D7.gif    |   Bin 0 -> 1048 bytes
 externs/GCL/externs/goog/demos/emoji/2D8.gif    |   Bin 0 -> 884 bytes
 externs/GCL/externs/goog/demos/emoji/2D9.gif    |   Bin 0 -> 974 bytes
 externs/GCL/externs/goog/demos/emoji/2DA.gif    |   Bin 0 -> 920 bytes
 externs/GCL/externs/goog/demos/emoji/2DB.gif    |   Bin 0 -> 949 bytes
 externs/GCL/externs/goog/demos/emoji/2DC.gif    |   Bin 0 -> 949 bytes
 externs/GCL/externs/goog/demos/emoji/2DD.gif    |   Bin 0 -> 1000 bytes
 externs/GCL/externs/goog/demos/emoji/2DE.gif    |   Bin 0 -> 963 bytes
 externs/GCL/externs/goog/demos/emoji/2DF.gif    |   Bin 0 -> 865 bytes
 externs/GCL/externs/goog/demos/emoji/2E0.gif    |   Bin 0 -> 1018 bytes
 externs/GCL/externs/goog/demos/emoji/2E1.gif    |   Bin 0 -> 1004 bytes
 externs/GCL/externs/goog/demos/emoji/2E2.gif    |   Bin 0 -> 1046 bytes
 externs/GCL/externs/goog/demos/emoji/2E3.gif    |   Bin 0 -> 1547 bytes
 externs/GCL/externs/goog/demos/emoji/2E4.gif    |   Bin 0 -> 999 bytes
 externs/GCL/externs/goog/demos/emoji/2E5.gif    |   Bin 0 -> 1032 bytes
 externs/GCL/externs/goog/demos/emoji/2E6.gif    |   Bin 0 -> 1013 bytes
 externs/GCL/externs/goog/demos/emoji/2E7.gif    |   Bin 0 -> 1040 bytes
 externs/GCL/externs/goog/demos/emoji/2E8.gif    |   Bin 0 -> 1028 bytes
 externs/GCL/externs/goog/demos/emoji/2E9.gif    |   Bin 0 -> 1030 bytes
 externs/GCL/externs/goog/demos/emoji/2EA.gif    |   Bin 0 -> 1001 bytes
 externs/GCL/externs/goog/demos/emoji/2EB.gif    |   Bin 0 -> 1086 bytes
 externs/GCL/externs/goog/demos/emoji/2EC.gif    |   Bin 0 -> 1007 bytes
 externs/GCL/externs/goog/demos/emoji/2ED.gif    |   Bin 0 -> 1045 bytes
 externs/GCL/externs/goog/demos/emoji/2EE.gif    |   Bin 0 -> 1016 bytes
 externs/GCL/externs/goog/demos/emoji/2EF.gif    |   Bin 0 -> 2363 bytes
 externs/GCL/externs/goog/demos/emoji/2F0.gif    |   Bin 0 -> 1014 bytes
 externs/GCL/externs/goog/demos/emoji/2F1.gif    |   Bin 0 -> 1902 bytes
 externs/GCL/externs/goog/demos/emoji/2F2.gif    |   Bin 0 -> 1092 bytes
 externs/GCL/externs/goog/demos/emoji/2F3.gif    |   Bin 0 -> 1033 bytes
 externs/GCL/externs/goog/demos/emoji/2F4.gif    |   Bin 0 -> 1065 bytes
 externs/GCL/externs/goog/demos/emoji/2F5.gif    |   Bin 0 -> 954 bytes
 externs/GCL/externs/goog/demos/emoji/2F6.gif    |   Bin 0 -> 1030 bytes
 externs/GCL/externs/goog/demos/emoji/2F7.gif    |   Bin 0 -> 1006 bytes
 externs/GCL/externs/goog/demos/emoji/2F8.gif    |   Bin 0 -> 1016 bytes
 externs/GCL/externs/goog/demos/emoji/2F9.gif    |   Bin 0 -> 1051 bytes
 externs/GCL/externs/goog/demos/emoji/2FA.gif    |   Bin 0 -> 1082 bytes
 externs/GCL/externs/goog/demos/emoji/2FB.gif    |   Bin 0 -> 1012 bytes
 externs/GCL/externs/goog/demos/emoji/2FC.gif    |   Bin 0 -> 977 bytes
 externs/GCL/externs/goog/demos/emoji/2FD.gif    |   Bin 0 -> 989 bytes
 externs/GCL/externs/goog/demos/emoji/2FE.gif    |   Bin 0 -> 1036 bytes
 externs/GCL/externs/goog/demos/emoji/2FF.gif    |   Bin 0 -> 1034 bytes
 externs/GCL/externs/goog/demos/emoji/none.gif   |   Bin 0 -> 834 bytes
 externs/GCL/externs/goog/demos/emoji/sprite.png |   Bin 0 -> 25195 bytes
 .../GCL/externs/goog/demos/emoji/sprite2.png    |   Bin 0 -> 27856 bytes
 .../GCL/externs/goog/demos/emoji/unknown.gif    |   Bin 0 -> 90 bytes
 .../externs/goog/demos/graphics/tigerdata.js    |  2841 ++
 .../GCL/externs/goog/demos/samplecomponent.js   |   189 +
 externs/GCL/externs/goog/demos/xpc/xpcdemo.js   |   308 +
 .../GCL/externs/goog/disposable/disposable.js   |   307 +
 .../GCL/externs/goog/disposable/idisposable.js  |    45 +
 .../GCL/externs/goog/dom/abstractmultirange.js  |    76 +
 externs/GCL/externs/goog/dom/abstractrange.js   |   529 +
 .../goog/dom/animationframe/animationframe.js   |   287 +
 .../externs/goog/dom/animationframe/polyfill.js |    61 +
 externs/GCL/externs/goog/dom/annotate.js        |   357 +
 externs/GCL/externs/goog/dom/browserfeature1.js |    72 +
 .../goog/dom/browserrange/abstractrange.js      |   350 +
 .../goog/dom/browserrange/browserrange.js       |   149 +
 .../externs/goog/dom/browserrange/geckorange.js |    88 +
 .../externs/goog/dom/browserrange/ierange.js    |   935 +
 .../externs/goog/dom/browserrange/operarange.js |    84 +
 .../externs/goog/dom/browserrange/w3crange.js   |   396 +
 .../goog/dom/browserrange/webkitrange.js        |   108 +
 .../goog/dom/bufferedviewportsizemonitor.js     |   201 +
 externs/GCL/externs/goog/dom/classes.js         |   239 +
 externs/GCL/externs/goog/dom/classlist.js       |   277 +
 externs/GCL/externs/goog/dom/controlrange.js    |   494 +
 externs/GCL/externs/goog/dom/dataset.js         |   154 +
 externs/GCL/externs/goog/dom/dom.js             |  2990 ++
 externs/GCL/externs/goog/dom/fontsizemonitor.js |   162 +
 externs/GCL/externs/goog/dom/forms.js           |   417 +
 externs/GCL/externs/goog/dom/fullscreen.js      |   144 +
 externs/GCL/externs/goog/dom/iframe.js          |   216 +
 externs/GCL/externs/goog/dom/inputtype.js       |    66 +
 externs/GCL/externs/goog/dom/iter.js            |   129 +
 externs/GCL/externs/goog/dom/multirange.js      |   510 +
 externs/GCL/externs/goog/dom/nodeiterator.js    |    87 +
 externs/GCL/externs/goog/dom/nodeoffset.js      |   114 +
 externs/GCL/externs/goog/dom/nodetype.js        |    48 +
 .../externs/goog/dom/pattern/abstractpattern.js |    58 +
 .../GCL/externs/goog/dom/pattern/allchildren.js |    72 +
 .../goog/dom/pattern/callback/callback.js       |    82 +
 .../goog/dom/pattern/callback/counter.js        |    69 +
 .../externs/goog/dom/pattern/childmatches.js    |   145 +
 externs/GCL/externs/goog/dom/pattern/endtag.js  |    54 +
 externs/GCL/externs/goog/dom/pattern/fulltag.js |    88 +
 externs/GCL/externs/goog/dom/pattern/matcher.js |   144 +
 .../GCL/externs/goog/dom/pattern/nodetype.js    |    59 +
 externs/GCL/externs/goog/dom/pattern/pattern.js |    93 +
 externs/GCL/externs/goog/dom/pattern/repeat.js  |   177 +
 .../GCL/externs/goog/dom/pattern/sequence.js    |   135 +
 .../GCL/externs/goog/dom/pattern/starttag.js    |    53 +
 externs/GCL/externs/goog/dom/pattern/tag.js     |   128 +
 externs/GCL/externs/goog/dom/pattern/text.js    |    67 +
 externs/GCL/externs/goog/dom/range.js           |   226 +
 externs/GCL/externs/goog/dom/rangeendpoint.js   |    32 +
 externs/GCL/externs/goog/dom/safe.js            |   325 +
 externs/GCL/externs/goog/dom/savedcaretrange.js |   215 +
 externs/GCL/externs/goog/dom/savedrange.js      |    74 +
 externs/GCL/externs/goog/dom/selection.js       |   472 +
 externs/GCL/externs/goog/dom/tagiterator.js     |   360 +
 externs/GCL/externs/goog/dom/tagname.js         |   160 +
 externs/GCL/externs/goog/dom/tags.js            |    42 +
 externs/GCL/externs/goog/dom/textrange.js       |   615 +
 .../GCL/externs/goog/dom/textrangeiterator.js   |   239 +
 externs/GCL/externs/goog/dom/vendor.js          |    96 +
 .../GCL/externs/goog/dom/viewportsizemonitor.js |   165 +
 externs/GCL/externs/goog/dom/xml.js             |   204 +
 .../GCL/externs/goog/editor/browserfeature2.js  |   273 +
 .../externs/goog/editor/clicktoeditwrapper.js   |   423 +
 externs/GCL/externs/goog/editor/command.js      |    76 +
 .../externs/goog/editor/contenteditablefield.js |   108 +
 externs/GCL/externs/goog/editor/defines.js      |    34 +
 externs/GCL/externs/goog/editor/field.js        |  2750 ++
 externs/GCL/externs/goog/editor/focus.js        |    32 +
 externs/GCL/externs/goog/editor/icontent.js     |   300 +
 externs/GCL/externs/goog/editor/link.js         |   390 +
 externs/GCL/externs/goog/editor/node.js         |   484 +
 externs/GCL/externs/goog/editor/plugin.js       |   463 +
 .../goog/editor/plugins/abstractbubbleplugin.js |   712 +
 .../goog/editor/plugins/abstractdialogplugin.js |   333 +
 .../goog/editor/plugins/abstracttabhandler.js   |    78 +
 .../goog/editor/plugins/basictextformatter.js   |  1769 ++
 .../externs/goog/editor/plugins/blockquote.js   |   451 +
 .../externs/goog/editor/plugins/emoticons.js    |    89 +
 .../externs/goog/editor/plugins/enterhandler.js |   768 +
 .../externs/goog/editor/plugins/firststrong.js  |   334 +
 .../goog/editor/plugins/headerformatter.js      |    96 +
 .../externs/goog/editor/plugins/linkbubble.js   |   585 +
 .../goog/editor/plugins/linkdialogplugin.js     |   438 +
 .../goog/editor/plugins/linkshortcutplugin.js   |    61 +
 .../goog/editor/plugins/listtabhandler.js       |    68 +
 .../externs/goog/editor/plugins/loremipsum.js   |   192 +
 .../goog/editor/plugins/removeformatting.js     |   780 +
 .../goog/editor/plugins/spacestabhandler.js     |    92 +
 .../externs/goog/editor/plugins/tableeditor.js  |   475 +
 .../goog/editor/plugins/tagonenterhandler.js    |   744 +
 .../GCL/externs/goog/editor/plugins/undoredo.js |  1016 +
 .../goog/editor/plugins/undoredomanager.js      |   338 +
 .../goog/editor/plugins/undoredostate.js        |    86 +
 externs/GCL/externs/goog/editor/range.js        |   632 +
 .../GCL/externs/goog/editor/seamlessfield.js    |   746 +
 externs/GCL/externs/goog/editor/style.js        |   225 +
 externs/GCL/externs/goog/editor/table.js        |   570 +
 .../externs/goog/events/actioneventwrapper.js   |   151 +
 .../GCL/externs/goog/events/actionhandler.js    |   184 +
 externs/GCL/externs/goog/events/browserevent.js |   386 +
 .../GCL/externs/goog/events/browserfeature3.js  |    85 +
 externs/GCL/externs/goog/events/event.js        |   143 +
 externs/GCL/externs/goog/events/eventhandler.js |   459 +
 externs/GCL/externs/goog/events/eventid.js      |    47 +
 externs/GCL/externs/goog/events/events.js       |   983 +
 externs/GCL/externs/goog/events/eventtarget.js  |   394 +
 externs/GCL/externs/goog/events/eventtype.js    |   233 +
 externs/GCL/externs/goog/events/eventwrapper.js |    66 +
 .../GCL/externs/goog/events/filedrophandler.js  |   222 +
 externs/GCL/externs/goog/events/focushandler.js |   107 +
 externs/GCL/externs/goog/events/imehandler.js   |   369 +
 externs/GCL/externs/goog/events/inputhandler.js |   212 +
 externs/GCL/externs/goog/events/keycodes.js     |   420 +
 externs/GCL/externs/goog/events/keyhandler.js   |   556 +
 externs/GCL/externs/goog/events/keynames.js     |   139 +
 externs/GCL/externs/goog/events/listenable.js   |   335 +
 externs/GCL/externs/goog/events/listener.js     |   131 +
 externs/GCL/externs/goog/events/listenermap.js  |   308 +
 .../externs/goog/events/mousewheelhandler.js    |   296 +
 .../GCL/externs/goog/events/onlinehandler.js    |   159 +
 externs/GCL/externs/goog/events/pastehandler.js |   517 +
 externs/GCL/externs/goog/events/wheelevent.js   |   169 +
 externs/GCL/externs/goog/events/wheelhandler.js |   159 +
 externs/GCL/externs/goog/format/emailaddress.js |   499 +
 externs/GCL/externs/goog/format/format.js       |   502 +
 .../externs/goog/format/htmlprettyprinter.js    |   408 +
 .../format/internationalizedemailaddress.js     |   256 +
 .../externs/goog/format/jsonprettyprinter.js    |   414 +
 externs/GCL/externs/goog/fs/entry.js            |   272 +
 externs/GCL/externs/goog/fs/entryimpl.js        |   404 +
 externs/GCL/externs/goog/fs/error3.js           |   181 +
 externs/GCL/externs/goog/fs/filereader.js       |   288 +
 externs/GCL/externs/goog/fs/filesaver.js        |   166 +
 externs/GCL/externs/goog/fs/filesystem.js       |    41 +
 externs/GCL/externs/goog/fs/filesystemimpl.js   |    65 +
 externs/GCL/externs/goog/fs/filewriter.js       |   111 +
 externs/GCL/externs/goog/fs/fs.js               |   278 +
 externs/GCL/externs/goog/fs/progressevent.js    |    69 +
 externs/GCL/externs/goog/fs/url.js              |   105 +
 externs/GCL/externs/goog/functions/functions.js |   332 +
 externs/GCL/externs/goog/fx/abstractdragdrop.js |  1540 +
 externs/GCL/externs/goog/fx/anim/anim.js        |   211 +
 externs/GCL/externs/goog/fx/animation.js        |   524 +
 externs/GCL/externs/goog/fx/animationqueue.js   |   310 +
 externs/GCL/externs/goog/fx/css3/fx.js          |    63 +
 externs/GCL/externs/goog/fx/css3/transition.js  |   201 +
 .../GCL/externs/goog/fx/cssspriteanimation.js   |   130 +
 externs/GCL/externs/goog/fx/dom.js              |   686 +
 externs/GCL/externs/goog/fx/dragdrop.js         |    50 +
 externs/GCL/externs/goog/fx/dragdropgroup.js    |   109 +
 externs/GCL/externs/goog/fx/dragger.js          |   869 +
 externs/GCL/externs/goog/fx/draglistgroup.js    |  1312 +
 .../GCL/externs/goog/fx/dragscrollsupport.js    |   300 +
 externs/GCL/externs/goog/fx/easing.js           |    85 +
 externs/GCL/externs/goog/fx/fx.js               |    34 +
 externs/GCL/externs/goog/fx/transition.js       |    76 +
 externs/GCL/externs/goog/fx/transitionbase.js   |   236 +
 .../externs/goog/graphics/abstractgraphics.js   |   454 +
 .../externs/goog/graphics/affinetransform.js    |   588 +
 .../GCL/externs/goog/graphics/canvaselement.js  |   812 +
 .../GCL/externs/goog/graphics/canvasgraphics.js |   670 +
 externs/GCL/externs/goog/graphics/element.js    |   164 +
 .../GCL/externs/goog/graphics/ellipseelement.js |    63 +
 .../externs/goog/graphics/ext/coordinates.js    |   159 +
 .../GCL/externs/goog/graphics/ext/element.js    |   963 +
 .../GCL/externs/goog/graphics/ext/ellipse.js    |    60 +
 externs/GCL/externs/goog/graphics/ext/ext.js    |    31 +
 .../GCL/externs/goog/graphics/ext/graphics.js   |   218 +
 externs/GCL/externs/goog/graphics/ext/group.js  |   216 +
 externs/GCL/externs/goog/graphics/ext/image.js  |    64 +
 externs/GCL/externs/goog/graphics/ext/path.js   |   142 +
 .../GCL/externs/goog/graphics/ext/rectangle.js  |    55 +
 externs/GCL/externs/goog/graphics/ext/shape.js  |   145 +
 .../goog/graphics/ext/strokeandfillelement.js   |    70 +
 externs/GCL/externs/goog/graphics/fill.js       |    46 +
 externs/GCL/externs/goog/graphics/font.js       |    64 +
 externs/GCL/externs/goog/graphics/graphics.js   |   142 +
 .../GCL/externs/goog/graphics/groupelement.js   |    58 +
 .../GCL/externs/goog/graphics/imageelement.js   |    70 +
 .../GCL/externs/goog/graphics/lineargradient.js |   175 +
 externs/GCL/externs/goog/graphics/path.js       |   511 +
 .../GCL/externs/goog/graphics/pathelement.js    |    54 +
 externs/GCL/externs/goog/graphics/paths.js      |    86 +
 .../GCL/externs/goog/graphics/rectelement.js    |    63 +
 externs/GCL/externs/goog/graphics/solidfill.js  |    74 +
 externs/GCL/externs/goog/graphics/stroke.js     |    86 +
 .../goog/graphics/strokeandfillelement.js       |   114 +
 externs/GCL/externs/goog/graphics/svgelement.js |   284 +
 .../GCL/externs/goog/graphics/svggraphics.js    |   878 +
 .../GCL/externs/goog/graphics/textelement.js    |    55 +
 externs/GCL/externs/goog/graphics/vmlelement.js |   438 +
 .../GCL/externs/goog/graphics/vmlgraphics.js    |   948 +
 externs/GCL/externs/goog/history/event.js       |    55 +
 externs/GCL/externs/goog/history/eventtype.js   |    30 +
 externs/GCL/externs/goog/history/history.js     |  1005 +
 .../GCL/externs/goog/history/html5history.js    |   303 +
 externs/GCL/externs/goog/html/flash.js          |   177 +
 .../GCL/externs/goog/html/legacyconversions.js  |   200 +
 externs/GCL/externs/goog/html/safehtml.js       |   756 +
 externs/GCL/externs/goog/html/safescript.js     |   234 +
 externs/GCL/externs/goog/html/safestyle.js      |   442 +
 externs/GCL/externs/goog/html/safestylesheet.js |   276 +
 externs/GCL/externs/goog/html/safeurl.js        |   431 +
 externs/GCL/externs/goog/html/silverlight.js    |    92 +
 .../GCL/externs/goog/html/trustedresourceurl.js |   224 +
 .../externs/goog/html/uncheckedconversions.js   |   231 +
 externs/GCL/externs/goog/html/utils.js          |    67 +
 externs/GCL/externs/goog/i18n/bidi.js           |   897 +
 externs/GCL/externs/goog/i18n/bidiformatter.js  |   596 +
 .../externs/goog/i18n/charlistdecompressor.js   |   158 +
 externs/GCL/externs/goog/i18n/charpickerdata.js |  3666 +++
 externs/GCL/externs/goog/i18n/collation.js      |    58 +
 .../goog/i18n/compactnumberformatsymbols.js     |  9763 ++++++
 .../goog/i18n/compactnumberformatsymbols_ext.js | 27778 +++++++++++++++++
 externs/GCL/externs/goog/i18n/currency.js       |   437 +
 .../GCL/externs/goog/i18n/currencycodemap.js    |   207 +
 externs/GCL/externs/goog/i18n/datetimeformat.js |   771 +
 externs/GCL/externs/goog/i18n/datetimeparse.js  |  1150 +
 .../GCL/externs/goog/i18n/datetimepatterns.js   |  2520 ++
 .../externs/goog/i18n/datetimepatternsext.js    | 14208 +++++++++
 .../GCL/externs/goog/i18n/datetimesymbols.js    |  4524 +++
 .../GCL/externs/goog/i18n/datetimesymbolsext.js | 22115 +++++++++++++
 externs/GCL/externs/goog/i18n/graphemebreak.js  |   214 +
 externs/GCL/externs/goog/i18n/messageformat.js  |   780 +
 externs/GCL/externs/goog/i18n/mime.js           |   111 +
 externs/GCL/externs/goog/i18n/numberformat.js   |  1266 +
 .../externs/goog/i18n/numberformatsymbols.js    |  4271 +++
 .../externs/goog/i18n/numberformatsymbolsext.js | 11335 +++++++
 externs/GCL/externs/goog/i18n/ordinalrules.js   |   748 +
 externs/GCL/externs/goog/i18n/pluralrules.js    |  1120 +
 externs/GCL/externs/goog/i18n/timezone.js       |   341 +
 externs/GCL/externs/goog/i18n/uchar.js          |   292 +
 .../externs/goog/i18n/uchar/localnamefetcher.js |    74 +
 .../GCL/externs/goog/i18n/uchar/namefetcher.js  |    70 +
 .../goog/i18n/uchar/remotenamefetcher.js        |   282 +
 externs/GCL/externs/goog/i18n/ucharnames.js     |  1098 +
 externs/GCL/externs/goog/images/blank.gif       |   Bin 0 -> 49 bytes
 .../GCL/externs/goog/images/bubble_close.jpg    |   Bin 0 -> 586 bytes
 externs/GCL/externs/goog/images/bubble_left.gif |   Bin 0 -> 85 bytes
 .../GCL/externs/goog/images/bubble_right.gif    |   Bin 0 -> 86 bytes
 externs/GCL/externs/goog/images/button-bg.gif   |   Bin 0 -> 454 bytes
 .../GCL/externs/goog/images/check-outline.gif   |   Bin 0 -> 69 bytes
 .../GCL/externs/goog/images/check-sprite.gif    |   Bin 0 -> 75 bytes
 externs/GCL/externs/goog/images/check.gif       |   Bin 0 -> 53 bytes
 externs/GCL/externs/goog/images/close_box.gif   |   Bin 0 -> 65 bytes
 .../externs/goog/images/color-swatch-tick.gif   |   Bin 0 -> 69 bytes
 .../externs/goog/images/dialog_close_box.gif    |   Bin 0 -> 86 bytes
 .../goog/images/dimension-highlighted.png       |   Bin 0 -> 171 bytes
 .../goog/images/dimension-unhighlighted.png     |   Bin 0 -> 171 bytes
 externs/GCL/externs/goog/images/dropdn.gif      |   Bin 0 -> 51 bytes
 .../GCL/externs/goog/images/dropdn_disabled.gif |   Bin 0 -> 51 bytes
 externs/GCL/externs/goog/images/dropdown.gif    |   Bin 0 -> 78 bytes
 .../GCL/externs/goog/images/gears_bluedot.gif   |   Bin 0 -> 236 bytes
 .../GCL/externs/goog/images/gears_online.gif    |   Bin 0 -> 137 bytes
 .../GCL/externs/goog/images/gears_paused.gif    |   Bin 0 -> 93 bytes
 .../GCL/externs/goog/images/gears_syncing.gif   |   Bin 0 -> 761 bytes
 .../GCL/externs/goog/images/hsv-sprite-sm.gif   |   Bin 0 -> 11851 bytes
 .../GCL/externs/goog/images/hsv-sprite-sm.png   |   Bin 0 -> 19537 bytes
 externs/GCL/externs/goog/images/hsv-sprite.gif  |   Bin 0 -> 33309 bytes
 externs/GCL/externs/goog/images/hsv-sprite.png  |   Bin 0 -> 58142 bytes
 .../GCL/externs/goog/images/hsva-sprite-sm.gif  |   Bin 0 -> 12571 bytes
 .../GCL/externs/goog/images/hsva-sprite-sm.png  |   Bin 0 -> 19921 bytes
 externs/GCL/externs/goog/images/hsva-sprite.gif |   Bin 0 -> 36428 bytes
 externs/GCL/externs/goog/images/hsva-sprite.png |   Bin 0 -> 60591 bytes
 .../goog/images/left_anchor_bubble_bot.gif      |   Bin 0 -> 431 bytes
 .../goog/images/left_anchor_bubble_top.gif      |   Bin 0 -> 332 bytes
 externs/GCL/externs/goog/images/menu-arrows.gif |   Bin 0 -> 113 bytes
 externs/GCL/externs/goog/images/minus.png       |   Bin 0 -> 238 bytes
 .../goog/images/no_anchor_bubble_bot.gif        |   Bin 0 -> 228 bytes
 .../goog/images/no_anchor_bubble_top.gif        |   Bin 0 -> 123 bytes
 .../GCL/externs/goog/images/offlineicons.png    |   Bin 0 -> 5643 bytes
 externs/GCL/externs/goog/images/plus.png        |   Bin 0 -> 239 bytes
 externs/GCL/externs/goog/images/ratingstars.gif |   Bin 0 -> 1139 bytes
 .../goog/images/right_anchor_bubble_bot.gif     |   Bin 0 -> 425 bytes
 .../goog/images/right_anchor_bubble_top.gif     |   Bin 0 -> 335 bytes
 externs/GCL/externs/goog/images/toolbar-bg.png  |   Bin 0 -> 203 bytes
 .../externs/goog/images/toolbar-separator.gif   |   Bin 0 -> 472 bytes
 .../GCL/externs/goog/images/toolbar_icons.gif   |   Bin 0 -> 1062 bytes
 externs/GCL/externs/goog/images/tree/I.png      |   Bin 0 -> 232 bytes
 .../GCL/externs/goog/images/tree/cleardot.gif   |   Bin 0 -> 43 bytes
 externs/GCL/externs/goog/images/tree/tree.gif   |   Bin 0 -> 1568 bytes
 externs/GCL/externs/goog/images/tree/tree.png   |   Bin 0 -> 1262 bytes
 externs/GCL/externs/goog/images/ui_controls.jpg |   Bin 0 -> 21680 bytes
 externs/GCL/externs/goog/iter/iter.js           |  1305 +
 .../GCL/externs/goog/json/evaljsonprocessor.js  |    67 +
 externs/GCL/externs/goog/json/hybrid.js         |   103 +
 .../externs/goog/json/hybridjsonprocessor.js    |    47 +
 externs/GCL/externs/goog/json/json.js           |   365 +
 externs/GCL/externs/goog/json/json_perf.js      |   112 +
 .../externs/goog/json/nativejsonprocessor.js    |    73 +
 externs/GCL/externs/goog/json/processor.js      |    33 +
 .../goog/labs/dom/pagevisibilitymonitor.js      |   211 +
 .../labs/events/nondisposableeventtarget.js     |   305 +
 externs/GCL/externs/goog/labs/events/touch.js   |    82 +
 externs/GCL/externs/goog/labs/format/csv.js     |   415 +
 .../goog/labs/html/attribute_rewriter.js        |    74 +
 externs/GCL/externs/goog/labs/html/sanitizer.js |   392 +
 externs/GCL/externs/goog/labs/html/scrubber.js  |  1027 +
 .../GCL/externs/goog/labs/i18n/listformat.js    |   261 +
 .../GCL/externs/goog/labs/i18n/listsymbols.js   |  1796 ++
 .../externs/goog/labs/i18n/listsymbolsext.js    | 10071 ++++++
 .../GCL/externs/goog/labs/iterable/iterable.js  |   139 +
 externs/GCL/externs/goog/labs/mock/mock.js      |   861 +
 externs/GCL/externs/goog/labs/net/image.js      |    94 +
 .../externs/goog/labs/net/testdata/cleardot.gif |   Bin 0 -> 43 bytes
 .../goog/labs/net/testdata/xhr_test_json.data   |     2 +
 .../goog/labs/net/testdata/xhr_test_text.data   |     1 +
 externs/GCL/externs/goog/labs/net/webchannel.js |   311 +
 .../externs/goog/labs/net/webchannel/channel.js |   181 +
 .../goog/labs/net/webchannel/channelrequest.js  |  1084 +
 .../goog/labs/net/webchannel/connectionstate.js |    50 +
 .../net/webchannel/forwardchannelrequestpool.js |   279 +
 .../goog/labs/net/webchannel/netutils.js        |   162 +
 .../goog/labs/net/webchannel/requeststats.js    |   383 +
 .../goog/labs/net/webchannel/webchannelbase.js  |  2084 ++
 .../net/webchannel/webchannelbasetransport.js   |   379 +
 .../goog/labs/net/webchannel/webchanneldebug.js |   260 +
 .../externs/goog/labs/net/webchannel/wire.js    |    75 +
 .../externs/goog/labs/net/webchannel/wirev8.js  |   136 +
 .../goog/labs/net/webchanneltransport.js        |    75 +
 .../goog/labs/net/webchanneltransportfactory.js |    37 +
 externs/GCL/externs/goog/labs/net/xhr.js        |   468 +
 externs/GCL/externs/goog/labs/object/object.js  |    47 +
 .../externs/goog/labs/pubsub/broadcastpubsub.js |   564 +
 .../labs/storage/boundedcollectablestorage.js   |   287 +
 externs/GCL/externs/goog/labs/structs/map.js    |   348 +
 .../GCL/externs/goog/labs/structs/map_perf.js   |   205 +
 .../GCL/externs/goog/labs/structs/multimap.js   |   282 +
 .../goog/labs/style/pixeldensitymonitor.js      |   179 +
 .../GCL/externs/goog/labs/testing/assertthat.js |    58 +
 .../goog/labs/testing/decoratormatcher.js       |    95 +
 .../goog/labs/testing/dictionarymatcher.js      |   273 +
 .../externs/goog/labs/testing/environment.js    |   293 +
 .../externs/goog/labs/testing/logicmatcher.js   |   212 +
 .../GCL/externs/goog/labs/testing/matcher.js    |    80 +
 .../externs/goog/labs/testing/numbermatcher.js  |   346 +
 .../externs/goog/labs/testing/objectmatcher.js  |   317 +
 .../externs/goog/labs/testing/stringmatcher.js  |   415 +
 .../GCL/externs/goog/labs/useragent/browser.js  |   327 +
 .../GCL/externs/goog/labs/useragent/device.js   |    65 +
 .../GCL/externs/goog/labs/useragent/engine.js   |   160 +
 .../GCL/externs/goog/labs/useragent/platform.js |   160 +
 externs/GCL/externs/goog/labs/useragent/util.js |   148 +
 externs/GCL/externs/goog/locale/countries.js    |   291 +
 .../goog/locale/defaultlocalenameconstants.js   |   941 +
 .../GCL/externs/goog/locale/genericfontnames.js |    73 +
 .../externs/goog/locale/genericfontnamesdata.js |   327 +
 externs/GCL/externs/goog/locale/locale.js       |   403 +
 .../externs/goog/locale/nativenameconstants.js  |  1354 +
 .../externs/goog/locale/scriptToLanguages.js    |   482 +
 .../externs/goog/locale/timezonedetection.js    |   116 +
 .../externs/goog/locale/timezonefingerprint.js  |   248 +
 externs/GCL/externs/goog/locale/timezonelist.js |   131 +
 externs/GCL/externs/goog/log/log.js             |   197 +
 .../GCL/externs/goog/math/affinetransform.js    |   589 +
 externs/GCL/externs/goog/math/bezier.js         |   340 +
 externs/GCL/externs/goog/math/box.js            |   389 +
 externs/GCL/externs/goog/math/coordinate.js     |   268 +
 externs/GCL/externs/goog/math/coordinate3.js    |   170 +
 .../GCL/externs/goog/math/exponentialbackoff.js |   104 +
 externs/GCL/externs/goog/math/integer.js        |   739 +
 .../goog/math/interpolator/interpolator1.js     |    64 +
 .../externs/goog/math/interpolator/linear1.js   |    84 +
 .../externs/goog/math/interpolator/pchip1.js    |    82 +
 .../externs/goog/math/interpolator/spline1.js   |   203 +
 externs/GCL/externs/goog/math/line.js           |   179 +
 externs/GCL/externs/goog/math/long.js           |   804 +
 externs/GCL/externs/goog/math/math.js           |   435 +
 externs/GCL/externs/goog/math/matrix.js         |   681 +
 externs/GCL/externs/goog/math/path.js           |   598 +
 externs/GCL/externs/goog/math/paths.js          |    86 +
 externs/GCL/externs/goog/math/range.js          |   186 +
 externs/GCL/externs/goog/math/rangeset.js       |   396 +
 externs/GCL/externs/goog/math/rect.js           |   464 +
 externs/GCL/externs/goog/math/size.js           |   227 +
 externs/GCL/externs/goog/math/tdma.js           |    73 +
 externs/GCL/externs/goog/math/vec2.js           |   284 +
 externs/GCL/externs/goog/math/vec3.js           |   310 +
 externs/GCL/externs/goog/memoize/memoize.js     |   104 +
 .../externs/goog/messaging/abstractchannel.js   |   209 +
 .../externs/goog/messaging/bufferedchannel.js   |   287 +
 .../externs/goog/messaging/deferredchannel.js   |    98 +
 .../GCL/externs/goog/messaging/loggerclient.js  |   132 +
 .../GCL/externs/goog/messaging/loggerserver.js  |   100 +
 .../externs/goog/messaging/messagechannel.js    |   116 +
 externs/GCL/externs/goog/messaging/messaging.js |    32 +
 .../GCL/externs/goog/messaging/multichannel.js  |   303 +
 .../GCL/externs/goog/messaging/portcaller.js    |   152 +
 .../GCL/externs/goog/messaging/portchannel.js   |   401 +
 .../GCL/externs/goog/messaging/portnetwork.js   |    78 +
 .../GCL/externs/goog/messaging/portoperator.js  |   198 +
 .../externs/goog/messaging/respondingchannel.js |   234 +
 .../messaging/testdata/portchannel_worker.js    |    37 +
 .../messaging/testdata/portnetwork_worker1.js   |    32 +
 .../messaging/testdata/portnetwork_worker2.js   |    32 +
 .../externs/goog/module/abstractmoduleloader.js |    58 +
 externs/GCL/externs/goog/module/basemodule.js   |    47 +
 externs/GCL/externs/goog/module/loader.js       |   347 +
 externs/GCL/externs/goog/module/module.js       |    33 +
 externs/GCL/externs/goog/module/moduleinfo.js   |   341 +
 .../externs/goog/module/moduleloadcallback.js   |    86 +
 externs/GCL/externs/goog/module/moduleloader.js |   461 +
 .../GCL/externs/goog/module/modulemanager.js    |  1358 +
 .../GCL/externs/goog/module/testdata/modA_1.js  |    26 +
 .../GCL/externs/goog/module/testdata/modA_2.js  |    29 +
 .../GCL/externs/goog/module/testdata/modB_1.js  |    33 +
 externs/GCL/externs/goog/net/browserchannel.js  |  2765 ++
 externs/GCL/externs/goog/net/bulkloader.js      |   182 +
 .../GCL/externs/goog/net/bulkloaderhelper.js    |   119 +
 externs/GCL/externs/goog/net/channeldebug.js    |   300 +
 externs/GCL/externs/goog/net/channelrequest.js  |  1339 +
 externs/GCL/externs/goog/net/cookies.js         |   371 +
 .../GCL/externs/goog/net/corsxmlhttpfactory.js  |   272 +
 externs/GCL/externs/goog/net/crossdomainrpc.js  |   894 +
 .../externs/goog/net/crossdomainrpc_test.css    |     7 +
 .../externs/goog/net/crossdomainrpc_test.gif    |     0
 externs/GCL/externs/goog/net/errorcode.js       |   130 +
 externs/GCL/externs/goog/net/eventtype.js       |    37 +
 externs/GCL/externs/goog/net/filedownloader.js  |   746 +
 externs/GCL/externs/goog/net/httpstatus.js      |   116 +
 externs/GCL/externs/goog/net/iframeio.js        |  1405 +
 .../goog/net/iframeio_different_base_test.data  |     2 +
 .../GCL/externs/goog/net/iframeloadmonitor.js   |   204 +
 externs/GCL/externs/goog/net/imageloader.js     |   338 +
 .../externs/goog/net/imageloader_testimg1.gif   |   Bin 0 -> 453 bytes
 .../externs/goog/net/imageloader_testimg2.gif   |   Bin 0 -> 460 bytes
 .../externs/goog/net/imageloader_testimg3.gif   |   Bin 0 -> 13446 bytes
 externs/GCL/externs/goog/net/ipaddress.js       |   509 +
 externs/GCL/externs/goog/net/jsloader.js        |   367 +
 externs/GCL/externs/goog/net/jsonp.js           |   340 +
 externs/GCL/externs/goog/net/mockiframeio.js    |   308 +
 .../externs/goog/net/multiiframeloadmonitor.js  |   118 +
 .../externs/goog/net/networkstatusmonitor.js    |    47 +
 externs/GCL/externs/goog/net/tmpnetwork.js      |   164 +
 externs/GCL/externs/goog/net/websocket.js       |   524 +
 .../externs/goog/net/wrapperxmlhttpfactory.js   |    71 +
 externs/GCL/externs/goog/net/xhrio.js           |  1224 +
 externs/GCL/externs/goog/net/xhriopool.js       |    79 +
 externs/GCL/externs/goog/net/xhrlike.js         |   124 +
 externs/GCL/externs/goog/net/xhrmanager.js      |   772 +
 externs/GCL/externs/goog/net/xmlhttp.js         |   246 +
 externs/GCL/externs/goog/net/xmlhttpfactory.js  |    67 +
 .../externs/goog/net/xpc/crosspagechannel.js    |   855 +
 .../goog/net/xpc/crosspagechannelrole.js        |    30 +
 .../GCL/externs/goog/net/xpc/directtransport.js |   635 +
 .../goog/net/xpc/frameelementmethodtransport.js |   270 +
 .../goog/net/xpc/iframepollingtransport.js      |   985 +
 .../goog/net/xpc/iframerelaytransport.js        |   410 +
 .../goog/net/xpc/nativemessagingtransport.js    |   648 +
 .../GCL/externs/goog/net/xpc/nixtransport.js    |   483 +
 externs/GCL/externs/goog/net/xpc/relay.js       |    73 +
 externs/GCL/externs/goog/net/xpc/transport.js   |   105 +
 externs/GCL/externs/goog/net/xpc/xpc.js         |   300 +
 externs/GCL/externs/goog/object/object.js       |   686 +
 .../goog/positioning/absoluteposition.js        |    73 +
 .../goog/positioning/abstractposition.js        |    44 +
 .../goog/positioning/anchoredposition.js        |    92 +
 .../positioning/anchoredviewportposition.js     |   189 +
 .../externs/goog/positioning/clientposition.js  |    89 +
 .../goog/positioning/menuanchoredposition.js    |    66 +
 .../GCL/externs/goog/positioning/positioning.js |   619 +
 .../goog/positioning/viewportclientposition.js  |   124 +
 .../goog/positioning/viewportposition.js        |    66 +
 externs/GCL/externs/goog/promise/promise.js     |  1304 +
 externs/GCL/externs/goog/promise/resolver.js    |    48 +
 externs/GCL/externs/goog/promise/thenable.js    |   111 +
 externs/GCL/externs/goog/proto/proto.js         |    44 +
 externs/GCL/externs/goog/proto/serializer.js    |    70 +
 externs/GCL/externs/goog/proto2/descriptor.js   |   202 +
 .../GCL/externs/goog/proto2/fielddescriptor.js  |   312 +
 .../GCL/externs/goog/proto2/lazydeserializer.js |    70 +
 externs/GCL/externs/goog/proto2/message.js      |   722 +
 .../GCL/externs/goog/proto2/objectserializer.js |   176 +
 .../GCL/externs/goog/proto2/pbliteserializer.js |   199 +
 externs/GCL/externs/goog/proto2/serializer.js   |   182 +
 .../externs/goog/proto2/textformatserializer.js |  1072 +
 externs/GCL/externs/goog/proto2/util.js         |    54 +
 externs/GCL/externs/goog/pubsub/pubsub.js       |   321 +
 externs/GCL/externs/goog/pubsub/topicid.js      |    61 +
 externs/GCL/externs/goog/pubsub/typedpubsub.js  |   126 +
 externs/GCL/externs/goog/reflect/reflect.js     |    78 +
 .../GCL/externs/goog/result/deferredadaptor.js  |    59 +
 .../GCL/externs/goog/result/dependentresult.js  |    45 +
 .../GCL/externs/goog/result/result_interface.js |   119 +
 externs/GCL/externs/goog/result/resultutil.js   |   556 +
 externs/GCL/externs/goog/result/simpleresult.js |   260 +
 externs/GCL/externs/goog/soy/data.js            |   160 +
 externs/GCL/externs/goog/soy/renderer.js        |   314 +
 externs/GCL/externs/goog/soy/soy.js             |   218 +
 externs/GCL/externs/goog/spell/spellcheck.js    |   478 +
 externs/GCL/externs/goog/stats/basicstat.js     |   270 +
 .../externs/goog/storage/collectablestorage.js  |   134 +
 .../externs/goog/storage/encryptedstorage.js    |   196 +
 externs/GCL/externs/goog/storage/errorcode.js   |    30 +
 .../GCL/externs/goog/storage/expiringstorage.js |   141 +
 .../externs/goog/storage/mechanism/errorcode.js |    31 +
 .../storage/mechanism/errorhandlingmechanism.js |   131 +
 .../goog/storage/mechanism/html5localstorage.js |    46 +
 .../storage/mechanism/html5sessionstorage.js    |    47 +
 .../goog/storage/mechanism/html5webstorage.js   |   172 +
 .../goog/storage/mechanism/ieuserdata.js        |   279 +
 .../goog/storage/mechanism/iterablemechanism.js |    86 +
 .../externs/goog/storage/mechanism/mechanism.js |    57 +
 .../goog/storage/mechanism/mechanismfactory.js  |   112 +
 .../goog/storage/mechanism/prefixedmechanism.js |    92 +
 externs/GCL/externs/goog/storage/richstorage.js |   150 +
 externs/GCL/externs/goog/storage/storage.js     |    97 +
 externs/GCL/externs/goog/string/const.js        |   182 +
 externs/GCL/externs/goog/string/linkify.js      |   252 +
 externs/GCL/externs/goog/string/newlines.js     |   154 +
 externs/GCL/externs/goog/string/parser.js       |    38 +
 externs/GCL/externs/goog/string/path.js         |   169 +
 externs/GCL/externs/goog/string/string.js       |  1565 +
 externs/GCL/externs/goog/string/stringbuffer.js |   103 +
 externs/GCL/externs/goog/string/stringformat.js |   250 +
 externs/GCL/externs/goog/string/stringifier.js  |    38 +
 externs/GCL/externs/goog/string/typedstring.js  |    48 +
 externs/GCL/externs/goog/structs/avltree.js     |   899 +
 .../GCL/externs/goog/structs/circularbuffer.js  |   216 +
 externs/GCL/externs/goog/structs/collection.js  |    56 +
 externs/GCL/externs/goog/structs/heap.js        |   334 +
 .../GCL/externs/goog/structs/inversionmap.js    |   155 +
 externs/GCL/externs/goog/structs/linkedmap.js   |   488 +
 externs/GCL/externs/goog/structs/map.js         |   456 +
 externs/GCL/externs/goog/structs/node.js        |    73 +
 externs/GCL/externs/goog/structs/pool.js        |   376 +
 .../GCL/externs/goog/structs/prioritypool.js    |   182 +
 .../GCL/externs/goog/structs/priorityqueue.js   |    66 +
 externs/GCL/externs/goog/structs/quadtree.js    |   570 +
 externs/GCL/externs/goog/structs/queue.js       |   187 +
 externs/GCL/externs/goog/structs/set.js         |   279 +
 externs/GCL/externs/goog/structs/simplepool.js  |   200 +
 externs/GCL/externs/goog/structs/stringset.js   |   405 +
 externs/GCL/externs/goog/structs/structs.js     |   354 +
 externs/GCL/externs/goog/structs/treenode.js    |   458 +
 externs/GCL/externs/goog/structs/trie.js        |   395 +
 externs/GCL/externs/goog/structs/weak/weak.js   |   159 +
 externs/GCL/externs/goog/style/bidi.js          |   184 +
 externs/GCL/externs/goog/style/cursor.js        |   116 +
 externs/GCL/externs/goog/style/style.js         |  2045 ++
 .../GCL/externs/goog/style/style_test_rect.svg  |    11 +
 externs/GCL/externs/goog/style/transform.js     |   169 +
 externs/GCL/externs/goog/style/transition.js    |   133 +
 externs/GCL/externs/goog/testing/asserts.js     |  1265 +
 .../externs/goog/testing/async/mockcontrol.js   |   175 +
 externs/GCL/externs/goog/testing/benchmark.js   |    96 +
 externs/GCL/externs/goog/testing/dom.js         |   633 +
 externs/GCL/externs/goog/testing/editor/dom.js  |   293 +
 .../externs/goog/testing/editor/fieldmock.js    |   116 +
 .../goog/testing/events/eventobserver.js        |    87 +
 .../GCL/externs/goog/testing/events/events.js   |   727 +
 .../GCL/externs/goog/testing/events/matchers.js |    42 +
 .../goog/testing/events/onlinehandler.js        |    65 +
 .../externs/goog/testing/expectedfailures.js    |   237 +
 externs/GCL/externs/goog/testing/fs/blob.js     |   135 +
 externs/GCL/externs/goog/testing/fs/entry.js    |   637 +
 externs/GCL/externs/goog/testing/fs/file.js     |    53 +
 .../GCL/externs/goog/testing/fs/filereader.js   |   275 +
 .../GCL/externs/goog/testing/fs/filesystem.js   |    64 +
 .../GCL/externs/goog/testing/fs/filewriter.js   |   268 +
 externs/GCL/externs/goog/testing/fs/fs.js       |   169 +
 .../externs/goog/testing/fs/progressevent.js    |    82 +
 .../GCL/externs/goog/testing/functionmock.js    |   176 +
 externs/GCL/externs/goog/testing/graphics.js    |    64 +
 .../GCL/externs/goog/testing/i18n/asserts.js    |    77 +
 externs/GCL/externs/goog/testing/jsunit.js      |   162 +
 externs/GCL/externs/goog/testing/loosemock.js   |   242 +
 .../testing/messaging/mockmessagechannel.js     |    80 +
 .../goog/testing/messaging/mockmessageevent.js  |   102 +
 .../goog/testing/messaging/mockmessageport.js   |    86 +
 .../goog/testing/messaging/mockportnetwork.js   |    66 +
 externs/GCL/externs/goog/testing/mock.js        |   645 +
 .../externs/goog/testing/mockclassfactory.js    |   585 +
 externs/GCL/externs/goog/testing/mockclock.js   |   600 +
 externs/GCL/externs/goog/testing/mockcontrol.js |   220 +
 .../GCL/externs/goog/testing/mockinterface.js   |    45 +
 .../GCL/externs/goog/testing/mockmatchers.js    |   400 +
 externs/GCL/externs/goog/testing/mockrandom.js  |   153 +
 externs/GCL/externs/goog/testing/mockrange.js   |    67 +
 externs/GCL/externs/goog/testing/mockstorage.js |   108 +
 .../GCL/externs/goog/testing/mockuseragent.js   |   143 +
 externs/GCL/externs/goog/testing/net/xhrio.js   |   743 +
 .../GCL/externs/goog/testing/net/xhriopool.js   |    65 +
 .../goog/testing/objectpropertystring.js        |    68 +
 .../externs/goog/testing/performancetable.css   |    46 +
 .../externs/goog/testing/performancetable.js    |   196 +
 .../externs/goog/testing/performancetimer.js    |   418 +
 .../externs/goog/testing/propertyreplacer.js    |   245 +
 .../GCL/externs/goog/testing/proto2/proto2.js   |   145 +
 .../GCL/externs/goog/testing/pseudorandom.js    |   180 +
 .../GCL/externs/goog/testing/recordfunction.js  |   215 +
 externs/GCL/externs/goog/testing/singleton.js   |    46 +
 externs/GCL/externs/goog/testing/stacktrace.js  |   594 +
 .../goog/testing/storage/fakemechanism.js       |    68 +
 externs/GCL/externs/goog/testing/strictmock.js  |   130 +
 .../externs/goog/testing/style/layoutasserts.js |   310 +
 externs/GCL/externs/goog/testing/style/style.js |   101 +
 .../externs/goog/testing/ui/rendererasserts.js  |    58 +
 .../externs/goog/testing/ui/rendererharness.js  |   177 +
 externs/GCL/externs/goog/testing/ui/style.js    |   140 +
 externs/GCL/externs/goog/testing/watchers.js    |    46 +
 externs/GCL/externs/goog/timer/timer.js         |   329 +
 externs/GCL/externs/goog/tweak/entries.js       |  1002 +
 externs/GCL/externs/goog/tweak/registry.js      |   315 +
 externs/GCL/externs/goog/tweak/tweak.js         |   301 +
 externs/GCL/externs/goog/tweak/tweakui.js       |   841 +
 .../GCL/externs/goog/ui/abstractspellchecker.js |  1231 +
 externs/GCL/externs/goog/ui/ac/ac.js            |    50 +
 externs/GCL/externs/goog/ui/ac/arraymatcher.js  |   216 +
 externs/GCL/externs/goog/ui/ac/autocomplete.js  |   921 +
 .../GCL/externs/goog/ui/ac/cachingmatcher.js    |   273 +
 externs/GCL/externs/goog/ui/ac/inputhandler.js  |  1327 +
 externs/GCL/externs/goog/ui/ac/remote.js        |   114 +
 .../externs/goog/ui/ac/remotearraymatcher.js    |   274 +
 externs/GCL/externs/goog/ui/ac/renderer.js      |  1109 +
 externs/GCL/externs/goog/ui/ac/renderoptions.js |    80 +
 .../GCL/externs/goog/ui/ac/richinputhandler.js  |    58 +
 externs/GCL/externs/goog/ui/ac/richremote.js    |   113 +
 .../goog/ui/ac/richremotearraymatcher.js        |   144 +
 externs/GCL/externs/goog/ui/activitymonitor.js  |   348 +
 externs/GCL/externs/goog/ui/advancedtooltip.js  |   367 +
 externs/GCL/externs/goog/ui/animatedzippy.js    |   202 +
 externs/GCL/externs/goog/ui/attachablemenu.js   |   476 +
 externs/GCL/externs/goog/ui/bidiinput.js        |   174 +
 externs/GCL/externs/goog/ui/bubble.js           |   490 +
 externs/GCL/externs/goog/ui/button.js           |   214 +
 externs/GCL/externs/goog/ui/buttonrenderer.js   |   219 +
 externs/GCL/externs/goog/ui/buttonside.js       |    41 +
 externs/GCL/externs/goog/ui/charcounter.js      |   199 +
 externs/GCL/externs/goog/ui/charpicker.js       |   925 +
 externs/GCL/externs/goog/ui/checkbox.js         |   272 +
 externs/GCL/externs/goog/ui/checkboxmenuitem.js |    53 +
 externs/GCL/externs/goog/ui/checkboxrenderer.js |   191 +
 externs/GCL/externs/goog/ui/colorbutton.js      |    59 +
 .../GCL/externs/goog/ui/colorbuttonrenderer.js  |    75 +
 externs/GCL/externs/goog/ui/colormenubutton.js  |   215 +
 .../externs/goog/ui/colormenubuttonrenderer.js  |   148 +
 externs/GCL/externs/goog/ui/colorpalette.js     |   179 +
 externs/GCL/externs/goog/ui/colorpicker.js      |   345 +
 .../GCL/externs/goog/ui/colorsplitbehavior.js   |    61 +
 externs/GCL/externs/goog/ui/combobox.js         |   993 +
 externs/GCL/externs/goog/ui/component.js        |  1298 +
 externs/GCL/externs/goog/ui/container.js        |  1354 +
 .../GCL/externs/goog/ui/containerrenderer.js    |   375 +
 .../GCL/externs/goog/ui/containerscroller.js    |   223 +
 externs/GCL/externs/goog/ui/control.js          |  1542 +
 externs/GCL/externs/goog/ui/controlcontent.js   |    28 +
 externs/GCL/externs/goog/ui/controlrenderer.js  |   949 +
 externs/GCL/externs/goog/ui/cookieeditor.js     |   185 +
 .../GCL/externs/goog/ui/css3buttonrenderer.js   |   155 +
 .../externs/goog/ui/css3menubuttonrenderer.js   |   148 +
 externs/GCL/externs/goog/ui/cssnames.js         |    29 +
 externs/GCL/externs/goog/ui/custombutton.js     |    58 +
 .../GCL/externs/goog/ui/custombuttonrenderer.js |   272 +
 .../GCL/externs/goog/ui/customcolorpalette.js   |   141 +
 externs/GCL/externs/goog/ui/datepicker.js       |  1550 +
 .../GCL/externs/goog/ui/datepickerrenderer.js   |    55 +
 externs/GCL/externs/goog/ui/decorate.js         |    38 +
 .../goog/ui/defaultdatepickerrenderer.js        |   202 +
 externs/GCL/externs/goog/ui/dialog.js           |  1611 +
 externs/GCL/externs/goog/ui/dimensionpicker.js  |   318 +
 .../externs/goog/ui/dimensionpickerrenderer.js  |   420 +
 externs/GCL/externs/goog/ui/dragdropdetector.js |   648 +
 externs/GCL/externs/goog/ui/drilldownrow.js     |   547 +
 .../externs/goog/ui/editor/abstractdialog.js    |   444 +
 externs/GCL/externs/goog/ui/editor/bubble.js    |   559 +
 .../externs/goog/ui/editor/defaulttoolbar.js    |  1066 +
 .../GCL/externs/goog/ui/editor/linkdialog.js    |  1065 +
 externs/GCL/externs/goog/ui/editor/messages.js  |   148 +
 externs/GCL/externs/goog/ui/editor/tabpane.js   |   202 +
 .../externs/goog/ui/editor/toolbarcontroller.js |   296 +
 .../externs/goog/ui/editor/toolbarfactory.js    |   439 +
 externs/GCL/externs/goog/ui/emoji/emoji.js      |    73 +
 .../GCL/externs/goog/ui/emoji/emojipalette.js   |   288 +
 .../goog/ui/emoji/emojipaletterenderer.js       |   210 +
 .../GCL/externs/goog/ui/emoji/emojipicker.js    |   802 +
 .../externs/goog/ui/emoji/popupemojipicker.js   |   411 +
 .../ui/emoji/progressiveemojipaletterenderer.js |   100 +
 externs/GCL/externs/goog/ui/emoji/spriteinfo.js |   213 +
 externs/GCL/externs/goog/ui/filteredmenu.js     |   638 +
 .../externs/goog/ui/filterobservingmenuitem.js  |    98 +
 .../goog/ui/filterobservingmenuitemrenderer.js  |    63 +
 .../GCL/externs/goog/ui/flatbuttonrenderer.js   |   148 +
 .../externs/goog/ui/flatmenubuttonrenderer.js   |   209 +
 externs/GCL/externs/goog/ui/formpost.js         |   109 +
 externs/GCL/externs/goog/ui/gauge.js            |  1014 +
 externs/GCL/externs/goog/ui/gaugetheme.js       |   170 +
 externs/GCL/externs/goog/ui/hovercard.js        |   458 +
 externs/GCL/externs/goog/ui/hsvapalette.js      |   295 +
 externs/GCL/externs/goog/ui/hsvpalette.js       |   527 +
 externs/GCL/externs/goog/ui/idgenerator.js      |    48 +
 externs/GCL/externs/goog/ui/idletimer.js        |   300 +
 externs/GCL/externs/goog/ui/iframemask.js       |   258 +
 .../externs/goog/ui/imagelessbuttonrenderer.js  |   208 +
 .../goog/ui/imagelessmenubuttonrenderer.js      |   213 +
 externs/GCL/externs/goog/ui/inputdatepicker.js  |   343 +
 externs/GCL/externs/goog/ui/itemevent.js        |    51 +
 .../externs/goog/ui/keyboardshortcuthandler.js  |  1162 +
 externs/GCL/externs/goog/ui/labelinput.js       |   614 +
 .../GCL/externs/goog/ui/linkbuttonrenderer.js   |    67 +
 .../GCL/externs/goog/ui/media/flashobject.js    |   632 +
 externs/GCL/externs/goog/ui/media/flickr.js     |   314 +
 .../GCL/externs/goog/ui/media/googlevideo.js    |   283 +
 externs/GCL/externs/goog/ui/media/media.js      |   290 +
 externs/GCL/externs/goog/ui/media/mediamodel.js |   978 +
 externs/GCL/externs/goog/ui/media/mp3.js        |   226 +
 externs/GCL/externs/goog/ui/media/photo.js      |   144 +
 externs/GCL/externs/goog/ui/media/picasa.js     |   327 +
 externs/GCL/externs/goog/ui/media/vimeo.js      |   278 +
 externs/GCL/externs/goog/ui/media/youtube.js    |   359 +
 externs/GCL/externs/goog/ui/menu.js             |   479 +
 externs/GCL/externs/goog/ui/menubar.js          |    44 +
 externs/GCL/externs/goog/ui/menubardecorator.js |    35 +
 externs/GCL/externs/goog/ui/menubarrenderer.js  |    68 +
 externs/GCL/externs/goog/ui/menubase.js         |   190 +
 externs/GCL/externs/goog/ui/menubutton.js       |  1052 +
 .../GCL/externs/goog/ui/menubuttonrenderer.js   |   192 +
 externs/GCL/externs/goog/ui/menuheader.js       |    62 +
 .../GCL/externs/goog/ui/menuheaderrenderer.js   |    54 +
 externs/GCL/externs/goog/ui/menuitem.js         |   322 +
 externs/GCL/externs/goog/ui/menuitemrenderer.js |   356 +
 externs/GCL/externs/goog/ui/menurenderer.js     |   115 +
 externs/GCL/externs/goog/ui/menuseparator.js    |    52 +
 .../externs/goog/ui/menuseparatorrenderer.js    |   114 +
 .../GCL/externs/goog/ui/mockactivitymonitor.js  |    72 +
 .../goog/ui/modalariavisibilityhelper.js        |    87 +
 externs/GCL/externs/goog/ui/modalpopup.js       |   732 +
 .../GCL/externs/goog/ui/nativebuttonrenderer.js |   213 +
 externs/GCL/externs/goog/ui/option.js           |    68 +
 externs/GCL/externs/goog/ui/palette.js          |   604 +
 externs/GCL/externs/goog/ui/paletterenderer.js  |   383 +
 .../externs/goog/ui/plaintextspellchecker.js    |   643 +
 externs/GCL/externs/goog/ui/popup.js            |   185 +
 externs/GCL/externs/goog/ui/popupbase.js        |   894 +
 externs/GCL/externs/goog/ui/popupcolorpicker.js |   475 +
 externs/GCL/externs/goog/ui/popupdatepicker.js  |   288 +
 externs/GCL/externs/goog/ui/popupmenu.js        |   643 +
 externs/GCL/externs/goog/ui/progressbar.js      |   408 +
 externs/GCL/externs/goog/ui/prompt.js           |   411 +
 externs/GCL/externs/goog/ui/rangemodel.js       |   303 +
 externs/GCL/externs/goog/ui/ratings.js          |   509 +
 externs/GCL/externs/goog/ui/registry.js         |   172 +
 .../GCL/externs/goog/ui/richtextspellchecker.js |   780 +
 externs/GCL/externs/goog/ui/roundedpanel.js     |   632 +
 .../GCL/externs/goog/ui/roundedtabrenderer.js   |   201 +
 externs/GCL/externs/goog/ui/scrollfloater.js    |   637 +
 externs/GCL/externs/goog/ui/select.js           |   538 +
 .../GCL/externs/goog/ui/selectionmenubutton.js  |   302 +
 externs/GCL/externs/goog/ui/selectionmodel.js   |   301 +
 externs/GCL/externs/goog/ui/separator.js        |    80 +
 externs/GCL/externs/goog/ui/serverchart.js      |  1840 ++
 externs/GCL/externs/goog/ui/slider.js           |   136 +
 externs/GCL/externs/goog/ui/sliderbase.js       |  1657 +
 externs/GCL/externs/goog/ui/splitbehavior.js    |   335 +
 externs/GCL/externs/goog/ui/splitpane.js        |   911 +
 .../externs/goog/ui/style/app/buttonrenderer.js |   205 +
 .../goog/ui/style/app/menubuttonrenderer.js     |   236 +
 .../ui/style/app/primaryactionbuttonrenderer.js |    89 +
 externs/GCL/externs/goog/ui/submenu.js          |   672 +
 externs/GCL/externs/goog/ui/submenurenderer.js  |   241 +
 externs/GCL/externs/goog/ui/tab.js              |   103 +
 externs/GCL/externs/goog/ui/tabbar.js           |   395 +
 externs/GCL/externs/goog/ui/tabbarrenderer.js   |   165 +
 externs/GCL/externs/goog/ui/tablesorter.js      |   324 +
 externs/GCL/externs/goog/ui/tabpane.js          |   682 +
 externs/GCL/externs/goog/ui/tabrenderer.js      |   153 +
 externs/GCL/externs/goog/ui/textarea.js         |   736 +
 externs/GCL/externs/goog/ui/textarearenderer.js |   170 +
 externs/GCL/externs/goog/ui/togglebutton.js     |    58 +
 externs/GCL/externs/goog/ui/toolbar.js          |    59 +
 externs/GCL/externs/goog/ui/toolbarbutton.js    |    54 +
 .../externs/goog/ui/toolbarbuttonrenderer.js    |    57 +
 .../externs/goog/ui/toolbarcolormenubutton.js   |    57 +
 .../goog/ui/toolbarcolormenubuttonrenderer.js   |   101 +
 .../GCL/externs/goog/ui/toolbarmenubutton.js    |    56 +
 .../goog/ui/toolbarmenubuttonrenderer.js        |    57 +
 externs/GCL/externs/goog/ui/toolbarrenderer.js  |    90 +
 externs/GCL/externs/goog/ui/toolbarselect.js    |    55 +
 externs/GCL/externs/goog/ui/toolbarseparator.js |    53 +
 .../externs/goog/ui/toolbarseparatorrenderer.js |    95 +
 .../GCL/externs/goog/ui/toolbartogglebutton.js  |    53 +
 externs/GCL/externs/goog/ui/tooltip.js          |  1050 +
 externs/GCL/externs/goog/ui/tree/basenode.js    |  1569 +
 externs/GCL/externs/goog/ui/tree/treecontrol.js |   642 +
 externs/GCL/externs/goog/ui/tree/treenode.js    |   100 +
 externs/GCL/externs/goog/ui/tree/typeahead.js   |   332 +
 externs/GCL/externs/goog/ui/tristatemenuitem.js |   196 +
 .../externs/goog/ui/tristatemenuitemrenderer.js |    92 +
 externs/GCL/externs/goog/ui/twothumbslider.js   |   159 +
 externs/GCL/externs/goog/ui/zippy.js            |   461 +
 externs/GCL/externs/goog/uri/uri.js             |  1507 +
 externs/GCL/externs/goog/uri/utils.js           |  1116 +
 .../GCL/externs/goog/useragent/adobereader.js   |    90 +
 externs/GCL/externs/goog/useragent/flash.js     |   156 +
 externs/GCL/externs/goog/useragent/iphoto.js    |    87 +
 externs/GCL/externs/goog/useragent/jscript.js   |    95 +
 externs/GCL/externs/goog/useragent/keyboard.js  |    49 +
 externs/GCL/externs/goog/useragent/platform.js  |    83 +
 externs/GCL/externs/goog/useragent/product.js   |   175 +
 .../externs/goog/useragent/product_isversion.js |   143 +
 externs/GCL/externs/goog/useragent/useragent.js |   538 +
 externs/GCL/externs/goog/vec/float32array.js    |   111 +
 externs/GCL/externs/goog/vec/float64array.js    |   118 +
 externs/GCL/externs/goog/vec/mat3.js            |  1211 +
 externs/GCL/externs/goog/vec/mat3d.js           |  1039 +
 externs/GCL/externs/goog/vec/mat3f.js           |  1039 +
 externs/GCL/externs/goog/vec/mat4.js            |  1822 ++
 externs/GCL/externs/goog/vec/mat4d.js           |  1769 ++
 externs/GCL/externs/goog/vec/mat4f.js           |  1769 ++
 externs/GCL/externs/goog/vec/matrix3.js         |   720 +
 externs/GCL/externs/goog/vec/matrix4.js         |  1405 +
 externs/GCL/externs/goog/vec/quaternion.js      |   458 +
 externs/GCL/externs/goog/vec/ray.js             |    95 +
 externs/GCL/externs/goog/vec/vec.js             |    73 +
 externs/GCL/externs/goog/vec/vec2.js            |   439 +
 externs/GCL/externs/goog/vec/vec2d.js           |   424 +
 externs/GCL/externs/goog/vec/vec2f.js           |   424 +
 externs/GCL/externs/goog/vec/vec3.js            |   542 +
 externs/GCL/externs/goog/vec/vec3d.js           |   426 +
 externs/GCL/externs/goog/vec/vec3f.js           |   426 +
 externs/GCL/externs/goog/vec/vec4.js            |   479 +
 externs/GCL/externs/goog/vec/vec4d.js           |   366 +
 externs/GCL/externs/goog/vec/vec4f.js           |   366 +
 externs/GCL/externs/goog/webgl/webgl.js         |  2194 ++
 externs/GCL/externs/goog/window/window.js       |   284 +
 externs/GCL/src/goog/Disposable.as              |   132 +
 externs/GCL/src/goog/disposable/Disposable.as   |    14 +
 externs/GCL/src/goog/disposable/IDisposable.as  |    14 +
 .../GCL/src/goog/disposable/MonitoringMode.as   |    31 +
 externs/GCL/src/goog/events.as                  |     6 +
 externs/GCL/src/goog/events/BrowserEvent.as     |    94 +
 .../src/goog/events/BrowserEvent/MouseButton.as |    33 +
 .../src/goog/events/CaptureSimulationMode.as    |    31 +
 externs/GCL/src/goog/events/Event.as            |    52 +
 externs/GCL/src/goog/events/EventTarget.as      |   213 +
 externs/GCL/src/goog/events/EventType.as        |   838 +
 externs/GCL/src/goog/events/Listenable.as       |   143 +
 externs/GCL/src/goog/events/ListenableKey.as    |    73 +
 externs/GCL/src/goog/events/listen.as           |     5 +
 1074 files changed, 412464 insertions(+)
----------------------------------------------------------------------



[38/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/debug.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/debug.js b/externs/GCL/externs/goog/debug/debug.js
new file mode 100644
index 0000000..ff15374
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/debug.js
@@ -0,0 +1,653 @@
+// 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 Logging and debugging utilities.
+ *
+ * @see ../demos/debug.html
+ */
+
+goog.provide('goog.debug');
+
+goog.require('goog.array');
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.SafeUrl');
+goog.require('goog.html.uncheckedconversions');
+goog.require('goog.string.Const');
+goog.require('goog.structs.Set');
+goog.require('goog.userAgent');
+
+
+/** @define {boolean} Whether logging should be enabled. */
+goog.define('goog.debug.LOGGING_ENABLED', goog.DEBUG);
+
+
+/**
+ * Catches onerror events fired by windows and similar objects.
+ * @param {function(Object)} logFunc The function to call with the error
+ *    information.
+ * @param {boolean=} opt_cancel Whether to stop the error from reaching the
+ *    browser.
+ * @param {Object=} opt_target Object that fires onerror events.
+ */
+goog.debug.catchErrors = function(logFunc, opt_cancel, opt_target) {
+  var target = opt_target || goog.global;
+  var oldErrorHandler = target.onerror;
+  var retVal = !!opt_cancel;
+
+  // Chrome interprets onerror return value backwards (http://crbug.com/92062)
+  // until it was fixed in webkit revision r94061 (Webkit 535.3). This
+  // workaround still needs to be skipped in Safari after the webkit change
+  // gets pushed out in Safari.
+  // See https://bugs.webkit.org/show_bug.cgi?id=67119
+  if (goog.userAgent.WEBKIT &&
+      !goog.userAgent.isVersionOrHigher('535.3')) {
+    retVal = !retVal;
+  }
+
+  /**
+   * New onerror handler for this target. This onerror handler follows the spec
+   * according to
+   * http://www.whatwg.org/specs/web-apps/current-work/#runtime-script-errors
+   * The spec was changed in August 2013 to support receiving column information
+   * and an error object for all scripts on the same origin or cross origin
+   * scripts with the proper headers. See
+   * https://mikewest.org/2013/08/debugging-runtime-errors-with-window-onerror
+   *
+   * @param {string} message The error message. For cross-origin errors, this
+   *     will be scrubbed to just "Script error.". For new browsers that have
+   *     updated to follow the latest spec, errors that come from origins that
+   *     have proper cross origin headers will not be scrubbed.
+   * @param {string} url The URL of the script that caused the error. The URL
+   *     will be scrubbed to "" for cross origin scripts unless the script has
+   *     proper cross origin headers and the browser has updated to the latest
+   *     spec.
+   * @param {number} line The line number in the script that the error
+   *     occurred on.
+   * @param {number=} opt_col The optional column number that the error
+   *     occurred on. Only browsers that have updated to the latest spec will
+   *     include this.
+   * @param {Error=} opt_error The optional actual error object for this
+   *     error that should include the stack. Only browsers that have updated
+   *     to the latest spec will inlude this parameter.
+   * @return {boolean} Whether to prevent the error from reaching the browser.
+   */
+  target.onerror = function(message, url, line, opt_col, opt_error) {
+    if (oldErrorHandler) {
+      oldErrorHandler(message, url, line, opt_col, opt_error);
+    }
+    logFunc({
+      message: message,
+      fileName: url,
+      line: line,
+      col: opt_col,
+      error: opt_error
+    });
+    return retVal;
+  };
+};
+
+
+/**
+ * Creates a string representing an object and all its properties.
+ * @param {Object|null|undefined} obj Object to expose.
+ * @param {boolean=} opt_showFn Show the functions as well as the properties,
+ *     default is false.
+ * @return {string} The string representation of {@code obj}.
+ */
+goog.debug.expose = function(obj, opt_showFn) {
+  if (typeof obj == 'undefined') {
+    return 'undefined';
+  }
+  if (obj == null) {
+    return 'NULL';
+  }
+  var str = [];
+
+  for (var x in obj) {
+    if (!opt_showFn && goog.isFunction(obj[x])) {
+      continue;
+    }
+    var s = x + ' = ';
+    /** @preserveTry */
+    try {
+      s += obj[x];
+    } catch (e) {
+      s += '*** ' + e + ' ***';
+    }
+    str.push(s);
+  }
+  return str.join('\n');
+};
+
+
+/**
+ * Creates a string representing a given primitive or object, and for an
+ * object, all its properties and nested objects.  WARNING: If an object is
+ * given, it and all its nested objects will be modified.  To detect reference
+ * cycles, this method identifies objects using goog.getUid() which mutates the
+ * object.
+ * @param {*} obj Object to expose.
+ * @param {boolean=} opt_showFn Also show properties that are functions (by
+ *     default, functions are omitted).
+ * @return {string} A string representation of {@code obj}.
+ */
+goog.debug.deepExpose = function(obj, opt_showFn) {
+  var str = [];
+
+  var helper = function(obj, space, parentSeen) {
+    var nestspace = space + '  ';
+    var seen = new goog.structs.Set(parentSeen);
+
+    var indentMultiline = function(str) {
+      return str.replace(/\n/g, '\n' + space);
+    };
+
+    /** @preserveTry */
+    try {
+      if (!goog.isDef(obj)) {
+        str.push('undefined');
+      } else if (goog.isNull(obj)) {
+        str.push('NULL');
+      } else if (goog.isString(obj)) {
+        str.push('"' + indentMultiline(obj) + '"');
+      } else if (goog.isFunction(obj)) {
+        str.push(indentMultiline(String(obj)));
+      } else if (goog.isObject(obj)) {
+        if (seen.contains(obj)) {
+          str.push('*** reference loop detected ***');
+        } else {
+          seen.add(obj);
+          str.push('{');
+          for (var x in obj) {
+            if (!opt_showFn && goog.isFunction(obj[x])) {
+              continue;
+            }
+            str.push('\n');
+            str.push(nestspace);
+            str.push(x + ' = ');
+            helper(obj[x], nestspace, seen);
+          }
+          str.push('\n' + space + '}');
+        }
+      } else {
+        str.push(obj);
+      }
+    } catch (e) {
+      str.push('*** ' + e + ' ***');
+    }
+  };
+
+  helper(obj, '', new goog.structs.Set());
+  return str.join('');
+};
+
+
+/**
+ * Recursively outputs a nested array as a string.
+ * @param {Array<?>} arr The array.
+ * @return {string} String representing nested array.
+ */
+goog.debug.exposeArray = function(arr) {
+  var str = [];
+  for (var i = 0; i < arr.length; i++) {
+    if (goog.isArray(arr[i])) {
+      str.push(goog.debug.exposeArray(arr[i]));
+    } else {
+      str.push(arr[i]);
+    }
+  }
+  return '[ ' + str.join(', ') + ' ]';
+};
+
+
+/**
+ * Exposes an exception that has been caught by a try...catch and outputs the
+ * error as HTML with a stack trace.
+ * @param {Object} err Error object or string.
+ * @param {Function=} opt_fn Optional function to start stack trace from.
+ * @return {string} Details of exception, as HTML.
+ */
+goog.debug.exposeException = function(err, opt_fn) {
+  var html = goog.debug.exposeExceptionAsHtml(err, opt_fn);
+  return goog.html.SafeHtml.unwrap(html);
+};
+
+
+/**
+ * Exposes an exception that has been caught by a try...catch and outputs the
+ * error with a stack trace.
+ * @param {Object} err Error object or string.
+ * @param {Function=} opt_fn Optional function to start stack trace from.
+ * @return {!goog.html.SafeHtml} Details of exception.
+ */
+goog.debug.exposeExceptionAsHtml = function(err, opt_fn) {
+  /** @preserveTry */
+  try {
+    var e = goog.debug.normalizeErrorObject(err);
+    // Create the error message
+    var viewSourceUrl = goog.debug.createViewSourceUrl_(e.fileName);
+    var error = goog.html.SafeHtml.concat(
+        goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(
+            'Message: ' + e.message + '\nUrl: '),
+        goog.html.SafeHtml.create('a',
+            {href: viewSourceUrl, target: '_new'}, e.fileName),
+        goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(
+            '\nLine: ' + e.lineNumber + '\n\nBrowser stack:\n' +
+            e.stack + '-> ' + '[end]\n\nJS stack traversal:\n' +
+            goog.debug.getStacktrace(opt_fn) + '-> '));
+    return error;
+  } catch (e2) {
+    return goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(
+        'Exception trying to expose exception! You win, we lose. ' + e2);
+  }
+};
+
+
+/**
+ * @param {?string=} opt_fileName
+ * @return {!goog.html.SafeUrl} SafeUrl with view-source scheme, pointing at
+ *     fileName.
+ * @private
+ */
+goog.debug.createViewSourceUrl_ = function(opt_fileName) {
+  if (!goog.isDefAndNotNull(opt_fileName)) {
+    opt_fileName = '';
+  }
+  if (!/^https?:\/\//i.test(opt_fileName)) {
+    return goog.html.SafeUrl.fromConstant(
+        goog.string.Const.from('sanitizedviewsrc'));
+  }
+  var sanitizedFileName = goog.html.SafeUrl.sanitize(opt_fileName);
+  return goog.html.uncheckedconversions.
+      safeUrlFromStringKnownToSatisfyTypeContract(
+          goog.string.Const.from('view-source scheme plus HTTP/HTTPS URL'),
+          'view-source:' + goog.html.SafeUrl.unwrap(sanitizedFileName));
+};
+
+
+/**
+ * Normalizes the error/exception object between browsers.
+ * @param {Object} err Raw error object.
+ * @return {!Object} Normalized error object.
+ */
+goog.debug.normalizeErrorObject = function(err) {
+  var href = goog.getObjectByName('window.location.href');
+  if (goog.isString(err)) {
+    return {
+      'message': err,
+      'name': 'Unknown error',
+      'lineNumber': 'Not available',
+      'fileName': href,
+      'stack': 'Not available'
+    };
+  }
+
+  var lineNumber, fileName;
+  var threwError = false;
+
+  try {
+    lineNumber = err.lineNumber || err.line || 'Not available';
+  } catch (e) {
+    // Firefox 2 sometimes throws an error when accessing 'lineNumber':
+    // Message: Permission denied to get property UnnamedClass.lineNumber
+    lineNumber = 'Not available';
+    threwError = true;
+  }
+
+  try {
+    fileName = err.fileName || err.filename || err.sourceURL ||
+        // $googDebugFname may be set before a call to eval to set the filename
+        // that the eval is supposed to present.
+        goog.global['$googDebugFname'] || href;
+  } catch (e) {
+    // Firefox 2 may also throw an error when accessing 'filename'.
+    fileName = 'Not available';
+    threwError = true;
+  }
+
+  // The IE Error object contains only the name and the message.
+  // The Safari Error object uses the line and sourceURL fields.
+  if (threwError || !err.lineNumber || !err.fileName || !err.stack ||
+      !err.message || !err.name) {
+    return {
+      'message': err.message || 'Not available',
+      'name': err.name || 'UnknownError',
+      'lineNumber': lineNumber,
+      'fileName': fileName,
+      'stack': err.stack || 'Not available'
+    };
+  }
+
+  // Standards error object
+  return err;
+};
+
+
+/**
+ * Converts an object to an Error if it's a String,
+ * adds a stacktrace if there isn't one,
+ * and optionally adds an extra message.
+ * @param {Error|string} err  the original thrown object or string.
+ * @param {string=} opt_message  optional additional message to add to the
+ *     error.
+ * @return {!Error} If err is a string, it is used to create a new Error,
+ *     which is enhanced and returned.  Otherwise err itself is enhanced
+ *     and returned.
+ */
+goog.debug.enhanceError = function(err, opt_message) {
+  var error;
+  if (typeof err == 'string') {
+    error = Error(err);
+    if (Error.captureStackTrace) {
+      // Trim this function off the call stack, if we can.
+      Error.captureStackTrace(error, goog.debug.enhanceError);
+    }
+  } else {
+    error = err;
+  }
+
+  if (!error.stack) {
+    error.stack = goog.debug.getStacktrace(goog.debug.enhanceError);
+  }
+  if (opt_message) {
+    // find the first unoccupied 'messageX' property
+    var x = 0;
+    while (error['message' + x]) {
+      ++x;
+    }
+    error['message' + x] = String(opt_message);
+  }
+  return error;
+};
+
+
+/**
+ * Gets the current stack trace. Simple and iterative - doesn't worry about
+ * catching circular references or getting the args.
+ * @param {number=} opt_depth Optional maximum depth to trace back to.
+ * @return {string} A string with the function names of all functions in the
+ *     stack, separated by \n.
+ * @suppress {es5Strict}
+ */
+goog.debug.getStacktraceSimple = function(opt_depth) {
+  if (goog.STRICT_MODE_COMPATIBLE) {
+    var stack = goog.debug.getNativeStackTrace_(goog.debug.getStacktraceSimple);
+    if (stack) {
+      return stack;
+    }
+    // NOTE: browsers that have strict mode support also have native "stack"
+    // properties.  Fall-through for legacy browser support.
+  }
+
+  var sb = [];
+  var fn = arguments.callee.caller;
+  var depth = 0;
+
+  while (fn && (!opt_depth || depth < opt_depth)) {
+    sb.push(goog.debug.getFunctionName(fn));
+    sb.push('()\n');
+    /** @preserveTry */
+    try {
+      fn = fn.caller;
+    } catch (e) {
+      sb.push('[exception trying to get caller]\n');
+      break;
+    }
+    depth++;
+    if (depth >= goog.debug.MAX_STACK_DEPTH) {
+      sb.push('[...long stack...]');
+      break;
+    }
+  }
+  if (opt_depth && depth >= opt_depth) {
+    sb.push('[...reached max depth limit...]');
+  } else {
+    sb.push('[end]');
+  }
+
+  return sb.join('');
+};
+
+
+/**
+ * Max length of stack to try and output
+ * @type {number}
+ */
+goog.debug.MAX_STACK_DEPTH = 50;
+
+
+/**
+ * @param {Function} fn The function to start getting the trace from.
+ * @return {?string}
+ * @private
+ */
+goog.debug.getNativeStackTrace_ = function(fn) {
+  var tempErr = new Error();
+  if (Error.captureStackTrace) {
+    Error.captureStackTrace(tempErr, fn);
+    return String(tempErr.stack);
+  } else {
+    // IE10, only adds stack traces when an exception is thrown.
+    try {
+      throw tempErr;
+    } catch (e) {
+      tempErr = e;
+    }
+    var stack = tempErr.stack;
+    if (stack) {
+      return String(stack);
+    }
+  }
+  return null;
+};
+
+
+/**
+ * Gets the current stack trace, either starting from the caller or starting
+ * from a specified function that's currently on the call stack.
+ * @param {Function=} opt_fn Optional function to start getting the trace from.
+ *     If not provided, defaults to the function that called this.
+ * @return {string} Stack trace.
+ * @suppress {es5Strict}
+ */
+goog.debug.getStacktrace = function(opt_fn) {
+  var stack;
+  if (goog.STRICT_MODE_COMPATIBLE) {
+    // Try to get the stack trace from the environment if it is available.
+    var contextFn = opt_fn || goog.debug.getStacktrace;
+    stack = goog.debug.getNativeStackTrace_(contextFn);
+  }
+  if (!stack) {
+    // NOTE: browsers that have strict mode support also have native "stack"
+    // properties. This function will throw in strict mode.
+    stack = goog.debug.getStacktraceHelper_(
+        opt_fn || arguments.callee.caller, []);
+  }
+  return stack;
+};
+
+
+/**
+ * Private helper for getStacktrace().
+ * @param {Function} fn Function to start getting the trace from.
+ * @param {Array<!Function>} visited List of functions visited so far.
+ * @return {string} Stack trace starting from function fn.
+ * @suppress {es5Strict}
+ * @private
+ */
+goog.debug.getStacktraceHelper_ = function(fn, visited) {
+  var sb = [];
+
+  // Circular reference, certain functions like bind seem to cause a recursive
+  // loop so we need to catch circular references
+  if (goog.array.contains(visited, fn)) {
+    sb.push('[...circular reference...]');
+
+  // Traverse the call stack until function not found or max depth is reached
+  } else if (fn && visited.length < goog.debug.MAX_STACK_DEPTH) {
+    sb.push(goog.debug.getFunctionName(fn) + '(');
+    var args = fn.arguments;
+    // Args may be null for some special functions such as host objects or eval.
+    for (var i = 0; args && i < args.length; i++) {
+      if (i > 0) {
+        sb.push(', ');
+      }
+      var argDesc;
+      var arg = args[i];
+      switch (typeof arg) {
+        case 'object':
+          argDesc = arg ? 'object' : 'null';
+          break;
+
+        case 'string':
+          argDesc = arg;
+          break;
+
+        case 'number':
+          argDesc = String(arg);
+          break;
+
+        case 'boolean':
+          argDesc = arg ? 'true' : 'false';
+          break;
+
+        case 'function':
+          argDesc = goog.debug.getFunctionName(arg);
+          argDesc = argDesc ? argDesc : '[fn]';
+          break;
+
+        case 'undefined':
+        default:
+          argDesc = typeof arg;
+          break;
+      }
+
+      if (argDesc.length > 40) {
+        argDesc = argDesc.substr(0, 40) + '...';
+      }
+      sb.push(argDesc);
+    }
+    visited.push(fn);
+    sb.push(')\n');
+    /** @preserveTry */
+    try {
+      sb.push(goog.debug.getStacktraceHelper_(fn.caller, visited));
+    } catch (e) {
+      sb.push('[exception trying to get caller]\n');
+    }
+
+  } else if (fn) {
+    sb.push('[...long stack...]');
+  } else {
+    sb.push('[end]');
+  }
+  return sb.join('');
+};
+
+
+/**
+ * Set a custom function name resolver.
+ * @param {function(Function): string} resolver Resolves functions to their
+ *     names.
+ */
+goog.debug.setFunctionResolver = function(resolver) {
+  goog.debug.fnNameResolver_ = resolver;
+};
+
+
+/**
+ * Gets a function name
+ * @param {Function} fn Function to get name of.
+ * @return {string} Function's name.
+ */
+goog.debug.getFunctionName = function(fn) {
+  if (goog.debug.fnNameCache_[fn]) {
+    return goog.debug.fnNameCache_[fn];
+  }
+  if (goog.debug.fnNameResolver_) {
+    var name = goog.debug.fnNameResolver_(fn);
+    if (name) {
+      goog.debug.fnNameCache_[fn] = name;
+      return name;
+    }
+  }
+
+  // Heuristically determine function name based on code.
+  var functionSource = String(fn);
+  if (!goog.debug.fnNameCache_[functionSource]) {
+    var matches = /function ([^\(]+)/.exec(functionSource);
+    if (matches) {
+      var method = matches[1];
+      goog.debug.fnNameCache_[functionSource] = method;
+    } else {
+      goog.debug.fnNameCache_[functionSource] = '[Anonymous]';
+    }
+  }
+
+  return goog.debug.fnNameCache_[functionSource];
+};
+
+
+/**
+ * Makes whitespace visible by replacing it with printable characters.
+ * This is useful in finding diffrences between the expected and the actual
+ * output strings of a testcase.
+ * @param {string} string whose whitespace needs to be made visible.
+ * @return {string} string whose whitespace is made visible.
+ */
+goog.debug.makeWhitespaceVisible = function(string) {
+  return string.replace(/ /g, '[_]')
+      .replace(/\f/g, '[f]')
+      .replace(/\n/g, '[n]\n')
+      .replace(/\r/g, '[r]')
+      .replace(/\t/g, '[t]');
+};
+
+
+/**
+ * Returns the type of a value. If a constructor is passed, and a suitable
+ * string cannot be found, 'unknown type name' will be returned.
+ *
+ * <p>Forked rather than moved from {@link goog.asserts.getType_}
+ * to avoid adding a dependency to goog.asserts.
+ * @param {*} value A constructor, object, or primitive.
+ * @return {string} The best display name for the value, or 'unknown type name'.
+ */
+goog.debug.runtimeType = function(value) {
+  if (value instanceof Function) {
+    return value.displayName || value.name || 'unknown type name';
+  } else if (value instanceof Object) {
+    return value.constructor.displayName || value.constructor.name ||
+        Object.prototype.toString.call(value);
+  } else {
+    return value === null ? 'null' : typeof value;
+  }
+};
+
+
+/**
+ * Hash map for storing function names that have already been looked up.
+ * @type {Object}
+ * @private
+ */
+goog.debug.fnNameCache_ = {};
+
+
+/**
+ * Resolves functions to their names.  Resolved function names will be cached.
+ * @type {function(Function):string}
+ * @private
+ */
+goog.debug.fnNameResolver_;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/debugwindow.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/debugwindow.js b/externs/GCL/externs/goog/debug/debugwindow.js
new file mode 100644
index 0000000..ab251ef
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/debugwindow.js
@@ -0,0 +1,632 @@
+// 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 Definition of the DebugWindow class. Please minimize
+ * dependencies this file has on other closure classes as any dependency it
+ * takes won't be able to use the logging infrastructure.
+ *
+ */
+
+goog.provide('goog.debug.DebugWindow');
+
+goog.require('goog.debug.HtmlFormatter');
+goog.require('goog.debug.LogManager');
+goog.require('goog.debug.Logger');
+goog.require('goog.dom.safe');
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.SafeStyleSheet');
+goog.require('goog.string.Const');
+goog.require('goog.structs.CircularBuffer');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Provides a debug DebugWindow that is bound to the goog.debug.Logger.
+ * It handles log messages and writes them to the DebugWindow. This doesn't
+ * provide a lot of functionality that the old Gmail logging infrastructure
+ * provided like saving debug logs for exporting to the server. Now that we
+ * have an event-based logging infrastructure, we can encapsulate that
+ * functionality in a separate class.
+ *
+ * @constructor
+ * @param {string=} opt_identifier Identifier for this logging class.
+ * @param {string=} opt_prefix Prefix prepended to messages.
+ */
+goog.debug.DebugWindow = function(opt_identifier, opt_prefix) {
+  /**
+   * Identifier for this logging class
+   * @protected {string}
+   */
+  this.identifier = opt_identifier || '';
+
+  /**
+   * Array used to buffer log output
+   * @protected {!Array<!goog.html.SafeHtml>}
+   */
+  this.outputBuffer = [];
+
+  /**
+   * Optional prefix to be prepended to error strings
+   * @private {string}
+   */
+  this.prefix_ = opt_prefix || '';
+
+  /**
+   * Buffer for saving the last 1000 messages
+   * @private {!goog.structs.CircularBuffer}
+   */
+  this.savedMessages_ =
+      new goog.structs.CircularBuffer(goog.debug.DebugWindow.MAX_SAVED);
+
+  /**
+   * Save the publish handler so it can be removed
+   * @private {!Function}
+   */
+  this.publishHandler_ = goog.bind(this.addLogRecord, this);
+
+  /**
+   * Formatter for formatted output
+   * @private {goog.debug.Formatter}
+   */
+  this.formatter_ = new goog.debug.HtmlFormatter(this.prefix_);
+
+  /**
+   * Loggers that we shouldn't output
+   * @private {!Object}
+   */
+  this.filteredLoggers_ = {};
+
+  // enable by default
+  this.setCapturing(true);
+
+  /**
+   * Whether we are currently enabled. When the DebugWindow is enabled, it tries
+   * to keep its window open. When it's disabled, it can still be capturing log
+   * output if, but it won't try to write them to the DebugWindow window until
+   * it's enabled.
+   * @private {boolean}
+   */
+  this.enabled_ = goog.debug.DebugWindow.isEnabled(this.identifier);
+
+  // timer to save the DebugWindow's window position in a cookie
+  goog.global.setInterval(goog.bind(this.saveWindowPositionSize_, this), 7500);
+};
+
+
+/**
+ * Max number of messages to be saved
+ * @type {number}
+ */
+goog.debug.DebugWindow.MAX_SAVED = 500;
+
+
+/**
+ * How long to keep the cookies for in milliseconds
+ * @type {number}
+ */
+goog.debug.DebugWindow.COOKIE_TIME = 30 * 24 * 60 * 60 * 1000; // 30-days
+
+
+/**
+ * HTML string printed when the debug window opens
+ * @type {string}
+ * @protected
+ */
+goog.debug.DebugWindow.prototype.welcomeMessage = 'LOGGING';
+
+
+/**
+ * Whether to force enable the window on a severe log.
+ * @type {boolean}
+ * @private
+ */
+goog.debug.DebugWindow.prototype.enableOnSevere_ = false;
+
+
+/**
+ * Reference to debug window
+ * @type {Window}
+ * @protected
+ */
+goog.debug.DebugWindow.prototype.win = null;
+
+
+/**
+ * In the process of opening the window
+ * @type {boolean}
+ * @private
+ */
+goog.debug.DebugWindow.prototype.winOpening_ = false;
+
+
+/**
+ * Whether we are currently capturing logger output.
+ *
+ * @type {boolean}
+ * @private
+ */
+goog.debug.DebugWindow.prototype.isCapturing_ = false;
+
+
+/**
+ * Whether we already showed an alert that the DebugWindow was blocked.
+ * @type {boolean}
+ * @private
+ */
+goog.debug.DebugWindow.showedBlockedAlert_ = false;
+
+
+/**
+ * Reference to timeout used to buffer the output stream.
+ * @type {?number}
+ * @private
+ */
+goog.debug.DebugWindow.prototype.bufferTimeout_ = null;
+
+
+/**
+ * Timestamp for the last time the log was written to.
+ * @protected {number}
+ */
+goog.debug.DebugWindow.prototype.lastCall = goog.now();
+
+
+/**
+ * Sets the welcome message shown when the window is first opened or reset.
+ *
+ * @param {string} msg An HTML string.
+ */
+goog.debug.DebugWindow.prototype.setWelcomeMessage = function(msg) {
+  this.welcomeMessage = msg;
+};
+
+
+/**
+ * Initializes the debug window.
+ */
+goog.debug.DebugWindow.prototype.init = function() {
+  if (this.enabled_) {
+    this.openWindow_();
+  }
+};
+
+
+/**
+ * Whether the DebugWindow is enabled. When the DebugWindow is enabled, it
+ * tries to keep its window open and logs all messages to the window.  When the
+ * DebugWindow is disabled, it stops logging messages to its window.
+ *
+ * @return {boolean} Whether the DebugWindow is enabled.
+ */
+goog.debug.DebugWindow.prototype.isEnabled = function() {
+  return this.enabled_;
+};
+
+
+/**
+ * Sets whether the DebugWindow is enabled. When the DebugWindow is enabled, it
+ * tries to keep its window open and log all messages to the window. When the
+ * DebugWindow is disabled, it stops logging messages to its window. The
+ * DebugWindow also saves this state to a cookie so that it's persisted across
+ * application refreshes.
+ * @param {boolean} enable Whether the DebugWindow is enabled.
+ */
+goog.debug.DebugWindow.prototype.setEnabled = function(enable) {
+  this.enabled_ = enable;
+
+  if (this.enabled_) {
+    this.openWindow_();
+  }
+
+  this.setCookie_('enabled', enable ? '1' : '0');
+};
+
+
+/**
+ * Sets whether the debug window should be force enabled when a severe log is
+ * encountered.
+ * @param {boolean} enableOnSevere Whether to enable on severe logs..
+ */
+goog.debug.DebugWindow.prototype.setForceEnableOnSevere =
+    function(enableOnSevere) {
+  this.enableOnSevere_ = enableOnSevere;
+};
+
+
+/**
+ * Whether we are currently capturing logger output.
+ * @return {boolean} whether we are currently capturing logger output.
+ */
+goog.debug.DebugWindow.prototype.isCapturing = function() {
+  return this.isCapturing_;
+};
+
+
+/**
+ * Sets whether we are currently capturing logger output.
+ * @param {boolean} capturing Whether to capture logger output.
+ */
+goog.debug.DebugWindow.prototype.setCapturing = function(capturing) {
+  if (capturing == this.isCapturing_) {
+    return;
+  }
+  this.isCapturing_ = capturing;
+
+  // attach or detach handler from the root logger
+  var rootLogger = goog.debug.LogManager.getRoot();
+  if (capturing) {
+    rootLogger.addHandler(this.publishHandler_);
+  } else {
+    rootLogger.removeHandler(this.publishHandler_);
+  }
+};
+
+
+/**
+ * Gets the formatter for outputting to the debug window. The default formatter
+ * is an instance of goog.debug.HtmlFormatter
+ * @return {goog.debug.Formatter} The formatter in use.
+ */
+goog.debug.DebugWindow.prototype.getFormatter = function() {
+  return this.formatter_;
+};
+
+
+/**
+ * Sets the formatter for outputting to the debug window.
+ * @param {goog.debug.Formatter} formatter The formatter to use.
+ */
+goog.debug.DebugWindow.prototype.setFormatter = function(formatter) {
+  this.formatter_ = formatter;
+};
+
+
+/**
+ * Adds a separator to the debug window.
+ */
+goog.debug.DebugWindow.prototype.addSeparator = function() {
+  this.write_(goog.html.SafeHtml.create('hr'));
+};
+
+
+/**
+ * @return {boolean} Whether there is an active window.
+ */
+goog.debug.DebugWindow.prototype.hasActiveWindow = function() {
+  return !!this.win && !this.win.closed;
+};
+
+
+/**
+ * Clears the contents of the debug window
+ * @protected
+ */
+goog.debug.DebugWindow.prototype.clear = function() {
+  this.savedMessages_.clear();
+  if (this.hasActiveWindow()) {
+    this.writeInitialDocument();
+  }
+};
+
+
+/**
+ * Adds a log record.
+ * @param {goog.debug.LogRecord} logRecord the LogRecord.
+ */
+goog.debug.DebugWindow.prototype.addLogRecord = function(logRecord) {
+  if (this.filteredLoggers_[logRecord.getLoggerName()]) {
+    return;
+  }
+  var html = this.formatter_.formatRecordAsHtml(logRecord);
+  this.write_(html);
+  if (this.enableOnSevere_ &&
+      logRecord.getLevel().value >= goog.debug.Logger.Level.SEVERE.value) {
+    this.setEnabled(true);
+  }
+};
+
+
+/**
+ * Writes a message to the log, possibly opening up the window if it's enabled,
+ * or saving it if it's disabled.
+ * @param {!goog.html.SafeHtml} html The HTML to write.
+ * @private
+ */
+goog.debug.DebugWindow.prototype.write_ = function(html) {
+  // If the logger is enabled, open window and write html message to log
+  // otherwise save it
+  if (this.enabled_) {
+    this.openWindow_();
+    this.savedMessages_.add(html);
+    this.writeToLog_(html);
+  } else {
+    this.savedMessages_.add(html);
+  }
+};
+
+
+/**
+ * Write to the buffer.  If a message hasn't been sent for more than 750ms just
+ * write, otherwise delay for a minimum of 250ms.
+ * @param {!goog.html.SafeHtml} html HTML to post to the log.
+ * @private
+ */
+goog.debug.DebugWindow.prototype.writeToLog_ = function(html) {
+  this.outputBuffer.push(html);
+  goog.global.clearTimeout(this.bufferTimeout_);
+
+  if (goog.now() - this.lastCall > 750) {
+    this.writeBufferToLog();
+  } else {
+    this.bufferTimeout_ =
+        goog.global.setTimeout(goog.bind(this.writeBufferToLog, this), 250);
+  }
+};
+
+
+/**
+ * Write to the log and maybe scroll into view.
+ * @protected
+ */
+goog.debug.DebugWindow.prototype.writeBufferToLog = function() {
+  this.lastCall = goog.now();
+  if (this.hasActiveWindow()) {
+    var body = this.win.document.body;
+    var scroll = body &&
+        body.scrollHeight - (body.scrollTop + body.clientHeight) <= 100;
+
+    goog.dom.safe.documentWrite(
+        this.win.document, goog.html.SafeHtml.concat(this.outputBuffer));
+    this.outputBuffer.length = 0;
+
+    if (scroll) {
+      this.win.scrollTo(0, 1000000);
+    }
+  }
+};
+
+
+/**
+ * Writes all saved messages to the DebugWindow.
+ * @protected
+ */
+goog.debug.DebugWindow.prototype.writeSavedMessages = function() {
+  var messages = this.savedMessages_.getValues();
+  for (var i = 0; i < messages.length; i++) {
+    this.writeToLog_(messages[i]);
+  }
+};
+
+
+/**
+ * Opens the debug window if it is not already referenced
+ * @private
+ */
+goog.debug.DebugWindow.prototype.openWindow_ = function() {
+  if (this.hasActiveWindow() || this.winOpening_) {
+    return;
+  }
+
+  var winpos = this.getCookie_('dbg', '0,0,800,500').split(',');
+  var x = Number(winpos[0]);
+  var y = Number(winpos[1]);
+  var w = Number(winpos[2]);
+  var h = Number(winpos[3]);
+
+  this.winOpening_ = true;
+  this.win = window.open('', this.getWindowName_(), 'width=' + w +
+                         ',height=' + h + ',toolbar=no,resizable=yes,' +
+                         'scrollbars=yes,left=' + x + ',top=' + y +
+                         ',status=no,screenx=' + x + ',screeny=' + y);
+
+  if (!this.win) {
+    if (!goog.debug.DebugWindow.showedBlockedAlert_) {
+      // only show this once
+      alert('Logger popup was blocked');
+      goog.debug.DebugWindow.showedBlockedAlert_ = true;
+    }
+  }
+
+  this.winOpening_ = false;
+
+  if (this.win) {
+    this.writeInitialDocument();
+  }
+};
+
+
+/**
+ * Gets a valid window name for the debug window. Replaces invalid characters in
+ * IE.
+ * @return {string} Valid window name.
+ * @private
+ */
+goog.debug.DebugWindow.prototype.getWindowName_ = function() {
+  return goog.userAgent.IE ?
+      this.identifier.replace(/[\s\-\.\,]/g, '_') : this.identifier;
+};
+
+
+/**
+ * @return {!goog.html.SafeStyleSheet} The stylesheet, for inclusion in the
+ *     initial HTML.
+ */
+goog.debug.DebugWindow.prototype.getStyleRules = function() {
+  return goog.html.SafeStyleSheet.fromConstant(goog.string.Const.from(
+      '*{font:normal 14px monospace;}' +
+      '.dbg-sev{color:#F00}' +
+      '.dbg-w{color:#E92}' +
+      '.dbg-sh{background-color:#fd4;font-weight:bold;color:#000}' +
+      '.dbg-i{color:#666}' +
+      '.dbg-f{color:#999}' +
+      '.dbg-ev{color:#0A0}' +
+      '.dbg-m{color:#990}'));
+};
+
+
+/**
+ * Writes the initial HTML of the debug window.
+ * @protected
+ */
+goog.debug.DebugWindow.prototype.writeInitialDocument = function() {
+  if (!this.hasActiveWindow()) {
+    return;
+  }
+
+  this.win.document.open();
+
+  var div = goog.html.SafeHtml.create(
+      'div', {
+        'class': 'dbg-ev',
+        'style': goog.string.Const.from('text-align:center;')},
+      goog.html.SafeHtml.concat(
+          this.welcomeMessage,
+          goog.html.SafeHtml.create('br'),
+          goog.html.SafeHtml.create(
+              'small', {}, 'Logger: ' + this.identifier)));
+  var html = goog.html.SafeHtml.concat(
+      goog.html.SafeHtml.createStyle(this.getStyleRules()),
+      goog.html.SafeHtml.create('hr'),
+      div,
+      goog.html.SafeHtml.create('hr'));
+
+  this.writeToLog_(html);
+  this.writeSavedMessages();
+};
+
+
+/**
+ * Save persistent data (using cookies) for 1 month (cookie specific to this
+ * logger object).
+ * @param {string} key Data name.
+ * @param {string} value Data value.
+ * @private
+ */
+goog.debug.DebugWindow.prototype.setCookie_ = function(key, value) {
+  var fullKey = goog.debug.DebugWindow.getCookieKey_(this.identifier, key);
+  document.cookie = fullKey + '=' + encodeURIComponent(value) +
+      ';path=/;expires=' +
+      (new Date(goog.now() + goog.debug.DebugWindow.COOKIE_TIME)).toUTCString();
+};
+
+
+/**
+ * Retrieve data (using cookies).
+ * @param {string} key Data name.
+ * @param {string=} opt_default Optional default value if cookie doesn't exist.
+ * @return {string} Cookie value.
+ * @private
+ */
+goog.debug.DebugWindow.prototype.getCookie_ = function(key, opt_default) {
+  return goog.debug.DebugWindow.getCookieValue_(
+      this.identifier, key, opt_default);
+};
+
+
+/**
+ * Creates a valid cookie key name which is scoped to the given identifier.
+ * Substitutes all occurences of invalid cookie name characters (whitespace,
+ * ';', and '=') with '_', which is a valid and readable alternative.
+ * @see goog.net.Cookies#isValidName
+ * @see <a href="http://tools.ietf.org/html/rfc2109">RFC 2109</a>
+ * @param {string} identifier Identifier for logging class.
+ * @param {string} key Data name.
+ * @return {string} Cookie key name.
+ * @private
+ */
+goog.debug.DebugWindow.getCookieKey_ = function(identifier, key) {
+  var fullKey = key + identifier;
+  return fullKey.replace(/[;=\s]/g, '_');
+};
+
+
+/**
+ * Retrieve data (using cookies).
+ * @param {string} identifier Identifier for logging class.
+ * @param {string} key Data name.
+ * @param {string=} opt_default Optional default value if cookie doesn't exist.
+ * @return {string} Cookie value.
+ * @private
+ */
+goog.debug.DebugWindow.getCookieValue_ = function(
+    identifier, key, opt_default) {
+  var fullKey = goog.debug.DebugWindow.getCookieKey_(identifier, key);
+  var cookie = String(document.cookie);
+  var start = cookie.indexOf(fullKey + '=');
+  if (start != -1) {
+    var end = cookie.indexOf(';', start);
+    return decodeURIComponent(cookie.substring(start + fullKey.length + 1,
+        end == -1 ? cookie.length : end));
+  } else {
+    return opt_default || '';
+  }
+};
+
+
+/**
+ * @param {string} identifier Identifier for logging class.
+ * @return {boolean} Whether the DebugWindow is enabled.
+ */
+goog.debug.DebugWindow.isEnabled = function(identifier) {
+  return goog.debug.DebugWindow.getCookieValue_(identifier, 'enabled') == '1';
+};
+
+
+/**
+ * Saves the window position size to a cookie
+ * @private
+ */
+goog.debug.DebugWindow.prototype.saveWindowPositionSize_ = function() {
+  if (!this.hasActiveWindow()) {
+    return;
+  }
+  var x = this.win.screenX || this.win.screenLeft || 0;
+  var y = this.win.screenY || this.win.screenTop || 0;
+  var w = this.win.outerWidth || 800;
+  var h = this.win.outerHeight || 500;
+  this.setCookie_('dbg', x + ',' + y + ',' + w + ',' + h);
+};
+
+
+/**
+ * Adds a logger name to be filtered.
+ * @param {string} loggerName the logger name to add.
+ */
+goog.debug.DebugWindow.prototype.addFilter = function(loggerName) {
+  this.filteredLoggers_[loggerName] = 1;
+};
+
+
+/**
+ * Removes a logger name to be filtered.
+ * @param {string} loggerName the logger name to remove.
+ */
+goog.debug.DebugWindow.prototype.removeFilter = function(loggerName) {
+  delete this.filteredLoggers_[loggerName];
+};
+
+
+/**
+ * Modify the size of the circular buffer. Allows the log to retain more
+ * information while the window is closed.
+ * @param {number} size New size of the circular buffer.
+ */
+goog.debug.DebugWindow.prototype.resetBufferWithNewSize = function(size) {
+  if (size > 0 && size < 50000) {
+    this.clear();
+    this.savedMessages_ = new goog.structs.CircularBuffer(size);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/devcss/devcss.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/devcss/devcss.js b/externs/GCL/externs/goog/debug/devcss/devcss.js
new file mode 100644
index 0000000..8716ca4
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/devcss/devcss.js
@@ -0,0 +1,445 @@
+// Copyright 2008 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 Runtime development CSS Compiler emulation, via javascript.
+ * This class provides an approximation to CSSCompiler's functionality by
+ * hacking the live CSSOM.
+ * This code is designed  to be inserted in the DOM immediately after the last
+ * style block in HEAD when in development mode, i.e. you are not using a
+ * running instance of a CSS Compiler to pass your CSS through.
+ */
+
+
+goog.provide('goog.debug.DevCss');
+goog.provide('goog.debug.DevCss.UserAgent');
+
+goog.require('goog.asserts');
+goog.require('goog.cssom');
+goog.require('goog.dom.classlist');
+goog.require('goog.events');
+goog.require('goog.events.EventType');
+goog.require('goog.string');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * A class for solving development CSS issues/emulating the CSS Compiler.
+ * @param {goog.debug.DevCss.UserAgent=} opt_userAgent The user agent, if not
+ *     passed in, will be determined using goog.userAgent.
+ * @param {number|string=} opt_userAgentVersion The user agent's version.
+ *     If not passed in, will be determined using goog.userAgent.
+ * @throws {Error} When userAgent detection fails.
+ * @constructor
+ * @final
+ */
+goog.debug.DevCss = function(opt_userAgent, opt_userAgentVersion) {
+  if (!opt_userAgent) {
+    // Walks through the known goog.userAgents.
+    if (goog.userAgent.IE) {
+      opt_userAgent = goog.debug.DevCss.UserAgent.IE;
+    } else if (goog.userAgent.GECKO) {
+      opt_userAgent = goog.debug.DevCss.UserAgent.GECKO;
+    } else if (goog.userAgent.WEBKIT) {
+      opt_userAgent = goog.debug.DevCss.UserAgent.WEBKIT;
+    } else if (goog.userAgent.MOBILE) {
+      opt_userAgent = goog.debug.DevCss.UserAgent.MOBILE;
+    } else if (goog.userAgent.OPERA) {
+      opt_userAgent = goog.debug.DevCss.UserAgent.OPERA;
+    }
+  }
+  switch (opt_userAgent) {
+    case goog.debug.DevCss.UserAgent.OPERA:
+    case goog.debug.DevCss.UserAgent.IE:
+    case goog.debug.DevCss.UserAgent.GECKO:
+    case goog.debug.DevCss.UserAgent.FIREFOX:
+    case goog.debug.DevCss.UserAgent.WEBKIT:
+    case goog.debug.DevCss.UserAgent.SAFARI:
+    case goog.debug.DevCss.UserAgent.MOBILE:
+      break;
+    default:
+      throw Error('Could not determine the user agent from known UserAgents');
+  }
+
+  /**
+   * One of goog.debug.DevCss.UserAgent.
+   * @type {string}
+   * @private
+   */
+  this.userAgent_ = opt_userAgent;
+
+  /**
+   * @const @private
+   */
+  this.userAgentTokens_ = {};
+
+  /**
+   * @type {number|string}
+   * @private
+   */
+  this.userAgentVersion_ = opt_userAgentVersion || goog.userAgent.VERSION;
+  this.generateUserAgentTokens_();
+
+  /**
+   * @type {boolean}
+   * @private
+   */
+  this.isIe6OrLess_ = this.userAgent_ == goog.debug.DevCss.UserAgent.IE &&
+      goog.string.compareVersions('7', this.userAgentVersion_) > 0;
+
+  if (this.isIe6OrLess_) {
+    /**
+     * @type {Array<{classNames,combinedClassName,els}>}
+     * @private
+     */
+    this.ie6CombinedMatches_ = [];
+  }
+};
+
+
+/**
+ * Rewrites the CSSOM as needed to activate any useragent-specific selectors.
+ * @param {boolean=} opt_enableIe6ReadyHandler If true(the default), and the
+ *     userAgent is ie6, we set a document "ready" event handler to walk the DOM
+ *     and make combined selector className changes. Having this parameter also
+ *     aids unit testing.
+ */
+goog.debug.DevCss.prototype.activateBrowserSpecificCssRules = function(
+    opt_enableIe6ReadyHandler) {
+  var enableIe6EventHandler = goog.isDef(opt_enableIe6ReadyHandler) ?
+      opt_enableIe6ReadyHandler : true;
+  var cssRules = goog.cssom.getAllCssStyleRules();
+
+  for (var i = 0, cssRule; cssRule = cssRules[i]; i++) {
+    this.replaceBrowserSpecificClassNames_(cssRule);
+  }
+
+  // Since we may have manipulated the rules above, we'll have to do a
+  // complete sweep again if we're in IE6. Luckily performance doesn't
+  // matter for this tool.
+  if (this.isIe6OrLess_) {
+    cssRules = goog.cssom.getAllCssStyleRules();
+    for (var i = 0, cssRule; cssRule = cssRules[i]; i++) {
+      this.replaceIe6CombinedSelectors_(cssRule);
+    }
+  }
+
+  // Add an event listener for document ready to rewrite any necessary
+  // combined classnames in IE6.
+  if (this.isIe6OrLess_ && enableIe6EventHandler) {
+    goog.events.listen(document, goog.events.EventType.LOAD, goog.bind(
+        this.addIe6CombinedClassNames_, this));
+  }
+};
+
+
+/**
+ * A list of possible user agent strings.
+ * @enum {string}
+ */
+goog.debug.DevCss.UserAgent = {
+  OPERA: 'OPERA',
+  IE: 'IE',
+  GECKO: 'GECKO',
+  FIREFOX: 'GECKO',
+  WEBKIT: 'WEBKIT',
+  SAFARI: 'WEBKIT',
+  MOBILE: 'MOBILE'
+};
+
+
+/**
+ * A list of strings that may be used for matching in CSS files/development.
+ * @enum {string}
+ * @private
+ */
+goog.debug.DevCss.CssToken_ = {
+  USERAGENT: 'USERAGENT',
+  SEPARATOR: '-',
+  LESS_THAN: 'LT',
+  GREATER_THAN: 'GT',
+  LESS_THAN_OR_EQUAL: 'LTE',
+  GREATER_THAN_OR_EQUAL: 'GTE',
+  IE6_SELECTOR_TEXT: 'goog-ie6-selector',
+  IE6_COMBINED_GLUE: '_'
+};
+
+
+/**
+ * Generates user agent token match strings with comparison and version bits.
+ * For example:
+ *   userAgentTokens_.ANY will be like 'GECKO'
+ *   userAgentTokens_.LESS_THAN will be like 'GECKO-LT3' etc...
+ * @private
+ */
+goog.debug.DevCss.prototype.generateUserAgentTokens_ = function() {
+  this.userAgentTokens_.ANY = goog.debug.DevCss.CssToken_.USERAGENT +
+      goog.debug.DevCss.CssToken_.SEPARATOR + this.userAgent_;
+  this.userAgentTokens_.EQUALS = this.userAgentTokens_.ANY +
+      goog.debug.DevCss.CssToken_.SEPARATOR;
+  this.userAgentTokens_.LESS_THAN = this.userAgentTokens_.ANY +
+      goog.debug.DevCss.CssToken_.SEPARATOR +
+      goog.debug.DevCss.CssToken_.LESS_THAN;
+  this.userAgentTokens_.LESS_THAN_OR_EQUAL = this.userAgentTokens_.ANY +
+      goog.debug.DevCss.CssToken_.SEPARATOR +
+      goog.debug.DevCss.CssToken_.LESS_THAN_OR_EQUAL;
+  this.userAgentTokens_.GREATER_THAN = this.userAgentTokens_.ANY +
+      goog.debug.DevCss.CssToken_.SEPARATOR +
+      goog.debug.DevCss.CssToken_.GREATER_THAN;
+  this.userAgentTokens_.GREATER_THAN_OR_EQUAL = this.userAgentTokens_.ANY +
+      goog.debug.DevCss.CssToken_.SEPARATOR +
+      goog.debug.DevCss.CssToken_.GREATER_THAN_OR_EQUAL;
+};
+
+
+/**
+ * Gets the version number bit from a selector matching userAgentToken.
+ * @param {string} selectorText The selector text of a CSS rule.
+ * @param {string} userAgentToken Includes the LTE/GTE bit to see if it matches.
+ * @return {string|undefined} The version number.
+ * @private
+ */
+goog.debug.DevCss.prototype.getVersionNumberFromSelectorText_ = function(
+    selectorText, userAgentToken) {
+  var regex = new RegExp(userAgentToken + '([\\d\\.]+)');
+  var matches = regex.exec(selectorText);
+  if (matches && matches.length == 2) {
+    return matches[1];
+  }
+};
+
+
+/**
+ * Extracts a rule version from the selector text, and if it finds one, calls
+ * compareVersions against it and the passed in token string to provide the
+ * value needed to determine if we have a match or not.
+ * @param {CSSRule} cssRule The rule to test against.
+ * @param {string} token The match token to test against the rule.
+ * @return {!Array|undefined} A tuple with the result of the compareVersions
+ *     call and the matched ruleVersion.
+ * @private
+ */
+goog.debug.DevCss.prototype.getRuleVersionAndCompare_ = function(cssRule,
+    token) {
+  if (!cssRule.selectorText.match(token)) {
+    return;
+  }
+  var ruleVersion = this.getVersionNumberFromSelectorText_(
+      cssRule.selectorText, token);
+  if (!ruleVersion) {
+    return;
+  }
+
+  var comparison = goog.string.compareVersions(this.userAgentVersion_,
+      ruleVersion);
+  return [comparison, ruleVersion];
+};
+
+
+/**
+ * Replaces a CSS selector if we have matches based on our useragent/version.
+ * Example: With a selector like ".USERAGENT-IE-LTE6 .class { prop: value }" if
+ * we are running IE6 we'll end up with ".class { prop: value }", thereby
+ * "activating" the selector.
+ * @param {CSSRule} cssRule The cssRule to potentially replace.
+ * @private
+ */
+goog.debug.DevCss.prototype.replaceBrowserSpecificClassNames_ = function(
+    cssRule) {
+
+  // If we don't match the browser token, we can stop now.
+  if (!cssRule.selectorText.match(this.userAgentTokens_.ANY)) {
+    return;
+  }
+
+  // We know it will begin as a classname.
+  var additionalRegexString;
+
+  // Tests "Less than or equals".
+  var compared = this.getRuleVersionAndCompare_(cssRule,
+      this.userAgentTokens_.LESS_THAN_OR_EQUAL);
+  if (compared && compared.length) {
+    if (compared[0] > 0) {
+      return;
+    }
+    additionalRegexString = this.userAgentTokens_.LESS_THAN_OR_EQUAL +
+        compared[1];
+  }
+
+  // Tests "Less than".
+  compared = this.getRuleVersionAndCompare_(cssRule,
+      this.userAgentTokens_.LESS_THAN);
+  if (compared && compared.length) {
+    if (compared[0] > -1) {
+      return;
+    }
+    additionalRegexString = this.userAgentTokens_.LESS_THAN + compared[1];
+  }
+
+  // Tests "Greater than or equals".
+  compared = this.getRuleVersionAndCompare_(cssRule,
+      this.userAgentTokens_.GREATER_THAN_OR_EQUAL);
+  if (compared && compared.length) {
+    if (compared[0] < 0) {
+      return;
+    }
+    additionalRegexString = this.userAgentTokens_.GREATER_THAN_OR_EQUAL +
+        compared[1];
+  }
+
+  // Tests "Greater than".
+  compared = this.getRuleVersionAndCompare_(cssRule,
+      this.userAgentTokens_.GREATER_THAN);
+  if (compared && compared.length) {
+    if (compared[0] < 1) {
+      return;
+    }
+    additionalRegexString = this.userAgentTokens_.GREATER_THAN + compared[1];
+  }
+
+  // Tests "Equals".
+  compared = this.getRuleVersionAndCompare_(cssRule,
+      this.userAgentTokens_.EQUALS);
+  if (compared && compared.length) {
+    if (compared[0] != 0) {
+      return;
+    }
+    additionalRegexString = this.userAgentTokens_.EQUALS + compared[1];
+  }
+
+  // If we got to here without generating the additionalRegexString, then
+  // we did not match any of our comparison token strings, and we want a
+  // general browser token replacement.
+  if (!additionalRegexString) {
+    additionalRegexString = this.userAgentTokens_.ANY;
+  }
+
+  // We need to match at least a single whitespace character to know that
+  // we are matching the entire useragent string token.
+  var regexString = '\\.' + additionalRegexString + '\\s+';
+  var re = new RegExp(regexString, 'g');
+
+  var currentCssText = goog.cssom.getCssTextFromCssRule(cssRule);
+
+  // Replacing the token with '' activates the selector for this useragent.
+  var newCssText = currentCssText.replace(re, '');
+
+  if (newCssText != currentCssText) {
+    goog.cssom.replaceCssRule(cssRule, newCssText);
+  }
+};
+
+
+/**
+ * Replaces IE6 combined selector rules with a workable development alternative.
+ * IE6 actually parses .class1.class2 {} to simply .class2 {} which is nasty.
+ * To fully support combined selectors in IE6 this function needs to be paired
+ * with a call to replace the relevant DOM elements classNames as well.
+ * @see {this.addIe6CombinedClassNames_}
+ * @param {CSSRule} cssRule The rule to potentially fix.
+ * @private
+ */
+goog.debug.DevCss.prototype.replaceIe6CombinedSelectors_ = function(cssRule) {
+  // This match only ever works in IE because other UA's won't have our
+  // IE6_SELECTOR_TEXT in the cssText property.
+  if (cssRule.style.cssText &&
+      cssRule.style.cssText.match(
+          goog.debug.DevCss.CssToken_.IE6_SELECTOR_TEXT)) {
+    var cssText = goog.cssom.getCssTextFromCssRule(cssRule);
+    var combinedSelectorText = this.getIe6CombinedSelectorText_(cssText);
+    if (combinedSelectorText) {
+      var newCssText = combinedSelectorText + '{' + cssRule.style.cssText + '}';
+      goog.cssom.replaceCssRule(cssRule, newCssText);
+    }
+  }
+};
+
+
+/**
+ * Gets the appropriate new combined selector text for IE6.
+ * Also adds an entry onto ie6CombinedMatches_ with relevant info for the
+ * likely following call to walk the DOM and rewrite the class attribute.
+ * Example: With a selector like
+ *     ".class2 { -goog-ie6-selector: .class1.class2; prop: value }".
+ * this function will return:
+ *     ".class1_class2 { prop: value }".
+ * @param {string} cssText The CSS selector text and css rule text combined.
+ * @return {?string} The rewritten css rule text.
+ * @private
+ */
+goog.debug.DevCss.prototype.getIe6CombinedSelectorText_ = function(cssText) {
+  var regex = new RegExp(goog.debug.DevCss.CssToken_.IE6_SELECTOR_TEXT +
+      '\\s*:\\s*\\"([^\\"]+)\\"', 'gi');
+  var matches = regex.exec(cssText);
+  if (matches) {
+    var combinedSelectorText = matches[1];
+    // To aid in later fixing the DOM, we need to split up the possible
+    // selector groups by commas.
+    var groupedSelectors = combinedSelectorText.split(/\s*\,\s*/);
+    for (var i = 0, selector; selector = groupedSelectors[i]; i++) {
+      // Strips off the leading ".".
+      var combinedClassName = selector.substr(1);
+      var classNames = combinedClassName.split(
+          goog.debug.DevCss.CssToken_.IE6_COMBINED_GLUE);
+      var entry = {
+        classNames: classNames,
+        combinedClassName: combinedClassName,
+        els: []
+      };
+      this.ie6CombinedMatches_.push(entry);
+    }
+    return combinedSelectorText;
+  }
+  return null;
+};
+
+
+/**
+ * Adds combined selectors with underscores to make them "work" in IE6.
+ * @see {this.replaceIe6CombinedSelectors_}
+ * @private
+ */
+goog.debug.DevCss.prototype.addIe6CombinedClassNames_ = function() {
+  if (!this.ie6CombinedMatches_.length) {
+    return;
+  }
+  var allEls = document.getElementsByTagName('*');
+  // Match nodes for all classNames.
+  for (var i = 0, classNameEntry; classNameEntry =
+      this.ie6CombinedMatches_[i]; i++) {
+    for (var j = 0, el; el = allEls[j]; j++) {
+      var classNamesLength = classNameEntry.classNames.length;
+      for (var k = 0, className; className = classNameEntry.classNames[k];
+          k++) {
+        if (!goog.dom.classlist.contains(goog.asserts.assert(el), className)) {
+          break;
+        }
+        if (k == classNamesLength - 1) {
+          classNameEntry.els.push(el);
+        }
+      }
+    }
+    // Walks over our matching nodes and fixes them.
+    if (classNameEntry.els.length) {
+      for (var j = 0, el; el = classNameEntry.els[j]; j++) {
+        goog.asserts.assert(el);
+        if (!goog.dom.classlist.contains(el,
+            classNameEntry.combinedClassName)) {
+          goog.dom.classlist.add(el, classNameEntry.combinedClassName);
+        }
+      }
+    }
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/devcss/devcssrunner.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/devcss/devcssrunner.js b/externs/GCL/externs/goog/debug/devcss/devcssrunner.js
new file mode 100644
index 0000000..cfe4f39
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/devcss/devcssrunner.js
@@ -0,0 +1,26 @@
+// Copyright 2008 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 Development CSS Compiler runtime execution.
+ */
+
+goog.provide('goog.debug.devCssRunner');
+
+goog.require('goog.debug.DevCss');
+
+(function() {
+  var devCssInstance = new goog.debug.DevCss();
+  devCssInstance.activateBrowserSpecificCssRules();
+})();

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/divconsole.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/divconsole.js b/externs/GCL/externs/goog/debug/divconsole.js
new file mode 100644
index 0000000..e3eacb9
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/divconsole.js
@@ -0,0 +1,150 @@
+// 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 Simple logger that logs a Div Element.
+ *
+ */
+
+goog.provide('goog.debug.DivConsole');
+
+goog.require('goog.debug.HtmlFormatter');
+goog.require('goog.debug.LogManager');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.safe');
+goog.require('goog.html.SafeHtml');
+goog.require('goog.style');
+
+
+
+/**
+ * A class for visualising logger calls in a div element.
+ * @param {Element} element The element to append to.
+ * @constructor
+ */
+goog.debug.DivConsole = function(element) {
+  this.publishHandler_ = goog.bind(this.addLogRecord, this);
+  this.formatter_ = new goog.debug.HtmlFormatter();
+  this.formatter_.showAbsoluteTime = false;
+  this.isCapturing_ = false;
+  this.element_ = element;
+  this.elementOwnerDocument_ =
+      this.element_.ownerDocument || this.element_.document;
+
+  this.installStyles();
+};
+
+
+/**
+ * Installs styles for the log messages and its div
+ */
+goog.debug.DivConsole.prototype.installStyles = function() {
+  goog.style.installStyles(
+      '.dbg-sev{color:#F00}' +
+      '.dbg-w{color:#C40}' +
+      '.dbg-sh{font-weight:bold;color:#000}' +
+      '.dbg-i{color:#444}' +
+      '.dbg-f{color:#999}' +
+      '.dbg-ev{color:#0A0}' +
+      '.dbg-m{color:#990}' +
+      '.logmsg{border-bottom:1px solid #CCC;padding:2px}' +
+      '.logsep{background-color: #8C8;}' +
+      '.logdiv{border:1px solid #CCC;background-color:#FCFCFC;' +
+      'font:medium monospace}',
+      this.element_);
+  this.element_.className += ' logdiv';
+};
+
+
+/**
+ * Sets whether we are currently capturing logger output.
+ * @param {boolean} capturing Whether to capture logger output.
+ */
+goog.debug.DivConsole.prototype.setCapturing = function(capturing) {
+  if (capturing == this.isCapturing_) {
+    return;
+  }
+
+  // attach or detach handler from the root logger
+  var rootLogger = goog.debug.LogManager.getRoot();
+  if (capturing) {
+    rootLogger.addHandler(this.publishHandler_);
+  } else {
+    rootLogger.removeHandler(this.publishHandler_);
+    this.logBuffer = '';
+  }
+  this.isCapturing_ = capturing;
+};
+
+
+/**
+ * Adds a log record.
+ * @param {goog.debug.LogRecord} logRecord The log entry.
+ */
+goog.debug.DivConsole.prototype.addLogRecord = function(logRecord) {
+  if (!logRecord) {
+    return;
+  }
+  var scroll = this.element_.scrollHeight - this.element_.scrollTop -
+      this.element_.clientHeight <= 100;
+
+  var div = this.elementOwnerDocument_.createElement(goog.dom.TagName.DIV);
+  div.className = 'logmsg';
+  goog.dom.safe.setInnerHtml(
+      div, this.formatter_.formatRecordAsHtml(logRecord));
+  this.element_.appendChild(div);
+
+  if (scroll) {
+    this.element_.scrollTop = this.element_.scrollHeight;
+  }
+};
+
+
+/**
+ * Gets the formatter for outputting to the console. The default formatter
+ * is an instance of goog.debug.HtmlFormatter
+ * @return {!goog.debug.Formatter} The formatter in use.
+ */
+goog.debug.DivConsole.prototype.getFormatter = function() {
+  return this.formatter_;
+};
+
+
+/**
+ * Sets the formatter for outputting to the console.
+ * @param {goog.debug.HtmlFormatter} formatter The formatter to use.
+ */
+goog.debug.DivConsole.prototype.setFormatter = function(formatter) {
+  this.formatter_ = formatter;
+};
+
+
+/**
+ * Adds a separator to the debug window.
+ */
+goog.debug.DivConsole.prototype.addSeparator = function() {
+  var div = this.elementOwnerDocument_.createElement(goog.dom.TagName.DIV);
+  div.className = 'logmsg logsep';
+  this.element_.appendChild(div);
+};
+
+
+/**
+ * Clears the console.
+ */
+goog.debug.DivConsole.prototype.clear = function() {
+  if (this.element_) {
+    goog.dom.safe.setInnerHtml(this.element_, goog.html.SafeHtml.EMPTY);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/entrypointregistry.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/entrypointregistry.js b/externs/GCL/externs/goog/debug/entrypointregistry.js
new file mode 100644
index 0000000..3ae7549
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/entrypointregistry.js
@@ -0,0 +1,158 @@
+// Copyright 2010 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 global registry for entry points into a program,
+ * so that they can be instrumented. Each module should register their
+ * entry points with this registry. Designed to be compiled out
+ * if no instrumentation is requested.
+ *
+ * Entry points may be registered before or after a call to
+ * goog.debug.entryPointRegistry.monitorAll. If an entry point is registered
+ * later, the existing monitor will instrument the new entry point.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.debug.EntryPointMonitor');
+goog.provide('goog.debug.entryPointRegistry');
+
+goog.require('goog.asserts');
+
+
+
+/**
+ * @interface
+ */
+goog.debug.EntryPointMonitor = function() {};
+
+
+/**
+ * Instruments a function.
+ *
+ * @param {!Function} fn A function to instrument.
+ * @return {!Function} The instrumented function.
+ */
+goog.debug.EntryPointMonitor.prototype.wrap;
+
+
+/**
+ * Try to remove an instrumentation wrapper created by this monitor.
+ * If the function passed to unwrap is not a wrapper created by this
+ * monitor, then we will do nothing.
+ *
+ * Notice that some wrappers may not be unwrappable. For example, if other
+ * monitors have applied their own wrappers, then it will be impossible to
+ * unwrap them because their wrappers will have captured our wrapper.
+ *
+ * So it is important that entry points are unwrapped in the reverse
+ * order that they were wrapped.
+ *
+ * @param {!Function} fn A function to unwrap.
+ * @return {!Function} The unwrapped function, or {@code fn} if it was not
+ *     a wrapped function created by this monitor.
+ */
+goog.debug.EntryPointMonitor.prototype.unwrap;
+
+
+/**
+ * An array of entry point callbacks.
+ * @type {!Array<function(!Function)>}
+ * @private
+ */
+goog.debug.entryPointRegistry.refList_ = [];
+
+
+/**
+ * Monitors that should wrap all the entry points.
+ * @type {!Array<!goog.debug.EntryPointMonitor>}
+ * @private
+ */
+goog.debug.entryPointRegistry.monitors_ = [];
+
+
+/**
+ * Whether goog.debug.entryPointRegistry.monitorAll has ever been called.
+ * Checking this allows the compiler to optimize out the registrations.
+ * @type {boolean}
+ * @private
+ */
+goog.debug.entryPointRegistry.monitorsMayExist_ = false;
+
+
+/**
+ * Register an entry point with this module.
+ *
+ * The entry point will be instrumented when a monitor is passed to
+ * goog.debug.entryPointRegistry.monitorAll. If this has already occurred, the
+ * entry point is instrumented immediately.
+ *
+ * @param {function(!Function)} callback A callback function which is called
+ *     with a transforming function to instrument the entry point. The callback
+ *     is responsible for wrapping the relevant entry point with the
+ *     transforming function.
+ */
+goog.debug.entryPointRegistry.register = function(callback) {
+  // Don't use push(), so that this can be compiled out.
+  goog.debug.entryPointRegistry.refList_[
+      goog.debug.entryPointRegistry.refList_.length] = callback;
+  // If no one calls monitorAll, this can be compiled out.
+  if (goog.debug.entryPointRegistry.monitorsMayExist_) {
+    var monitors = goog.debug.entryPointRegistry.monitors_;
+    for (var i = 0; i < monitors.length; i++) {
+      callback(goog.bind(monitors[i].wrap, monitors[i]));
+    }
+  }
+};
+
+
+/**
+ * Configures a monitor to wrap all entry points.
+ *
+ * Entry points that have already been registered are immediately wrapped by
+ * the monitor. When an entry point is registered in the future, it will also
+ * be wrapped by the monitor when it is registered.
+ *
+ * @param {!goog.debug.EntryPointMonitor} monitor An entry point monitor.
+ */
+goog.debug.entryPointRegistry.monitorAll = function(monitor) {
+  goog.debug.entryPointRegistry.monitorsMayExist_ = true;
+  var transformer = goog.bind(monitor.wrap, monitor);
+  for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) {
+    goog.debug.entryPointRegistry.refList_[i](transformer);
+  }
+  goog.debug.entryPointRegistry.monitors_.push(monitor);
+};
+
+
+/**
+ * Try to unmonitor all the entry points that have already been registered. If
+ * an entry point is registered in the future, it will not be wrapped by the
+ * monitor when it is registered. Note that this may fail if the entry points
+ * have additional wrapping.
+ *
+ * @param {!goog.debug.EntryPointMonitor} monitor The last monitor to wrap
+ *     the entry points.
+ * @throws {Error} If the monitor is not the most recently configured monitor.
+ */
+goog.debug.entryPointRegistry.unmonitorAllIfPossible = function(monitor) {
+  var monitors = goog.debug.entryPointRegistry.monitors_;
+  goog.asserts.assert(monitor == monitors[monitors.length - 1],
+      'Only the most recent monitor can be unwrapped.');
+  var transformer = goog.bind(monitor.unwrap, monitor);
+  for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) {
+    goog.debug.entryPointRegistry.refList_[i](transformer);
+  }
+  monitors.length--;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/error2.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/error2.js b/externs/GCL/externs/goog/debug/error2.js
new file mode 100644
index 0000000..5f1bd3e
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/error2.js
@@ -0,0 +1,63 @@
+// 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 Provides a base class for custom Error objects such that the
+ * stack is correctly maintained.
+ *
+ * You should never need to throw goog.debug.Error(msg) directly, Error(msg) is
+ * sufficient.
+ *
+ */
+
+goog.provide('goog.debug.Error');
+
+
+
+/**
+ * Base class for custom error objects.
+ * @param {*=} opt_msg The message associated with the error.
+ * @constructor
+ * @extends {Error}
+ */
+goog.debug.Error = function(opt_msg) {
+
+  // Attempt to ensure there is a stack trace.
+  if (Error.captureStackTrace) {
+    Error.captureStackTrace(this, goog.debug.Error);
+  } else {
+    var stack = new Error().stack;
+    if (stack) {
+      this.stack = stack;
+    }
+  }
+
+  if (opt_msg) {
+    this.message = String(opt_msg);
+  }
+
+  /**
+   * Whether to report this error to the server. Setting this to false will
+   * cause the error reporter to not report the error back to the server,
+   * which can be useful if the client knows that the error has already been
+   * logged on the server.
+   * @type {boolean}
+   */
+  this.reportErrorToServer = true;
+};
+goog.inherits(goog.debug.Error, Error);
+
+
+/** @override */
+goog.debug.Error.prototype.name = 'CustomError';

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/errorhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/errorhandler.js b/externs/GCL/externs/goog/debug/errorhandler.js
new file mode 100644
index 0000000..3d8b004
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/errorhandler.js
@@ -0,0 +1,367 @@
+// 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 Error handling utilities.
+ *
+ */
+
+goog.provide('goog.debug.ErrorHandler');
+goog.provide('goog.debug.ErrorHandler.ProtectedFunctionError');
+
+goog.require('goog.Disposable');
+goog.require('goog.asserts');
+goog.require('goog.debug');
+goog.require('goog.debug.EntryPointMonitor');
+goog.require('goog.debug.Error');
+goog.require('goog.debug.Trace');
+
+
+
+/**
+ * The ErrorHandler can be used to to wrap functions with a try/catch
+ * statement. If an exception is thrown, the given error handler function will
+ * be called.
+ *
+ * When this object is disposed, it will stop handling exceptions and tracing.
+ * It will also try to restore window.setTimeout and window.setInterval
+ * if it wrapped them. Notice that in the general case, it is not technically
+ * possible to remove the wrapper, because functions have no knowledge of
+ * what they have been assigned to. So the app is responsible for other
+ * forms of unwrapping.
+ *
+ * @param {Function} handler Handler for exceptions.
+ * @constructor
+ * @extends {goog.Disposable}
+ * @implements {goog.debug.EntryPointMonitor}
+ */
+goog.debug.ErrorHandler = function(handler) {
+  goog.debug.ErrorHandler.base(this, 'constructor');
+
+  /**
+   * Handler for exceptions, which can do logging, reporting, etc.
+   * @type {Function}
+   * @private
+   */
+  this.errorHandlerFn_ = handler;
+
+  /**
+   * Whether errors should be wrapped in
+   * goog.debug.ErrorHandler.ProtectedFunctionError before rethrowing.
+   * @type {boolean}
+   * @private
+   */
+  this.wrapErrors_ = true;  // TODO(user) Change default.
+
+  /**
+   * Whether to add a prefix to all error messages. The prefix is
+   * goog.debug.ErrorHandler.ProtectedFunctionError.MESSAGE_PREFIX. This option
+   * only has an effect if this.wrapErrors_  is set to false.
+   * @type {boolean}
+   * @private
+   */
+  this.prefixErrorMessages_ = false;
+};
+goog.inherits(goog.debug.ErrorHandler, goog.Disposable);
+
+
+/**
+ * Whether to add tracers when instrumenting entry points.
+ * @type {boolean}
+ * @private
+ */
+goog.debug.ErrorHandler.prototype.addTracersToProtectedFunctions_ = false;
+
+
+/**
+ * Enable tracers when instrumenting entry points.
+ * @param {boolean} newVal See above.
+ */
+goog.debug.ErrorHandler.prototype.setAddTracersToProtectedFunctions =
+    function(newVal) {
+  this.addTracersToProtectedFunctions_ = newVal;
+};
+
+
+/** @override */
+goog.debug.ErrorHandler.prototype.wrap = function(fn) {
+  return this.protectEntryPoint(goog.asserts.assertFunction(fn));
+};
+
+
+/** @override */
+goog.debug.ErrorHandler.prototype.unwrap = function(fn) {
+  goog.asserts.assertFunction(fn);
+  return fn[this.getFunctionIndex_(false)] || fn;
+};
+
+
+/**
+ * Private helper function to return a span that can be clicked on to display
+ * an alert with the current stack trace. Newlines are replaced with a
+ * placeholder so that they will not be html-escaped.
+ * @param {string} stackTrace The stack trace to create a span for.
+ * @return {string} A span which can be clicked on to show the stack trace.
+ * @private
+ */
+goog.debug.ErrorHandler.prototype.getStackTraceHolder_ = function(stackTrace) {
+  var buffer = [];
+  buffer.push('##PE_STACK_START##');
+  buffer.push(stackTrace.replace(/(\r\n|\r|\n)/g, '##STACK_BR##'));
+  buffer.push('##PE_STACK_END##');
+  return buffer.join('');
+};
+
+
+/**
+ * Get the index for a function. Used for internal indexing.
+ * @param {boolean} wrapper True for the wrapper; false for the wrapped.
+ * @return {string} The index where we should store the function in its
+ *     wrapper/wrapped function.
+ * @private
+ */
+goog.debug.ErrorHandler.prototype.getFunctionIndex_ = function(wrapper) {
+  return (wrapper ? '__wrapper_' : '__protected_') + goog.getUid(this) + '__';
+};
+
+
+/**
+ * Installs exception protection for an entry point function. When an exception
+ * is thrown from a protected function, a handler will be invoked to handle it.
+ *
+ * @param {Function} fn An entry point function to be protected.
+ * @return {!Function} A protected wrapper function that calls the entry point
+ *     function.
+ */
+goog.debug.ErrorHandler.prototype.protectEntryPoint = function(fn) {
+  var protectedFnName = this.getFunctionIndex_(true);
+  if (!fn[protectedFnName]) {
+    var wrapper = fn[protectedFnName] = this.getProtectedFunction(fn);
+    wrapper[this.getFunctionIndex_(false)] = fn;
+  }
+  return fn[protectedFnName];
+};
+
+
+/**
+ * Helps {@link #protectEntryPoint} by actually creating the protected
+ * wrapper function, after {@link #protectEntryPoint} determines that one does
+ * not already exist for the given function.  Can be overriden by subclasses
+ * that may want to implement different error handling, or add additional
+ * entry point hooks.
+ * @param {!Function} fn An entry point function to be protected.
+ * @return {!Function} protected wrapper function.
+ * @protected
+ */
+goog.debug.ErrorHandler.prototype.getProtectedFunction = function(fn) {
+  var that = this;
+  var tracers = this.addTracersToProtectedFunctions_;
+  if (tracers) {
+    var stackTrace = goog.debug.getStacktraceSimple(15);
+  }
+  var googDebugErrorHandlerProtectedFunction = function() {
+    if (that.isDisposed()) {
+      return fn.apply(this, arguments);
+    }
+
+    if (tracers) {
+      var tracer = goog.debug.Trace.startTracer('protectedEntryPoint: ' +
+          that.getStackTraceHolder_(stackTrace));
+    }
+    try {
+      return fn.apply(this, arguments);
+    } catch (e) {
+      that.errorHandlerFn_(e);
+      if (!that.wrapErrors_) {
+        // Add the prefix to the existing message.
+        if (that.prefixErrorMessages_) {
+          if (typeof e === 'object') {
+            e.message =
+                goog.debug.ErrorHandler.ProtectedFunctionError.MESSAGE_PREFIX +
+                e.message;
+          } else {
+            e = goog.debug.ErrorHandler.ProtectedFunctionError.MESSAGE_PREFIX +
+                e;
+          }
+        }
+        if (goog.DEBUG) {
+          // Work around for https://code.google.com/p/v8/issues/detail?id=2625
+          // and https://code.google.com/p/chromium/issues/detail?id=237059
+          // Custom errors and errors with custom stack traces show the wrong
+          // stack trace
+          // If it has a stack and Error.captureStackTrace is supported (only
+          // supported in V8 as of May 2013) log the stack to the console.
+          if (e && e.stack && Error.captureStackTrace &&
+              goog.global['console']) {
+            goog.global['console']['error'](e.message, e.stack);
+          }
+        }
+        // Re-throw original error. This is great for debugging as it makes
+        // browser JS dev consoles show the correct error and stack trace.
+        throw e;
+      }
+      // Re-throw it since this may be expected by the caller.
+      throw new goog.debug.ErrorHandler.ProtectedFunctionError(e);
+    } finally {
+      if (tracers) {
+        goog.debug.Trace.stopTracer(tracer);
+      }
+    }
+  };
+  googDebugErrorHandlerProtectedFunction[this.getFunctionIndex_(false)] = fn;
+  return googDebugErrorHandlerProtectedFunction;
+};
+
+
+// TODO(mknichel): Allow these functions to take in the window to protect.
+/**
+ * Installs exception protection for window.setTimeout to handle exceptions.
+ */
+goog.debug.ErrorHandler.prototype.protectWindowSetTimeout =
+    function() {
+  this.protectWindowFunctionsHelper_('setTimeout');
+};
+
+
+/**
+ * Install exception protection for window.setInterval to handle exceptions.
+ */
+goog.debug.ErrorHandler.prototype.protectWindowSetInterval =
+    function() {
+  this.protectWindowFunctionsHelper_('setInterval');
+};
+
+
+/**
+ * Install exception protection for window.requestAnimationFrame to handle
+ * exceptions.
+ */
+goog.debug.ErrorHandler.prototype.protectWindowRequestAnimationFrame =
+    function() {
+  var win = goog.getObjectByName('window');
+  var fnNames = [
+    'requestAnimationFrame',
+    'mozRequestAnimationFrame',
+    'webkitAnimationFrame',
+    'msRequestAnimationFrame'
+  ];
+  for (var i = 0; i < fnNames.length; i++) {
+    var fnName = fnNames[i];
+    if (fnNames[i] in win) {
+      this.protectWindowFunctionsHelper_(fnName);
+    }
+  }
+};
+
+
+/**
+ * Helper function for protecting a function that causes a function to be
+ * asynchronously called, for example setTimeout or requestAnimationFrame.
+ * @param {string} fnName The name of the function to protect.
+ * @private
+ */
+goog.debug.ErrorHandler.prototype.protectWindowFunctionsHelper_ =
+    function(fnName) {
+  var win = goog.getObjectByName('window');
+  var originalFn = win[fnName];
+  var that = this;
+  win[fnName] = function(fn, time) {
+    // Don't try to protect strings. In theory, we could try to globalEval
+    // the string, but this seems to lead to permission errors on IE6.
+    if (goog.isString(fn)) {
+      fn = goog.partial(goog.globalEval, fn);
+    }
+    fn = that.protectEntryPoint(fn);
+
+    // IE doesn't support .call for setInterval/setTimeout, but it
+    // also doesn't care what "this" is, so we can just call the
+    // original function directly
+    if (originalFn.call) {
+      return originalFn.call(this, fn, time);
+    } else {
+      return originalFn(fn, time);
+    }
+  };
+  win[fnName][this.getFunctionIndex_(false)] = originalFn;
+};
+
+
+/**
+ * Set whether to wrap errors that occur in protected functions in a
+ * goog.debug.ErrorHandler.ProtectedFunctionError.
+ * @param {boolean} wrapErrors Whether to wrap errors.
+ */
+goog.debug.ErrorHandler.prototype.setWrapErrors = function(wrapErrors) {
+  this.wrapErrors_ = wrapErrors;
+};
+
+
+/**
+ * Set whether to add a prefix to all error messages that occur in protected
+ * functions.
+ * @param {boolean} prefixErrorMessages Whether to add a prefix to error
+ *     messages.
+ */
+goog.debug.ErrorHandler.prototype.setPrefixErrorMessages =
+    function(prefixErrorMessages) {
+  this.prefixErrorMessages_ = prefixErrorMessages;
+};
+
+
+/** @override */
+goog.debug.ErrorHandler.prototype.disposeInternal = function() {
+  // Try to unwrap window.setTimeout and window.setInterval.
+  var win = goog.getObjectByName('window');
+  win.setTimeout = this.unwrap(win.setTimeout);
+  win.setInterval = this.unwrap(win.setInterval);
+
+  goog.debug.ErrorHandler.base(this, 'disposeInternal');
+};
+
+
+
+/**
+ * Error thrown to the caller of a protected entry point if the entry point
+ * throws an error.
+ * @param {*} cause The error thrown by the entry point.
+ * @constructor
+ * @extends {goog.debug.Error}
+ * @final
+ */
+goog.debug.ErrorHandler.ProtectedFunctionError = function(cause) {
+  var message = goog.debug.ErrorHandler.ProtectedFunctionError.MESSAGE_PREFIX +
+      (cause && cause.message ? String(cause.message) : String(cause));
+  goog.debug.ErrorHandler.ProtectedFunctionError.base(
+      this, 'constructor', message);
+
+  /**
+   * The error thrown by the entry point.
+   * @type {*}
+   */
+  this.cause = cause;
+
+  var stack = cause && cause.stack;
+  if (stack && goog.isString(stack)) {
+    this.stack = /** @type {string} */ (stack);
+  }
+};
+goog.inherits(goog.debug.ErrorHandler.ProtectedFunctionError, goog.debug.Error);
+
+
+/**
+ * Text to prefix the message with.
+ * @type {string}
+ */
+goog.debug.ErrorHandler.ProtectedFunctionError.MESSAGE_PREFIX =
+    'Error in protected function: ';

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/errorhandlerweakdep.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/errorhandlerweakdep.js b/externs/GCL/externs/goog/debug/errorhandlerweakdep.js
new file mode 100644
index 0000000..284ddb0
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/errorhandlerweakdep.js
@@ -0,0 +1,38 @@
+// Copyright 2008 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 File which defines dummy object to work around undefined
+ * properties compiler warning for weak dependencies on
+ * {@link goog.debug.ErrorHandler#protectEntryPoint}.
+ *
+ */
+
+goog.provide('goog.debug.errorHandlerWeakDep');
+
+
+/**
+ * Dummy object to work around undefined properties compiler warning.
+ * @type {!Object<string,Function>}
+ */
+goog.debug.errorHandlerWeakDep = {
+  /**
+   * @param {Function} fn An entry point function to be protected.
+   * @param {boolean=} opt_tracers Whether to install tracers around the
+   *     fn.
+   * @return {Function} A protected wrapper function that calls the
+   *     entry point function.
+   */
+  protectEntryPoint: function(fn, opt_tracers) { return fn; }
+};


[04/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/i18n/collation.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/i18n/collation.js b/externs/GCL/externs/goog/i18n/collation.js
new file mode 100644
index 0000000..7314912
--- /dev/null
+++ b/externs/GCL/externs/goog/i18n/collation.js
@@ -0,0 +1,58 @@
+// Copyright 2013 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 Contains helper functions for performing locale-sensitive
+ *     collation.
+ */
+
+
+goog.provide('goog.i18n.collation');
+
+
+/**
+ * Returns the comparator for a locale. If a locale is not explicitly specified,
+ * a comparator for the user's locale will be returned. Note that if the browser
+ * does not support locale-sensitive string comparisons, the comparator returned
+ * will be a simple codepoint comparator.
+ *
+ * @param {string=} opt_locale the locale that the comparator is used for.
+ * @return {function(string, string): number} The locale-specific comparator.
+ */
+goog.i18n.collation.createComparator = function(opt_locale) {
+  // See http://code.google.com/p/v8-i18n.
+  if (goog.i18n.collation.hasNativeComparator()) {
+    var intl = goog.global.Intl;
+    return new intl.Collator([opt_locale || goog.LOCALE]).compare;
+  } else {
+    return function(arg1, arg2) {
+      return arg1.localeCompare(arg2);
+    };
+  }
+};
+
+
+/**
+ * Returns true if a locale-sensitive comparator is available for a locale. If
+ * a locale is not explicitly specified, the user's locale is used instead.
+ *
+ * @param {string=} opt_locale The locale to be checked.
+ * @return {boolean} Whether there is a locale-sensitive comparator available
+ *     for the locale.
+ */
+goog.i18n.collation.hasNativeComparator = function(opt_locale) {
+  var intl = goog.global.Intl;
+  return !!(intl && intl.Collator);
+};


[10/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/groupelement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/groupelement.js b/externs/GCL/externs/goog/graphics/groupelement.js
new file mode 100644
index 0000000..9e60cd7
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/groupelement.js
@@ -0,0 +1,58 @@
+// 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 A thin wrapper around the DOM element for graphics groups.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.GroupElement');
+
+goog.require('goog.graphics.Element');
+
+
+
+/**
+ * Interface for a graphics group element.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.AbstractGraphics} graphics The graphics creating
+ *     this element.
+ * @constructor
+ * @extends {goog.graphics.Element}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.GroupElement = function(element, graphics) {
+  goog.graphics.Element.call(this, element, graphics);
+};
+goog.inherits(goog.graphics.GroupElement, goog.graphics.Element);
+
+
+/**
+ * Remove all drawing elements from the group.
+ */
+goog.graphics.GroupElement.prototype.clear = goog.abstractMethod;
+
+
+/**
+ * Set the size of the group element.
+ * @param {number|string} width The width of the group element.
+ * @param {number|string} height The height of the group element.
+ */
+goog.graphics.GroupElement.prototype.setSize = goog.abstractMethod;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/imageelement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/imageelement.js b/externs/GCL/externs/goog/graphics/imageelement.js
new file mode 100644
index 0000000..2f2d9b7
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/imageelement.js
@@ -0,0 +1,70 @@
+// 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 A thin wrapper around the DOM element for images.
+ */
+
+
+goog.provide('goog.graphics.ImageElement');
+
+goog.require('goog.graphics.Element');
+
+
+
+/**
+ * Interface for a graphics image element.
+ * You should not construct objects from this constructor. Instead,
+ * you should use {@code goog.graphics.Graphics.drawImage} and it
+ * will return an implementation of this interface for you.
+ *
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.AbstractGraphics} graphics The graphics creating
+ *     this element.
+ * @constructor
+ * @extends {goog.graphics.Element}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.ImageElement = function(element, graphics) {
+  goog.graphics.Element.call(this, element, graphics);
+};
+goog.inherits(goog.graphics.ImageElement, goog.graphics.Element);
+
+
+/**
+ * Update the position of the image.
+ *
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ */
+goog.graphics.ImageElement.prototype.setPosition = goog.abstractMethod;
+
+
+/**
+ * Update the size of the image.
+ *
+ * @param {number} width Width of image.
+ * @param {number} height Height of image.
+ */
+goog.graphics.ImageElement.prototype.setSize = goog.abstractMethod;
+
+
+/**
+ * Update the source of the image.
+ * @param {string} src Source of the image.
+ */
+goog.graphics.ImageElement.prototype.setSource = goog.abstractMethod;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/lineargradient.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/lineargradient.js b/externs/GCL/externs/goog/graphics/lineargradient.js
new file mode 100644
index 0000000..df59cbf
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/lineargradient.js
@@ -0,0 +1,175 @@
+// 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 Represents a gradient to be used with a Graphics implementor.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.LinearGradient');
+
+
+goog.require('goog.asserts');
+goog.require('goog.graphics.Fill');
+
+
+
+/**
+ * Creates an immutable linear gradient fill object.
+ *
+ * @param {number} x1 Start X position of the gradient.
+ * @param {number} y1 Start Y position of the gradient.
+ * @param {number} x2 End X position of the gradient.
+ * @param {number} y2 End Y position of the gradient.
+ * @param {string} color1 Start color of the gradient.
+ * @param {string} color2 End color of the gradient.
+ * @param {?number=} opt_opacity1 Start opacity of the gradient, both or neither
+ *     of opt_opacity1 and opt_opacity2 have to be set.
+ * @param {?number=} opt_opacity2 End opacity of the gradient.
+ * @constructor
+ * @extends {goog.graphics.Fill}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.LinearGradient =
+    function(x1, y1, x2, y2, color1, color2, opt_opacity1, opt_opacity2) {
+  /**
+   * Start X position of the gradient.
+   * @type {number}
+   * @private
+   */
+  this.x1_ = x1;
+
+  /**
+   * Start Y position of the gradient.
+   * @type {number}
+   * @private
+   */
+  this.y1_ = y1;
+
+  /**
+   * End X position of the gradient.
+   * @type {number}
+   * @private
+   */
+  this.x2_ = x2;
+
+  /**
+   * End Y position of the gradient.
+   * @type {number}
+   * @private
+   */
+  this.y2_ = y2;
+
+  /**
+   * Start color of the gradient.
+   * @type {string}
+   * @private
+   */
+  this.color1_ = color1;
+
+  /**
+   * End color of the gradient.
+   * @type {string}
+   * @private
+   */
+  this.color2_ = color2;
+
+  goog.asserts.assert(
+      goog.isNumber(opt_opacity1) == goog.isNumber(opt_opacity2),
+      'Both or neither of opt_opacity1 and opt_opacity2 have to be set.');
+
+  /**
+   * Start opacity of the gradient.
+   * @type {?number}
+   * @private
+   */
+  this.opacity1_ = goog.isDef(opt_opacity1) ? opt_opacity1 : null;
+
+  /**
+   * End opacity of the gradient.
+   * @type {?number}
+   * @private
+   */
+  this.opacity2_ = goog.isDef(opt_opacity2) ? opt_opacity2 : null;
+};
+goog.inherits(goog.graphics.LinearGradient, goog.graphics.Fill);
+
+
+/**
+ * @return {number} The start X position of the gradient.
+ */
+goog.graphics.LinearGradient.prototype.getX1 = function() {
+  return this.x1_;
+};
+
+
+/**
+ * @return {number} The start Y position of the gradient.
+ */
+goog.graphics.LinearGradient.prototype.getY1 = function() {
+  return this.y1_;
+};
+
+
+/**
+ * @return {number} The end X position of the gradient.
+ */
+goog.graphics.LinearGradient.prototype.getX2 = function() {
+  return this.x2_;
+};
+
+
+/**
+ * @return {number} The end Y position of the gradient.
+ */
+goog.graphics.LinearGradient.prototype.getY2 = function() {
+  return this.y2_;
+};
+
+
+/**
+ * @override
+ */
+goog.graphics.LinearGradient.prototype.getColor1 = function() {
+  return this.color1_;
+};
+
+
+/**
+ * @override
+ */
+goog.graphics.LinearGradient.prototype.getColor2 = function() {
+  return this.color2_;
+};
+
+
+/**
+ * @return {?number} The start opacity of the gradient.
+ */
+goog.graphics.LinearGradient.prototype.getOpacity1 = function() {
+  return this.opacity1_;
+};
+
+
+/**
+ * @return {?number} The end opacity of the gradient.
+ */
+goog.graphics.LinearGradient.prototype.getOpacity2 = function() {
+  return this.opacity2_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/path.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/path.js b/externs/GCL/externs/goog/graphics/path.js
new file mode 100644
index 0000000..c19f2d9
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/path.js
@@ -0,0 +1,511 @@
+// 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 Represents a path used with a Graphics implementation.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+goog.provide('goog.graphics.Path');
+goog.provide('goog.graphics.Path.Segment');
+
+goog.require('goog.array');
+goog.require('goog.math');
+
+
+
+/**
+ * Creates a path object. A path is a sequence of segments and may be open or
+ * closed. Path uses the EVEN-ODD fill rule for determining the interior of the
+ * path. A path must start with a moveTo command.
+ *
+ * A "simple" path does not contain any arcs and may be transformed using
+ * the {@code transform} method.
+ *
+ * @constructor
+ */
+goog.graphics.Path = function() {
+  /**
+   * The segment types that constitute this path.
+   * @type {!Array<number>}
+   * @private
+   */
+  this.segments_ = [];
+
+  /**
+   * The number of repeated segments of the current type.
+   * @type {!Array<number>}
+   * @private
+   */
+  this.count_ = [];
+
+  /**
+   * The arguments corresponding to each of the segments.
+   * @type {!Array<number>}
+   * @private
+   */
+  this.arguments_ = [];
+};
+
+
+/**
+ * The coordinates of the point which closes the path (the point of the
+ * last moveTo command).
+ * @type {Array<number>?}
+ * @private
+ */
+goog.graphics.Path.prototype.closePoint_ = null;
+
+
+/**
+ * The coordinates most recently added to the end of the path.
+ * @type {Array<number>?}
+ * @private
+ */
+goog.graphics.Path.prototype.currentPoint_ = null;
+
+
+/**
+ * Flag for whether this is a simple path (contains no arc segments).
+ * @type {boolean}
+ * @private
+ */
+goog.graphics.Path.prototype.simple_ = true;
+
+
+/**
+ * Path segment types.
+ * @enum {number}
+ */
+goog.graphics.Path.Segment = {
+  MOVETO: 0,
+  LINETO: 1,
+  CURVETO: 2,
+  ARCTO: 3,
+  CLOSE: 4
+};
+
+
+/**
+ * The number of points for each segment type.
+ * @type {!Array<number>}
+ * @private
+ */
+goog.graphics.Path.segmentArgCounts_ = (function() {
+  var counts = [];
+  counts[goog.graphics.Path.Segment.MOVETO] = 2;
+  counts[goog.graphics.Path.Segment.LINETO] = 2;
+  counts[goog.graphics.Path.Segment.CURVETO] = 6;
+  counts[goog.graphics.Path.Segment.ARCTO] = 6;
+  counts[goog.graphics.Path.Segment.CLOSE] = 0;
+  return counts;
+})();
+
+
+/**
+ * Returns the number of points for a segment type.
+ *
+ * @param {number} segment The segment type.
+ * @return {number} The number of points.
+ */
+goog.graphics.Path.getSegmentCount = function(segment) {
+  return goog.graphics.Path.segmentArgCounts_[segment];
+};
+
+
+/**
+ * Appends another path to the end of this path.
+ *
+ * @param {!goog.graphics.Path} path The path to append.
+ * @return {!goog.graphics.Path} This path.
+ */
+goog.graphics.Path.prototype.appendPath = function(path) {
+  if (path.currentPoint_) {
+    Array.prototype.push.apply(this.segments_, path.segments_);
+    Array.prototype.push.apply(this.count_, path.count_);
+    Array.prototype.push.apply(this.arguments_, path.arguments_);
+    this.currentPoint_ = path.currentPoint_.concat();
+    this.closePoint_ = path.closePoint_.concat();
+    this.simple_ = this.simple_ && path.simple_;
+  }
+  return this;
+};
+
+
+/**
+ * Clears the path.
+ *
+ * @return {!goog.graphics.Path} The path itself.
+ */
+goog.graphics.Path.prototype.clear = function() {
+  this.segments_.length = 0;
+  this.count_.length = 0;
+  this.arguments_.length = 0;
+  delete this.closePoint_;
+  delete this.currentPoint_;
+  delete this.simple_;
+  return this;
+};
+
+
+/**
+ * Adds a point to the path by moving to the specified point. Repeated moveTo
+ * commands are collapsed into a single moveTo.
+ *
+ * @param {number} x X coordinate of destination point.
+ * @param {number} y Y coordinate of destination point.
+ * @return {!goog.graphics.Path} The path itself.
+ */
+goog.graphics.Path.prototype.moveTo = function(x, y) {
+  if (goog.array.peek(this.segments_) == goog.graphics.Path.Segment.MOVETO) {
+    this.arguments_.length -= 2;
+  } else {
+    this.segments_.push(goog.graphics.Path.Segment.MOVETO);
+    this.count_.push(1);
+  }
+  this.arguments_.push(x, y);
+  this.currentPoint_ = this.closePoint_ = [x, y];
+  return this;
+};
+
+
+/**
+ * Adds points to the path by drawing a straight line to each point.
+ *
+ * @param {...number} var_args The coordinates of each destination point as x, y
+ *     value pairs.
+ * @return {!goog.graphics.Path} The path itself.
+ */
+goog.graphics.Path.prototype.lineTo = function(var_args) {
+  var lastSegment = goog.array.peek(this.segments_);
+  if (lastSegment == null) {
+    throw Error('Path cannot start with lineTo');
+  }
+  if (lastSegment != goog.graphics.Path.Segment.LINETO) {
+    this.segments_.push(goog.graphics.Path.Segment.LINETO);
+    this.count_.push(0);
+  }
+  for (var i = 0; i < arguments.length; i += 2) {
+    var x = arguments[i];
+    var y = arguments[i + 1];
+    this.arguments_.push(x, y);
+  }
+  this.count_[this.count_.length - 1] += i / 2;
+  this.currentPoint_ = [x, y];
+  return this;
+};
+
+
+/**
+ * Adds points to the path by drawing cubic Bezier curves. Each curve is
+ * specified using 3 points (6 coordinates) - two control points and the end
+ * point of the curve.
+ *
+ * @param {...number} var_args The coordinates specifiying each curve in sets of
+ *     6 points: {@code [x1, y1]} the first control point, {@code [x2, y2]} the
+ *     second control point and {@code [x, y]} the end point.
+ * @return {!goog.graphics.Path} The path itself.
+ */
+goog.graphics.Path.prototype.curveTo = function(var_args) {
+  var lastSegment = goog.array.peek(this.segments_);
+  if (lastSegment == null) {
+    throw Error('Path cannot start with curve');
+  }
+  if (lastSegment != goog.graphics.Path.Segment.CURVETO) {
+    this.segments_.push(goog.graphics.Path.Segment.CURVETO);
+    this.count_.push(0);
+  }
+  for (var i = 0; i < arguments.length; i += 6) {
+    var x = arguments[i + 4];
+    var y = arguments[i + 5];
+    this.arguments_.push(arguments[i], arguments[i + 1],
+        arguments[i + 2], arguments[i + 3], x, y);
+  }
+  this.count_[this.count_.length - 1] += i / 6;
+  this.currentPoint_ = [x, y];
+  return this;
+};
+
+
+/**
+ * Adds a path command to close the path by connecting the
+ * last point to the first point.
+ *
+ * @return {!goog.graphics.Path} The path itself.
+ */
+goog.graphics.Path.prototype.close = function() {
+  var lastSegment = goog.array.peek(this.segments_);
+  if (lastSegment == null) {
+    throw Error('Path cannot start with close');
+  }
+  if (lastSegment != goog.graphics.Path.Segment.CLOSE) {
+    this.segments_.push(goog.graphics.Path.Segment.CLOSE);
+    this.count_.push(1);
+    this.currentPoint_ = this.closePoint_;
+  }
+  return this;
+};
+
+
+/**
+ * Adds a path command to draw an arc centered at the point {@code (cx, cy)}
+ * with radius {@code rx} along the x-axis and {@code ry} along the y-axis from
+ * {@code startAngle} through {@code extent} degrees. Positive rotation is in
+ * the direction from positive x-axis to positive y-axis.
+ *
+ * @param {number} cx X coordinate of center of ellipse.
+ * @param {number} cy Y coordinate of center of ellipse.
+ * @param {number} rx Radius of ellipse on x axis.
+ * @param {number} ry Radius of ellipse on y axis.
+ * @param {number} fromAngle Starting angle measured in degrees from the
+ *     positive x-axis.
+ * @param {number} extent The span of the arc in degrees.
+ * @param {boolean} connect If true, the starting point of the arc is connected
+ *     to the current point.
+ * @return {!goog.graphics.Path} The path itself.
+ * @deprecated Use {@code arcTo} or {@code arcToAsCurves} instead.
+ */
+goog.graphics.Path.prototype.arc = function(cx, cy, rx, ry,
+    fromAngle, extent, connect) {
+  var startX = cx + goog.math.angleDx(fromAngle, rx);
+  var startY = cy + goog.math.angleDy(fromAngle, ry);
+  if (connect) {
+    if (!this.currentPoint_ || startX != this.currentPoint_[0] ||
+        startY != this.currentPoint_[1]) {
+      this.lineTo(startX, startY);
+    }
+  } else {
+    this.moveTo(startX, startY);
+  }
+  return this.arcTo(rx, ry, fromAngle, extent);
+};
+
+
+/**
+ * Adds a path command to draw an arc starting at the path's current point,
+ * with radius {@code rx} along the x-axis and {@code ry} along the y-axis from
+ * {@code startAngle} through {@code extent} degrees. Positive rotation is in
+ * the direction from positive x-axis to positive y-axis.
+ *
+ * This method makes the path non-simple.
+ *
+ * @param {number} rx Radius of ellipse on x axis.
+ * @param {number} ry Radius of ellipse on y axis.
+ * @param {number} fromAngle Starting angle measured in degrees from the
+ *     positive x-axis.
+ * @param {number} extent The span of the arc in degrees.
+ * @return {!goog.graphics.Path} The path itself.
+ */
+goog.graphics.Path.prototype.arcTo = function(rx, ry, fromAngle, extent) {
+  var cx = this.currentPoint_[0] - goog.math.angleDx(fromAngle, rx);
+  var cy = this.currentPoint_[1] - goog.math.angleDy(fromAngle, ry);
+  var ex = cx + goog.math.angleDx(fromAngle + extent, rx);
+  var ey = cy + goog.math.angleDy(fromAngle + extent, ry);
+  this.segments_.push(goog.graphics.Path.Segment.ARCTO);
+  this.count_.push(1);
+  this.arguments_.push(rx, ry, fromAngle, extent, ex, ey);
+  this.simple_ = false;
+  this.currentPoint_ = [ex, ey];
+  return this;
+};
+
+
+/**
+ * Same as {@code arcTo}, but approximates the arc using bezier curves.
+.* As a result, this method does not affect the simplified status of this path.
+ * The algorithm is adapted from {@code java.awt.geom.ArcIterator}.
+ *
+ * @param {number} rx Radius of ellipse on x axis.
+ * @param {number} ry Radius of ellipse on y axis.
+ * @param {number} fromAngle Starting angle measured in degrees from the
+ *     positive x-axis.
+ * @param {number} extent The span of the arc in degrees.
+ * @return {!goog.graphics.Path} The path itself.
+ */
+goog.graphics.Path.prototype.arcToAsCurves = function(
+    rx, ry, fromAngle, extent) {
+  var cx = this.currentPoint_[0] - goog.math.angleDx(fromAngle, rx);
+  var cy = this.currentPoint_[1] - goog.math.angleDy(fromAngle, ry);
+  var extentRad = goog.math.toRadians(extent);
+  var arcSegs = Math.ceil(Math.abs(extentRad) / Math.PI * 2);
+  var inc = extentRad / arcSegs;
+  var angle = goog.math.toRadians(fromAngle);
+  for (var j = 0; j < arcSegs; j++) {
+    var relX = Math.cos(angle);
+    var relY = Math.sin(angle);
+    var z = 4 / 3 * Math.sin(inc / 2) / (1 + Math.cos(inc / 2));
+    var c0 = cx + (relX - z * relY) * rx;
+    var c1 = cy + (relY + z * relX) * ry;
+    angle += inc;
+    relX = Math.cos(angle);
+    relY = Math.sin(angle);
+    this.curveTo(c0, c1,
+        cx + (relX + z * relY) * rx,
+        cy + (relY - z * relX) * ry,
+        cx + relX * rx,
+        cy + relY * ry);
+  }
+  return this;
+};
+
+
+/**
+ * Iterates over the path calling the supplied callback once for each path
+ * segment. The arguments to the callback function are the segment type and
+ * an array of its arguments.
+ *
+ * The {@code LINETO} and {@code CURVETO} arrays can contain multiple
+ * segments of the same type. The number of segments is the length of the
+ * array divided by the segment length (2 for lines, 6 for  curves).
+ *
+ * As a convenience the {@code ARCTO} segment also includes the end point as the
+ * last two arguments: {@code rx, ry, fromAngle, extent, x, y}.
+ *
+ * @param {function(number, Array)} callback The function to call with each
+ *     path segment.
+ */
+goog.graphics.Path.prototype.forEachSegment = function(callback) {
+  var points = this.arguments_;
+  var index = 0;
+  for (var i = 0, length = this.segments_.length; i < length; i++) {
+    var seg = this.segments_[i];
+    var n = goog.graphics.Path.segmentArgCounts_[seg] * this.count_[i];
+    callback(seg, points.slice(index, index + n));
+    index += n;
+  }
+};
+
+
+/**
+ * Returns the coordinates most recently added to the end of the path.
+ *
+ * @return {Array<number>?} An array containing the ending coordinates of the
+ *     path of the form {@code [x, y]}.
+ */
+goog.graphics.Path.prototype.getCurrentPoint = function() {
+  return this.currentPoint_ && this.currentPoint_.concat();
+};
+
+
+/**
+ * @return {!goog.graphics.Path} A copy of this path.
+ */
+goog.graphics.Path.prototype.clone = function() {
+  var path = new this.constructor();
+  path.segments_ = this.segments_.concat();
+  path.count_ = this.count_.concat();
+  path.arguments_ = this.arguments_.concat();
+  path.closePoint_ = this.closePoint_ && this.closePoint_.concat();
+  path.currentPoint_ = this.currentPoint_ && this.currentPoint_.concat();
+  path.simple_ = this.simple_;
+  return path;
+};
+
+
+/**
+ * Returns true if this path contains no arcs. Simplified paths can be
+ * created using {@code createSimplifiedPath}.
+ *
+ * @return {boolean} True if the path contains no arcs.
+ */
+goog.graphics.Path.prototype.isSimple = function() {
+  return this.simple_;
+};
+
+
+/**
+ * A map from segment type to the path function to call to simplify a path.
+ * @type {!Object}
+ * @private
+ * @suppress {deprecated} goog.graphics.Path is deprecated.
+ */
+goog.graphics.Path.simplifySegmentMap_ = (function() {
+  var map = {};
+  map[goog.graphics.Path.Segment.MOVETO] = goog.graphics.Path.prototype.moveTo;
+  map[goog.graphics.Path.Segment.LINETO] = goog.graphics.Path.prototype.lineTo;
+  map[goog.graphics.Path.Segment.CLOSE] = goog.graphics.Path.prototype.close;
+  map[goog.graphics.Path.Segment.CURVETO] =
+      goog.graphics.Path.prototype.curveTo;
+  map[goog.graphics.Path.Segment.ARCTO] =
+      goog.graphics.Path.prototype.arcToAsCurves;
+  return map;
+})();
+
+
+/**
+ * Creates a copy of the given path, replacing {@code arcTo} with
+ * {@code arcToAsCurves}. The resulting path is simplified and can
+ * be transformed.
+ *
+ * @param {!goog.graphics.Path} src The path to simplify.
+ * @return {!goog.graphics.Path} A new simplified path.
+ * @suppress {deprecated} goog.graphics is deprecated.
+ */
+goog.graphics.Path.createSimplifiedPath = function(src) {
+  if (src.isSimple()) {
+    return src.clone();
+  }
+  var path = new goog.graphics.Path();
+  src.forEachSegment(function(segment, args) {
+    goog.graphics.Path.simplifySegmentMap_[segment].apply(path, args);
+  });
+  return path;
+};
+
+
+// TODO(chrisn): Delete this method
+/**
+ * Creates a transformed copy of this path. The path is simplified
+ * {@see #createSimplifiedPath} prior to transformation.
+ *
+ * @param {!goog.graphics.AffineTransform} tx The transformation to perform.
+ * @return {!goog.graphics.Path} A new, transformed path.
+ */
+goog.graphics.Path.prototype.createTransformedPath = function(tx) {
+  var path = goog.graphics.Path.createSimplifiedPath(this);
+  path.transform(tx);
+  return path;
+};
+
+
+/**
+ * Transforms the path. Only simple paths are transformable. Attempting
+ * to transform a non-simple path will throw an error.
+ *
+ * @param {!goog.graphics.AffineTransform} tx The transformation to perform.
+ * @return {!goog.graphics.Path} The path itself.
+ */
+goog.graphics.Path.prototype.transform = function(tx) {
+  if (!this.isSimple()) {
+    throw Error('Non-simple path');
+  }
+  tx.transform(this.arguments_, 0, this.arguments_, 0,
+      this.arguments_.length / 2);
+  if (this.closePoint_) {
+    tx.transform(this.closePoint_, 0, this.closePoint_, 0, 1);
+  }
+  if (this.currentPoint_ && this.closePoint_ != this.currentPoint_) {
+    tx.transform(this.currentPoint_, 0, this.currentPoint_, 0, 1);
+  }
+  return this;
+};
+
+
+/**
+ * @return {boolean} Whether the path is empty.
+ */
+goog.graphics.Path.prototype.isEmpty = function() {
+  return this.segments_.length == 0;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/pathelement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/pathelement.js b/externs/GCL/externs/goog/graphics/pathelement.js
new file mode 100644
index 0000000..b58b8c6
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/pathelement.js
@@ -0,0 +1,54 @@
+// 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 A thin wrapper around the DOM element for paths.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.PathElement');
+
+goog.require('goog.graphics.StrokeAndFillElement');
+
+
+
+/**
+ * Interface for a graphics path element.
+ * You should not construct objects from this constructor. The graphics
+ * will return an implementation of this interface for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.AbstractGraphics} graphics The graphics creating
+ *     this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.StrokeAndFillElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.PathElement = function(element, graphics, stroke, fill) {
+  goog.graphics.StrokeAndFillElement.call(this, element, graphics, stroke,
+      fill);
+};
+goog.inherits(goog.graphics.PathElement, goog.graphics.StrokeAndFillElement);
+
+
+/**
+ * Update the underlying path.
+ * @param {!goog.graphics.Path} path The path object to draw.
+ */
+goog.graphics.PathElement.prototype.setPath = goog.abstractMethod;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/paths.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/paths.js b/externs/GCL/externs/goog/graphics/paths.js
new file mode 100644
index 0000000..37b53d9
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/paths.js
@@ -0,0 +1,86 @@
+// Copyright 2010 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 Factories for common path types.
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+
+goog.provide('goog.graphics.paths');
+
+goog.require('goog.graphics.Path');
+goog.require('goog.math.Coordinate');
+
+
+/**
+ * Defines a regular n-gon by specifing the center, a vertex, and the total
+ * number of vertices.
+ * @param {goog.math.Coordinate} center The center point.
+ * @param {goog.math.Coordinate} vertex The vertex, which implicitly defines
+ *     a radius as well.
+ * @param {number} n The number of vertices.
+ * @return {!goog.graphics.Path} The path.
+ */
+goog.graphics.paths.createRegularNGon = function(center, vertex, n) {
+  var path = new goog.graphics.Path();
+  path.moveTo(vertex.x, vertex.y);
+
+  var startAngle = Math.atan2(vertex.y - center.y, vertex.x - center.x);
+  var radius = goog.math.Coordinate.distance(center, vertex);
+  for (var i = 1; i < n; i++) {
+    var angle = startAngle + 2 * Math.PI * (i / n);
+    path.lineTo(center.x + radius * Math.cos(angle),
+                center.y + radius * Math.sin(angle));
+  }
+  path.close();
+  return path;
+};
+
+
+/**
+ * Defines an arrow.
+ * @param {goog.math.Coordinate} a Point A.
+ * @param {goog.math.Coordinate} b Point B.
+ * @param {?number} aHead The size of the arrow head at point A.
+ *     0 omits the head.
+ * @param {?number} bHead The size of the arrow head at point B.
+ *     0 omits the head.
+ * @return {!goog.graphics.Path} The path.
+ */
+goog.graphics.paths.createArrow = function(a, b, aHead, bHead) {
+  var path = new goog.graphics.Path();
+  path.moveTo(a.x, a.y);
+  path.lineTo(b.x, b.y);
+
+  var angle = Math.atan2(b.y - a.y, b.x - a.x);
+  if (aHead) {
+    path.appendPath(
+        goog.graphics.paths.createRegularNGon(
+            new goog.math.Coordinate(
+                a.x + aHead * Math.cos(angle),
+                a.y + aHead * Math.sin(angle)),
+            a, 3));
+  }
+  if (bHead) {
+    path.appendPath(
+        goog.graphics.paths.createRegularNGon(
+            new goog.math.Coordinate(
+                b.x + bHead * Math.cos(angle + Math.PI),
+                b.y + bHead * Math.sin(angle + Math.PI)),
+            b, 3));
+  }
+  return path;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/rectelement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/rectelement.js b/externs/GCL/externs/goog/graphics/rectelement.js
new file mode 100644
index 0000000..9a6e9a1
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/rectelement.js
@@ -0,0 +1,63 @@
+// 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 A thin wrapper around the DOM element for rectangles.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.RectElement');
+
+goog.require('goog.graphics.StrokeAndFillElement');
+
+
+
+/**
+ * Interface for a graphics rectangle element.
+ * You should not construct objects from this constructor. The graphics
+ * will return an implementation of this interface for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.AbstractGraphics} graphics The graphics creating
+ *     this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.StrokeAndFillElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.RectElement = function(element, graphics, stroke, fill) {
+  goog.graphics.StrokeAndFillElement.call(this, element, graphics, stroke,
+      fill);
+};
+goog.inherits(goog.graphics.RectElement, goog.graphics.StrokeAndFillElement);
+
+
+/**
+ * Update the position of the rectangle.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ */
+goog.graphics.RectElement.prototype.setPosition = goog.abstractMethod;
+
+
+/**
+ * Update the size of the rectangle.
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ */
+goog.graphics.RectElement.prototype.setSize = goog.abstractMethod;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/solidfill.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/solidfill.js b/externs/GCL/externs/goog/graphics/solidfill.js
new file mode 100644
index 0000000..fae3fc4
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/solidfill.js
@@ -0,0 +1,74 @@
+// 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 Represents a solid color fill goog.graphics.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.SolidFill');
+
+
+goog.require('goog.graphics.Fill');
+
+
+
+/**
+ * Creates an immutable solid color fill object.
+ *
+ * @param {string} color The color of the background.
+ * @param {number=} opt_opacity The opacity of the background fill. The value
+ *    must be greater than or equal to zero (transparent) and less than or
+ *    equal to 1 (opaque).
+ * @constructor
+ * @extends {goog.graphics.Fill}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.SolidFill = function(color, opt_opacity) {
+  /**
+   * The color with which to fill.
+   * @type {string}
+   * @private
+   */
+  this.color_ = color;
+
+
+  /**
+   * The opacity of the fill.
+   * @type {number}
+   * @private
+   */
+  this.opacity_ = opt_opacity == null ? 1.0 : opt_opacity;
+};
+goog.inherits(goog.graphics.SolidFill, goog.graphics.Fill);
+
+
+/**
+ * @return {string} The color of this fill.
+ */
+goog.graphics.SolidFill.prototype.getColor = function() {
+  return this.color_;
+};
+
+
+/**
+ * @return {number} The opacity of this fill.
+ */
+goog.graphics.SolidFill.prototype.getOpacity = function() {
+  return this.opacity_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/stroke.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/stroke.js b/externs/GCL/externs/goog/graphics/stroke.js
new file mode 100644
index 0000000..ae1eb8e
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/stroke.js
@@ -0,0 +1,86 @@
+// 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 Represents a stroke object for goog.graphics.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.Stroke');
+
+
+
+/**
+ * Creates an immutable stroke object.
+ *
+ * @param {number|string} width The width of the stroke.
+ * @param {string} color The color of the stroke.
+ * @param {number=} opt_opacity The opacity of the background fill. The value
+ *    must be greater than or equal to zero (transparent) and less than or
+ *    equal to 1 (opaque).
+ * @constructor
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.Stroke = function(width, color, opt_opacity) {
+  /**
+   * The width of the stroke.
+   * @type {number|string}
+   * @private
+   */
+  this.width_ = width;
+
+
+  /**
+   * The color with which to fill.
+   * @type {string}
+   * @private
+   */
+  this.color_ = color;
+
+
+  /**
+   * The opacity of the fill.
+   * @type {number}
+   * @private
+   */
+  this.opacity_ = opt_opacity == null ? 1.0 : opt_opacity;
+};
+
+
+/**
+ * @return {number|string} The width of this stroke.
+ */
+goog.graphics.Stroke.prototype.getWidth = function() {
+  return this.width_;
+};
+
+
+/**
+ * @return {string} The color of this stroke.
+ */
+goog.graphics.Stroke.prototype.getColor = function() {
+  return this.color_;
+};
+
+
+/**
+ * @return {number} The opacity of this fill.
+ */
+goog.graphics.Stroke.prototype.getOpacity = function() {
+  return this.opacity_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/strokeandfillelement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/strokeandfillelement.js b/externs/GCL/externs/goog/graphics/strokeandfillelement.js
new file mode 100644
index 0000000..e3b50f9
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/strokeandfillelement.js
@@ -0,0 +1,114 @@
+// 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 A thin wrapper around the DOM element for elements with a
+ * stroke and fill.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.StrokeAndFillElement');
+
+goog.require('goog.graphics.Element');
+
+
+
+/**
+ * Interface for a graphics element with a stroke and fill.
+ * This is the base interface for ellipse, rectangle and other
+ * shape interfaces.
+ * You should not construct objects from this constructor. The graphics
+ * will return an implementation of this interface for you.
+ *
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.AbstractGraphics} graphics The graphics creating
+ *     this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.Element}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.StrokeAndFillElement = function(element, graphics, stroke, fill) {
+  goog.graphics.Element.call(this, element, graphics);
+  this.setStroke(stroke);
+  this.setFill(fill);
+};
+goog.inherits(goog.graphics.StrokeAndFillElement, goog.graphics.Element);
+
+
+/**
+ * The latest fill applied to this element.
+ * @type {goog.graphics.Fill?}
+ * @protected
+ */
+goog.graphics.StrokeAndFillElement.prototype.fill = null;
+
+
+/**
+ * The latest stroke applied to this element.
+ * @type {goog.graphics.Stroke?}
+ * @private
+ */
+goog.graphics.StrokeAndFillElement.prototype.stroke_ = null;
+
+
+/**
+ * Sets the fill for this element.
+ * @param {goog.graphics.Fill?} fill The fill object.
+ */
+goog.graphics.StrokeAndFillElement.prototype.setFill = function(fill) {
+  this.fill = fill;
+  this.getGraphics().setElementFill(this, fill);
+};
+
+
+/**
+ * @return {goog.graphics.Fill?} fill The fill object.
+ */
+goog.graphics.StrokeAndFillElement.prototype.getFill = function() {
+  return this.fill;
+};
+
+
+/**
+ * Sets the stroke for this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke object.
+ */
+goog.graphics.StrokeAndFillElement.prototype.setStroke = function(stroke) {
+  this.stroke_ = stroke;
+  this.getGraphics().setElementStroke(this, stroke);
+};
+
+
+/**
+ * @return {goog.graphics.Stroke?} stroke The stroke object.
+ */
+goog.graphics.StrokeAndFillElement.prototype.getStroke = function() {
+  return this.stroke_;
+};
+
+
+/**
+ * Re-strokes the element to react to coordinate size changes.
+ */
+goog.graphics.StrokeAndFillElement.prototype.reapplyStroke = function() {
+  if (this.stroke_) {
+    this.setStroke(this.stroke_);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/svgelement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/svgelement.js b/externs/GCL/externs/goog/graphics/svgelement.js
new file mode 100644
index 0000000..eddcbb5
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/svgelement.js
@@ -0,0 +1,284 @@
+// 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 Thin wrappers around the DOM element returned from
+ * the different draw methods of the graphics. This is the SVG implementation.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+goog.provide('goog.graphics.SvgEllipseElement');
+goog.provide('goog.graphics.SvgGroupElement');
+goog.provide('goog.graphics.SvgImageElement');
+goog.provide('goog.graphics.SvgPathElement');
+goog.provide('goog.graphics.SvgRectElement');
+goog.provide('goog.graphics.SvgTextElement');
+
+
+goog.require('goog.dom');
+goog.require('goog.graphics.EllipseElement');
+goog.require('goog.graphics.GroupElement');
+goog.require('goog.graphics.ImageElement');
+goog.require('goog.graphics.PathElement');
+goog.require('goog.graphics.RectElement');
+goog.require('goog.graphics.TextElement');
+
+
+
+/**
+ * Thin wrapper for SVG group elements.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.SvgGraphics} graphics The graphics creating
+ *     this element.
+ * @constructor
+ * @extends {goog.graphics.GroupElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.SvgGroupElement = function(element, graphics) {
+  goog.graphics.GroupElement.call(this, element, graphics);
+};
+goog.inherits(goog.graphics.SvgGroupElement, goog.graphics.GroupElement);
+
+
+/**
+ * Remove all drawing elements from the group.
+ * @override
+ */
+goog.graphics.SvgGroupElement.prototype.clear = function() {
+  goog.dom.removeChildren(this.getElement());
+};
+
+
+/**
+ * Set the size of the group element.
+ * @param {number|string} width The width of the group element.
+ * @param {number|string} height The height of the group element.
+ * @override
+ */
+goog.graphics.SvgGroupElement.prototype.setSize = function(width, height) {
+  this.getGraphics().setElementAttributes(this.getElement(),
+      {'width': width, 'height': height});
+};
+
+
+
+/**
+ * Thin wrapper for SVG ellipse elements.
+ * This is an implementation of the goog.graphics.EllipseElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.SvgGraphics} graphics The graphics creating
+ *     this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.EllipseElement}
+ * @final
+ */
+goog.graphics.SvgEllipseElement = function(element, graphics, stroke, fill) {
+  goog.graphics.EllipseElement.call(this, element, graphics, stroke, fill);
+};
+goog.inherits(goog.graphics.SvgEllipseElement, goog.graphics.EllipseElement);
+
+
+/**
+ * Update the center point of the ellipse.
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @override
+ */
+goog.graphics.SvgEllipseElement.prototype.setCenter = function(cx, cy) {
+  this.getGraphics().setElementAttributes(this.getElement(),
+      {'cx': cx, 'cy': cy});
+};
+
+
+/**
+ * Update the radius of the ellipse.
+ * @param {number} rx Radius length for the x-axis.
+ * @param {number} ry Radius length for the y-axis.
+ * @override
+ */
+goog.graphics.SvgEllipseElement.prototype.setRadius = function(rx, ry) {
+  this.getGraphics().setElementAttributes(this.getElement(),
+      {'rx': rx, 'ry': ry});
+};
+
+
+
+/**
+ * Thin wrapper for SVG rectangle elements.
+ * This is an implementation of the goog.graphics.RectElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.SvgGraphics} graphics The graphics creating
+ *     this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.RectElement}
+ * @final
+ */
+goog.graphics.SvgRectElement = function(element, graphics, stroke, fill) {
+  goog.graphics.RectElement.call(this, element, graphics, stroke, fill);
+};
+goog.inherits(goog.graphics.SvgRectElement, goog.graphics.RectElement);
+
+
+/**
+ * Update the position of the rectangle.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @override
+ */
+goog.graphics.SvgRectElement.prototype.setPosition = function(x, y) {
+  this.getGraphics().setElementAttributes(this.getElement(), {'x': x, 'y': y});
+};
+
+
+/**
+ * Update the size of the rectangle.
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @override
+ */
+goog.graphics.SvgRectElement.prototype.setSize = function(width, height) {
+  this.getGraphics().setElementAttributes(this.getElement(),
+      {'width': width, 'height': height});
+};
+
+
+
+/**
+ * Thin wrapper for SVG path elements.
+ * This is an implementation of the goog.graphics.PathElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.SvgGraphics} graphics The graphics creating
+ *     this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.PathElement}
+ * @final
+ */
+goog.graphics.SvgPathElement = function(element, graphics, stroke, fill) {
+  goog.graphics.PathElement.call(this, element, graphics, stroke, fill);
+};
+goog.inherits(goog.graphics.SvgPathElement, goog.graphics.PathElement);
+
+
+/**
+ * Update the underlying path.
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @override
+ */
+goog.graphics.SvgPathElement.prototype.setPath = function(path) {
+  this.getGraphics().setElementAttributes(this.getElement(),
+      {'d': /** @suppress {missingRequire} */
+            goog.graphics.SvgGraphics.getSvgPath(path)});
+};
+
+
+
+/**
+ * Thin wrapper for SVG text elements.
+ * This is an implementation of the goog.graphics.TextElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.SvgGraphics} graphics The graphics creating
+ *     this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.TextElement}
+ * @final
+ */
+goog.graphics.SvgTextElement = function(element, graphics, stroke, fill) {
+  goog.graphics.TextElement.call(this, element, graphics, stroke, fill);
+};
+goog.inherits(goog.graphics.SvgTextElement, goog.graphics.TextElement);
+
+
+/**
+ * Update the displayed text of the element.
+ * @param {string} text The text to draw.
+ * @override
+ */
+goog.graphics.SvgTextElement.prototype.setText = function(text) {
+  this.getElement().firstChild.data = text;
+};
+
+
+
+/**
+ * Thin wrapper for SVG image elements.
+ * This is an implementation of the goog.graphics.ImageElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.SvgGraphics} graphics The graphics creating
+ *     this element.
+ * @constructor
+ * @extends {goog.graphics.ImageElement}
+ * @final
+ */
+goog.graphics.SvgImageElement = function(element, graphics) {
+  goog.graphics.ImageElement.call(this, element, graphics);
+};
+goog.inherits(goog.graphics.SvgImageElement, goog.graphics.ImageElement);
+
+
+/**
+ * Update the position of the image.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @override
+ */
+goog.graphics.SvgImageElement.prototype.setPosition = function(x, y) {
+  this.getGraphics().setElementAttributes(this.getElement(), {'x': x, 'y': y});
+};
+
+
+/**
+ * Update the size of the image.
+ * @param {number} width Width of image.
+ * @param {number} height Height of image.
+ * @override
+ */
+goog.graphics.SvgImageElement.prototype.setSize = function(width, height) {
+  this.getGraphics().setElementAttributes(this.getElement(),
+      {'width': width, 'height': height});
+};
+
+
+/**
+ * Update the source of the image.
+ * @param {string} src Source of the image.
+ * @override
+ */
+goog.graphics.SvgImageElement.prototype.setSource = function(src) {
+  this.getGraphics().setElementAttributes(this.getElement(),
+      {'xlink:href': src});
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/svggraphics.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/svggraphics.js b/externs/GCL/externs/goog/graphics/svggraphics.js
new file mode 100644
index 0000000..59db4a2
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/svggraphics.js
@@ -0,0 +1,878 @@
+// 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 SvgGraphics sub class that uses SVG to draw the graphics.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+goog.provide('goog.graphics.SvgGraphics');
+
+goog.require('goog.Timer');
+goog.require('goog.dom');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventType');
+goog.require('goog.graphics.AbstractGraphics');
+goog.require('goog.graphics.LinearGradient');
+goog.require('goog.graphics.Path');
+goog.require('goog.graphics.SolidFill');
+goog.require('goog.graphics.Stroke');
+goog.require('goog.graphics.SvgEllipseElement');
+goog.require('goog.graphics.SvgGroupElement');
+goog.require('goog.graphics.SvgImageElement');
+goog.require('goog.graphics.SvgPathElement');
+goog.require('goog.graphics.SvgRectElement');
+goog.require('goog.graphics.SvgTextElement');
+goog.require('goog.math');
+goog.require('goog.math.Size');
+goog.require('goog.style');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * A Graphics implementation for drawing using SVG.
+ * @param {string|number} width The width in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {string|number} height The height in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {?number=} opt_coordWidth The coordinate width - if
+ *     omitted or null, defaults to same as width.
+ * @param {?number=} opt_coordHeight The coordinate height - if
+ *     omitted or null, defaults to same as height.
+ * @param {goog.dom.DomHelper=} opt_domHelper The DOM helper object for the
+ *     document we want to render in.
+ * @constructor
+ * @extends {goog.graphics.AbstractGraphics}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.SvgGraphics = function(width, height,
+                                     opt_coordWidth, opt_coordHeight,
+                                     opt_domHelper) {
+  goog.graphics.AbstractGraphics.call(this, width, height,
+                                      opt_coordWidth, opt_coordHeight,
+                                      opt_domHelper);
+
+  /**
+   * Map from def key to id of def root element.
+   * Defs are global "defines" of svg that are used to share common attributes,
+   * for example gradients.
+   * @type {Object}
+   * @private
+   */
+  this.defs_ = {};
+
+  /**
+   * Whether to manually implement viewBox by using a coordinate transform.
+   * As of 1/11/08 this is necessary for Safari 3 but not for the nightly
+   * WebKit build. Apply to webkit versions < 526. 525 is the
+   * last version used by Safari 3.1.
+   * @type {boolean}
+   * @private
+   */
+  this.useManualViewbox_ = goog.userAgent.WEBKIT &&
+                           !goog.userAgent.isVersionOrHigher(526);
+
+  /**
+   * Event handler.
+   * @type {goog.events.EventHandler<!goog.graphics.SvgGraphics>}
+   * @private
+   */
+  this.handler_ = new goog.events.EventHandler(this);
+};
+goog.inherits(goog.graphics.SvgGraphics, goog.graphics.AbstractGraphics);
+
+
+/**
+ * The SVG namespace URN
+ * @private
+ * @type {string}
+ */
+goog.graphics.SvgGraphics.SVG_NS_ = 'http://www.w3.org/2000/svg';
+
+
+/**
+ * The name prefix for def entries
+ * @private
+ * @type {string}
+ */
+goog.graphics.SvgGraphics.DEF_ID_PREFIX_ = '_svgdef_';
+
+
+/**
+ * The next available unique identifier for a def entry.
+ * This is a static variable, so that when multiple graphics are used in one
+ * document, the same def id can not be re-defined by another SvgGraphics.
+ * @type {number}
+ * @private
+ */
+goog.graphics.SvgGraphics.nextDefId_ = 0;
+
+
+/**
+ * Svg element for definitions for other elements, e.g. linear gradients.
+ * @type {Element}
+ * @private
+ */
+goog.graphics.SvgGraphics.prototype.defsElement_;
+
+
+/**
+ * Creates an SVG element. Used internally and by different SVG classes.
+ * @param {string} tagName The type of element to create.
+ * @param {Object=} opt_attributes Map of name-value pairs for attributes.
+ * @return {!Element} The created element.
+ * @private
+ */
+goog.graphics.SvgGraphics.prototype.createSvgElement_ = function(tagName,
+    opt_attributes) {
+  var element = this.dom_.getDocument().createElementNS(
+      goog.graphics.SvgGraphics.SVG_NS_, tagName);
+
+  if (opt_attributes) {
+    this.setElementAttributes(element, opt_attributes);
+  }
+
+  return element;
+};
+
+
+/**
+ * Sets properties to an SVG element. Used internally and by different
+ * SVG elements.
+ * @param {Element} element The svg element.
+ * @param {Object} attributes Map of name-value pairs for attributes.
+ */
+goog.graphics.SvgGraphics.prototype.setElementAttributes = function(element,
+    attributes) {
+  for (var key in attributes) {
+    element.setAttribute(key, attributes[key]);
+  }
+};
+
+
+/**
+ * Appends an element.
+ *
+ * @param {goog.graphics.Element} element The element wrapper.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ * @private
+ */
+goog.graphics.SvgGraphics.prototype.append_ = function(element, opt_group) {
+  var parent = opt_group || this.canvasElement;
+  parent.getElement().appendChild(element.getElement());
+};
+
+
+/**
+ * Sets the fill of the given element.
+ * @param {goog.graphics.StrokeAndFillElement} element The element wrapper.
+ * @param {goog.graphics.Fill?} fill The fill object.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.setElementFill = function(element, fill) {
+  var svgElement = element.getElement();
+  if (fill instanceof goog.graphics.SolidFill) {
+    svgElement.setAttribute('fill', fill.getColor());
+    svgElement.setAttribute('fill-opacity', fill.getOpacity());
+  } else if (fill instanceof goog.graphics.LinearGradient) {
+    // create a def key which is just a concat of all the relevant fields
+    var defKey = 'lg-' +
+                 fill.getX1() + '-' + fill.getY1() + '-' +
+                 fill.getX2() + '-' + fill.getY2() + '-' +
+                 fill.getColor1() + '-' + fill.getColor2();
+    // It seems that the SVG version accepts opacity where the VML does not
+
+    var id = this.getDef(defKey);
+
+    if (!id) { // No def for this yet, create it
+      // Create the gradient def entry (only linear gradient are supported)
+      var gradient = this.createSvgElement_('linearGradient', {
+        'x1': fill.getX1(),
+        'y1': fill.getY1(),
+        'x2': fill.getX2(),
+        'y2': fill.getY2(),
+        'gradientUnits': 'userSpaceOnUse'
+      });
+
+      var gstyle = 'stop-color:' + fill.getColor1();
+      if (goog.isNumber(fill.getOpacity1())) {
+        gstyle += ';stop-opacity:' + fill.getOpacity1();
+      }
+      var stop1 = this.createSvgElement_(
+          'stop', {'offset': '0%', 'style': gstyle});
+      gradient.appendChild(stop1);
+
+      // LinearGradients don't have opacity in VML so implement that before
+      // enabling the following code.
+      // if (fill.getOpacity() != null) {
+      //   gstyles += 'opacity:' + fill.getOpacity() + ';'
+      // }
+      gstyle = 'stop-color:' + fill.getColor2();
+      if (goog.isNumber(fill.getOpacity2())) {
+        gstyle += ';stop-opacity:' + fill.getOpacity2();
+      }
+      var stop2 = this.createSvgElement_(
+          'stop', {'offset': '100%', 'style': gstyle});
+      gradient.appendChild(stop2);
+
+      // LinearGradients don't have opacity in VML so implement that before
+      // enabling the following code.
+      // if (fill.getOpacity() != null) {
+      //   gstyles += 'opacity:' + fill.getOpacity() + ';'
+      // }
+
+      id = this.addDef(defKey, gradient);
+    }
+
+    // Link element to linearGradient definition
+    svgElement.setAttribute('fill', 'url(#' + id + ')');
+  } else {
+    svgElement.setAttribute('fill', 'none');
+  }
+};
+
+
+/**
+ * Sets the stroke of the given element.
+ * @param {goog.graphics.StrokeAndFillElement} element The element wrapper.
+ * @param {goog.graphics.Stroke?} stroke The stroke object.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.setElementStroke = function(element,
+    stroke) {
+  var svgElement = element.getElement();
+  if (stroke) {
+    svgElement.setAttribute('stroke', stroke.getColor());
+    svgElement.setAttribute('stroke-opacity', stroke.getOpacity());
+
+    var width = stroke.getWidth();
+    if (goog.isString(width) && width.indexOf('px') != -1) {
+      svgElement.setAttribute('stroke-width',
+          parseFloat(width) / this.getPixelScaleX());
+    } else {
+      svgElement.setAttribute('stroke-width', width);
+    }
+  } else {
+    svgElement.setAttribute('stroke', 'none');
+  }
+};
+
+
+/**
+ * Set the translation and rotation of an element.
+ *
+ * If a more general affine transform is needed than this provides
+ * (e.g. skew and scale) then use setElementAffineTransform.
+ * @param {goog.graphics.Element} element The element wrapper.
+ * @param {number} x The x coordinate of the translation transform.
+ * @param {number} y The y coordinate of the translation transform.
+ * @param {number} angle The angle of the rotation transform.
+ * @param {number} centerX The horizontal center of the rotation transform.
+ * @param {number} centerY The vertical center of the rotation transform.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.setElementTransform = function(element, x,
+    y, angle, centerX, centerY) {
+  element.getElement().setAttribute('transform', 'translate(' + x + ',' + y +
+      ') rotate(' + angle + ' ' + centerX + ' ' + centerY + ')');
+};
+
+
+/**
+ * Set the transformation of an element.
+ * @param {goog.graphics.Element} element The element wrapper.
+ * @param {!goog.graphics.AffineTransform} affineTransform The
+ *     transformation applied to this element.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.setElementAffineTransform = function(
+    element, affineTransform) {
+  var t = affineTransform;
+  var substr = [t.getScaleX(), t.getShearY(), t.getShearX(), t.getScaleY(),
+                t.getTranslateX(), t.getTranslateY()].join(',');
+  element.getElement().setAttribute('transform', 'matrix(' + substr + ')');
+};
+
+
+/**
+ * Creates the DOM representation of the graphics area.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.createDom = function() {
+  // Set up the standard attributes.
+  var attributes = {
+    'width': this.width,
+    'height': this.height,
+    'overflow': 'hidden'
+  };
+
+  var svgElement = this.createSvgElement_('svg', attributes);
+
+  var groupElement = this.createSvgElement_('g');
+
+  this.defsElement_ = this.createSvgElement_('defs');
+  this.canvasElement = new goog.graphics.SvgGroupElement(groupElement, this);
+
+  svgElement.appendChild(this.defsElement_);
+  svgElement.appendChild(groupElement);
+
+  // Use the svgElement as the root element.
+  this.setElementInternal(svgElement);
+
+  // Set up the coordinate system.
+  this.setViewBox_();
+};
+
+
+/**
+ * Changes the coordinate system position.
+ * @param {number} left The coordinate system left bound.
+ * @param {number} top The coordinate system top bound.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.setCoordOrigin = function(left, top) {
+  this.coordLeft = left;
+  this.coordTop = top;
+
+  this.setViewBox_();
+};
+
+
+/**
+ * Changes the coordinate size.
+ * @param {number} coordWidth The coordinate width.
+ * @param {number} coordHeight The coordinate height.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.setCoordSize = function(coordWidth,
+    coordHeight) {
+  goog.graphics.SvgGraphics.superClass_.setCoordSize.apply(
+      this, arguments);
+  this.setViewBox_();
+};
+
+
+/**
+ * @return {string} The view box string.
+ * @private
+ */
+goog.graphics.SvgGraphics.prototype.getViewBox_ = function() {
+  return this.coordLeft + ' ' + this.coordTop + ' ' +
+      (this.coordWidth ? this.coordWidth + ' ' + this.coordHeight : '');
+};
+
+
+/**
+ * Sets up the view box.
+ * @private
+ */
+goog.graphics.SvgGraphics.prototype.setViewBox_ = function() {
+  if (this.coordWidth || this.coordLeft || this.coordTop) {
+    this.getElement().setAttribute('preserveAspectRatio', 'none');
+    if (this.useManualViewbox_) {
+      this.updateManualViewBox_();
+    } else {
+      this.getElement().setAttribute('viewBox', this.getViewBox_());
+    }
+  }
+};
+
+
+/**
+ * Updates the transform of the root element to fake a viewBox.  Should only
+ * be called when useManualViewbox_ is set.
+ * @private
+ */
+goog.graphics.SvgGraphics.prototype.updateManualViewBox_ = function() {
+  if (!this.isInDocument() ||
+      !(this.coordWidth || this.coordLeft || !this.coordTop)) {
+    return;
+  }
+
+  var size = this.getPixelSize();
+  if (size.width == 0) {
+    // In Safari, invisible SVG is sometimes shown.  Explicitly hide it.
+    this.getElement().style.visibility = 'hidden';
+    return;
+  }
+
+  this.getElement().style.visibility = '';
+
+  var offsetX = - this.coordLeft;
+  var offsetY = - this.coordTop;
+  var scaleX = size.width / this.coordWidth;
+  var scaleY = size.height / this.coordHeight;
+
+  this.canvasElement.getElement().setAttribute('transform',
+      'scale(' + scaleX + ' ' + scaleY + ') ' +
+      'translate(' + offsetX + ' ' + offsetY + ')');
+};
+
+
+/**
+ * Change the size of the canvas.
+ * @param {number} pixelWidth The width in pixels.
+ * @param {number} pixelHeight The height in pixels.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.setSize = function(pixelWidth,
+    pixelHeight) {
+  goog.style.setSize(this.getElement(), pixelWidth, pixelHeight);
+};
+
+
+/** @override */
+goog.graphics.SvgGraphics.prototype.getPixelSize = function() {
+  if (!goog.userAgent.GECKO) {
+    return this.isInDocument() ?
+        goog.style.getSize(this.getElement()) :
+        goog.graphics.SvgGraphics.base(this, 'getPixelSize');
+  }
+
+  // In Gecko, goog.style.getSize does not work for SVG elements.  We have to
+  // compute the size manually if it is percentage based.
+  var width = this.width;
+  var height = this.height;
+  var computeWidth = goog.isString(width) && width.indexOf('%') != -1;
+  var computeHeight = goog.isString(height) && height.indexOf('%') != -1;
+
+  if (!this.isInDocument() && (computeWidth || computeHeight)) {
+    return null;
+  }
+
+  var parent;
+  var parentSize;
+
+  if (computeWidth) {
+    parent = /** @type {Element} */ (this.getElement().parentNode);
+    parentSize = goog.style.getSize(parent);
+    width = parseFloat(/** @type {string} */ (width)) * parentSize.width / 100;
+  }
+
+  if (computeHeight) {
+    parent = parent || /** @type {Element} */ (this.getElement().parentNode);
+    parentSize = parentSize || goog.style.getSize(parent);
+    height = parseFloat(/** @type {string} */ (height)) * parentSize.height /
+        100;
+  }
+
+  return new goog.math.Size(/** @type {number} */ (width),
+      /** @type {number} */ (height));
+};
+
+
+/**
+ * Remove all drawing elements from the graphics.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.clear = function() {
+  this.canvasElement.clear();
+  goog.dom.removeChildren(this.defsElement_);
+  this.defs_ = {};
+};
+
+
+/**
+ * Draw an ellipse.
+ *
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @param {number} rx Radius length for the x-axis.
+ * @param {number} ry Radius length for the y-axis.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.EllipseElement} The newly created element.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.drawEllipse = function(
+    cx, cy, rx, ry, stroke, fill, opt_group) {
+  var element = this.createSvgElement_('ellipse',
+      {'cx': cx, 'cy': cy, 'rx': rx, 'ry': ry});
+  var wrapper = new goog.graphics.SvgEllipseElement(element, this, stroke,
+      fill);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * Draw a rectangle.
+ *
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.RectElement} The newly created element.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.drawRect = function(x, y, width, height,
+    stroke, fill, opt_group) {
+  var element = this.createSvgElement_('rect',
+      {'x': x, 'y': y, 'width': width, 'height': height});
+  var wrapper = new goog.graphics.SvgRectElement(element, this, stroke, fill);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * Draw an image.
+ *
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} width Width of the image.
+ * @param {number} height Height of the image.
+ * @param {string} src The source fo the image.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.ImageElement} The newly created image wrapped in a
+ *     rectangle element.
+ */
+goog.graphics.SvgGraphics.prototype.drawImage = function(x, y, width, height,
+    src, opt_group) {
+  var element = this.createSvgElement_('image', {
+    'x': x,
+    'y': y,
+    'width': width,
+    'height': height,
+    'image-rendering': 'optimizeQuality',
+    'preserveAspectRatio': 'none'
+  });
+  element.setAttributeNS('http://www.w3.org/1999/xlink', 'href', src);
+  var wrapper = new goog.graphics.SvgImageElement(element, this);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * Draw a text string vertically centered on a given line.
+ *
+ * @param {string} text The text to draw.
+ * @param {number} x1 X coordinate of start of line.
+ * @param {number} y1 Y coordinate of start of line.
+ * @param {number} x2 X coordinate of end of line.
+ * @param {number} y2 Y coordinate of end of line.
+ * @param {string} align Horizontal alignment: left (default), center, right.
+ * @param {goog.graphics.Font} font Font describing the font properties.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.TextElement} The newly created element.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.drawTextOnLine = function(
+    text, x1, y1, x2, y2, align, font, stroke, fill, opt_group) {
+  var angle = Math.round(goog.math.angle(x1, y1, x2, y2));
+  var dx = x2 - x1;
+  var dy = y2 - y1;
+  var lineLength = Math.round(Math.sqrt(dx * dx + dy * dy)); // Length of line
+
+  // SVG baseline is on the glyph's base line. We estimate it as 85% of the
+  // font height. This is just a rough estimate, but do not have a better way.
+  var fontSize = font.size;
+  var attributes = {'font-family': font.family, 'font-size': fontSize};
+  var baseline = Math.round(fontSize * 0.85);
+  var textY = Math.round(y1 - (fontSize / 2) + baseline);
+  var textX = x1;
+  if (align == 'center') {
+    textX += Math.round(lineLength / 2);
+    attributes['text-anchor'] = 'middle';
+  } else if (align == 'right') {
+    textX += lineLength;
+    attributes['text-anchor'] = 'end';
+  }
+  attributes['x'] = textX;
+  attributes['y'] = textY;
+  if (font.bold) {
+    attributes['font-weight'] = 'bold';
+  }
+  if (font.italic) {
+    attributes['font-style'] = 'italic';
+  }
+  if (angle != 0) {
+    attributes['transform'] = 'rotate(' + angle + ' ' + x1 + ' ' + y1 + ')';
+  }
+
+  var element = this.createSvgElement_('text', attributes);
+  element.appendChild(this.dom_.getDocument().createTextNode(text));
+
+  // Bypass a Firefox-Mac bug where text fill is ignored. If text has no stroke,
+  // set a stroke, otherwise the text will not be visible.
+  if (stroke == null && goog.userAgent.GECKO && goog.userAgent.MAC) {
+    var color = 'black';
+    // For solid fills, use the fill color
+    if (fill instanceof goog.graphics.SolidFill) {
+      color = fill.getColor();
+    }
+    stroke = new goog.graphics.Stroke(1, color);
+  }
+
+  var wrapper = new goog.graphics.SvgTextElement(element, this, stroke, fill);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * Draw a path.
+ *
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.PathElement} The newly created element.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.drawPath = function(
+    path, stroke, fill, opt_group) {
+
+  var element = this.createSvgElement_('path',
+      {'d': goog.graphics.SvgGraphics.getSvgPath(path)});
+  var wrapper = new goog.graphics.SvgPathElement(element, this, stroke, fill);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * Returns a string representation of a logical path suitable for use in
+ * an SVG element.
+ *
+ * @param {goog.graphics.Path} path The logical path.
+ * @return {string} The SVG path representation.
+ * @suppress {deprecated} goog.graphics is deprecated.
+ */
+goog.graphics.SvgGraphics.getSvgPath = function(path) {
+  var list = [];
+  path.forEachSegment(function(segment, args) {
+    switch (segment) {
+      case goog.graphics.Path.Segment.MOVETO:
+        list.push('M');
+        Array.prototype.push.apply(list, args);
+        break;
+      case goog.graphics.Path.Segment.LINETO:
+        list.push('L');
+        Array.prototype.push.apply(list, args);
+        break;
+      case goog.graphics.Path.Segment.CURVETO:
+        list.push('C');
+        Array.prototype.push.apply(list, args);
+        break;
+      case goog.graphics.Path.Segment.ARCTO:
+        var extent = args[3];
+        list.push('A', args[0], args[1],
+            0, Math.abs(extent) > 180 ? 1 : 0, extent > 0 ? 1 : 0,
+            args[4], args[5]);
+        break;
+      case goog.graphics.Path.Segment.CLOSE:
+        list.push('Z');
+        break;
+    }
+  });
+  return list.join(' ');
+};
+
+
+/**
+ * Create an empty group of drawing elements.
+ *
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.GroupElement} The newly created group.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.createGroup = function(opt_group) {
+  var element = this.createSvgElement_('g');
+  var parent = opt_group || this.canvasElement;
+  parent.getElement().appendChild(element);
+  return new goog.graphics.SvgGroupElement(element, this);
+};
+
+
+/**
+ * Measure and return the width (in pixels) of a given text string.
+ * Text measurement is needed to make sure a text can fit in the allocated area.
+ * The way text length is measured is by writing it into a div that is after
+ * the visible area, measure the div width, and immediatly erase the written
+ * value.
+ *
+ * @param {string} text The text string to measure.
+ * @param {goog.graphics.Font} font The font object describing the font style.
+ * @override
+ */
+goog.graphics.SvgGraphics.prototype.getTextWidth = function(text, font) {
+  // TODO(user) Implement
+};
+
+
+/**
+ * Adds a defintion of an element to the global definitions.
+ * @param {string} defKey This is a key that should be unique in a way that
+ *     if two definitions are equal the should have the same key.
+ * @param {Element} defElement DOM element to add as a definition. It must
+ *     have an id attribute set.
+ * @return {string} The assigned id of the defElement.
+ */
+goog.graphics.SvgGraphics.prototype.addDef = function(defKey, defElement) {
+  if (defKey in this.defs_) {
+    return this.defs_[defKey];
+  }
+  var id = goog.graphics.SvgGraphics.DEF_ID_PREFIX_ +
+      goog.graphics.SvgGraphics.nextDefId_++;
+  defElement.setAttribute('id', id);
+  this.defs_[defKey] = id;
+
+  // Add the def defElement of the defs list.
+  var defs = this.defsElement_;
+  defs.appendChild(defElement);
+  return id;
+};
+
+
+/**
+ * Returns the id of a definition element.
+ * @param {string} defKey This is a key that should be unique in a way that
+ *     if two definitions are equal the should have the same key.
+ * @return {?string} The id of the found definition element or null if
+ *     not found.
+ */
+goog.graphics.SvgGraphics.prototype.getDef = function(defKey) {
+  return defKey in this.defs_ ? this.defs_[defKey] : null;
+};
+
+
+/**
+ * Removes a definition of an elemnt from the global definitions.
+ * @param {string} defKey This is a key that should be unique in a way that
+ *     if two definitions are equal they should have the same key.
+ */
+goog.graphics.SvgGraphics.prototype.removeDef = function(defKey) {
+  var id = this.getDef(defKey);
+  if (id) {
+    var element = this.dom_.getElement(id);
+    this.defsElement_.removeChild(element);
+    delete this.defs_[defKey];
+  }
+};
+
+
+/** @override */
+goog.graphics.SvgGraphics.prototype.enterDocument = function() {
+  var oldPixelSize = this.getPixelSize();
+  goog.graphics.SvgGraphics.superClass_.enterDocument.call(this);
+
+  // Dispatch a resize if this is the first time the size value is accurate.
+  if (!oldPixelSize) {
+    this.dispatchEvent(goog.events.EventType.RESIZE);
+  }
+
+
+  // For percentage based heights, listen for changes to size.
+  if (this.useManualViewbox_) {
+    var width = this.width;
+    var height = this.height;
+
+    if (typeof width == 'string' && width.indexOf('%') != -1 &&
+        typeof height == 'string' && height.indexOf('%') != -1) {
+      // SVG elements don't behave well with respect to size events, so we
+      // resort to polling.
+      this.handler_.listen(goog.graphics.SvgGraphics.getResizeCheckTimer_(),
+          goog.Timer.TICK, this.updateManualViewBox_);
+    }
+
+    this.updateManualViewBox_();
+  }
+};
+
+
+/** @override */
+goog.graphics.SvgGraphics.prototype.exitDocument = function() {
+  goog.graphics.SvgGraphics.superClass_.exitDocument.call(this);
+
+  // Stop polling.
+  if (this.useManualViewbox_) {
+    this.handler_.unlisten(goog.graphics.SvgGraphics.getResizeCheckTimer_(),
+        goog.Timer.TICK, this.updateManualViewBox_);
+  }
+};
+
+
+/**
+ * Disposes of the component by removing event handlers, detacing DOM nodes from
+ * the document body, and removing references to them.
+ * @override
+ * @protected
+ */
+goog.graphics.SvgGraphics.prototype.disposeInternal = function() {
+  delete this.defs_;
+  delete this.defsElement_;
+  delete this.canvasElement;
+  this.handler_.dispose();
+  delete this.handler_;
+  goog.graphics.SvgGraphics.superClass_.disposeInternal.call(this);
+};
+
+
+/**
+ * The centralized resize checking timer.
+ * @type {goog.Timer|undefined}
+ * @private
+ */
+goog.graphics.SvgGraphics.resizeCheckTimer_;
+
+
+/**
+ * @return {goog.Timer} The centralized timer object used for interval timing.
+ * @private
+ */
+goog.graphics.SvgGraphics.getResizeCheckTimer_ = function() {
+  if (!goog.graphics.SvgGraphics.resizeCheckTimer_) {
+    goog.graphics.SvgGraphics.resizeCheckTimer_ = new goog.Timer(400);
+    goog.graphics.SvgGraphics.resizeCheckTimer_.start();
+  }
+
+  return /** @type {goog.Timer} */ (
+      goog.graphics.SvgGraphics.resizeCheckTimer_);
+};
+
+
+/** @override */
+goog.graphics.SvgGraphics.prototype.isDomClonable = function() {
+  return true;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/textelement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/textelement.js b/externs/GCL/externs/goog/graphics/textelement.js
new file mode 100644
index 0000000..c96ae6d
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/textelement.js
@@ -0,0 +1,55 @@
+// 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 A thin wrapper around the DOM element for text elements.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.TextElement');
+
+goog.require('goog.graphics.StrokeAndFillElement');
+
+
+
+/**
+ * Interface for a graphics text element.
+ * You should not construct objects from this constructor. The graphics
+ * will return an implementation of this interface for you.
+ *
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.AbstractGraphics} graphics The graphics creating
+ *     this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.StrokeAndFillElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.TextElement = function(element, graphics, stroke, fill) {
+  goog.graphics.StrokeAndFillElement.call(this, element, graphics, stroke,
+      fill);
+};
+goog.inherits(goog.graphics.TextElement, goog.graphics.StrokeAndFillElement);
+
+
+/**
+ * Update the displayed text of the element.
+ * @param {string} text The text to draw.
+ */
+goog.graphics.TextElement.prototype.setText = goog.abstractMethod;


[21/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/tagonenterhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/tagonenterhandler.js b/externs/GCL/externs/goog/editor/plugins/tagonenterhandler.js
new file mode 100644
index 0000000..e5776fd
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/tagonenterhandler.js
@@ -0,0 +1,744 @@
+// Copyright 2008 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 TrogEdit plugin to handle enter keys by inserting the
+ * specified block level tag.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.editor.plugins.TagOnEnterHandler');
+
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.Range');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.Command');
+goog.require('goog.editor.node');
+goog.require('goog.editor.plugins.EnterHandler');
+goog.require('goog.editor.range');
+goog.require('goog.editor.style');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.functions');
+goog.require('goog.string.Unicode');
+goog.require('goog.style');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Plugin to handle enter keys. This subclass normalizes all browsers to use
+ * the given block tag on enter.
+ * @param {goog.dom.TagName} tag The type of tag to add on enter.
+ * @constructor
+ * @extends {goog.editor.plugins.EnterHandler}
+ */
+goog.editor.plugins.TagOnEnterHandler = function(tag) {
+  this.tag = tag;
+
+  goog.editor.plugins.EnterHandler.call(this);
+};
+goog.inherits(goog.editor.plugins.TagOnEnterHandler,
+    goog.editor.plugins.EnterHandler);
+
+
+/** @override */
+goog.editor.plugins.TagOnEnterHandler.prototype.getTrogClassId = function() {
+  return 'TagOnEnterHandler';
+};
+
+
+/** @override */
+goog.editor.plugins.TagOnEnterHandler.prototype.getNonCollapsingBlankHtml =
+    function() {
+  if (this.tag == goog.dom.TagName.P) {
+    return '<p>&nbsp;</p>';
+  } else if (this.tag == goog.dom.TagName.DIV) {
+    return '<div><br></div>';
+  }
+  return '<br>';
+};
+
+
+/**
+ * This plugin is active on uneditable fields so it can provide a value for
+ * queryCommandValue calls asking for goog.editor.Command.BLOCKQUOTE.
+ * @return {boolean} True.
+ * @override
+ */
+goog.editor.plugins.TagOnEnterHandler.prototype.activeOnUneditableFields =
+    goog.functions.TRUE;
+
+
+/** @override */
+goog.editor.plugins.TagOnEnterHandler.prototype.isSupportedCommand = function(
+    command) {
+  return command == goog.editor.Command.DEFAULT_TAG;
+};
+
+
+/** @override */
+goog.editor.plugins.TagOnEnterHandler.prototype.queryCommandValue = function(
+    command) {
+  return command == goog.editor.Command.DEFAULT_TAG ? this.tag : null;
+};
+
+
+/** @override */
+goog.editor.plugins.TagOnEnterHandler.prototype.handleBackspaceInternal =
+    function(e, range) {
+  goog.editor.plugins.TagOnEnterHandler.superClass_.handleBackspaceInternal.
+      call(this, e, range);
+
+  if (goog.userAgent.GECKO) {
+    this.markBrToNotBeRemoved_(range, true);
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.TagOnEnterHandler.prototype.processParagraphTagsInternal =
+    function(e, split) {
+  if ((goog.userAgent.OPERA || goog.userAgent.IE) &&
+      this.tag != goog.dom.TagName.P) {
+    this.ensureBlockIeOpera(this.tag);
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.TagOnEnterHandler.prototype.handleDeleteGecko = function(
+    e) {
+  var range = this.getFieldObject().getRange();
+  var container = goog.editor.style.getContainer(
+      range && range.getContainerElement());
+  if (this.getFieldObject().getElement().lastChild == container &&
+      goog.editor.plugins.EnterHandler.isBrElem(container)) {
+    // Don't delete if it's the last node in the field and just has a BR.
+    e.preventDefault();
+    // TODO(user): I think we probably don't need to stopPropagation here
+    e.stopPropagation();
+  } else {
+    // Go ahead with deletion.
+    // Prevent an existing BR immediately following the selection being deleted
+    // from being removed in the keyup stage (as opposed to a BR added by FF
+    // after deletion, which we do remove).
+    this.markBrToNotBeRemoved_(range, false);
+    // Manually delete the selection if it's at a BR.
+    this.deleteBrGecko(e);
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.TagOnEnterHandler.prototype.handleKeyUpInternal = function(
+    e) {
+  if (goog.userAgent.GECKO) {
+    if (e.keyCode == goog.events.KeyCodes.DELETE) {
+      this.removeBrIfNecessary_(false);
+    } else if (e.keyCode == goog.events.KeyCodes.BACKSPACE) {
+      this.removeBrIfNecessary_(true);
+    }
+  } else if ((goog.userAgent.IE || goog.userAgent.OPERA) &&
+             e.keyCode == goog.events.KeyCodes.ENTER) {
+    this.ensureBlockIeOpera(this.tag, true);
+  }
+  // Safari uses DIVs by default.
+};
+
+
+/**
+ * String that matches a single BR tag or NBSP surrounded by non-breaking
+ * whitespace
+ * @type {string}
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.BrOrNbspSurroundedWithWhiteSpace_ =
+    '[\t\n\r ]*(<br[^>]*\/?>|&nbsp;)[\t\n\r ]*';
+
+
+/**
+ * String that matches a single BR tag or NBSP surrounded by non-breaking
+ * whitespace
+ * @type {RegExp}
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.emptyLiRegExp_ = new RegExp('^' +
+    goog.editor.plugins.TagOnEnterHandler.BrOrNbspSurroundedWithWhiteSpace_ +
+    '$');
+
+
+/**
+ * Ensures the current node is wrapped in the tag.
+ * @param {Node} node The node to ensure gets wrapped.
+ * @param {Element} container Element containing the selection.
+ * @return {Element} Element containing the selection, after the wrapping.
+  * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.prototype.ensureNodeIsWrappedW3c_ =
+    function(node, container) {
+  if (container == this.getFieldObject().getElement()) {
+    // If the first block-level ancestor of cursor is the field,
+    // don't split the tree. Find all the text from the cursor
+    // to both block-level elements surrounding it (if they exist)
+    // and split the text into two elements.
+    // This is the IE contentEditable behavior.
+
+    // The easy way to do this is to wrap all the text in an element
+    // and then split the element as if the user had hit enter
+    // in the paragraph
+
+    // However, simply wrapping the text into an element creates problems
+    // if the text was already wrapped using some other element such as an
+    // anchor.  For example, wrapping the text of
+    //   <a href="">Text</a>
+    // would produce
+    //   <a href=""><p>Text</p></a>
+    // which is not what we want.  What we really want is
+    //   <p><a href="">Text</a></p>
+    // So we need to search for an ancestor of position.node to be wrapped.
+    // We do this by iterating up the hierarchy of postiion.node until we've
+    // reached the node that's just under the container.
+    var isChildOfFn = function(child) {
+      return container == child.parentNode; };
+    var nodeToWrap = goog.dom.getAncestor(node, isChildOfFn, true);
+    container = goog.editor.plugins.TagOnEnterHandler.wrapInContainerW3c_(
+        this.tag, {node: nodeToWrap, offset: 0}, container);
+  }
+  return container;
+};
+
+
+/** @override */
+goog.editor.plugins.TagOnEnterHandler.prototype.handleEnterWebkitInternal =
+    function(e) {
+  if (this.tag == goog.dom.TagName.DIV) {
+    var range = this.getFieldObject().getRange();
+    var container =
+        goog.editor.style.getContainer(range.getContainerElement());
+
+    var position = goog.editor.range.getDeepEndPoint(range, true);
+    container = this.ensureNodeIsWrappedW3c_(position.node, container);
+    goog.dom.Range.createCaret(position.node, position.offset).select();
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.TagOnEnterHandler.prototype.
+    handleEnterAtCursorGeckoInternal = function(e, wasCollapsed, range) {
+  // We use this because there are a few cases where FF default
+  // implementation doesn't follow IE's:
+  //   -Inserts BRs into empty elements instead of NBSP which has nasty
+  //    side effects w/ making/deleting selections
+  //   -Hitting enter when your cursor is in the field itself. IE will
+  //    create two elements. FF just inserts a BR.
+  //   -Hitting enter inside an empty list-item doesn't create a block
+  //    tag. It just splits the list and puts your cursor in the middle.
+  var li = null;
+  if (wasCollapsed) {
+    // Only break out of lists for collapsed selections.
+    li = goog.dom.getAncestorByTagNameAndClass(
+        range && range.getContainerElement(), goog.dom.TagName.LI);
+  }
+  var isEmptyLi = (li &&
+      li.innerHTML.match(
+          goog.editor.plugins.TagOnEnterHandler.emptyLiRegExp_));
+  var elementAfterCursor = isEmptyLi ?
+      this.breakOutOfEmptyListItemGecko_(li) :
+      this.handleRegularEnterGecko_();
+
+  // Move the cursor in front of "nodeAfterCursor", and make sure it
+  // is visible
+  this.scrollCursorIntoViewGecko_(elementAfterCursor);
+
+  // Fix for http://b/1991234 :
+  if (goog.editor.plugins.EnterHandler.isBrElem(elementAfterCursor)) {
+    // The first element in the new line is a line with just a BR and maybe some
+    // whitespace.
+    // Calling normalize() is needed because there might be empty text nodes
+    // before BR and empty text nodes cause the cursor position bug in Firefox.
+    // See http://b/5220858
+    elementAfterCursor.normalize();
+    var br = elementAfterCursor.getElementsByTagName(goog.dom.TagName.BR)[0];
+    if (br.previousSibling &&
+        br.previousSibling.nodeType == goog.dom.NodeType.TEXT) {
+      // If there is some whitespace before the BR, don't put the selection on
+      // the BR, put it in the text node that's there, otherwise when you type
+      // it will create adjacent text nodes.
+      elementAfterCursor = br.previousSibling;
+    }
+  }
+
+  goog.editor.range.selectNodeStart(elementAfterCursor);
+
+  e.preventDefault();
+  // TODO(user): I think we probably don't need to stopPropagation here
+  e.stopPropagation();
+};
+
+
+/**
+ * If The cursor is in an empty LI then break out of the list like in IE
+ * @param {Node} li LI to break out of.
+ * @return {!Element} Element to put the cursor after.
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.prototype.breakOutOfEmptyListItemGecko_ =
+    function(li) {
+  // Do this as follows:
+  // 1. <ul>...<li>&nbsp;</li>...</ul>
+  // 2. <ul id='foo1'>...<li id='foo2'>&nbsp;</li>...</ul>
+  // 3. <ul id='foo1'>...</ul><p id='foo3'>&nbsp;</p><ul id='foo2'>...</ul>
+  // 4. <ul>...</ul><p>&nbsp;</p><ul>...</ul>
+  //
+  // There are a couple caveats to the above. If the UL is contained in
+  // a list, then the new node inserted is an LI, not a P.
+  // For an OL, it's all the same, except the tagname of course.
+  // Finally, it's possible that with the LI at the beginning or the end
+  // of the list that we'll end up with an empty list. So we special case
+  // those cases.
+
+  var listNode = li.parentNode;
+  var grandparent = listNode.parentNode;
+  var inSubList = grandparent.tagName == goog.dom.TagName.OL ||
+      grandparent.tagName == goog.dom.TagName.UL;
+
+  // TODO(robbyw): Should we apply the list or list item styles to the new node?
+  var newNode = goog.dom.getDomHelper(li).createElement(
+      inSubList ? goog.dom.TagName.LI : this.tag);
+
+  if (!li.previousSibling) {
+    goog.dom.insertSiblingBefore(newNode, listNode);
+  } else {
+    if (li.nextSibling) {
+      var listClone = listNode.cloneNode(false);
+      while (li.nextSibling) {
+        listClone.appendChild(li.nextSibling);
+      }
+      goog.dom.insertSiblingAfter(listClone, listNode);
+    }
+    goog.dom.insertSiblingAfter(newNode, listNode);
+  }
+  if (goog.editor.node.isEmpty(listNode)) {
+    goog.dom.removeNode(listNode);
+  }
+  goog.dom.removeNode(li);
+  newNode.innerHTML = '&nbsp;';
+
+  return newNode;
+};
+
+
+/**
+ * Wrap the text indicated by "position" in an HTML container of type
+ * "nodeName".
+ * @param {string} nodeName Type of container, e.g. "p" (paragraph).
+ * @param {Object} position The W3C cursor position object
+ *     (from getCursorPositionW3c).
+ * @param {Node} container The field containing position.
+ * @return {!Element} The container element that holds the contents from
+ *     position.
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.wrapInContainerW3c_ = function(nodeName,
+    position, container) {
+  var start = position.node;
+  while (start.previousSibling &&
+         !goog.editor.style.isContainer(start.previousSibling)) {
+    start = start.previousSibling;
+  }
+
+  var end = position.node;
+  while (end.nextSibling &&
+         !goog.editor.style.isContainer(end.nextSibling)) {
+    end = end.nextSibling;
+  }
+
+  var para = container.ownerDocument.createElement(nodeName);
+  while (start != end) {
+    var newStart = start.nextSibling;
+    goog.dom.appendChild(para, start);
+    start = newStart;
+  }
+  var nextSibling = end.nextSibling;
+  goog.dom.appendChild(para, end);
+  container.insertBefore(para, nextSibling);
+
+  return para;
+};
+
+
+/**
+ * When we delete an element, FF inserts a BR. We want to strip that
+ * BR after the fact, but in the case where your cursor is at a character
+ * right before a BR and you delete that character, we don't want to
+ * strip it. So we detect this case on keydown and mark the BR as not needing
+ * removal.
+ * @param {goog.dom.AbstractRange} range The closure range object.
+ * @param {boolean} isBackspace Whether this is handling the backspace key.
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.prototype.markBrToNotBeRemoved_ =
+    function(range, isBackspace) {
+  var focusNode = range.getFocusNode();
+  var focusOffset = range.getFocusOffset();
+  var newEndOffset = isBackspace ? focusOffset : focusOffset + 1;
+
+  if (goog.editor.node.getLength(focusNode) == newEndOffset) {
+    var sibling = focusNode.nextSibling;
+    if (sibling && sibling.tagName == goog.dom.TagName.BR) {
+      this.brToKeep_ = sibling;
+    }
+  }
+};
+
+
+/**
+ * If we hit delete/backspace to merge elements, FF inserts a BR.
+ * We want to strip that BR. In markBrToNotBeRemoved, we detect if
+ * there was already a BR there before the delete/backspace so that
+ * we don't accidentally remove a user-inserted BR.
+ * @param {boolean} isBackSpace Whether this is handling the backspace key.
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.prototype.removeBrIfNecessary_ = function(
+    isBackSpace) {
+  var range = this.getFieldObject().getRange();
+  var focusNode = range.getFocusNode();
+  var focusOffset = range.getFocusOffset();
+
+  var sibling;
+  if (isBackSpace && focusNode.data == '') {
+    // nasty hack. sometimes firefox will backspace a paragraph and put
+    // the cursor before the BR. when it does this, the focusNode is
+    // an empty textnode.
+    sibling = focusNode.nextSibling;
+  } else if (isBackSpace && focusOffset == 0) {
+    var node = focusNode;
+    while (node && !node.previousSibling &&
+           node.parentNode != this.getFieldObject().getElement()) {
+      node = node.parentNode;
+    }
+    sibling = node.previousSibling;
+  } else if (focusNode.length == focusOffset) {
+    sibling = focusNode.nextSibling;
+  }
+
+  if (!sibling || sibling.tagName != goog.dom.TagName.BR ||
+      this.brToKeep_ == sibling) {
+    return;
+  }
+
+  goog.dom.removeNode(sibling);
+  if (focusNode.nodeType == goog.dom.NodeType.TEXT) {
+    // Sometimes firefox inserts extra whitespace. Do our best to deal.
+    // This is buggy though.
+    focusNode.data =
+        goog.editor.plugins.TagOnEnterHandler.trimTabsAndLineBreaks_(
+            focusNode.data);
+    // When we strip whitespace, make sure that our cursor is still at
+    // the end of the textnode.
+    goog.dom.Range.createCaret(focusNode,
+        Math.min(focusOffset, focusNode.length)).select();
+  }
+};
+
+
+/**
+ * Trim the tabs and line breaks from a string.
+ * @param {string} string String to trim.
+ * @return {string} Trimmed string.
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.trimTabsAndLineBreaks_ = function(
+    string) {
+  return string.replace(/^[\t\n\r]|[\t\n\r]$/g, '');
+};
+
+
+/**
+ * Called in response to a normal enter keystroke. It has the action of
+ * splitting elements.
+ * @return {Element} The node that the cursor should be before.
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.prototype.handleRegularEnterGecko_ =
+    function() {
+  var range = this.getFieldObject().getRange();
+  var container =
+      goog.editor.style.getContainer(range.getContainerElement());
+  var newNode;
+  if (goog.editor.plugins.EnterHandler.isBrElem(container)) {
+    if (container.tagName == goog.dom.TagName.BODY) {
+      // If the field contains only a single BR, this code ensures we don't
+      // try to clone the body tag.
+      container = this.ensureNodeIsWrappedW3c_(
+          container.getElementsByTagName(goog.dom.TagName.BR)[0],
+          container);
+    }
+
+    newNode = container.cloneNode(true);
+    goog.dom.insertSiblingAfter(newNode, container);
+  } else {
+    if (!container.firstChild) {
+      container.innerHTML = '&nbsp;';
+    }
+
+    var position = goog.editor.range.getDeepEndPoint(range, true);
+    container = this.ensureNodeIsWrappedW3c_(position.node, container);
+
+    newNode = goog.editor.plugins.TagOnEnterHandler.splitDomAndAppend_(
+        position.node, position.offset, container);
+
+    // If the left half and right half of the splitted node are anchors then
+    // that means the user pressed enter while the caret was inside
+    // an anchor tag and split it.  The left half is the first anchor
+    // found while traversing the right branch of container.  The right half
+    // is the first anchor found while traversing the left branch of newNode.
+    var leftAnchor =
+        goog.editor.plugins.TagOnEnterHandler.findAnchorInTraversal_(
+            container);
+    var rightAnchor =
+        goog.editor.plugins.TagOnEnterHandler.findAnchorInTraversal_(
+            newNode, true);
+    if (leftAnchor && rightAnchor &&
+        leftAnchor.tagName == goog.dom.TagName.A &&
+        rightAnchor.tagName == goog.dom.TagName.A) {
+      // If the original anchor (left anchor) is now empty, that means
+      // the user pressed [Enter] at the beginning of the anchor,
+      // in which case we we
+      // want to replace that anchor with its child nodes
+      // Otherwise, we take the second half of the splitted text and break
+      // it out of the anchor.
+      var anchorToRemove = goog.editor.node.isEmpty(leftAnchor, false) ?
+          leftAnchor : rightAnchor;
+      goog.dom.flattenElement(/** @type {!Element} */ (anchorToRemove));
+    }
+  }
+  return /** @type {!Element} */ (newNode);
+};
+
+
+/**
+ * Scroll the cursor into view, resulting from splitting the paragraph/adding
+ * a br. It behaves differently than scrollIntoView
+ * @param {Element} element The element immediately following the cursor. Will
+ *     be used to determine how to scroll in order to make the cursor visible.
+ *     CANNOT be a BR, as they do not have offsetHeight/offsetTop.
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.prototype.scrollCursorIntoViewGecko_ =
+    function(element) {
+  if (!this.getFieldObject().isFixedHeight()) {
+    return; // Only need to scroll fixed height fields.
+  }
+
+  var field = this.getFieldObject().getElement();
+
+  // Get the y position of the element we want to scroll to
+  var elementY = goog.style.getPageOffsetTop(element);
+
+  // Determine the height of that element, since we want the bottom of the
+  // element to be in view.
+  var bottomOfNode = elementY + element.offsetHeight;
+
+  var dom = this.getFieldDomHelper();
+  var win = this.getFieldDomHelper().getWindow();
+  var scrollY = dom.getDocumentScroll().y;
+  var viewportHeight = goog.dom.getViewportSize(win).height;
+
+  // If the botom of the element is outside the viewport, move it into view
+  if (bottomOfNode > viewportHeight + scrollY) {
+    // In standards mode, use the html element and not the body
+    if (field.tagName == goog.dom.TagName.BODY &&
+        goog.editor.node.isStandardsMode(field)) {
+      field = field.parentNode;
+    }
+    field.scrollTop = bottomOfNode - viewportHeight;
+  }
+};
+
+
+/**
+ * Splits the DOM tree around the given node and returns the node
+ * containing the second half of the tree. The first half of the tree
+ * is modified, but not removed from the DOM.
+ * @param {Node} positionNode Node to split at.
+ * @param {number} positionOffset Offset into positionNode to split at.  If
+ *     positionNode is a text node, this offset is an offset in to the text
+ *     content of that node.  Otherwise, positionOffset is an offset in to
+ *     the childNodes array.  All elements with child index of  positionOffset
+ *     or greater will be moved to the second half.  If positionNode is an
+ *     empty element, the dom will be split at that element, with positionNode
+ *     ending up in the second half.  positionOffset must be 0 in this case.
+ * @param {Node=} opt_root Node at which to stop splitting the dom (the root
+ *     is also split).
+ * @return {!Node} The node containing the second half of the tree.
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.splitDom_ = function(
+    positionNode, positionOffset, opt_root) {
+  if (!opt_root) opt_root = positionNode.ownerDocument.body;
+
+  // Split the node.
+  var textSplit = positionNode.nodeType == goog.dom.NodeType.TEXT;
+  var secondHalfOfSplitNode;
+  if (textSplit) {
+    if (goog.userAgent.IE &&
+        positionOffset == positionNode.nodeValue.length) {
+      // Since splitText fails in IE at the end of a node, we split it manually.
+      secondHalfOfSplitNode = goog.dom.getDomHelper(positionNode).
+          createTextNode('');
+      goog.dom.insertSiblingAfter(secondHalfOfSplitNode, positionNode);
+    } else {
+      secondHalfOfSplitNode = positionNode.splitText(positionOffset);
+    }
+  } else {
+    // Here we ensure positionNode is the last node in the first half of the
+    // resulting tree.
+    if (positionOffset) {
+      // Use offset as an index in to childNodes.
+      positionNode = positionNode.childNodes[positionOffset - 1];
+    } else {
+      // In this case, positionNode would be the last node in the first half
+      // of the tree, but we actually want to move it to the second half.
+      // Therefore we set secondHalfOfSplitNode to the same node.
+      positionNode = secondHalfOfSplitNode = positionNode.firstChild ||
+          positionNode;
+    }
+  }
+
+  // Create second half of the tree.
+  var secondHalf = goog.editor.node.splitDomTreeAt(
+      positionNode, secondHalfOfSplitNode, opt_root);
+
+  if (textSplit) {
+    // Join secondHalfOfSplitNode and its right text siblings together and
+    // then replace leading NonNbspWhiteSpace with a Nbsp.  If
+    // secondHalfOfSplitNode has a right sibling that isn't a text node,
+    // then we can leave secondHalfOfSplitNode empty.
+    secondHalfOfSplitNode =
+        goog.editor.plugins.TagOnEnterHandler.joinTextNodes_(
+            secondHalfOfSplitNode, true);
+    goog.editor.plugins.TagOnEnterHandler.replaceWhiteSpaceWithNbsp_(
+        secondHalfOfSplitNode, true, !!secondHalfOfSplitNode.nextSibling);
+
+    // Join positionNode and its left text siblings together and then replace
+    // trailing NonNbspWhiteSpace with a Nbsp.
+    var firstHalf = goog.editor.plugins.TagOnEnterHandler.joinTextNodes_(
+        positionNode, false);
+    goog.editor.plugins.TagOnEnterHandler.replaceWhiteSpaceWithNbsp_(
+        firstHalf, false, false);
+  }
+
+  return secondHalf;
+};
+
+
+/**
+ * Splits the DOM tree around the given node and returns the node containing
+ * second half of the tree, which is appended after the old node.  The first
+ * half of the tree is modified, but not removed from the DOM.
+ * @param {Node} positionNode Node to split at.
+ * @param {number} positionOffset Offset into positionNode to split at.  If
+ *     positionNode is a text node, this offset is an offset in to the text
+ *     content of that node.  Otherwise, positionOffset is an offset in to
+ *     the childNodes array.  All elements with child index of  positionOffset
+ *     or greater will be moved to the second half.  If positionNode is an
+ *     empty element, the dom will be split at that element, with positionNode
+ *     ending up in the second half.  positionOffset must be 0 in this case.
+ * @param {Node} node Node to split.
+ * @return {!Node} The node containing the second half of the tree.
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.splitDomAndAppend_ = function(
+    positionNode, positionOffset, node) {
+  var newNode = goog.editor.plugins.TagOnEnterHandler.splitDom_(
+      positionNode, positionOffset, node);
+  goog.dom.insertSiblingAfter(newNode, node);
+  return newNode;
+};
+
+
+/**
+ * Joins node and its adjacent text nodes together.
+ * @param {Node} node The node to start joining.
+ * @param {boolean} moveForward Determines whether to join left siblings (false)
+ *     or right siblings (true).
+ * @return {Node} The joined text node.
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.joinTextNodes_ = function(node,
+    moveForward) {
+  if (node && node.nodeName == '#text') {
+    var nextNodeFn = moveForward ? 'nextSibling' : 'previousSibling';
+    var prevNodeFn = moveForward ? 'previousSibling' : 'nextSibling';
+    var nodeValues = [node.nodeValue];
+    while (node[nextNodeFn] &&
+           node[nextNodeFn].nodeType == goog.dom.NodeType.TEXT) {
+      node = node[nextNodeFn];
+      nodeValues.push(node.nodeValue);
+      goog.dom.removeNode(node[prevNodeFn]);
+    }
+    if (!moveForward) {
+      nodeValues.reverse();
+    }
+    node.nodeValue = nodeValues.join('');
+  }
+  return node;
+};
+
+
+/**
+ * Replaces leading or trailing spaces of a text node to a single Nbsp.
+ * @param {Node} textNode The text node to search and replace white spaces.
+ * @param {boolean} fromStart Set to true to replace leading spaces, false to
+ *     replace trailing spaces.
+ * @param {boolean} isLeaveEmpty Set to true to leave the node empty if the
+ *     text node was empty in the first place, otherwise put a Nbsp into the
+ *     text node.
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.replaceWhiteSpaceWithNbsp_ = function(
+    textNode, fromStart, isLeaveEmpty) {
+  var regExp = fromStart ? /^[ \t\r\n]+/ : /[ \t\r\n]+$/;
+  textNode.nodeValue = textNode.nodeValue.replace(regExp,
+                                                  goog.string.Unicode.NBSP);
+
+  if (!isLeaveEmpty && textNode.nodeValue == '') {
+    textNode.nodeValue = goog.string.Unicode.NBSP;
+  }
+};
+
+
+/**
+ * Finds the first A element in a traversal from the input node.  The input
+ * node itself is not included in the search.
+ * @param {Node} node The node to start searching from.
+ * @param {boolean=} opt_useFirstChild Whether to traverse along the first child
+ *     (true) or last child (false).
+ * @return {Node} The first anchor node found in the search, or null if none
+ *     was found.
+ * @private
+ */
+goog.editor.plugins.TagOnEnterHandler.findAnchorInTraversal_ = function(node,
+    opt_useFirstChild) {
+  while ((node = opt_useFirstChild ? node.firstChild : node.lastChild) &&
+         node.tagName != goog.dom.TagName.A) {
+    // Do nothing - advancement is handled in the condition.
+  }
+  return node;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/undoredo.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/undoredo.js b/externs/GCL/externs/goog/editor/plugins/undoredo.js
new file mode 100644
index 0000000..d273a4c
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/undoredo.js
@@ -0,0 +1,1016 @@
+// Copyright 2005 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 Code for handling edit history (undo/redo).
+ *
+ */
+
+
+goog.provide('goog.editor.plugins.UndoRedo');
+
+goog.require('goog.dom');
+goog.require('goog.dom.NodeOffset');
+goog.require('goog.dom.Range');
+goog.require('goog.editor.BrowserFeature');
+goog.require('goog.editor.Command');
+goog.require('goog.editor.Field');
+goog.require('goog.editor.Plugin');
+goog.require('goog.editor.node');
+goog.require('goog.editor.plugins.UndoRedoManager');
+goog.require('goog.editor.plugins.UndoRedoState');
+goog.require('goog.events');
+goog.require('goog.events.EventHandler');
+goog.require('goog.log');
+goog.require('goog.object');
+
+
+
+/**
+ * Encapsulates undo/redo logic using a custom undo stack (i.e. not browser
+ * built-in). Browser built-in undo stacks are too flaky (e.g. IE's gets
+ * clobbered on DOM modifications). Also, this allows interleaving non-editing
+ * commands into the undo stack via the UndoRedoManager.
+ *
+ * @param {goog.editor.plugins.UndoRedoManager=} opt_manager An undo redo
+ *    manager to be used by this plugin. If none is provided one is created.
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ */
+goog.editor.plugins.UndoRedo = function(opt_manager) {
+  goog.editor.Plugin.call(this);
+
+  this.setUndoRedoManager(opt_manager ||
+      new goog.editor.plugins.UndoRedoManager());
+
+  // Map of goog.editor.Field hashcode to goog.events.EventHandler
+  this.eventHandlers_ = {};
+
+  this.currentStates_ = {};
+
+  /**
+   * @type {?string}
+   * @private
+   */
+  this.initialFieldChange_ = null;
+
+  /**
+   * A copy of {@code goog.editor.plugins.UndoRedo.restoreState} bound to this,
+   * used by undo-redo state objects to restore the state of an editable field.
+   * @type {Function}
+   * @see goog.editor.plugins.UndoRedo#restoreState
+   * @private
+   */
+  this.boundRestoreState_ = goog.bind(this.restoreState, this);
+};
+goog.inherits(goog.editor.plugins.UndoRedo, goog.editor.Plugin);
+
+
+/**
+ * The logger for this class.
+ * @type {goog.log.Logger}
+ * @protected
+ * @override
+ */
+goog.editor.plugins.UndoRedo.prototype.logger =
+    goog.log.getLogger('goog.editor.plugins.UndoRedo');
+
+
+/**
+ * The {@code UndoState_} whose change is in progress, null if an undo or redo
+ * is not in progress.
+ *
+ * @type {goog.editor.plugins.UndoRedo.UndoState_?}
+ * @private
+ */
+goog.editor.plugins.UndoRedo.prototype.inProgressUndo_ = null;
+
+
+/**
+ * The undo-redo stack manager used by this plugin.
+ * @type {goog.editor.plugins.UndoRedoManager}
+ * @private
+ */
+goog.editor.plugins.UndoRedo.prototype.undoManager_;
+
+
+/**
+ * The key for the event listener handling state change events from the
+ * undo-redo manager.
+ * @type {goog.events.Key}
+ * @private
+ */
+goog.editor.plugins.UndoRedo.prototype.managerStateChangeKey_;
+
+
+/**
+ * Commands implemented by this plugin.
+ * @enum {string}
+ */
+goog.editor.plugins.UndoRedo.COMMAND = {
+  UNDO: '+undo',
+  REDO: '+redo'
+};
+
+
+/**
+ * Inverse map of execCommand strings to
+ * {@link goog.editor.plugins.UndoRedo.COMMAND} constants. Used to determine
+ * whether a string corresponds to a command this plugin handles in O(1) time.
+ * @type {Object}
+ * @private
+ */
+goog.editor.plugins.UndoRedo.SUPPORTED_COMMANDS_ =
+    goog.object.transpose(goog.editor.plugins.UndoRedo.COMMAND);
+
+
+/**
+ * Set the max undo stack depth (not the real memory usage).
+ * @param {number} depth Depth of the stack.
+ */
+goog.editor.plugins.UndoRedo.prototype.setMaxUndoDepth = function(depth) {
+  this.undoManager_.setMaxUndoDepth(depth);
+};
+
+
+/**
+ * Set the undo-redo manager used by this plugin. Any state on a previous
+ * undo-redo manager is lost.
+ * @param {goog.editor.plugins.UndoRedoManager} manager The undo-redo manager.
+ */
+goog.editor.plugins.UndoRedo.prototype.setUndoRedoManager = function(manager) {
+  if (this.managerStateChangeKey_) {
+    goog.events.unlistenByKey(this.managerStateChangeKey_);
+  }
+
+  this.undoManager_ = manager;
+  this.managerStateChangeKey_ =
+      goog.events.listen(this.undoManager_,
+          goog.editor.plugins.UndoRedoManager.EventType.STATE_CHANGE,
+          this.dispatchCommandValueChange_,
+          false,
+          this);
+};
+
+
+/**
+ * Whether the string corresponds to a command this plugin handles.
+ * @param {string} command Command string to check.
+ * @return {boolean} Whether the string corresponds to a command
+ *     this plugin handles.
+ * @override
+ */
+goog.editor.plugins.UndoRedo.prototype.isSupportedCommand = function(command) {
+  return command in goog.editor.plugins.UndoRedo.SUPPORTED_COMMANDS_;
+};
+
+
+/**
+ * Unregisters and disables the fieldObject with this plugin. Thie does *not*
+ * clobber the undo stack for the fieldObject though.
+ * TODO(user): For the multifield version, we really should add a way to
+ * ignore undo actions on field's that have been made uneditable.
+ * This is probably as simple as skipping over entries in the undo stack
+ * that have a hashcode of an uneditable field.
+ * @param {goog.editor.Field} fieldObject The field to register with the plugin.
+ * @override
+ */
+goog.editor.plugins.UndoRedo.prototype.unregisterFieldObject = function(
+    fieldObject) {
+  this.disable(fieldObject);
+  this.setFieldObject(null);
+};
+
+
+/**
+ * This is so subclasses can deal with multifield undo-redo.
+ * @return {goog.editor.Field} The active field object for this field. This is
+ *     the one registered field object for the single-plugin case and the
+ *     focused field for the multi-field plugin case.
+ */
+goog.editor.plugins.UndoRedo.prototype.getCurrentFieldObject = function() {
+  return this.getFieldObject();
+};
+
+
+/**
+ * This is so subclasses can deal with multifield undo-redo.
+ * @param {string} fieldHashCode The Field's hashcode.
+ * @return {goog.editor.Field} The field object with the hashcode.
+ */
+goog.editor.plugins.UndoRedo.prototype.getFieldObjectForHash = function(
+    fieldHashCode) {
+  // With single field undoredo, there's only one Field involved.
+  return this.getFieldObject();
+};
+
+
+/**
+ * This is so subclasses can deal with multifield undo-redo.
+ * @return {goog.editor.Field} Target for COMMAND_VALUE_CHANGE events.
+ */
+goog.editor.plugins.UndoRedo.prototype.getCurrentEventTarget = function() {
+  return this.getFieldObject();
+};
+
+
+/** @override */
+goog.editor.plugins.UndoRedo.prototype.enable = function(fieldObject) {
+  if (this.isEnabled(fieldObject)) {
+    return;
+  }
+
+  // Don't want pending delayed changes from when undo-redo was disabled
+  // firing after undo-redo is enabled since they might cause undo-redo stack
+  // updates.
+  fieldObject.clearDelayedChange();
+
+  var eventHandler = new goog.events.EventHandler(this);
+
+  // TODO(user): From ojan during a code review:
+  // The beforechange handler is meant to be there so you can grab the cursor
+  // position *before* the change is made as that's where you want the cursor to
+  // be after an undo.
+  //
+  // It kinda looks like updateCurrentState_ doesn't do that correctly right
+  // now, but it really should be fixed to do so. The cursor position stored in
+  // the state should be the cursor position before any changes are made, not
+  // the cursor position when the change finishes.
+  //
+  // It also seems like the if check below is just a bad one. We should do this
+  // for browsers that use mutation events as well even though the beforechange
+  // happens too late...maybe not. I don't know about this.
+  if (!goog.editor.BrowserFeature.USE_MUTATION_EVENTS) {
+    // We don't listen to beforechange in mutation-event browsers because
+    // there we fire beforechange, then syncronously file change. The point
+    // of before change is to capture before the user has changed anything.
+    eventHandler.listen(fieldObject,
+        goog.editor.Field.EventType.BEFORECHANGE, this.handleBeforeChange_);
+  }
+  eventHandler.listen(fieldObject,
+      goog.editor.Field.EventType.DELAYEDCHANGE, this.handleDelayedChange_);
+  eventHandler.listen(fieldObject, goog.editor.Field.EventType.BLUR,
+      this.handleBlur_);
+
+  this.eventHandlers_[fieldObject.getHashCode()] = eventHandler;
+
+  // We want to capture the initial state of a Trogedit field before any
+  // editing has happened. This is necessary so that we can undo the first
+  // change to a field, even if we don't handle beforeChange.
+  this.updateCurrentState_(fieldObject);
+};
+
+
+/** @override */
+goog.editor.plugins.UndoRedo.prototype.disable = function(fieldObject) {
+  // Process any pending changes so we don't lose any undo-redo states that we
+  // want prior to disabling undo-redo.
+  fieldObject.clearDelayedChange();
+
+  var eventHandler = this.eventHandlers_[fieldObject.getHashCode()];
+  if (eventHandler) {
+    eventHandler.dispose();
+    delete this.eventHandlers_[fieldObject.getHashCode()];
+  }
+
+  // We delete the current state of the field on disable. When we re-enable
+  // the state will be re-fetched. In most cases the content will be the same,
+  // but this allows us to pick up changes while not editable. That way, when
+  // undoing after starting an editable session, you can always undo to the
+  // state you started in. Given this sequence of events:
+  // Make editable
+  // Type 'anakin'
+  // Make not editable
+  // Set HTML to be 'padme'
+  // Make editable
+  // Type 'dark side'
+  // Undo
+  // Without re-snapshoting current state on enable, the undo would go from
+  // 'dark-side' -> 'anakin', rather than 'dark-side' -> 'padme'. You couldn't
+  // undo the field to the state that existed immediately after it was made
+  // editable for the second time.
+  if (this.currentStates_[fieldObject.getHashCode()]) {
+    delete this.currentStates_[fieldObject.getHashCode()];
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.UndoRedo.prototype.isEnabled = function(fieldObject) {
+  // All enabled plugins have a eventHandler so reuse that map rather than
+  // storing additional enabled state.
+  return !!this.eventHandlers_[fieldObject.getHashCode()];
+};
+
+
+/** @override */
+goog.editor.plugins.UndoRedo.prototype.disposeInternal = function() {
+  goog.editor.plugins.UndoRedo.superClass_.disposeInternal.call(this);
+
+  for (var hashcode in this.eventHandlers_) {
+    this.eventHandlers_[hashcode].dispose();
+    delete this.eventHandlers_[hashcode];
+  }
+  this.setFieldObject(null);
+
+  if (this.undoManager_) {
+    this.undoManager_.dispose();
+    delete this.undoManager_;
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.UndoRedo.prototype.getTrogClassId = function() {
+  return 'UndoRedo';
+};
+
+
+/** @override */
+goog.editor.plugins.UndoRedo.prototype.execCommand = function(command,
+    var_args) {
+  if (command == goog.editor.plugins.UndoRedo.COMMAND.UNDO) {
+    this.undoManager_.undo();
+  } else if (command == goog.editor.plugins.UndoRedo.COMMAND.REDO) {
+    this.undoManager_.redo();
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.UndoRedo.prototype.queryCommandValue = function(command) {
+  var state = null;
+  if (command == goog.editor.plugins.UndoRedo.COMMAND.UNDO) {
+    state = this.undoManager_.hasUndoState();
+  } else if (command == goog.editor.plugins.UndoRedo.COMMAND.REDO) {
+    state = this.undoManager_.hasRedoState();
+  }
+  return state;
+};
+
+
+/**
+ * Dispatches the COMMAND_VALUE_CHANGE event on the editable field or the field
+ * manager, as appropriate.
+ * Note: Really, people using multi field mode should be listening directly
+ * to the undo-redo manager for events.
+ * @private
+ */
+goog.editor.plugins.UndoRedo.prototype.dispatchCommandValueChange_ =
+    function() {
+  var eventTarget = this.getCurrentEventTarget();
+  eventTarget.dispatchEvent({
+    type: goog.editor.Field.EventType.COMMAND_VALUE_CHANGE,
+    commands: [goog.editor.plugins.UndoRedo.COMMAND.REDO,
+      goog.editor.plugins.UndoRedo.COMMAND.UNDO]});
+};
+
+
+/**
+ * Restores the state of the editable field.
+ * @param {goog.editor.plugins.UndoRedo.UndoState_} state The state initiating
+ *    the restore.
+ * @param {string} content The content to restore.
+ * @param {goog.editor.plugins.UndoRedo.CursorPosition_?} cursorPosition
+ *     The cursor position within the content.
+ */
+goog.editor.plugins.UndoRedo.prototype.restoreState = function(
+    state, content, cursorPosition) {
+  // Fire any pending changes to get the current field state up to date and
+  // then stop listening to changes while doing the undo/redo.
+  var fieldObj = this.getFieldObjectForHash(state.fieldHashCode);
+  if (!fieldObj) {
+    return;
+  }
+
+  // Fires any pending changes, and stops the change events. Still want to
+  // dispatch before change, as a change is being made and the change event
+  // will be manually dispatched below after the new content has been restored
+  // (also restarting change events).
+  fieldObj.stopChangeEvents(true, true);
+
+  // To prevent the situation where we stop change events and then an exception
+  // happens before we can restart change events, the following code must be in
+  // a try-finally block.
+  try {
+    fieldObj.dispatchBeforeChange();
+
+    // Restore the state
+    fieldObj.execCommand(goog.editor.Command.CLEAR_LOREM, true);
+
+    // We specifically set the raw innerHTML of the field here as that's what
+    // we get from the field when we save an undo/redo state. There's
+    // no need to clean/unclean the contents in either direction.
+    goog.editor.node.replaceInnerHtml(fieldObj.getElement(), content);
+
+    if (cursorPosition) {
+      cursorPosition.select();
+    }
+
+    var previousFieldObject = this.getCurrentFieldObject();
+    fieldObj.focus();
+
+    // Apps that integrate their undo-redo with Trogedit may be
+    // in a state where there is no previous field object (no field focused at
+    // the time of undo), so check for existence first.
+    if (previousFieldObject &&
+        previousFieldObject.getHashCode() != state.fieldHashCode) {
+      previousFieldObject.execCommand(goog.editor.Command.UPDATE_LOREM);
+    }
+
+    // We need to update currentState_ to reflect the change.
+    this.currentStates_[state.fieldHashCode].setUndoState(
+        content, cursorPosition);
+  } catch (e) {
+    goog.log.error(this.logger, 'Error while restoring undo state', e);
+  } finally {
+    // Clear the delayed change event, set flag so we know not to act on it.
+    this.inProgressUndo_ = state;
+    // Notify the editor that we've changed (fire autosave).
+    // Note that this starts up change events again, so we don't have to
+    // manually do so even though we stopped change events above.
+    fieldObj.dispatchChange();
+    fieldObj.dispatchSelectionChangeEvent();
+  }
+};
+
+
+/**
+ * @override
+ */
+goog.editor.plugins.UndoRedo.prototype.handleKeyboardShortcut = function(e, key,
+    isModifierPressed) {
+  if (isModifierPressed) {
+    var command;
+    if (key == 'z') {
+      command = e.shiftKey ? goog.editor.plugins.UndoRedo.COMMAND.REDO :
+          goog.editor.plugins.UndoRedo.COMMAND.UNDO;
+    } else if (key == 'y') {
+      command = goog.editor.plugins.UndoRedo.COMMAND.REDO;
+    }
+
+    if (command) {
+      // In the case where Trogedit shares its undo redo stack with another
+      // application it's possible that an undo or redo will not be for an
+      // goog.editor.Field. In this case we don't want to go through the
+      // goog.editor.Field execCommand flow which stops and restarts events on
+      // the current field. Only Trogedit UndoState's have a fieldHashCode so
+      // use that to distinguish between Trogedit and other states.
+      var state = command == goog.editor.plugins.UndoRedo.COMMAND.UNDO ?
+          this.undoManager_.undoPeek() : this.undoManager_.redoPeek();
+      if (state && state.fieldHashCode) {
+        this.getCurrentFieldObject().execCommand(command);
+      } else {
+        this.execCommand(command);
+      }
+
+      return true;
+    }
+  }
+
+  return false;
+};
+
+
+/**
+ * Clear the undo/redo stack.
+ */
+goog.editor.plugins.UndoRedo.prototype.clearHistory = function() {
+  // Fire all pending change events, so that they don't come back
+  // asynchronously to fill the queue.
+  this.getFieldObject().stopChangeEvents(true, true);
+  this.undoManager_.clearHistory();
+  this.getFieldObject().startChangeEvents();
+};
+
+
+/**
+ * Refreshes the current state of the editable field as maintained by undo-redo,
+ * without adding any undo-redo states to the stack.
+ * @param {goog.editor.Field} fieldObject The editable field.
+ */
+goog.editor.plugins.UndoRedo.prototype.refreshCurrentState = function(
+    fieldObject) {
+  if (this.isEnabled(fieldObject)) {
+    if (this.currentStates_[fieldObject.getHashCode()]) {
+      delete this.currentStates_[fieldObject.getHashCode()];
+    }
+    this.updateCurrentState_(fieldObject);
+  }
+};
+
+
+/**
+ * Before the field changes, we want to save the state.
+ * @param {goog.events.Event} e The event.
+ * @private
+ */
+goog.editor.plugins.UndoRedo.prototype.handleBeforeChange_ = function(e) {
+  if (this.inProgressUndo_) {
+    // We are in between a previous undo and its delayed change event.
+    // Continuing here clobbers the redo stack.
+    // This does mean that if you are trying to undo/redo really quickly, it
+    // will be gated by the speed of delayed change events.
+    return;
+  }
+
+  var fieldObj = /** @type {goog.editor.Field} */ (e.target);
+  var fieldHashCode = fieldObj.getHashCode();
+
+  if (this.initialFieldChange_ != fieldHashCode) {
+    this.initialFieldChange_ = fieldHashCode;
+    this.updateCurrentState_(fieldObj);
+  }
+};
+
+
+/**
+ * After some idle time, we want to save the state.
+ * @param {goog.events.Event} e The event.
+ * @private
+ */
+goog.editor.plugins.UndoRedo.prototype.handleDelayedChange_ = function(e) {
+  // This was undo making a change, don't add it BACK into the history
+  if (this.inProgressUndo_) {
+    // Must clear this.inProgressUndo_ before dispatching event because the
+    // dispatch can cause another, queued undo that should be allowed to go
+    // through.
+    var state = this.inProgressUndo_;
+    this.inProgressUndo_ = null;
+    state.dispatchEvent(goog.editor.plugins.UndoRedoState.ACTION_COMPLETED);
+    return;
+  }
+
+  this.updateCurrentState_(/** @type {goog.editor.Field} */ (e.target));
+};
+
+
+/**
+ * When the user blurs away, we need to save the state on that field.
+ * @param {goog.events.Event} e The event.
+ * @private
+ */
+goog.editor.plugins.UndoRedo.prototype.handleBlur_ = function(e) {
+  var fieldObj = /** @type {goog.editor.Field} */ (e.target);
+  if (fieldObj) {
+    fieldObj.clearDelayedChange();
+  }
+};
+
+
+/**
+ * Returns the goog.editor.plugins.UndoRedo.CursorPosition_ for the current
+ * selection in the given Field.
+ * @param {goog.editor.Field} fieldObj The field object.
+ * @return {goog.editor.plugins.UndoRedo.CursorPosition_} The CursorPosition_ or
+ *    null if there is no valid selection.
+ * @private
+ */
+goog.editor.plugins.UndoRedo.prototype.getCursorPosition_ = function(fieldObj) {
+  var cursorPos = new goog.editor.plugins.UndoRedo.CursorPosition_(fieldObj);
+  if (!cursorPos.isValid()) {
+    return null;
+  }
+  return cursorPos;
+};
+
+
+/**
+ * Helper method for saving state.
+ * @param {goog.editor.Field} fieldObj The field object.
+ * @private
+ */
+goog.editor.plugins.UndoRedo.prototype.updateCurrentState_ = function(
+    fieldObj) {
+  var fieldHashCode = fieldObj.getHashCode();
+  // We specifically grab the raw innerHTML of the field here as that's what
+  // we would set on the field in the case of an undo/redo operation. There's
+  // no need to clean/unclean the contents in either direction. In the case of
+  // lorem ipsum being used, we want to capture the effective state (empty, no
+  // cursor position) rather than capturing the lorem html.
+  var content, cursorPos;
+  if (fieldObj.queryCommandValue(goog.editor.Command.USING_LOREM)) {
+    content = '';
+    cursorPos = null;
+  } else {
+    content = fieldObj.getElement().innerHTML;
+    cursorPos = this.getCursorPosition_(fieldObj);
+  }
+
+  var currentState = this.currentStates_[fieldHashCode];
+  if (currentState) {
+    // Don't create states if the content hasn't changed (spurious
+    // delayed change). This can happen when lorem is cleared, for example.
+    if (currentState.undoContent_ == content) {
+      return;
+    } else if (content == '' || currentState.undoContent_ == '') {
+      // If lorem ipsum is on we say the contents are the empty string. However,
+      // for an empty text shape with focus, the empty contents might not be
+      // the same, depending on plugins. We want these two empty states to be
+      // considered identical because to the user they are indistinguishable,
+      // so we use fieldObj.getInjectableContents to map between them.
+      // We cannot use getInjectableContents when first creating the undo
+      // content for a field with lorem, because on enable when this is first
+      // called we can't guarantee plugin registration order, so the
+      // injectableContents at that time might not match the final
+      // injectableContents.
+      var emptyContents = fieldObj.getInjectableContents('', {});
+      if (content == emptyContents && currentState.undoContent_ == '' ||
+          currentState.undoContent_ == emptyContents && content == '') {
+        return;
+      }
+    }
+
+    currentState.setRedoState(content, cursorPos);
+    this.undoManager_.addState(currentState);
+  }
+
+  this.currentStates_[fieldHashCode] =
+      new goog.editor.plugins.UndoRedo.UndoState_(fieldHashCode, content,
+          cursorPos, this.boundRestoreState_);
+};
+
+
+
+/**
+ * This object encapsulates the state of an editable field.
+ *
+ * @param {string} fieldHashCode String the id of the field we're saving the
+ *     content of.
+ * @param {string} content String the actual text we're saving.
+ * @param {goog.editor.plugins.UndoRedo.CursorPosition_?} cursorPosition
+ *     CursorPosLite object for the cursor position in the field.
+ * @param {Function} restore The function used to restore editable field state.
+ * @private
+ * @constructor
+ * @extends {goog.editor.plugins.UndoRedoState}
+ */
+goog.editor.plugins.UndoRedo.UndoState_ = function(fieldHashCode, content,
+    cursorPosition, restore) {
+  goog.editor.plugins.UndoRedoState.call(this, true);
+
+  /**
+   * The hash code for the field whose content is being saved.
+   * @type {string}
+   */
+  this.fieldHashCode = fieldHashCode;
+
+  /**
+   * The bound copy of {@code goog.editor.plugins.UndoRedo.restoreState} used by
+   * this state.
+   * @type {Function}
+   * @private
+   */
+  this.restore_ = restore;
+
+  this.setUndoState(content, cursorPosition);
+};
+goog.inherits(goog.editor.plugins.UndoRedo.UndoState_,
+    goog.editor.plugins.UndoRedoState);
+
+
+/**
+ * The content to restore on undo.
+ * @type {string}
+ * @private
+ */
+goog.editor.plugins.UndoRedo.UndoState_.prototype.undoContent_;
+
+
+/**
+ * The cursor position to restore on undo.
+ * @type {goog.editor.plugins.UndoRedo.CursorPosition_?}
+ * @private
+ */
+goog.editor.plugins.UndoRedo.UndoState_.prototype.undoCursorPosition_;
+
+
+/**
+ * The content to restore on redo, undefined until the state is pushed onto the
+ * undo stack.
+ * @type {string|undefined}
+ * @private
+ */
+goog.editor.plugins.UndoRedo.UndoState_.prototype.redoContent_;
+
+
+/**
+ * The cursor position to restore on redo, undefined until the state is pushed
+ * onto the undo stack.
+ * @type {goog.editor.plugins.UndoRedo.CursorPosition_|null|undefined}
+ * @private
+ */
+goog.editor.plugins.UndoRedo.UndoState_.prototype.redoCursorPosition_;
+
+
+/**
+ * Performs the undo operation represented by this state.
+ * @override
+ */
+goog.editor.plugins.UndoRedo.UndoState_.prototype.undo = function() {
+  this.restore_(this, this.undoContent_,
+      this.undoCursorPosition_);
+};
+
+
+/**
+ * Performs the redo operation represented by this state.
+ * @override
+ */
+goog.editor.plugins.UndoRedo.UndoState_.prototype.redo = function() {
+  this.restore_(this, this.redoContent_,
+      this.redoCursorPosition_);
+};
+
+
+/**
+ * Updates the undo portion of this state. Should only be used to update the
+ * current state of an editable field, which is not yet on the undo stack after
+ * an undo or redo operation. You should never be modifying states on the stack!
+ * @param {string} content The current content.
+ * @param {goog.editor.plugins.UndoRedo.CursorPosition_?} cursorPosition
+ *     The current cursor position.
+ */
+goog.editor.plugins.UndoRedo.UndoState_.prototype.setUndoState = function(
+    content, cursorPosition) {
+  this.undoContent_ = content;
+  this.undoCursorPosition_ = cursorPosition;
+};
+
+
+/**
+ * Adds redo information to this state. This method should be called before the
+ * state is added onto the undo stack.
+ *
+ * @param {string} content The content to restore on a redo.
+ * @param {goog.editor.plugins.UndoRedo.CursorPosition_?} cursorPosition
+ *     The cursor position to restore on a redo.
+ */
+goog.editor.plugins.UndoRedo.UndoState_.prototype.setRedoState = function(
+    content, cursorPosition) {
+  this.redoContent_ = content;
+  this.redoCursorPosition_ = cursorPosition;
+};
+
+
+/**
+ * Checks if the *contents* of two
+ * {@code goog.editor.plugins.UndoRedo.UndoState_}s are the same.  We don't
+ * bother checking the cursor position (that's not something we'd want to save
+ * anyway).
+ * @param {goog.editor.plugins.UndoRedoState} rhs The state to compare.
+ * @return {boolean} Whether the contents are the same.
+ * @override
+ */
+goog.editor.plugins.UndoRedo.UndoState_.prototype.equals = function(rhs) {
+  return this.fieldHashCode == rhs.fieldHashCode &&
+      this.undoContent_ == rhs.undoContent_ &&
+      this.redoContent_ == rhs.redoContent_;
+};
+
+
+
+/**
+ * Stores the state of the selection in a way the survives DOM modifications
+ * that don't modify the user-interactable content (e.g. making something bold
+ * vs. typing a character).
+ *
+ * TODO(user): Completely get rid of this and use goog.dom.SavedCaretRange.
+ *
+ * @param {goog.editor.Field} field The field the selection is in.
+ * @private
+ * @constructor
+ */
+goog.editor.plugins.UndoRedo.CursorPosition_ = function(field) {
+  this.field_ = field;
+
+  var win = field.getEditableDomHelper().getWindow();
+  var range = field.getRange();
+  var isValidRange = !!range && range.isRangeInDocument() &&
+      range.getWindow() == win;
+  range = isValidRange ? range : null;
+
+  if (goog.editor.BrowserFeature.HAS_W3C_RANGES) {
+    this.initW3C_(range);
+  } else if (goog.editor.BrowserFeature.HAS_IE_RANGES) {
+    this.initIE_(range);
+  }
+};
+
+
+/**
+ * The standards compliant version keeps a list of childNode offsets.
+ * @param {goog.dom.AbstractRange?} range The range to save.
+ * @private
+ */
+goog.editor.plugins.UndoRedo.CursorPosition_.prototype.initW3C_ = function(
+    range) {
+  this.isValid_ = false;
+
+  // TODO: Check if the range is in the field before trying to save it
+  // for FF 3 contentEditable.
+  if (!range) {
+    return;
+  }
+
+  var anchorNode = range.getAnchorNode();
+  var focusNode = range.getFocusNode();
+  if (!anchorNode || !focusNode) {
+    return;
+  }
+
+  var anchorOffset = range.getAnchorOffset();
+  var anchor = new goog.dom.NodeOffset(anchorNode, this.field_.getElement());
+
+  var focusOffset = range.getFocusOffset();
+  var focus = new goog.dom.NodeOffset(focusNode, this.field_.getElement());
+
+  // Test range direction.
+  if (range.isReversed()) {
+    this.startOffset_ = focus;
+    this.startChildOffset_ = focusOffset;
+    this.endOffset_ = anchor;
+    this.endChildOffset_ = anchorOffset;
+  } else {
+    this.startOffset_ = anchor;
+    this.startChildOffset_ = anchorOffset;
+    this.endOffset_ = focus;
+    this.endChildOffset_ = focusOffset;
+  }
+
+  this.isValid_ = true;
+};
+
+
+/**
+ * In IE, we just keep track of the text offset (number of characters).
+ * @param {goog.dom.AbstractRange?} range The range to save.
+ * @private
+ */
+goog.editor.plugins.UndoRedo.CursorPosition_.prototype.initIE_ = function(
+    range) {
+  this.isValid_ = false;
+
+  if (!range) {
+    return;
+  }
+
+  var ieRange = range.getTextRange(0).getBrowserRangeObject();
+
+  if (!goog.dom.contains(this.field_.getElement(), ieRange.parentElement())) {
+    return;
+  }
+
+  // Create a range that encompasses the contentEditable region to serve
+  // as a reference to form ranges below.
+  var contentEditableRange =
+      this.field_.getEditableDomHelper().getDocument().body.createTextRange();
+  contentEditableRange.moveToElementText(this.field_.getElement());
+
+  // startMarker is a range from the start of the contentEditable node to the
+  // start of the current selection.
+  var startMarker = ieRange.duplicate();
+  startMarker.collapse(true);
+  startMarker.setEndPoint('StartToStart', contentEditableRange);
+  this.startOffset_ =
+      goog.editor.plugins.UndoRedo.CursorPosition_.computeEndOffsetIE_(
+          startMarker);
+
+  // endMarker is a range from the start of teh contentEditable node to the
+  // end of the current selection.
+  var endMarker = ieRange.duplicate();
+  endMarker.setEndPoint('StartToStart', contentEditableRange);
+  this.endOffset_ =
+      goog.editor.plugins.UndoRedo.CursorPosition_.computeEndOffsetIE_(
+          endMarker);
+
+  this.isValid_ = true;
+};
+
+
+/**
+ * @return {boolean} Whether this object is valid.
+ */
+goog.editor.plugins.UndoRedo.CursorPosition_.prototype.isValid = function() {
+  return this.isValid_;
+};
+
+
+/**
+ * @return {string} A string representation of this object.
+ * @override
+ */
+goog.editor.plugins.UndoRedo.CursorPosition_.prototype.toString = function() {
+  if (goog.editor.BrowserFeature.HAS_W3C_RANGES) {
+    return 'W3C:' + this.startOffset_.toString() + '\n' +
+        this.startChildOffset_ + ':' + this.endOffset_.toString() + '\n' +
+        this.endChildOffset_;
+  }
+  return 'IE:' + this.startOffset_ + ',' + this.endOffset_;
+};
+
+
+/**
+ * Makes the browser's selection match the cursor position.
+ */
+goog.editor.plugins.UndoRedo.CursorPosition_.prototype.select = function() {
+  var range = this.getRange_(this.field_.getElement());
+  if (range) {
+    if (goog.editor.BrowserFeature.HAS_IE_RANGES) {
+      this.field_.getElement().focus();
+    }
+    goog.dom.Range.createFromBrowserRange(range).select();
+  }
+};
+
+
+/**
+ * Get the range that encompases the the cursor position relative to a given
+ * base node.
+ * @param {Element} baseNode The node to get the cursor position relative to.
+ * @return {Range|TextRange|null} The browser range for this position.
+ * @private
+ */
+goog.editor.plugins.UndoRedo.CursorPosition_.prototype.getRange_ =
+    function(baseNode) {
+  if (goog.editor.BrowserFeature.HAS_W3C_RANGES) {
+    var startNode = this.startOffset_.findTargetNode(baseNode);
+    var endNode = this.endOffset_.findTargetNode(baseNode);
+    if (!startNode || !endNode) {
+      return null;
+    }
+
+    // Create range.
+    return /** @type {Range} */ (
+        goog.dom.Range.createFromNodes(startNode, this.startChildOffset_,
+            endNode, this.endChildOffset_).getBrowserRangeObject());
+  }
+
+  // Create a collapsed selection at the start of the contentEditable region,
+  // which the offsets were calculated relative to before.  Note that we force
+  // a text range here so we can use moveToElementText.
+  var sel = baseNode.ownerDocument.body.createTextRange();
+  sel.moveToElementText(baseNode);
+  sel.collapse(true);
+  sel.moveEnd('character', this.endOffset_);
+  sel.moveStart('character', this.startOffset_);
+  return sel;
+};
+
+
+/**
+ * Compute the number of characters to the end of the range in IE.
+ * @param {TextRange} range The range to compute an offset for.
+ * @return {number} The number of characters to the end of the range.
+ * @private
+ */
+goog.editor.plugins.UndoRedo.CursorPosition_.computeEndOffsetIE_ =
+    function(range) {
+  var testRange = range.duplicate();
+
+  // The number of offset characters is a little off depending on
+  // what type of block elements happen to be between the start of the
+  // textedit and the cursor position.  We fudge the offset until the
+  // two ranges match.
+  var text = range.text;
+  var guess = text.length;
+
+  testRange.collapse(true);
+  testRange.moveEnd('character', guess);
+
+  // Adjust the range until the end points match.  This doesn't quite
+  // work if we're at the end of the field so we give up after a few
+  // iterations.
+  var diff;
+  var numTries = 10;
+  while (diff = testRange.compareEndPoints('EndToEnd', range)) {
+    guess -= diff;
+    testRange.moveEnd('character', -diff);
+    --numTries;
+    if (0 == numTries) {
+      break;
+    }
+  }
+  // When we set innerHTML, blank lines become a single space, causing
+  // the cursor position to be off by one.  So we accommodate for blank
+  // lines.
+  var offset = 0;
+  var pos = text.indexOf('\n\r');
+  while (pos != -1) {
+    ++offset;
+    pos = text.indexOf('\n\r', pos + 1);
+  }
+  return guess + offset;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/undoredomanager.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/undoredomanager.js b/externs/GCL/externs/goog/editor/plugins/undoredomanager.js
new file mode 100644
index 0000000..5e054fd
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/undoredomanager.js
@@ -0,0 +1,338 @@
+// Copyright 2008 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 Code for managing series of undo-redo actions in the form of
+ * {@link goog.editor.plugins.UndoRedoState}s.
+ *
+ */
+
+
+goog.provide('goog.editor.plugins.UndoRedoManager');
+goog.provide('goog.editor.plugins.UndoRedoManager.EventType');
+
+goog.require('goog.editor.plugins.UndoRedoState');
+goog.require('goog.events');
+goog.require('goog.events.EventTarget');
+
+
+
+/**
+ * Manages undo and redo operations through a series of {@code UndoRedoState}s
+ * maintained on undo and redo stacks.
+ *
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.editor.plugins.UndoRedoManager = function() {
+  goog.events.EventTarget.call(this);
+
+  /**
+   * The maximum number of states on the undo stack at any time. Used to limit
+   * the memory footprint of the undo-redo stack.
+   * TODO(user) have a separate memory size based limit.
+   * @type {number}
+   * @private
+   */
+  this.maxUndoDepth_ = 100;
+
+  /**
+   * The undo stack.
+   * @type {Array<goog.editor.plugins.UndoRedoState>}
+   * @private
+   */
+  this.undoStack_ = [];
+
+  /**
+   * The redo stack.
+   * @type {Array<goog.editor.plugins.UndoRedoState>}
+   * @private
+   */
+  this.redoStack_ = [];
+
+  /**
+   * A queue of pending undo or redo actions. Stored as objects with two
+   * properties: func and state. The func property stores the undo or redo
+   * function to be called, the state property stores the state that method
+   * came from.
+   * @type {Array<Object>}
+   * @private
+   */
+  this.pendingActions_ = [];
+};
+goog.inherits(goog.editor.plugins.UndoRedoManager, goog.events.EventTarget);
+
+
+/**
+ * Event types for the events dispatched by undo-redo manager.
+ * @enum {string}
+ */
+goog.editor.plugins.UndoRedoManager.EventType = {
+  /**
+   * Signifies that he undo or redo stack transitioned between 0 and 1 states,
+   * meaning that the ability to peform undo or redo operations has changed.
+   */
+  STATE_CHANGE: 'state_change',
+
+  /**
+   * Signifies that a state was just added to the undo stack. Events of this
+   * type will have a {@code state} property whose value is the state that
+   * was just added.
+   */
+  STATE_ADDED: 'state_added',
+
+  /**
+   * Signifies that the undo method of a state is about to be called.
+   * Events of this type will have a {@code state} property whose value is the
+   * state whose undo action is about to be performed. If the event is cancelled
+   * the action does not proceed, but the state will still transition between
+   * stacks.
+   */
+  BEFORE_UNDO: 'before_undo',
+
+  /**
+   * Signifies that the redo method of a state is about to be called.
+   * Events of this type will have a {@code state} property whose value is the
+   * state whose redo action is about to be performed. If the event is cancelled
+   * the action does not proceed, but the state will still transition between
+   * stacks.
+   */
+  BEFORE_REDO: 'before_redo'
+};
+
+
+/**
+ * The key for the listener for the completion of the asynchronous state whose
+ * undo or redo action is in progress. Null if no action is in progress.
+ * @type {goog.events.Key}
+ * @private
+ */
+goog.editor.plugins.UndoRedoManager.prototype.inProgressActionKey_ = null;
+
+
+/**
+ * Set the max undo stack depth (not the real memory usage).
+ * @param {number} depth Depth of the stack.
+ */
+goog.editor.plugins.UndoRedoManager.prototype.setMaxUndoDepth =
+    function(depth) {
+  this.maxUndoDepth_ = depth;
+};
+
+
+/**
+ * Add state to the undo stack. This clears the redo stack.
+ *
+ * @param {goog.editor.plugins.UndoRedoState} state The state to add to the undo
+ *     stack.
+ */
+goog.editor.plugins.UndoRedoManager.prototype.addState = function(state) {
+  // TODO: is the state.equals check necessary?
+  if (this.undoStack_.length == 0 ||
+      !state.equals(this.undoStack_[this.undoStack_.length - 1])) {
+    this.undoStack_.push(state);
+    if (this.undoStack_.length > this.maxUndoDepth_) {
+      this.undoStack_.shift();
+    }
+    // Clobber the redo stack.
+    var redoLength = this.redoStack_.length;
+    this.redoStack_.length = 0;
+
+    this.dispatchEvent({
+      type: goog.editor.plugins.UndoRedoManager.EventType.STATE_ADDED,
+      state: state
+    });
+
+    // If the redo state had states on it, then clobbering the redo stack above
+    // has caused a state change.
+    if (this.undoStack_.length == 1 || redoLength) {
+      this.dispatchStateChange_();
+    }
+  }
+};
+
+
+/**
+ * Dispatches a STATE_CHANGE event with this manager as the target.
+ * @private
+ */
+goog.editor.plugins.UndoRedoManager.prototype.dispatchStateChange_ =
+    function() {
+  this.dispatchEvent(
+      goog.editor.plugins.UndoRedoManager.EventType.STATE_CHANGE);
+};
+
+
+/**
+ * Performs the undo operation of the state at the top of the undo stack, moving
+ * that state to the top of the redo stack. If the undo stack is empty, does
+ * nothing.
+ */
+goog.editor.plugins.UndoRedoManager.prototype.undo = function() {
+  this.shiftState_(this.undoStack_, this.redoStack_);
+};
+
+
+/**
+ * Performs the redo operation of the state at the top of the redo stack, moving
+ * that state to the top of the undo stack. If redo undo stack is empty, does
+ * nothing.
+ */
+goog.editor.plugins.UndoRedoManager.prototype.redo = function() {
+  this.shiftState_(this.redoStack_, this.undoStack_);
+};
+
+
+/**
+ * @return {boolean} Wether the undo stack has items on it, i.e., if it is
+ *     possible to perform an undo operation.
+ */
+goog.editor.plugins.UndoRedoManager.prototype.hasUndoState = function() {
+  return this.undoStack_.length > 0;
+};
+
+
+/**
+ * @return {boolean} Wether the redo stack has items on it, i.e., if it is
+ *     possible to perform a redo operation.
+ */
+goog.editor.plugins.UndoRedoManager.prototype.hasRedoState = function() {
+  return this.redoStack_.length > 0;
+};
+
+
+/**
+ * Move a state from one stack to the other, performing the appropriate undo
+ * or redo action.
+ *
+ * @param {Array<goog.editor.plugins.UndoRedoState>} fromStack Stack to move
+ *     the state from.
+ * @param {Array<goog.editor.plugins.UndoRedoState>} toStack Stack to move
+ *     the state to.
+ * @private
+ */
+goog.editor.plugins.UndoRedoManager.prototype.shiftState_ = function(
+    fromStack, toStack) {
+  if (fromStack.length) {
+    var state = fromStack.pop();
+
+    // Push the current state into the redo stack.
+    toStack.push(state);
+
+    this.addAction_({
+      type: fromStack == this.undoStack_ ?
+          goog.editor.plugins.UndoRedoManager.EventType.BEFORE_UNDO :
+          goog.editor.plugins.UndoRedoManager.EventType.BEFORE_REDO,
+      func: fromStack == this.undoStack_ ? state.undo : state.redo,
+      state: state
+    });
+
+    // If either stack transitioned between 0 and 1 in size then the ability
+    // to do an undo or redo has changed and we must dispatch a state change.
+    if (fromStack.length == 0 || toStack.length == 1) {
+      this.dispatchStateChange_();
+    }
+  }
+};
+
+
+/**
+ * Adds an action to the queue of pending undo or redo actions. If no actions
+ * are pending, immediately performs the action.
+ *
+ * @param {Object} action An undo or redo action. Stored as an object with two
+ *     properties: func and state. The func property stores the undo or redo
+ *     function to be called, the state property stores the state that method
+ *     came from.
+ * @private
+ */
+goog.editor.plugins.UndoRedoManager.prototype.addAction_ = function(action) {
+  this.pendingActions_.push(action);
+  if (this.pendingActions_.length == 1) {
+    this.doAction_();
+  }
+};
+
+
+/**
+ * Executes the action at the front of the pending actions queue. If an action
+ * is already in progress or the queue is empty, does nothing.
+ * @private
+ */
+goog.editor.plugins.UndoRedoManager.prototype.doAction_ = function() {
+  if (this.inProgressActionKey_ || this.pendingActions_.length == 0) {
+    return;
+  }
+
+  var action = this.pendingActions_.shift();
+
+  var e = {
+    type: action.type,
+    state: action.state
+  };
+
+  if (this.dispatchEvent(e)) {
+    if (action.state.isAsynchronous()) {
+      this.inProgressActionKey_ = goog.events.listen(action.state,
+          goog.editor.plugins.UndoRedoState.ACTION_COMPLETED,
+          this.finishAction_, false, this);
+      action.func.call(action.state);
+    } else {
+      action.func.call(action.state);
+      this.doAction_();
+    }
+  }
+};
+
+
+/**
+ * Finishes processing the current in progress action, starting the next queued
+ * action if one exists.
+ * @private
+ */
+goog.editor.plugins.UndoRedoManager.prototype.finishAction_ = function() {
+  goog.events.unlistenByKey(/** @type {number} */ (this.inProgressActionKey_));
+  this.inProgressActionKey_ = null;
+  this.doAction_();
+};
+
+
+/**
+ * Clears the undo and redo stacks.
+ */
+goog.editor.plugins.UndoRedoManager.prototype.clearHistory = function() {
+  if (this.undoStack_.length > 0 || this.redoStack_.length > 0) {
+    this.undoStack_.length = 0;
+    this.redoStack_.length = 0;
+    this.dispatchStateChange_();
+  }
+};
+
+
+/**
+ * @return {goog.editor.plugins.UndoRedoState|undefined} The state at the top of
+ *     the undo stack without removing it from the stack.
+ */
+goog.editor.plugins.UndoRedoManager.prototype.undoPeek = function() {
+  return this.undoStack_[this.undoStack_.length - 1];
+};
+
+
+/**
+ * @return {goog.editor.plugins.UndoRedoState|undefined} The state at the top of
+ *     the redo stack without removing it from the stack.
+ */
+goog.editor.plugins.UndoRedoManager.prototype.redoPeek = function() {
+  return this.redoStack_[this.redoStack_.length - 1];
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/undoredostate.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/undoredostate.js b/externs/GCL/externs/goog/editor/plugins/undoredostate.js
new file mode 100644
index 0000000..9a772dd
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/undoredostate.js
@@ -0,0 +1,86 @@
+// Copyright 2008 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 Code for an UndoRedoState interface representing an undo and
+ * redo action for a particular state change. To be used by
+ * {@link goog.editor.plugins.UndoRedoManager}.
+ *
+ */
+
+
+goog.provide('goog.editor.plugins.UndoRedoState');
+
+goog.require('goog.events.EventTarget');
+
+
+
+/**
+ * Represents an undo and redo action for a particular state transition.
+ *
+ * @param {boolean} asynchronous Whether the undo or redo actions for this
+ *     state complete asynchronously. If true, then this state must fire
+ *     an ACTION_COMPLETED event when undo or redo is complete.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.editor.plugins.UndoRedoState = function(asynchronous) {
+  goog.editor.plugins.UndoRedoState.base(this, 'constructor');
+
+  /**
+   * Indicates if the undo or redo actions for this state complete
+   * asynchronously.
+   * @type {boolean}
+   * @private
+   */
+  this.asynchronous_ = asynchronous;
+};
+goog.inherits(goog.editor.plugins.UndoRedoState, goog.events.EventTarget);
+
+
+/**
+ * Event type for events indicating that this state has completed an undo or
+ * redo operation.
+ */
+goog.editor.plugins.UndoRedoState.ACTION_COMPLETED = 'action_completed';
+
+
+/**
+ * @return {boolean} Whether or not the undo and redo actions of this state
+ *     complete asynchronously. If true, the state will fire an ACTION_COMPLETED
+ *     event when an undo or redo action is complete.
+ */
+goog.editor.plugins.UndoRedoState.prototype.isAsynchronous = function() {
+  return this.asynchronous_;
+};
+
+
+/**
+ * Undoes the action represented by this state.
+ */
+goog.editor.plugins.UndoRedoState.prototype.undo = goog.abstractMethod;
+
+
+/**
+ * Redoes the action represented by this state.
+ */
+goog.editor.plugins.UndoRedoState.prototype.redo = goog.abstractMethod;
+
+
+/**
+ * Checks if two undo-redo states are the same.
+ * @param {goog.editor.plugins.UndoRedoState} state The state to compare.
+ * @return {boolean} Wether the two states are equal.
+ */
+goog.editor.plugins.UndoRedoState.prototype.equals = goog.abstractMethod;


[28/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/nodetype.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/nodetype.js b/externs/GCL/externs/goog/dom/pattern/nodetype.js
new file mode 100644
index 0000000..a12c9a1
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/nodetype.js
@@ -0,0 +1,59 @@
+// Copyright 2008 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 DOM pattern to match a node of the given type.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.NodeType');
+
+goog.require('goog.dom.pattern.AbstractPattern');
+goog.require('goog.dom.pattern.MatchType');
+
+
+
+/**
+ * Pattern object that matches any node of the given type.
+ * @param {goog.dom.NodeType} nodeType The node type to match.
+ * @constructor
+ * @extends {goog.dom.pattern.AbstractPattern}
+ * @final
+ */
+goog.dom.pattern.NodeType = function(nodeType) {
+  /**
+   * The node type to match.
+   * @type {goog.dom.NodeType}
+   * @private
+   */
+  this.nodeType_ = nodeType;
+};
+goog.inherits(goog.dom.pattern.NodeType, goog.dom.pattern.AbstractPattern);
+
+
+/**
+ * Test whether the given token is a text token which matches the string or
+ * regular expression provided in the constructor.
+ * @param {Node} token Token to match against.
+ * @param {goog.dom.TagWalkType} type The type of token.
+ * @return {goog.dom.pattern.MatchType} <code>MATCH</code> if the pattern
+ *     matches, <code>NO_MATCH</code> otherwise.
+ * @override
+ */
+goog.dom.pattern.NodeType.prototype.matchToken = function(token, type) {
+  return token.nodeType == this.nodeType_ ?
+      goog.dom.pattern.MatchType.MATCH :
+      goog.dom.pattern.MatchType.NO_MATCH;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/pattern.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/pattern.js b/externs/GCL/externs/goog/dom/pattern/pattern.js
new file mode 100644
index 0000000..19f4d1b
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/pattern.js
@@ -0,0 +1,93 @@
+// 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 DOM patterns.  Allows for description of complex DOM patterns
+ * using regular expression like constructs.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern');
+goog.provide('goog.dom.pattern.MatchType');
+
+
+/**
+ * Regular expression for breaking text nodes.
+ * @type {RegExp}
+ */
+goog.dom.pattern.BREAKING_TEXTNODE_RE = /^\s*$/;
+
+
+/**
+ * Utility function to match a string against either a string or a regular
+ * expression.
+ *
+ * @param {string|RegExp} obj Either a string or a regular expression.
+ * @param {string} str The string to match.
+ * @return {boolean} Whether the strings are equal, or if the string matches
+ *     the regular expression.
+ */
+goog.dom.pattern.matchStringOrRegex = function(obj, str) {
+  if (goog.isString(obj)) {
+    // Match a string
+    return str == obj;
+  } else {
+    // Match a regular expression
+    return !!(str && str.match(obj));
+  }
+};
+
+
+/**
+ * Utility function to match a DOM attribute against either a string or a
+ * regular expression.  Conforms to the interface spec for
+ * {@link goog.object#every}.
+ *
+ * @param {string|RegExp} elem Either a string or a regular expression.
+ * @param {string} index The attribute name to match.
+ * @param {Object} orig The original map of matches to test.
+ * @return {boolean} Whether the strings are equal, or if the attribute matches
+ *     the regular expression.
+ * @this {Element} Called using goog.object every on an Element.
+ */
+goog.dom.pattern.matchStringOrRegexMap = function(elem, index, orig) {
+  return goog.dom.pattern.matchStringOrRegex(elem,
+      index in this ? this[index] :
+          (this.getAttribute ? this.getAttribute(index) : null));
+};
+
+
+/**
+ * When matched to a token, a pattern may return any of the following statuses:
+ *  <ol>
+ *    <li><code>NO_MATCH</code> - The pattern does not match.  This is the only
+ *      value that evaluates to <code>false</code> in a boolean context.
+ *    <li><code>MATCHING</code> - The token is part of an incomplete match.
+ *    <li><code>MATCH</code> - The token completes a match.
+ *    <li><code>BACKTRACK_MATCH</code> - The token does not match, but indicates
+ *      the end of a repetitive match.  For instance, in regular expressions,
+ *      the pattern <code>/a+/</code> would match <code>'aaaaaaaab'</code>.
+ *      Every <code>'a'</code> token would give a status of
+ *      <code>MATCHING</code> while the <code>'b'</code> token would give a
+ *      status of <code>BACKTRACK_MATCH</code>.
+ *  </ol>
+ * @enum {number}
+ */
+goog.dom.pattern.MatchType = {
+  NO_MATCH: 0,
+  MATCHING: 1,
+  MATCH: 2,
+  BACKTRACK_MATCH: 3
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/repeat.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/repeat.js b/externs/GCL/externs/goog/dom/pattern/repeat.js
new file mode 100644
index 0000000..392a6a6
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/repeat.js
@@ -0,0 +1,177 @@
+// 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 DOM pattern to match a tag and all of its children.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.Repeat');
+
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.pattern.AbstractPattern');
+goog.require('goog.dom.pattern.MatchType');
+
+
+
+/**
+ * Pattern object that matches a repetition of another pattern.
+ * @param {goog.dom.pattern.AbstractPattern} pattern The pattern to
+ *     repetitively match.
+ * @param {number=} opt_minimum The minimum number of times to match.  Defaults
+ *     to 0.
+ * @param {number=} opt_maximum The maximum number of times to match.  Defaults
+ *     to unlimited.
+ * @constructor
+ * @extends {goog.dom.pattern.AbstractPattern}
+ * @final
+ */
+goog.dom.pattern.Repeat = function(pattern,
+                                   opt_minimum,
+                                   opt_maximum) {
+  /**
+   * Pattern to repetitively match.
+   *
+   * @private {goog.dom.pattern.AbstractPattern}
+   */
+  this.pattern_ = pattern;
+
+  /**
+   * Minimum number of times to match the pattern.
+   *
+   * @private {number}
+   */
+  this.minimum_ = opt_minimum || 0;
+
+  /**
+   * Optional maximum number of times to match the pattern. A {@code null} value
+   * will be treated as infinity.
+   *
+   * @private {?number}
+   */
+  this.maximum_ = opt_maximum || null;
+
+  /**
+   * The matched nodes.
+   *
+   * @type {Array<Node>}
+   */
+  this.matches = [];
+
+  /**
+   * Number of times the pattern has matched.
+   *
+   * @type {number}
+   */
+  this.count = 0;
+
+  /**
+   * Whether the pattern has recently matched or failed to match and will need
+   * to be reset when starting a new round of matches.
+   *
+   * @private {boolean}
+   */
+  this.needsReset_ = false;
+};
+goog.inherits(goog.dom.pattern.Repeat, goog.dom.pattern.AbstractPattern);
+
+
+/**
+ * Test whether the given token continues a repeated series of matches of the
+ * pattern given in the constructor.
+ *
+ * @param {Node} token Token to match against.
+ * @param {goog.dom.TagWalkType} type The type of token.
+ * @return {goog.dom.pattern.MatchType} <code>MATCH</code> if the pattern
+ *     matches, <code>BACKTRACK_MATCH</code> if the pattern does not match
+ *     but already had accumulated matches, <code>MATCHING</code> if the pattern
+ *     starts a match, and <code>NO_MATCH</code> if the pattern does not match.
+ * @suppress {missingProperties} See the broken line below.
+ * @override
+ */
+goog.dom.pattern.Repeat.prototype.matchToken = function(token, type) {
+  // Reset if we're starting a new match
+  if (this.needsReset_) {
+    this.reset();
+  }
+
+  // If the option is set, ignore any whitespace only text nodes
+  if (token.nodeType == goog.dom.NodeType.TEXT &&
+      token.nodeValue.match(/^\s+$/)) {
+    return goog.dom.pattern.MatchType.MATCHING;
+  }
+
+  switch (this.pattern_.matchToken(token, type)) {
+    case goog.dom.pattern.MatchType.MATCH:
+      // Record the first token we match.
+      if (this.count == 0) {
+        this.matchedNode = token;
+      }
+
+      // Mark the match
+      this.count++;
+
+      // Add to the list
+      this.matches.push(this.pattern_.matchedNode);
+
+      // Check if this match hits our maximum
+      if (this.maximum_ !== null && this.count == this.maximum_) {
+        this.needsReset_ = true;
+        return goog.dom.pattern.MatchType.MATCH;
+      } else {
+        return goog.dom.pattern.MatchType.MATCHING;
+      }
+
+    case goog.dom.pattern.MatchType.MATCHING:
+      // This can happen when our child pattern is a sequence or a repetition.
+      return goog.dom.pattern.MatchType.MATCHING;
+
+    case goog.dom.pattern.MatchType.BACKTRACK_MATCH:
+      // This happens if our child pattern is repetitive too.
+      // TODO(robbyw): Backtrack further if necessary.
+      this.count++;
+
+      // NOTE(nicksantos): This line of code is broken. this.patterns_ doesn't
+      // exist, and this.currentPosition_ doesn't exit. When this is fixed,
+      // remove the missingProperties suppression above.
+      if (this.currentPosition_ == this.patterns_.length) {
+        this.needsReset_ = true;
+        return goog.dom.pattern.MatchType.BACKTRACK_MATCH;
+      } else {
+        // Retry the same token on the next iteration of the child pattern.
+        return this.matchToken(token, type);
+      }
+
+    default:
+      this.needsReset_ = true;
+      if (this.count >= this.minimum_) {
+        return goog.dom.pattern.MatchType.BACKTRACK_MATCH;
+      } else {
+        return goog.dom.pattern.MatchType.NO_MATCH;
+      }
+  }
+};
+
+
+/**
+ * Reset any internal state this pattern keeps.
+ * @override
+ */
+goog.dom.pattern.Repeat.prototype.reset = function() {
+  this.pattern_.reset();
+  this.count = 0;
+  this.needsReset_ = false;
+  this.matches.length = 0;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/sequence.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/sequence.js b/externs/GCL/externs/goog/dom/pattern/sequence.js
new file mode 100644
index 0000000..2282361
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/sequence.js
@@ -0,0 +1,135 @@
+// 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 DOM pattern to match a sequence of other patterns.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.Sequence');
+
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.pattern');
+goog.require('goog.dom.pattern.AbstractPattern');
+goog.require('goog.dom.pattern.MatchType');
+
+
+
+/**
+ * Pattern object that matches a sequence of other patterns.
+ *
+ * @param {Array<goog.dom.pattern.AbstractPattern>} patterns Ordered array of
+ *     patterns to match.
+ * @param {boolean=} opt_ignoreWhitespace Optional flag to ignore text nodes
+ *     consisting entirely of whitespace.  The default is to not ignore them.
+ * @constructor
+ * @extends {goog.dom.pattern.AbstractPattern}
+ * @final
+ */
+goog.dom.pattern.Sequence = function(patterns, opt_ignoreWhitespace) {
+  /**
+   * Ordered array of patterns to match.
+   *
+   * @type {Array<goog.dom.pattern.AbstractPattern>}
+   */
+  this.patterns = patterns;
+
+  /**
+   * Whether or not to ignore whitespace only Text nodes.
+   *
+   * @private {boolean}
+   */
+  this.ignoreWhitespace_ = !!opt_ignoreWhitespace;
+
+  /**
+   * Position in the patterns array we have reached by successful matches.
+   *
+   * @private {number}
+   */
+  this.currentPosition_ = 0;
+};
+goog.inherits(goog.dom.pattern.Sequence, goog.dom.pattern.AbstractPattern);
+
+
+/**
+ * Test whether the given token starts, continues, or finishes the sequence
+ * of patterns given in the constructor.
+ *
+ * @param {Node} token Token to match against.
+ * @param {goog.dom.TagWalkType} type The type of token.
+ * @return {goog.dom.pattern.MatchType} <code>MATCH</code> if the pattern
+ *     matches, <code>MATCHING</code> if the pattern starts a match, and
+ *     <code>NO_MATCH</code> if the pattern does not match.
+ * @override
+ */
+goog.dom.pattern.Sequence.prototype.matchToken = function(token, type) {
+  // If the option is set, ignore any whitespace only text nodes
+  if (this.ignoreWhitespace_ && token.nodeType == goog.dom.NodeType.TEXT &&
+      goog.dom.pattern.BREAKING_TEXTNODE_RE.test(token.nodeValue)) {
+    return goog.dom.pattern.MatchType.MATCHING;
+  }
+
+  switch (this.patterns[this.currentPosition_].matchToken(token, type)) {
+    case goog.dom.pattern.MatchType.MATCH:
+      // Record the first token we match.
+      if (this.currentPosition_ == 0) {
+        this.matchedNode = token;
+      }
+
+      // Move forward one position.
+      this.currentPosition_++;
+
+      // Check if this is the last position.
+      if (this.currentPosition_ == this.patterns.length) {
+        this.reset();
+        return goog.dom.pattern.MatchType.MATCH;
+      } else {
+        return goog.dom.pattern.MatchType.MATCHING;
+      }
+
+    case goog.dom.pattern.MatchType.MATCHING:
+      // This can happen when our child pattern is a sequence or a repetition.
+      return goog.dom.pattern.MatchType.MATCHING;
+
+    case goog.dom.pattern.MatchType.BACKTRACK_MATCH:
+      // This means a repetitive match succeeded 1 token ago.
+      // TODO(robbyw): Backtrack further if necessary.
+      this.currentPosition_++;
+
+      if (this.currentPosition_ == this.patterns.length) {
+        this.reset();
+        return goog.dom.pattern.MatchType.BACKTRACK_MATCH;
+      } else {
+        // Retry the same token on the next pattern.
+        return this.matchToken(token, type);
+      }
+
+    default:
+      this.reset();
+      return goog.dom.pattern.MatchType.NO_MATCH;
+  }
+};
+
+
+/**
+ * Reset any internal state this pattern keeps.
+ * @override
+ */
+goog.dom.pattern.Sequence.prototype.reset = function() {
+  if (this.patterns[this.currentPosition_]) {
+    this.patterns[this.currentPosition_].reset();
+  }
+  this.currentPosition_ = 0;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/starttag.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/starttag.js b/externs/GCL/externs/goog/dom/pattern/starttag.js
new file mode 100644
index 0000000..4ce0113
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/starttag.js
@@ -0,0 +1,53 @@
+// 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 DOM pattern to match the start of a tag.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.StartTag');
+
+goog.require('goog.dom.TagWalkType');
+goog.require('goog.dom.pattern.Tag');
+
+
+
+/**
+ * Pattern object that matches an opening tag.
+ *
+ * @param {string|RegExp} tag Name of the tag.  Also will accept a regular
+ *     expression to match against the tag name.
+ * @param {Object=} opt_attrs Optional map of attribute names to desired values.
+ *     This pattern will only match when all attributes are present and match
+ *     the string or regular expression value provided here.
+ * @param {Object=} opt_styles Optional map of CSS style names to desired
+ *     values. This pattern will only match when all styles are present and
+ *     match the string or regular expression value provided here.
+ * @param {Function=} opt_test Optional function that takes the element as a
+ *     parameter and returns true if this pattern should match it.
+ * @constructor
+ * @extends {goog.dom.pattern.Tag}
+ */
+goog.dom.pattern.StartTag = function(tag, opt_attrs, opt_styles, opt_test) {
+  goog.dom.pattern.Tag.call(
+      this,
+      tag,
+      goog.dom.TagWalkType.START_TAG,
+      opt_attrs,
+      opt_styles,
+      opt_test);
+};
+goog.inherits(goog.dom.pattern.StartTag, goog.dom.pattern.Tag);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/tag.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/tag.js b/externs/GCL/externs/goog/dom/pattern/tag.js
new file mode 100644
index 0000000..ba95123
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/tag.js
@@ -0,0 +1,128 @@
+// 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 DOM pattern to match a tag.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.Tag');
+
+goog.require('goog.dom.pattern');
+goog.require('goog.dom.pattern.AbstractPattern');
+goog.require('goog.dom.pattern.MatchType');
+goog.require('goog.object');
+
+
+
+/**
+ * Pattern object that matches an tag.
+ *
+ * @param {string|RegExp} tag Name of the tag.  Also will accept a regular
+ *     expression to match against the tag name.
+ * @param {goog.dom.TagWalkType} type Type of token to match.
+ * @param {Object=} opt_attrs Optional map of attribute names to desired values.
+ *     This pattern will only match when all attributes are present and match
+ *     the string or regular expression value provided here.
+ * @param {Object=} opt_styles Optional map of CSS style names to desired
+ *     values. This pattern will only match when all styles are present and
+ *     match the string or regular expression value provided here.
+ * @param {Function=} opt_test Optional function that takes the element as a
+ *     parameter and returns true if this pattern should match it.
+ * @constructor
+ * @extends {goog.dom.pattern.AbstractPattern}
+ */
+goog.dom.pattern.Tag = function(tag, type, opt_attrs, opt_styles, opt_test) {
+  /**
+   * The tag to match.
+   *
+   * @private {string|RegExp}
+   */
+  this.tag_ = goog.isString(tag) ? tag.toUpperCase() : tag;
+
+  /**
+   * The type of token to match.
+   *
+   * @private {goog.dom.TagWalkType}
+   */
+  this.type_ = type;
+
+  /**
+   * The attributes to test for.
+   *
+   * @private {Object}
+   */
+  this.attrs_ = opt_attrs || null;
+
+  /**
+   * The styles to test for.
+   *
+   * @private {Object}
+   */
+  this.styles_ = opt_styles || null;
+
+  /**
+   * Function that takes the element as a parameter and returns true if this
+   * pattern should match it.
+   *
+   * @private {Function}
+   */
+  this.test_ = opt_test || null;
+};
+goog.inherits(goog.dom.pattern.Tag, goog.dom.pattern.AbstractPattern);
+
+
+/**
+ * Test whether the given token is a tag token which matches the tag name,
+ * style, and attributes provided in the constructor.
+ *
+ * @param {Node} token Token to match against.
+ * @param {goog.dom.TagWalkType} type The type of token.
+ * @return {goog.dom.pattern.MatchType} <code>MATCH</code> if the pattern
+ *     matches, <code>NO_MATCH</code> otherwise.
+ * @override
+ */
+goog.dom.pattern.Tag.prototype.matchToken = function(token, type) {
+  // Check the direction and tag name.
+  if (type == this.type_ &&
+      goog.dom.pattern.matchStringOrRegex(this.tag_, token.nodeName)) {
+    // Check the attributes.
+    if (this.attrs_ &&
+        !goog.object.every(
+            this.attrs_,
+            goog.dom.pattern.matchStringOrRegexMap,
+            token)) {
+      return goog.dom.pattern.MatchType.NO_MATCH;
+    }
+    // Check the styles.
+    if (this.styles_ &&
+        !goog.object.every(
+            this.styles_,
+            goog.dom.pattern.matchStringOrRegexMap,
+            token.style)) {
+      return goog.dom.pattern.MatchType.NO_MATCH;
+    }
+
+    if (this.test_ && !this.test_(token)) {
+      return goog.dom.pattern.MatchType.NO_MATCH;
+    }
+
+    // If we reach this point, we have a match and should save it.
+    this.matchedNode = token;
+    return goog.dom.pattern.MatchType.MATCH;
+  }
+
+  return goog.dom.pattern.MatchType.NO_MATCH;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/text.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/text.js b/externs/GCL/externs/goog/dom/pattern/text.js
new file mode 100644
index 0000000..cf920e1
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/text.js
@@ -0,0 +1,67 @@
+// 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 DOM pattern to match a text node.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.Text');
+
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.pattern');
+goog.require('goog.dom.pattern.AbstractPattern');
+goog.require('goog.dom.pattern.MatchType');
+
+
+
+/**
+ * Pattern object that matches text by exact matching or regular expressions.
+ *
+ * @param {string|RegExp} match String or regular expression to match against.
+ * @constructor
+ * @extends {goog.dom.pattern.AbstractPattern}
+ * @final
+ */
+goog.dom.pattern.Text = function(match) {
+  /**
+   * The text or regular expression to match.
+   *
+   * @private {string|RegExp}
+   */
+  this.match_ = match;
+};
+goog.inherits(goog.dom.pattern.Text, goog.dom.pattern.AbstractPattern);
+
+
+/**
+ * Test whether the given token is a text token which matches the string or
+ * regular expression provided in the constructor.
+ *
+ * @param {Node} token Token to match against.
+ * @param {goog.dom.TagWalkType} type The type of token.
+ * @return {goog.dom.pattern.MatchType} <code>MATCH</code> if the pattern
+ *     matches, <code>NO_MATCH</code> otherwise.
+ * @override
+ */
+goog.dom.pattern.Text.prototype.matchToken = function(token, type) {
+  if (token.nodeType == goog.dom.NodeType.TEXT &&
+      goog.dom.pattern.matchStringOrRegex(this.match_, token.nodeValue)) {
+    this.matchedNode = token;
+    return goog.dom.pattern.MatchType.MATCH;
+  }
+
+  return goog.dom.pattern.MatchType.NO_MATCH;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/range.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/range.js b/externs/GCL/externs/goog/dom/range.js
new file mode 100644
index 0000000..eec784a
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/range.js
@@ -0,0 +1,226 @@
+// 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 Utilities for working with ranges in HTML documents.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.Range');
+
+goog.require('goog.dom');
+goog.require('goog.dom.AbstractRange');
+goog.require('goog.dom.BrowserFeature');
+goog.require('goog.dom.ControlRange');
+goog.require('goog.dom.MultiRange');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.TextRange');
+
+
+/**
+ * Create a new selection from the given browser window's current selection.
+ * Note that this object does not auto-update if the user changes their
+ * selection and should be used as a snapshot.
+ * @param {Window=} opt_win The window to get the selection of.  Defaults to the
+ *     window this class was defined in.
+ * @return {goog.dom.AbstractRange?} A range wrapper object, or null if there
+ *     was an error.
+ */
+goog.dom.Range.createFromWindow = function(opt_win) {
+  var sel = goog.dom.AbstractRange.getBrowserSelectionForWindow(
+      opt_win || window);
+  return sel && goog.dom.Range.createFromBrowserSelection(sel);
+};
+
+
+/**
+ * Create a new range wrapper from the given browser selection object.  Note
+ * that this object does not auto-update if the user changes their selection and
+ * should be used as a snapshot.
+ * @param {!Object} selection The browser selection object.
+ * @return {goog.dom.AbstractRange?} A range wrapper object or null if there
+ *    was an error.
+ */
+goog.dom.Range.createFromBrowserSelection = function(selection) {
+  var range;
+  var isReversed = false;
+  if (selection.createRange) {
+    /** @preserveTry */
+    try {
+      range = selection.createRange();
+    } catch (e) {
+      // Access denied errors can be thrown here in IE if the selection was
+      // a flash obj or if there are cross domain issues
+      return null;
+    }
+  } else if (selection.rangeCount) {
+    if (selection.rangeCount > 1) {
+      return goog.dom.MultiRange.createFromBrowserSelection(
+          /** @type {!Selection} */ (selection));
+    } else {
+      range = selection.getRangeAt(0);
+      isReversed = goog.dom.Range.isReversed(selection.anchorNode,
+          selection.anchorOffset, selection.focusNode, selection.focusOffset);
+    }
+  } else {
+    return null;
+  }
+
+  return goog.dom.Range.createFromBrowserRange(range, isReversed);
+};
+
+
+/**
+ * Create a new range wrapper from the given browser range object.
+ * @param {Range|TextRange} range The browser range object.
+ * @param {boolean=} opt_isReversed Whether the focus node is before the anchor
+ *     node.
+ * @return {!goog.dom.AbstractRange} A range wrapper object.
+ */
+goog.dom.Range.createFromBrowserRange = function(range, opt_isReversed) {
+  // Create an IE control range when appropriate.
+  return goog.dom.AbstractRange.isNativeControlRange(range) ?
+      goog.dom.ControlRange.createFromBrowserRange(range) :
+      goog.dom.TextRange.createFromBrowserRange(range, opt_isReversed);
+};
+
+
+/**
+ * Create a new range wrapper that selects the given node's text.
+ * @param {Node} node The node to select.
+ * @param {boolean=} opt_isReversed Whether the focus node is before the anchor
+ *     node.
+ * @return {!goog.dom.AbstractRange} A range wrapper object.
+ */
+goog.dom.Range.createFromNodeContents = function(node, opt_isReversed) {
+  return goog.dom.TextRange.createFromNodeContents(node, opt_isReversed);
+};
+
+
+/**
+ * Create a new range wrapper that represents a caret at the given node,
+ * accounting for the given offset.  This always creates a TextRange, regardless
+ * of whether node is an image node or other control range type node.
+ * @param {Node} node The node to place a caret at.
+ * @param {number} offset The offset within the node to place the caret at.
+ * @return {!goog.dom.AbstractRange} A range wrapper object.
+ */
+goog.dom.Range.createCaret = function(node, offset) {
+  return goog.dom.TextRange.createFromNodes(node, offset, node, offset);
+};
+
+
+/**
+ * Create a new range wrapper that selects the area between the given nodes,
+ * accounting for the given offsets.
+ * @param {Node} anchorNode The node to anchor on.
+ * @param {number} anchorOffset The offset within the node to anchor on.
+ * @param {Node} focusNode The node to focus on.
+ * @param {number} focusOffset The offset within the node to focus on.
+ * @return {!goog.dom.AbstractRange} A range wrapper object.
+ */
+goog.dom.Range.createFromNodes = function(anchorNode, anchorOffset, focusNode,
+    focusOffset) {
+  return goog.dom.TextRange.createFromNodes(anchorNode, anchorOffset, focusNode,
+      focusOffset);
+};
+
+
+/**
+ * Clears the window's selection.
+ * @param {Window=} opt_win The window to get the selection of.  Defaults to the
+ *     window this class was defined in.
+ */
+goog.dom.Range.clearSelection = function(opt_win) {
+  var sel = goog.dom.AbstractRange.getBrowserSelectionForWindow(
+      opt_win || window);
+  if (!sel) {
+    return;
+  }
+  if (sel.empty) {
+    // We can't just check that the selection is empty, becuase IE
+    // sometimes gets confused.
+    try {
+      sel.empty();
+    } catch (e) {
+      // Emptying an already empty selection throws an exception in IE
+    }
+  } else {
+    try {
+      sel.removeAllRanges();
+    } catch (e) {
+      // This throws in IE9 if the range has been invalidated; for example, if
+      // the user clicked on an element which disappeared during the event
+      // handler.
+    }
+  }
+};
+
+
+/**
+ * Tests if the window has a selection.
+ * @param {Window=} opt_win The window to check the selection of.  Defaults to
+ *     the window this class was defined in.
+ * @return {boolean} Whether the window has a selection.
+ */
+goog.dom.Range.hasSelection = function(opt_win) {
+  var sel = goog.dom.AbstractRange.getBrowserSelectionForWindow(
+      opt_win || window);
+  return !!sel &&
+      (goog.dom.BrowserFeature.LEGACY_IE_RANGES ?
+       sel.type != 'None' : !!sel.rangeCount);
+};
+
+
+/**
+ * Returns whether the focus position occurs before the anchor position.
+ * @param {Node} anchorNode The node to anchor on.
+ * @param {number} anchorOffset The offset within the node to anchor on.
+ * @param {Node} focusNode The node to focus on.
+ * @param {number} focusOffset The offset within the node to focus on.
+ * @return {boolean} Whether the focus position occurs before the anchor
+ *     position.
+ */
+goog.dom.Range.isReversed = function(anchorNode, anchorOffset, focusNode,
+    focusOffset) {
+  if (anchorNode == focusNode) {
+    return focusOffset < anchorOffset;
+  }
+  var child;
+  if (anchorNode.nodeType == goog.dom.NodeType.ELEMENT && anchorOffset) {
+    child = anchorNode.childNodes[anchorOffset];
+    if (child) {
+      anchorNode = child;
+      anchorOffset = 0;
+    } else if (goog.dom.contains(anchorNode, focusNode)) {
+      // If focus node is contained in anchorNode, it must be before the
+      // end of the node.  Hence we are reversed.
+      return true;
+    }
+  }
+  if (focusNode.nodeType == goog.dom.NodeType.ELEMENT && focusOffset) {
+    child = focusNode.childNodes[focusOffset];
+    if (child) {
+      focusNode = child;
+      focusOffset = 0;
+    } else if (goog.dom.contains(focusNode, anchorNode)) {
+      // If anchor node is contained in focusNode, it must be before the
+      // end of the node.  Hence we are not reversed.
+      return false;
+    }
+  }
+  return (goog.dom.compareNodeOrder(anchorNode, focusNode) ||
+      anchorOffset - focusOffset) > 0;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/rangeendpoint.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/rangeendpoint.js b/externs/GCL/externs/goog/dom/rangeendpoint.js
new file mode 100644
index 0000000..f8d0fe4
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/rangeendpoint.js
@@ -0,0 +1,32 @@
+// 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 Simple struct for endpoints of a range.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.RangeEndpoint');
+
+
+/**
+ * Constants for selection endpoints.
+ * @enum {number}
+ */
+goog.dom.RangeEndpoint = {
+  START: 1,
+  END: 0
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/safe.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/safe.js b/externs/GCL/externs/goog/dom/safe.js
new file mode 100644
index 0000000..8aa9d9e
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/safe.js
@@ -0,0 +1,325 @@
+// Copyright 2013 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 Type-safe wrappers for unsafe DOM APIs.
+ *
+ * This file provides type-safe wrappers for DOM APIs that can result in
+ * cross-site scripting (XSS) vulnerabilities, if the API is supplied with
+ * untrusted (attacker-controlled) input.  Instead of plain strings, the type
+ * safe wrappers consume values of types from the goog.html package whose
+ * contract promises that values are safe to use in the corresponding context.
+ *
+ * Hence, a program that exclusively uses the wrappers in this file (i.e., whose
+ * only reference to security-sensitive raw DOM APIs are in this file) is
+ * guaranteed to be free of XSS due to incorrect use of such DOM APIs (modulo
+ * correctness of code that produces values of the respective goog.html types,
+ * and absent code that violates type safety).
+ *
+ * For example, assigning to an element's .innerHTML property a string that is
+ * derived (even partially) from untrusted input typically results in an XSS
+ * vulnerability. The type-safe wrapper goog.html.setInnerHtml consumes a value
+ * of type goog.html.SafeHtml, whose contract states that using its values in a
+ * HTML context will not result in XSS. Hence a program that is free of direct
+ * assignments to any element's innerHTML property (with the exception of the
+ * assignment to .innerHTML in this file) is guaranteed to be free of XSS due to
+ * assignment of untrusted strings to the innerHTML property.
+ */
+
+goog.provide('goog.dom.safe');
+
+goog.require('goog.asserts');
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.SafeUrl');
+goog.require('goog.html.TrustedResourceUrl');
+goog.require('goog.string');
+goog.require('goog.string.Const');
+
+
+/**
+ * Assigns known-safe HTML to an element's innerHTML property.
+ * @param {!Element} elem The element whose innerHTML is to be assigned to.
+ * @param {!goog.html.SafeHtml} html The known-safe HTML to assign.
+ */
+goog.dom.safe.setInnerHtml = function(elem, html) {
+  elem.innerHTML = goog.html.SafeHtml.unwrap(html);
+};
+
+
+/**
+ * Assigns known-safe HTML to an element's outerHTML property.
+ * @param {!Element} elem The element whose outerHTML is to be assigned to.
+ * @param {!goog.html.SafeHtml} html The known-safe HTML to assign.
+ */
+goog.dom.safe.setOuterHtml = function(elem, html) {
+  elem.outerHTML = goog.html.SafeHtml.unwrap(html);
+};
+
+
+/**
+ * Writes known-safe HTML to a document.
+ * @param {!Document} doc The document to be written to.
+ * @param {!goog.html.SafeHtml} html The known-safe HTML to assign.
+ */
+goog.dom.safe.documentWrite = function(doc, html) {
+  doc.write(goog.html.SafeHtml.unwrap(html));
+};
+
+
+/**
+ * Safely assigns a URL to an anchor element's href property.
+ *
+ * If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
+ * anchor's href property.  If url is of type string however, it is first
+ * sanitized using goog.html.SafeUrl.sanitize.
+ *
+ * Example usage:
+ *   goog.dom.safe.setAnchorHref(anchorEl, url);
+ * which is a safe alternative to
+ *   anchorEl.href = url;
+ * The latter can result in XSS vulnerabilities if url is a
+ * user-/attacker-controlled value.
+ *
+ * @param {!HTMLAnchorElement} anchor The anchor element whose href property
+ *     is to be assigned to.
+ * @param {string|!goog.html.SafeUrl} url The URL to assign.
+ * @see goog.html.SafeUrl#sanitize
+ */
+goog.dom.safe.setAnchorHref = function(anchor, url) {
+  /** @type {!goog.html.SafeUrl} */
+  var safeUrl;
+  if (url instanceof goog.html.SafeUrl) {
+    safeUrl = url;
+  } else {
+    safeUrl = goog.html.SafeUrl.sanitize(url);
+  }
+  anchor.href = goog.html.SafeUrl.unwrap(safeUrl);
+};
+
+
+/**
+ * Safely assigns a URL to an embed element's src property.
+ *
+ * Example usage:
+ *   goog.dom.safe.setEmbedSrc(embedEl, url);
+ * which is a safe alternative to
+ *   embedEl.src = url;
+ * The latter can result in loading untrusted code unless it is ensured that
+ * the URL refers to a trustworthy resource.
+ *
+ * @param {!HTMLEmbedElement} embed The embed element whose src property
+ *     is to be assigned to.
+ * @param {!goog.html.TrustedResourceUrl} url The URL to assign.
+ */
+goog.dom.safe.setEmbedSrc = function(embed, url) {
+  embed.src = goog.html.TrustedResourceUrl.unwrap(url);
+};
+
+
+/**
+ * Safely assigns a URL to a frame element's src property.
+ *
+ * Example usage:
+ *   goog.dom.safe.setFrameSrc(frameEl, url);
+ * which is a safe alternative to
+ *   frameEl.src = url;
+ * The latter can result in loading untrusted code unless it is ensured that
+ * the URL refers to a trustworthy resource.
+ *
+ * @param {!HTMLFrameElement} frame The frame element whose src property
+ *     is to be assigned to.
+ * @param {!goog.html.TrustedResourceUrl} url The URL to assign.
+ */
+goog.dom.safe.setFrameSrc = function(frame, url) {
+  frame.src = goog.html.TrustedResourceUrl.unwrap(url);
+};
+
+
+/**
+ * Safely assigns a URL to an iframe element's src property.
+ *
+ * Example usage:
+ *   goog.dom.safe.setIframeSrc(iframeEl, url);
+ * which is a safe alternative to
+ *   iframeEl.src = url;
+ * The latter can result in loading untrusted code unless it is ensured that
+ * the URL refers to a trustworthy resource.
+ *
+ * @param {!HTMLIFrameElement} iframe The iframe element whose src property
+ *     is to be assigned to.
+ * @param {!goog.html.TrustedResourceUrl} url The URL to assign.
+ */
+goog.dom.safe.setIframeSrc = function(iframe, url) {
+  iframe.src = goog.html.TrustedResourceUrl.unwrap(url);
+};
+
+
+/**
+ * Safely sets a link element's href and rel properties. Whether or not
+ * the URL assigned to href has to be a goog.html.TrustedResourceUrl
+ * depends on the value of the rel property. If rel contains "stylesheet"
+ * then a TrustedResourceUrl is required.
+ *
+ * Example usage:
+ *   goog.dom.safe.setLinkHrefAndRel(linkEl, url, 'stylesheet');
+ * which is a safe alternative to
+ *   linkEl.rel = 'stylesheet';
+ *   linkEl.href = url;
+ * The latter can result in loading untrusted code unless it is ensured that
+ * the URL refers to a trustworthy resource.
+ *
+ * @param {!HTMLLinkElement} link The link element whose href property
+ *     is to be assigned to.
+ * @param {string|!goog.html.SafeUrl|!goog.html.TrustedResourceUrl} url The URL
+ *     to assign to the href property. Must be a TrustedResourceUrl if the
+ *     value assigned to rel contains "stylesheet". A string value is
+ *     sanitized with goog.html.SafeUrl.sanitize.
+ * @param {string} rel The value to assign to the rel property.
+ * @throws {Error} if rel contains "stylesheet" and url is not a
+ *     TrustedResourceUrl
+ * @see goog.html.SafeUrl#sanitize
+ */
+goog.dom.safe.setLinkHrefAndRel = function(link, url, rel) {
+  link.rel = rel;
+  if (goog.string.caseInsensitiveContains(rel, 'stylesheet')) {
+    goog.asserts.assert(
+        url instanceof goog.html.TrustedResourceUrl,
+        'URL must be TrustedResourceUrl because "rel" contains "stylesheet"');
+    link.href = goog.html.TrustedResourceUrl.unwrap(url);
+  } else if (url instanceof goog.html.TrustedResourceUrl) {
+    link.href = goog.html.TrustedResourceUrl.unwrap(url);
+  } else if (url instanceof goog.html.SafeUrl) {
+    link.href = goog.html.SafeUrl.unwrap(url);
+  } else {  // string
+    // SafeUrl.sanitize must return legitimate SafeUrl when passed a string.
+    link.href = goog.html.SafeUrl.sanitize(url).getTypedStringValue();
+  }
+};
+
+
+/**
+ * Safely assigns a URL to an object element's data property.
+ *
+ * Example usage:
+ *   goog.dom.safe.setObjectData(objectEl, url);
+ * which is a safe alternative to
+ *   objectEl.data = url;
+ * The latter can result in loading untrusted code unless setit is ensured that
+ * the URL refers to a trustworthy resource.
+ *
+ * @param {!HTMLObjectElement} object The object element whose data property
+ *     is to be assigned to.
+ * @param {!goog.html.TrustedResourceUrl} url The URL to assign.
+ */
+goog.dom.safe.setObjectData = function(object, url) {
+  object.data = goog.html.TrustedResourceUrl.unwrap(url);
+};
+
+
+/**
+ * Safely assigns a URL to an iframe element's src property.
+ *
+ * Example usage:
+ *   goog.dom.safe.setScriptSrc(scriptEl, url);
+ * which is a safe alternative to
+ *   scriptEl.src = url;
+ * The latter can result in loading untrusted code unless it is ensured that
+ * the URL refers to a trustworthy resource.
+ *
+ * @param {!HTMLScriptElement} script The script element whose src property
+ *     is to be assigned to.
+ * @param {!goog.html.TrustedResourceUrl} url The URL to assign.
+ */
+goog.dom.safe.setScriptSrc = function(script, url) {
+  script.src = goog.html.TrustedResourceUrl.unwrap(url);
+};
+
+
+/**
+ * Safely assigns a URL to a Location object's href property.
+ *
+ * If url is of type goog.html.SafeUrl, its value is unwrapped and assigned to
+ * loc's href property.  If url is of type string however, it is first sanitized
+ * using goog.html.SafeUrl.sanitize.
+ *
+ * Example usage:
+ *   goog.dom.safe.setLocationHref(document.location, redirectUrl);
+ * which is a safe alternative to
+ *   document.location.href = redirectUrl;
+ * The latter can result in XSS vulnerabilities if redirectUrl is a
+ * user-/attacker-controlled value.
+ *
+ * @param {!Location} loc The Location object whose href property is to be
+ *     assigned to.
+ * @param {string|!goog.html.SafeUrl} url The URL to assign.
+ * @see goog.html.SafeUrl#sanitize
+ */
+goog.dom.safe.setLocationHref = function(loc, url) {
+  /** @type {!goog.html.SafeUrl} */
+  var safeUrl;
+  if (url instanceof goog.html.SafeUrl) {
+    safeUrl = url;
+  } else {
+    safeUrl = goog.html.SafeUrl.sanitize(url);
+  }
+  loc.href = goog.html.SafeUrl.unwrap(safeUrl);
+};
+
+
+/**
+ * Safely opens a URL in a new window (via window.open).
+ *
+ * If url is of type goog.html.SafeUrl, its value is unwrapped and passed in to
+ * window.open.  If url is of type string however, it is first sanitized
+ * using goog.html.SafeUrl.sanitize.
+ *
+ * Note that this function does not prevent leakages via the referer that is
+ * sent by window.open. It is advised to only use this to open 1st party URLs.
+ *
+ * Example usage:
+ *   goog.dom.safe.openInWindow(url);
+ * which is a safe alternative to
+ *   window.open(url);
+ * The latter can result in XSS vulnerabilities if redirectUrl is a
+ * user-/attacker-controlled value.
+ *
+ * @param {string|!goog.html.SafeUrl} url The URL to open.
+ * @param {Window=} opt_openerWin Window of which to call the .open() method.
+ *     Defaults to the global window.
+ * @param {!goog.string.Const=} opt_name Name of the window to open in. Can be
+ *     _top, etc as allowed by window.open().
+ * @param {string=} opt_specs Comma-separated list of specifications, same as
+ *     in window.open().
+ * @param {boolean=} opt_replace Whether to replace the current entry in browser
+ *     history, same as in window.open().
+ * @return {Window} Window the url was opened in.
+ */
+goog.dom.safe.openInWindow = function(
+    url, opt_openerWin, opt_name, opt_specs, opt_replace) {
+  /** @type {!goog.html.SafeUrl} */
+  var safeUrl;
+  if (url instanceof goog.html.SafeUrl) {
+    safeUrl = url;
+  } else {
+    safeUrl = goog.html.SafeUrl.sanitize(url);
+  }
+  var win = opt_openerWin || window;
+  return win.open(goog.html.SafeUrl.unwrap(safeUrl),
+      // If opt_name is undefined, simply passing that in to open() causes IE to
+      // reuse the current window instead of opening a new one. Thus we pass ''
+      // in instead, which according to spec opens a new window. See
+      // https://html.spec.whatwg.org/multipage/browsers.html#dom-open .
+      opt_name ? goog.string.Const.unwrap(opt_name) : '',
+      opt_specs, opt_replace);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/savedcaretrange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/savedcaretrange.js b/externs/GCL/externs/goog/dom/savedcaretrange.js
new file mode 100644
index 0000000..ea61050
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/savedcaretrange.js
@@ -0,0 +1,215 @@
+// Copyright 2008 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 An API for saving and restoring ranges as HTML carets.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+
+goog.provide('goog.dom.SavedCaretRange');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.SavedRange');
+goog.require('goog.dom.TagName');
+goog.require('goog.string');
+
+
+
+/**
+ * A struct for holding context about saved selections.
+ * This can be used to preserve the selection and restore while the DOM is
+ * manipulated, or through an asynchronous call. Use goog.dom.Range factory
+ * methods to obtain an {@see goog.dom.AbstractRange} instance, and use
+ * {@see goog.dom.AbstractRange#saveUsingCarets} to obtain a SavedCaretRange.
+ * For editor ranges under content-editable elements or design-mode iframes,
+ * prefer using {@see goog.editor.range.saveUsingNormalizedCarets}.
+ * @param {goog.dom.AbstractRange} range The range being saved.
+ * @constructor
+ * @extends {goog.dom.SavedRange}
+ */
+goog.dom.SavedCaretRange = function(range) {
+  goog.dom.SavedRange.call(this);
+
+  /**
+   * The DOM id of the caret at the start of the range.
+   * @type {string}
+   * @private
+   */
+  this.startCaretId_ = goog.string.createUniqueString();
+
+  /**
+   * The DOM id of the caret at the end of the range.
+   * @type {string}
+   * @private
+   */
+  this.endCaretId_ = goog.string.createUniqueString();
+
+  /**
+   * Whether the range is reversed (anchor at the end).
+   * @private {boolean}
+   */
+  this.reversed_ = range.isReversed();
+
+  /**
+   * A DOM helper for storing the current document context.
+   * @type {goog.dom.DomHelper}
+   * @private
+   */
+  this.dom_ = goog.dom.getDomHelper(range.getDocument());
+
+  range.surroundWithNodes(this.createCaret_(true), this.createCaret_(false));
+};
+goog.inherits(goog.dom.SavedCaretRange, goog.dom.SavedRange);
+
+
+/**
+ * Gets the range that this SavedCaretRage represents, without selecting it
+ * or removing the carets from the DOM.
+ * @return {goog.dom.AbstractRange?} An abstract range.
+ */
+goog.dom.SavedCaretRange.prototype.toAbstractRange = function() {
+  var range = null;
+  var startCaret = this.getCaret(true);
+  var endCaret = this.getCaret(false);
+  if (startCaret && endCaret) {
+    /** @suppress {missingRequire} circular dependency */
+    range = goog.dom.Range.createFromNodes(startCaret, 0, endCaret, 0);
+  }
+  return range;
+};
+
+
+/**
+ * Gets carets.
+ * @param {boolean} start If true, returns the start caret. Otherwise, get the
+ *     end caret.
+ * @return {Element} The start or end caret in the given document.
+ */
+goog.dom.SavedCaretRange.prototype.getCaret = function(start) {
+  return this.dom_.getElement(start ? this.startCaretId_ : this.endCaretId_);
+};
+
+
+/**
+ * Removes the carets from the current restoration document.
+ * @param {goog.dom.AbstractRange=} opt_range A range whose offsets have already
+ *     been adjusted for caret removal; it will be adjusted if it is also
+ *     affected by post-removal operations, such as text node normalization.
+ * @return {goog.dom.AbstractRange|undefined} The adjusted range, if opt_range
+ *     was provided.
+ */
+goog.dom.SavedCaretRange.prototype.removeCarets = function(opt_range) {
+  goog.dom.removeNode(this.getCaret(true));
+  goog.dom.removeNode(this.getCaret(false));
+  return opt_range;
+};
+
+
+/**
+ * Sets the document where the range will be restored.
+ * @param {!Document} doc An HTML document.
+ */
+goog.dom.SavedCaretRange.prototype.setRestorationDocument = function(doc) {
+  this.dom_.setDocument(doc);
+};
+
+
+/**
+ * Reconstruct the selection from the given saved range. Removes carets after
+ * restoring the selection. If restore does not dispose this saved range, it may
+ * only be restored a second time if innerHTML or some other mechanism is used
+ * to restore the carets to the dom.
+ * @return {goog.dom.AbstractRange?} Restored selection.
+ * @override
+ * @protected
+ */
+goog.dom.SavedCaretRange.prototype.restoreInternal = function() {
+  var range = null;
+  var anchorCaret = this.getCaret(!this.reversed_);
+  var focusCaret = this.getCaret(this.reversed_);
+  if (anchorCaret && focusCaret) {
+    var anchorNode = anchorCaret.parentNode;
+    var anchorOffset = goog.array.indexOf(anchorNode.childNodes, anchorCaret);
+    var focusNode = focusCaret.parentNode;
+    var focusOffset = goog.array.indexOf(focusNode.childNodes, focusCaret);
+    if (focusNode == anchorNode) {
+      // Compensate for the start caret being removed.
+      if (this.reversed_) {
+        anchorOffset--;
+      } else {
+        focusOffset--;
+      }
+    }
+    /** @suppress {missingRequire} circular dependency */
+    range = goog.dom.Range.createFromNodes(anchorNode, anchorOffset,
+                                           focusNode, focusOffset);
+    range = this.removeCarets(range);
+    range.select();
+  } else {
+    // If only one caret was found, remove it.
+    this.removeCarets();
+  }
+  return range;
+};
+
+
+/**
+ * Dispose the saved range and remove the carets from the DOM.
+ * @override
+ * @protected
+ */
+goog.dom.SavedCaretRange.prototype.disposeInternal = function() {
+  this.removeCarets();
+  this.dom_ = null;
+};
+
+
+/**
+ * Creates a caret element.
+ * @param {boolean} start If true, creates the start caret. Otherwise,
+ *     creates the end caret.
+ * @return {!Element} The new caret element.
+ * @private
+ */
+goog.dom.SavedCaretRange.prototype.createCaret_ = function(start) {
+  return this.dom_.createDom(goog.dom.TagName.SPAN,
+      {'id': start ? this.startCaretId_ : this.endCaretId_});
+};
+
+
+/**
+ * A regex that will match all saved range carets in a string.
+ * @type {RegExp}
+ */
+goog.dom.SavedCaretRange.CARET_REGEX = /<span\s+id="?goog_\d+"?><\/span>/ig;
+
+
+/**
+ * Returns whether two strings of html are equal, ignoring any saved carets.
+ * Thus two strings of html whose only difference is the id of their saved
+ * carets will be considered equal, since they represent html with the
+ * same selection.
+ * @param {string} str1 The first string.
+ * @param {string} str2 The second string.
+ * @return {boolean} Whether two strings of html are equal, ignoring any
+ *     saved carets.
+ */
+goog.dom.SavedCaretRange.htmlEqual = function(str1, str2) {
+  return str1 == str2 ||
+      str1.replace(goog.dom.SavedCaretRange.CARET_REGEX, '') ==
+          str2.replace(goog.dom.SavedCaretRange.CARET_REGEX, '');
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/savedrange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/savedrange.js b/externs/GCL/externs/goog/dom/savedrange.js
new file mode 100644
index 0000000..5a7e951
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/savedrange.js
@@ -0,0 +1,74 @@
+// 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 A generic interface for saving and restoring ranges.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.SavedRange');
+
+goog.require('goog.Disposable');
+goog.require('goog.log');
+
+
+
+/**
+ * Abstract interface for a saved range.
+ * @constructor
+ * @extends {goog.Disposable}
+ */
+goog.dom.SavedRange = function() {
+  goog.Disposable.call(this);
+};
+goog.inherits(goog.dom.SavedRange, goog.Disposable);
+
+
+/**
+ * Logging object.
+ * @type {goog.log.Logger}
+ * @private
+ */
+goog.dom.SavedRange.logger_ =
+    goog.log.getLogger('goog.dom.SavedRange');
+
+
+/**
+ * Restores the range and by default disposes of the saved copy.  Take note:
+ * this means the by default SavedRange objects are single use objects.
+ * @param {boolean=} opt_stayAlive Whether this SavedRange should stay alive
+ *     (not be disposed) after restoring the range. Defaults to false (dispose).
+ * @return {goog.dom.AbstractRange} The restored range.
+ */
+goog.dom.SavedRange.prototype.restore = function(opt_stayAlive) {
+  if (this.isDisposed()) {
+    goog.log.error(goog.dom.SavedRange.logger_,
+        'Disposed SavedRange objects cannot be restored.');
+  }
+
+  var range = this.restoreInternal();
+  if (!opt_stayAlive) {
+    this.dispose();
+  }
+  return range;
+};
+
+
+/**
+ * Internal method to restore the saved range.
+ * @return {goog.dom.AbstractRange} The restored range.
+ */
+goog.dom.SavedRange.prototype.restoreInternal = goog.abstractMethod;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/selection.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/selection.js b/externs/GCL/externs/goog/dom/selection.js
new file mode 100644
index 0000000..4afb4f7
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/selection.js
@@ -0,0 +1,472 @@
+// 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 working with selections in input boxes and text
+ * areas.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/dom_selection.html
+ */
+
+
+goog.provide('goog.dom.selection');
+
+goog.require('goog.dom.InputType');
+goog.require('goog.string');
+goog.require('goog.userAgent');
+
+
+/**
+ * Sets the place where the selection should start inside a textarea or a text
+ * input
+ * @param {Element} textfield A textarea or text input.
+ * @param {number} pos The position to set the start of the selection at.
+ */
+goog.dom.selection.setStart = function(textfield, pos) {
+  if (goog.dom.selection.useSelectionProperties_(textfield)) {
+    textfield.selectionStart = pos;
+  } else if (goog.userAgent.IE) {
+    // destructuring assignment would have been sweet
+    var tmp = goog.dom.selection.getRangeIe_(textfield);
+    var range = tmp[0];
+    var selectionRange = tmp[1];
+
+    if (range.inRange(selectionRange)) {
+      pos = goog.dom.selection.canonicalizePositionIe_(textfield, pos);
+
+      range.collapse(true);
+      range.move('character', pos);
+      range.select();
+    }
+  }
+};
+
+
+/**
+ * Return the place where the selection starts inside a textarea or a text
+ * input
+ * @param {Element} textfield A textarea or text input.
+ * @return {number} The position where the selection starts or 0 if it was
+ *     unable to find the position or no selection exists. Note that we can't
+ *     reliably tell the difference between an element that has no selection and
+ *     one where it starts at 0.
+ */
+goog.dom.selection.getStart = function(textfield) {
+  return goog.dom.selection.getEndPoints_(textfield, true)[0];
+};
+
+
+/**
+ * Returns the start and end points of the selection within a textarea in IE.
+ * IE treats newline characters as \r\n characters, and we need to check for
+ * these characters at the edge of our selection, to ensure that we return the
+ * right cursor position.
+ * @param {TextRange} range Complete range object, e.g., "Hello\r\n".
+ * @param {TextRange} selRange Selected range object.
+ * @param {boolean} getOnlyStart Value indicating if only start
+ *     cursor position is to be returned. In IE, obtaining the end position
+ *     involves extra work, hence we have this parameter for calls which need
+ *     only start position.
+ * @return {!Array<number>} An array with the start and end positions where the
+ *     selection starts and ends or [0,0] if it was unable to find the
+ *     positions or no selection exists. Note that we can't reliably tell the
+ *     difference between an element that has no selection and one where
+ *     it starts and ends at 0. If getOnlyStart was true, we return
+ *     -1 as end offset.
+ * @private
+ */
+goog.dom.selection.getEndPointsTextareaIe_ = function(
+    range, selRange, getOnlyStart) {
+  // Create a duplicate of the selected range object to perform our actions
+  // against. Example of selectionRange = "" (assuming that the cursor is
+  // just after the \r\n combination)
+  var selectionRange = selRange.duplicate();
+
+  // Text before the selection start, e.g.,"Hello" (notice how range.text
+  // excludes the \r\n sequence)
+  var beforeSelectionText = range.text;
+  // Text before the selection start, e.g., "Hello" (this will later include
+  // the \r\n sequences also)
+  var untrimmedBeforeSelectionText = beforeSelectionText;
+  // Text within the selection , e.g. "" assuming that the cursor is just after
+  // the \r\n combination.
+  var selectionText = selectionRange.text;
+  // Text within the selection, e.g.,  "" (this will later include the \r\n
+  // sequences also)
+  var untrimmedSelectionText = selectionText;
+
+  // Boolean indicating whether we are done dealing with the text before the
+  // selection's beginning.
+  var isRangeEndTrimmed = false;
+  // Go over the range until it becomes a 0-lengthed range or until the range
+  // text starts changing when we move the end back by one character.
+  // If after moving the end back by one character, the text remains the same,
+  // then we need to add a "\r\n" at the end to get the actual text.
+  while (!isRangeEndTrimmed) {
+    if (range.compareEndPoints('StartToEnd', range) == 0) {
+      isRangeEndTrimmed = true;
+    } else {
+      range.moveEnd('character', -1);
+      if (range.text == beforeSelectionText) {
+        // If the start position of the cursor was after a \r\n string,
+        // we would skip over it in one go with the moveEnd call, but
+        // range.text will still show "Hello" (because of the IE range.text
+        // bug) - this implies that we should add a \r\n to our
+        // untrimmedBeforeSelectionText string.
+        untrimmedBeforeSelectionText += '\r\n';
+      } else {
+        isRangeEndTrimmed = true;
+      }
+    }
+  }
+
+  if (getOnlyStart) {
+    // We return -1 as end, since the caller is only interested in the start
+    // value.
+    return [untrimmedBeforeSelectionText.length, -1];
+  }
+  // Boolean indicating whether we are done dealing with the text inside the
+  // selection.
+  var isSelectionRangeEndTrimmed = false;
+  // Go over the selected range until it becomes a 0-lengthed range or until
+  // the range text starts changing when we move the end back by one character.
+  // If after moving the end back by one character, the text remains the same,
+  // then we need to add a "\r\n" at the end to get the actual text.
+  while (!isSelectionRangeEndTrimmed) {
+    if (selectionRange.compareEndPoints('StartToEnd', selectionRange) == 0) {
+      isSelectionRangeEndTrimmed = true;
+    } else {
+      selectionRange.moveEnd('character', -1);
+      if (selectionRange.text == selectionText) {
+        // If the selection was not empty, and the end point of the selection
+        // was just after a \r\n, we would have skipped it in one go with the
+        // moveEnd call, and this implies that we should add a \r\n to the
+        // untrimmedSelectionText string.
+        untrimmedSelectionText += '\r\n';
+      } else {
+        isSelectionRangeEndTrimmed = true;
+      }
+    }
+  }
+  return [
+    untrimmedBeforeSelectionText.length,
+    untrimmedBeforeSelectionText.length + untrimmedSelectionText.length];
+};
+
+
+/**
+ * Returns the start and end points of the selection inside a textarea or a
+ * text input.
+ * @param {Element} textfield A textarea or text input.
+ * @return {!Array<number>} An array with the start and end positions where the
+ *     selection starts and ends or [0,0] if it was unable to find the
+ *     positions or no selection exists. Note that we can't reliably tell the
+ *     difference between an element that has no selection and one where
+ *     it starts and ends at 0.
+ */
+goog.dom.selection.getEndPoints = function(textfield) {
+  return goog.dom.selection.getEndPoints_(textfield, false);
+};
+
+
+/**
+ * Returns the start and end points of the selection inside a textarea or a
+ * text input.
+ * @param {Element} textfield A textarea or text input.
+ * @param {boolean} getOnlyStart Value indicating if only start
+ *     cursor position is to be returned. In IE, obtaining the end position
+ *     involves extra work, hence we have this parameter. In FF, there is not
+ *     much extra effort involved.
+ * @return {!Array<number>} An array with the start and end positions where the
+ *     selection starts and ends or [0,0] if it was unable to find the
+ *     positions or no selection exists. Note that we can't reliably tell the
+ *     difference between an element that has no selection and one where
+ *     it starts and ends at 0. If getOnlyStart was true, we return
+ *     -1 as end offset.
+ * @private
+ */
+goog.dom.selection.getEndPoints_ = function(textfield, getOnlyStart) {
+  var startPos = 0;
+  var endPos = 0;
+  if (goog.dom.selection.useSelectionProperties_(textfield)) {
+    startPos = textfield.selectionStart;
+    endPos = getOnlyStart ? -1 : textfield.selectionEnd;
+  } else if (goog.userAgent.IE) {
+    var tmp = goog.dom.selection.getRangeIe_(textfield);
+    var range = tmp[0];
+    var selectionRange = tmp[1];
+
+    if (range.inRange(selectionRange)) {
+      range.setEndPoint('EndToStart', selectionRange);
+      if (textfield.type == goog.dom.InputType.TEXTAREA) {
+        return goog.dom.selection.getEndPointsTextareaIe_(
+            range, selectionRange, getOnlyStart);
+      }
+      startPos = range.text.length;
+      if (!getOnlyStart) {
+        endPos = range.text.length + selectionRange.text.length;
+      } else {
+        endPos = -1;  // caller did not ask for end position
+      }
+    }
+  }
+  return [startPos, endPos];
+};
+
+
+/**
+ * Sets the place where the selection should end inside a text area or a text
+ * input
+ * @param {Element} textfield A textarea or text input.
+ * @param {number} pos The position to end the selection at.
+ */
+goog.dom.selection.setEnd = function(textfield, pos) {
+  if (goog.dom.selection.useSelectionProperties_(textfield)) {
+    textfield.selectionEnd = pos;
+  } else if (goog.userAgent.IE) {
+    var tmp = goog.dom.selection.getRangeIe_(textfield);
+    var range = tmp[0];
+    var selectionRange = tmp[1];
+
+    if (range.inRange(selectionRange)) {
+      // Both the current position and the start cursor position need
+      // to be canonicalized to take care of possible \r\n miscounts.
+      pos = goog.dom.selection.canonicalizePositionIe_(textfield, pos);
+      var startCursorPos = goog.dom.selection.canonicalizePositionIe_(
+          textfield, goog.dom.selection.getStart(textfield));
+
+      selectionRange.collapse(true);
+      selectionRange.moveEnd('character', pos - startCursorPos);
+      selectionRange.select();
+    }
+  }
+};
+
+
+/**
+ * Returns the place where the selection ends inside a textarea or a text input
+ * @param {Element} textfield A textarea or text input.
+ * @return {number} The position where the selection ends or 0 if it was
+ *     unable to find the position or no selection exists.
+ */
+goog.dom.selection.getEnd = function(textfield) {
+  return goog.dom.selection.getEndPoints_(textfield, false)[1];
+};
+
+
+/**
+ * Sets the cursor position within a textfield.
+ * @param {Element} textfield A textarea or text input.
+ * @param {number} pos The position within the text field.
+ */
+goog.dom.selection.setCursorPosition = function(textfield, pos) {
+  if (goog.dom.selection.useSelectionProperties_(textfield)) {
+    // Mozilla directly supports this
+    textfield.selectionStart = pos;
+    textfield.selectionEnd = pos;
+
+  } else if (goog.userAgent.IE) {
+    pos = goog.dom.selection.canonicalizePositionIe_(textfield, pos);
+
+    // IE has textranges. A textfield's textrange encompasses the
+    // entire textfield's text by default
+    var sel = textfield.createTextRange();
+
+    sel.collapse(true);
+    sel.move('character', pos);
+    sel.select();
+  }
+};
+
+
+/**
+ * Sets the selected text inside a textarea or a text input
+ * @param {Element} textfield A textarea or text input.
+ * @param {string} text The text to change the selection to.
+ */
+goog.dom.selection.setText = function(textfield, text) {
+  if (goog.dom.selection.useSelectionProperties_(textfield)) {
+    var value = textfield.value;
+    var oldSelectionStart = textfield.selectionStart;
+    var before = value.substr(0, oldSelectionStart);
+    var after = value.substr(textfield.selectionEnd);
+    textfield.value = before + text + after;
+    textfield.selectionStart = oldSelectionStart;
+    textfield.selectionEnd = oldSelectionStart + text.length;
+  } else if (goog.userAgent.IE) {
+    var tmp = goog.dom.selection.getRangeIe_(textfield);
+    var range = tmp[0];
+    var selectionRange = tmp[1];
+
+    if (!range.inRange(selectionRange)) {
+      return;
+    }
+    // When we set the selection text the selection range is collapsed to the
+    // end. We therefore duplicate the current selection so we know where it
+    // started. Once we've set the selection text we move the start of the
+    // selection range to the old start
+    var range2 = selectionRange.duplicate();
+    selectionRange.text = text;
+    selectionRange.setEndPoint('StartToStart', range2);
+    selectionRange.select();
+  } else {
+    throw Error('Cannot set the selection end');
+  }
+};
+
+
+/**
+ * Returns the selected text inside a textarea or a text input
+ * @param {Element} textfield A textarea or text input.
+ * @return {string} The selected text.
+ */
+goog.dom.selection.getText = function(textfield) {
+  if (goog.dom.selection.useSelectionProperties_(textfield)) {
+    var s = textfield.value;
+    return s.substring(textfield.selectionStart, textfield.selectionEnd);
+  }
+
+  if (goog.userAgent.IE) {
+    var tmp = goog.dom.selection.getRangeIe_(textfield);
+    var range = tmp[0];
+    var selectionRange = tmp[1];
+
+    if (!range.inRange(selectionRange)) {
+      return '';
+    } else if (textfield.type == goog.dom.InputType.TEXTAREA) {
+      return goog.dom.selection.getSelectionRangeText_(selectionRange);
+    }
+    return selectionRange.text;
+  }
+
+  throw Error('Cannot get the selection text');
+};
+
+
+/**
+ * Returns the selected text within a textarea in IE.
+ * IE treats newline characters as \r\n characters, and we need to check for
+ * these characters at the edge of our selection, to ensure that we return the
+ * right string.
+ * @param {TextRange} selRange Selected range object.
+ * @return {string} Selected text in the textarea.
+ * @private
+ */
+goog.dom.selection.getSelectionRangeText_ = function(selRange) {
+  // Create a duplicate of the selected range object to perform our actions
+  // against. Suppose the text in the textarea is "Hello\r\nWorld" and the
+  // selection encompasses the "o\r\n" bit, initial selectionRange will be "o"
+  // (assuming that the cursor is just after the \r\n combination)
+  var selectionRange = selRange.duplicate();
+
+  // Text within the selection , e.g. "o" assuming that the cursor is just after
+  // the \r\n combination.
+  var selectionText = selectionRange.text;
+  // Text within the selection, e.g.,  "o" (this will later include the \r\n
+  // sequences also)
+  var untrimmedSelectionText = selectionText;
+
+  // Boolean indicating whether we are done dealing with the text inside the
+  // selection.
+  var isSelectionRangeEndTrimmed = false;
+  // Go over the selected range until it becomes a 0-lengthed range or until
+  // the range text starts changing when we move the end back by one character.
+  // If after moving the end back by one character, the text remains the same,
+  // then we need to add a "\r\n" at the end to get the actual text.
+  while (!isSelectionRangeEndTrimmed) {
+    if (selectionRange.compareEndPoints('StartToEnd', selectionRange) == 0) {
+      isSelectionRangeEndTrimmed = true;
+    } else {
+      selectionRange.moveEnd('character', -1);
+      if (selectionRange.text == selectionText) {
+        // If the selection was not empty, and the end point of the selection
+        // was just after a \r\n, we would have skipped it in one go with the
+        // moveEnd call, and this implies that we should add a \r\n to the
+        // untrimmedSelectionText string.
+        untrimmedSelectionText += '\r\n';
+      } else {
+        isSelectionRangeEndTrimmed = true;
+      }
+    }
+  }
+  return untrimmedSelectionText;
+};
+
+
+/**
+ * Helper function for returning the range for an object as well as the
+ * selection range
+ * @private
+ * @param {Element} el The element to get the range for.
+ * @return {!Array<TextRange>} Range of object and selection range in two
+ *     element array.
+ */
+goog.dom.selection.getRangeIe_ = function(el) {
+  var doc = el.ownerDocument || el.document;
+
+  var selectionRange = doc.selection.createRange();
+  // el.createTextRange() doesn't work on textareas
+  var range;
+
+  if (el.type == goog.dom.InputType.TEXTAREA) {
+    range = doc.body.createTextRange();
+    range.moveToElementText(el);
+  } else {
+    range = el.createTextRange();
+  }
+
+  return [range, selectionRange];
+};
+
+
+/**
+ * Helper function for canonicalizing a position inside a textfield in IE.
+ * Deals with the issue that \r\n counts as 2 characters, but
+ * move('character', n) passes over both characters in one move.
+ * @private
+ * @param {Element} textfield The text element.
+ * @param {number} pos The position desired in that element.
+ * @return {number} The canonicalized position that will work properly with
+ *     move('character', pos).
+ */
+goog.dom.selection.canonicalizePositionIe_ = function(textfield, pos) {
+  if (textfield.type == goog.dom.InputType.TEXTAREA) {
+    // We do this only for textarea because it is the only one which can
+    // have a \r\n (input cannot have this).
+    var value = textfield.value.substring(0, pos);
+    pos = goog.string.canonicalizeNewlines(value).length;
+  }
+  return pos;
+};
+
+
+/**
+ * Helper function to determine whether it's okay to use
+ * selectionStart/selectionEnd.
+ *
+ * @param {Element} el The element to check for.
+ * @return {boolean} Whether it's okay to use the selectionStart and
+ *     selectionEnd properties on {@code el}.
+ * @private
+ */
+goog.dom.selection.useSelectionProperties_ = function(el) {
+  try {
+    return typeof el.selectionStart == 'number';
+  } catch (e) {
+    // Firefox throws an exception if you try to access selectionStart
+    // on an element with display: none.
+    return false;
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/tagiterator.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/tagiterator.js b/externs/GCL/externs/goog/dom/tagiterator.js
new file mode 100644
index 0000000..4b6354c
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/tagiterator.js
@@ -0,0 +1,360 @@
+// Copyright 2008 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 Iterator subclass for DOM tree traversal.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.TagIterator');
+goog.provide('goog.dom.TagWalkType');
+
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.iter.Iterator');
+goog.require('goog.iter.StopIteration');
+
+
+/**
+ * There are three types of token:
+ *  <ol>
+ *    <li>{@code START_TAG} - The beginning of a tag.
+ *    <li>{@code OTHER} - Any non-element node position.
+ *    <li>{@code END_TAG} - The end of a tag.
+ *  </ol>
+ * Users of this enumeration can rely on {@code START_TAG + END_TAG = 0} and
+ * that {@code OTHER = 0}.
+ *
+ * @enum {number}
+ */
+goog.dom.TagWalkType = {
+  START_TAG: 1,
+  OTHER: 0,
+  END_TAG: -1
+};
+
+
+
+/**
+ * A DOM tree traversal iterator.
+ *
+ * Starting with the given node, the iterator walks the DOM in order, reporting
+ * events for the start and end of Elements, and the presence of text nodes. For
+ * example:
+ *
+ * <pre>
+ * &lt;div&gt;1&lt;span&gt;2&lt;/span&gt;3&lt;/div&gt;
+ * </pre>
+ *
+ * Will return the following nodes:
+ *
+ * <code>[div, 1, span, 2, span, 3, div]</code>
+ *
+ * With the following states:
+ *
+ * <code>[START, OTHER, START, OTHER, END, OTHER, END]</code>
+ *
+ * And the following depths
+ *
+ * <code>[1, 1, 2, 2, 1, 1, 0]</code>
+ *
+ * Imagining <code>|</code> represents iterator position, the traversal stops at
+ * each of the following locations:
+ *
+ * <pre>
+ * &lt;div&gt;|1|&lt;span&gt;|2|&lt;/span&gt;|3|&lt;/div&gt;|
+ * </pre>
+ *
+ * The iterator can also be used in reverse mode, which will return the nodes
+ * and states in the opposite order.  The depths will be slightly different
+ * since, like in normal mode, the depth is computed *after* the given node.
+ *
+ * Lastly, it is possible to create an iterator that is unconstrained, meaning
+ * that it will continue iterating until the end of the document instead of
+ * until exiting the start node.
+ *
+ * @param {Node=} opt_node The start node.  If unspecified or null, defaults to
+ *     an empty iterator.
+ * @param {boolean=} opt_reversed Whether to traverse the tree in reverse.
+ * @param {boolean=} opt_unconstrained Whether the iterator is not constrained
+ *     to the starting node and its children.
+ * @param {goog.dom.TagWalkType?=} opt_tagType The type of the position.
+ *     Defaults to the start of the given node for forward iterators, and
+ *     the end of the node for reverse iterators.
+ * @param {number=} opt_depth The starting tree depth.
+ * @constructor
+ * @extends {goog.iter.Iterator<Node>}
+ */
+goog.dom.TagIterator = function(opt_node, opt_reversed,
+    opt_unconstrained, opt_tagType, opt_depth) {
+  /**
+   * Whether the node iterator is moving in reverse.
+   * @type {boolean}
+   */
+  this.reversed = !!opt_reversed;
+
+  /**
+   * The node this position is located on.
+   * @type {Node}
+   */
+  this.node = null;
+
+  /**
+   * The type of this position.
+   * @type {goog.dom.TagWalkType}
+   */
+  this.tagType = goog.dom.TagWalkType.OTHER;
+
+  /**
+   * The tree depth of this position relative to where the iterator started.
+   * The depth is considered to be the tree depth just past the current node,
+   * so if an iterator is at position
+   * <pre>
+   *     <div>|</div>
+   * </pre>
+   * (i.e. the node is the div and the type is START_TAG) its depth will be 1.
+   * @type {number}
+   */
+  this.depth;
+
+  /**
+   * Whether iteration has started.
+   * @private {boolean}
+   */
+  this.started_ = false;
+
+  /**
+   * Whether the iterator is constrained to the starting node and its children.
+   * @type {boolean}
+   */
+  this.constrained = !opt_unconstrained;
+
+  if (opt_node) {
+    this.setPosition(opt_node, opt_tagType);
+  }
+  this.depth = opt_depth != undefined ? opt_depth : this.tagType || 0;
+  if (this.reversed) {
+    this.depth *= -1;
+  }
+};
+goog.inherits(goog.dom.TagIterator, goog.iter.Iterator);
+
+
+/**
+ * Set the position of the iterator.  Overwrite the tree node and the position
+ * type which can be one of the {@link goog.dom.TagWalkType} token types.
+ * Only overwrites the tree depth when the parameter is specified.
+ * @param {Node} node The node to set the position to.
+ * @param {goog.dom.TagWalkType?=} opt_tagType The type of the position
+ *     Defaults to the start of the given node.
+ * @param {number=} opt_depth The tree depth.
+ */
+goog.dom.TagIterator.prototype.setPosition = function(node,
+    opt_tagType, opt_depth) {
+  this.node = node;
+
+  if (node) {
+    if (goog.isNumber(opt_tagType)) {
+      this.tagType = opt_tagType;
+    } else {
+      // Auto-determine the proper type
+      this.tagType = this.node.nodeType != goog.dom.NodeType.ELEMENT ?
+          goog.dom.TagWalkType.OTHER :
+          this.reversed ? goog.dom.TagWalkType.END_TAG :
+          goog.dom.TagWalkType.START_TAG;
+    }
+  }
+
+  if (goog.isNumber(opt_depth)) {
+    this.depth = opt_depth;
+  }
+};
+
+
+/**
+ * Replace this iterator's values with values from another. The two iterators
+ * must be of the same type.
+ * @param {goog.dom.TagIterator} other The iterator to copy.
+ * @protected
+ */
+goog.dom.TagIterator.prototype.copyFrom = function(other) {
+  this.node = other.node;
+  this.tagType = other.tagType;
+  this.depth = other.depth;
+  this.reversed = other.reversed;
+  this.constrained = other.constrained;
+};
+
+
+/**
+ * @return {!goog.dom.TagIterator} A copy of this iterator.
+ */
+goog.dom.TagIterator.prototype.clone = function() {
+  return new goog.dom.TagIterator(this.node, this.reversed,
+      !this.constrained, this.tagType, this.depth);
+};
+
+
+/**
+ * Skip the current tag.
+ */
+goog.dom.TagIterator.prototype.skipTag = function() {
+  var check = this.reversed ? goog.dom.TagWalkType.END_TAG :
+              goog.dom.TagWalkType.START_TAG;
+  if (this.tagType == check) {
+    this.tagType = /** @type {goog.dom.TagWalkType} */ (check * -1);
+    this.depth += this.tagType * (this.reversed ? -1 : 1);
+  }
+};
+
+
+/**
+ * Restart the current tag.
+ */
+goog.dom.TagIterator.prototype.restartTag = function() {
+  var check = this.reversed ? goog.dom.TagWalkType.START_TAG :
+              goog.dom.TagWalkType.END_TAG;
+  if (this.tagType == check) {
+    this.tagType = /** @type {goog.dom.TagWalkType} */ (check * -1);
+    this.depth += this.tagType * (this.reversed ? -1 : 1);
+  }
+};
+
+
+/**
+ * Move to the next position in the DOM tree.
+ * @return {Node} Returns the next node, or throws a goog.iter.StopIteration
+ *     exception if the end of the iterator's range has been reached.
+ * @override
+ */
+goog.dom.TagIterator.prototype.next = function() {
+  var node;
+
+  if (this.started_) {
+    if (!this.node || this.constrained && this.depth == 0) {
+      throw goog.iter.StopIteration;
+    }
+    node = this.node;
+
+    var startType = this.reversed ? goog.dom.TagWalkType.END_TAG :
+        goog.dom.TagWalkType.START_TAG;
+
+    if (this.tagType == startType) {
+      // If we have entered the tag, test if there are any children to move to.
+      var child = this.reversed ? node.lastChild : node.firstChild;
+      if (child) {
+        this.setPosition(child);
+      } else {
+        // If not, move on to exiting this tag.
+        this.setPosition(node,
+            /** @type {goog.dom.TagWalkType} */ (startType * -1));
+      }
+    } else {
+      var sibling = this.reversed ? node.previousSibling : node.nextSibling;
+      if (sibling) {
+        // Try to move to the next node.
+        this.setPosition(sibling);
+      } else {
+        // If no such node exists, exit our parent.
+        this.setPosition(node.parentNode,
+            /** @type {goog.dom.TagWalkType} */ (startType * -1));
+      }
+    }
+
+    this.depth += this.tagType * (this.reversed ? -1 : 1);
+  } else {
+    this.started_ = true;
+  }
+
+  // Check the new position for being last, and return it if it's not.
+  node = this.node;
+  if (!this.node) {
+    throw goog.iter.StopIteration;
+  }
+  return node;
+};
+
+
+/**
+ * @return {boolean} Whether next has ever been called on this iterator.
+ * @protected
+ */
+goog.dom.TagIterator.prototype.isStarted = function() {
+  return this.started_;
+};
+
+
+/**
+ * @return {boolean} Whether this iterator's position is a start tag position.
+ */
+goog.dom.TagIterator.prototype.isStartTag = function() {
+  return this.tagType == goog.dom.TagWalkType.START_TAG;
+};
+
+
+/**
+ * @return {boolean} Whether this iterator's position is an end tag position.
+ */
+goog.dom.TagIterator.prototype.isEndTag = function() {
+  return this.tagType == goog.dom.TagWalkType.END_TAG;
+};
+
+
+/**
+ * @return {boolean} Whether this iterator's position is not at an element node.
+ */
+goog.dom.TagIterator.prototype.isNonElement = function() {
+  return this.tagType == goog.dom.TagWalkType.OTHER;
+};
+
+
+/**
+ * Test if two iterators are at the same position - i.e. if the node and tagType
+ * is the same.  This will still return true if the two iterators are moving in
+ * opposite directions or have different constraints.
+ * @param {goog.dom.TagIterator} other The iterator to compare to.
+ * @return {boolean} Whether the two iterators are at the same position.
+ */
+goog.dom.TagIterator.prototype.equals = function(other) {
+  // Nodes must be equal, and we must either have reached the end of our tree
+  // or be at the same position.
+  return other.node == this.node && (!this.node ||
+      other.tagType == this.tagType);
+};
+
+
+/**
+ * Replace the current node with the list of nodes. Reset the iterator so that
+ * it visits the first of the nodes next.
+ * @param {...Object} var_args A list of nodes to replace the current node with.
+ *     If the first argument is array-like, it will be used, otherwise all the
+ *     arguments are assumed to be nodes.
+ */
+goog.dom.TagIterator.prototype.splice = function(var_args) {
+  // Reset the iterator so that it iterates over the first replacement node in
+  // the arguments on the next iteration.
+  var node = this.node;
+  this.restartTag();
+  this.reversed = !this.reversed;
+  goog.dom.TagIterator.prototype.next.call(this);
+  this.reversed = !this.reversed;
+
+  // Replace the node with the arguments.
+  var arr = goog.isArrayLike(arguments[0]) ? arguments[0] : arguments;
+  for (var i = arr.length - 1; i >= 0; i--) {
+    goog.dom.insertSiblingAfter(arr[i], node);
+  }
+  goog.dom.removeNode(node);
+};


[16/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/format/format.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/format/format.js b/externs/GCL/externs/goog/format/format.js
new file mode 100644
index 0000000..f78067d
--- /dev/null
+++ b/externs/GCL/externs/goog/format/format.js
@@ -0,0 +1,502 @@
+// 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 Provides utility functions for formatting strings, numbers etc.
+ *
+ */
+
+goog.provide('goog.format');
+
+goog.require('goog.i18n.GraphemeBreak');
+goog.require('goog.string');
+goog.require('goog.userAgent');
+
+
+/**
+ * Formats a number of bytes in human readable form.
+ * 54, 450K, 1.3M, 5G etc.
+ * @param {number} bytes The number of bytes to show.
+ * @param {number=} opt_decimals The number of decimals to use.  Defaults to 2.
+ * @return {string} The human readable form of the byte size.
+ */
+goog.format.fileSize = function(bytes, opt_decimals) {
+  return goog.format.numBytesToString(bytes, opt_decimals, false);
+};
+
+
+/**
+ * Checks whether string value containing scaling units (K, M, G, T, P, m,
+ * u, n) can be converted to a number.
+ *
+ * Where there is a decimal, there must be a digit to the left of the
+ * decimal point.
+ *
+ * Negative numbers are valid.
+ *
+ * Examples:
+ *   0, 1, 1.0, 10.4K, 2.3M, -0.3P, 1.2m
+ *
+ * @param {string} val String value to check.
+ * @return {boolean} True if string could be converted to a numeric value.
+ */
+goog.format.isConvertableScaledNumber = function(val) {
+  return goog.format.SCALED_NUMERIC_RE_.test(val);
+};
+
+
+/**
+ * Converts a string to numeric value, taking into account the units.
+ * If string ends in 'B', use binary conversion.
+ * @param {string} stringValue String to be converted to numeric value.
+ * @return {number} Numeric value for string.
+ */
+goog.format.stringToNumericValue = function(stringValue) {
+  if (goog.string.endsWith(stringValue, 'B')) {
+    return goog.format.stringToNumericValue_(
+        stringValue, goog.format.NUMERIC_SCALES_BINARY_);
+  }
+  return goog.format.stringToNumericValue_(
+      stringValue, goog.format.NUMERIC_SCALES_SI_);
+};
+
+
+/**
+ * Converts a string to number of bytes, taking into account the units.
+ * Binary conversion.
+ * @param {string} stringValue String to be converted to numeric value.
+ * @return {number} Numeric value for string.
+ */
+goog.format.stringToNumBytes = function(stringValue) {
+  return goog.format.stringToNumericValue_(
+      stringValue, goog.format.NUMERIC_SCALES_BINARY_);
+};
+
+
+/**
+ * Converts a numeric value to string representation. SI conversion.
+ * @param {number} val Value to be converted.
+ * @param {number=} opt_decimals The number of decimals to use.  Defaults to 2.
+ * @return {string} String representation of number.
+ */
+goog.format.numericValueToString = function(val, opt_decimals) {
+  return goog.format.numericValueToString_(
+      val, goog.format.NUMERIC_SCALES_SI_, opt_decimals);
+};
+
+
+/**
+ * Converts number of bytes to string representation. Binary conversion.
+ * Default is to return the additional 'B' suffix, e.g. '10.5KB' to minimize
+ * confusion with counts that are scaled by powers of 1000.
+ * @param {number} val Value to be converted.
+ * @param {number=} opt_decimals The number of decimals to use.  Defaults to 2.
+ * @param {boolean=} opt_suffix If true, include trailing 'B' in returned
+ *     string.  Default is true.
+ * @param {boolean=} opt_useSeparator If true, number and scale will be
+ *     separated by a no break space. Default is false.
+ * @return {string} String representation of number of bytes.
+ */
+goog.format.numBytesToString = function(val, opt_decimals, opt_suffix,
+    opt_useSeparator) {
+  var suffix = '';
+  if (!goog.isDef(opt_suffix) || opt_suffix) {
+    suffix = 'B';
+  }
+  return goog.format.numericValueToString_(
+      val, goog.format.NUMERIC_SCALES_BINARY_, opt_decimals, suffix,
+      opt_useSeparator);
+};
+
+
+/**
+ * Converts a string to numeric value, taking into account the units.
+ * @param {string} stringValue String to be converted to numeric value.
+ * @param {Object} conversion Dictionary of conversion scales.
+ * @return {number} Numeric value for string.  If it cannot be converted,
+ *    returns NaN.
+ * @private
+ */
+goog.format.stringToNumericValue_ = function(stringValue, conversion) {
+  var match = stringValue.match(goog.format.SCALED_NUMERIC_RE_);
+  if (!match) {
+    return NaN;
+  }
+  var val = match[1] * conversion[match[2]];
+  return val;
+};
+
+
+/**
+ * Converts a numeric value to string, using specified conversion
+ * scales.
+ * @param {number} val Value to be converted.
+ * @param {Object} conversion Dictionary of scaling factors.
+ * @param {number=} opt_decimals The number of decimals to use.  Default is 2.
+ * @param {string=} opt_suffix Optional suffix to append.
+ * @param {boolean=} opt_useSeparator If true, number and scale will be
+ *     separated by a space. Default is false.
+ * @return {string} The human readable form of the byte size.
+ * @private
+ */
+goog.format.numericValueToString_ = function(val, conversion,
+    opt_decimals, opt_suffix, opt_useSeparator) {
+  var prefixes = goog.format.NUMERIC_SCALE_PREFIXES_;
+  var orig_val = val;
+  var symbol = '';
+  var separator = '';
+  var scale = 1;
+  if (val < 0) {
+    val = -val;
+  }
+  for (var i = 0; i < prefixes.length; i++) {
+    var unit = prefixes[i];
+    scale = conversion[unit];
+    if (val >= scale || (scale <= 1 && val > 0.1 * scale)) {
+      // Treat values less than 1 differently, allowing 0.5 to be "0.5" rather
+      // than "500m"
+      symbol = unit;
+      break;
+    }
+  }
+  if (!symbol) {
+    scale = 1;
+  } else {
+    if (opt_suffix) {
+      symbol += opt_suffix;
+    }
+    if (opt_useSeparator) {
+      separator = ' ';
+    }
+  }
+  var ex = Math.pow(10, goog.isDef(opt_decimals) ? opt_decimals : 2);
+  return Math.round(orig_val / scale * ex) / ex + separator + symbol;
+};
+
+
+/**
+ * Regular expression for detecting scaling units, such as K, M, G, etc. for
+ * converting a string representation to a numeric value.
+ *
+ * Also allow 'k' to be aliased to 'K'.  These could be used for SI (powers
+ * of 1000) or Binary (powers of 1024) conversions.
+ *
+ * Also allow final 'B' to be interpreted as byte-count, implicitly triggering
+ * binary conversion (e.g., '10.2MB').
+ *
+ * @type {RegExp}
+ * @private
+ */
+goog.format.SCALED_NUMERIC_RE_ = /^([-]?\d+\.?\d*)([K,M,G,T,P,k,m,u,n]?)[B]?$/;
+
+
+/**
+ * Ordered list of scaling prefixes in decreasing order.
+ * @private {Array<string>}
+ */
+goog.format.NUMERIC_SCALE_PREFIXES_ = [
+  'P', 'T', 'G', 'M', 'K', '', 'm', 'u', 'n'
+];
+
+
+/**
+ * Scaling factors for conversion of numeric value to string.  SI conversion.
+ * @type {Object}
+ * @private
+ */
+goog.format.NUMERIC_SCALES_SI_ = {
+  '': 1,
+  'n': 1e-9,
+  'u': 1e-6,
+  'm': 1e-3,
+  'k': 1e3,
+  'K': 1e3,
+  'M': 1e6,
+  'G': 1e9,
+  'T': 1e12,
+  'P': 1e15
+};
+
+
+/**
+ * Scaling factors for conversion of numeric value to string.  Binary
+ * conversion.
+ * @type {Object}
+ * @private
+ */
+goog.format.NUMERIC_SCALES_BINARY_ = {
+  '': 1,
+  'n': Math.pow(1024, -3),
+  'u': Math.pow(1024, -2),
+  'm': 1.0 / 1024,
+  'k': 1024,
+  'K': 1024,
+  'M': Math.pow(1024, 2),
+  'G': Math.pow(1024, 3),
+  'T': Math.pow(1024, 4),
+  'P': Math.pow(1024, 5)
+};
+
+
+/**
+ * First Unicode code point that has the Mark property.
+ * @type {number}
+ * @private
+ */
+goog.format.FIRST_GRAPHEME_EXTEND_ = 0x300;
+
+
+/**
+ * Returns true if and only if given character should be treated as a breaking
+ * space. All ASCII control characters, the main Unicode range of spacing
+ * characters (U+2000 to U+200B inclusive except for U+2007), and several other
+ * Unicode space characters are treated as breaking spaces.
+ * @param {number} charCode The character code under consideration.
+ * @return {boolean} True if the character is a breaking space.
+ * @private
+ */
+goog.format.isTreatedAsBreakingSpace_ = function(charCode) {
+  return (charCode <= goog.format.WbrToken_.SPACE) ||
+         (charCode >= 0x1000 &&
+          ((charCode >= 0x2000 && charCode <= 0x2006) ||
+           (charCode >= 0x2008 && charCode <= 0x200B) ||
+           charCode == 0x1680 ||
+           charCode == 0x180E ||
+           charCode == 0x2028 ||
+           charCode == 0x2029 ||
+           charCode == 0x205f ||
+           charCode == 0x3000));
+};
+
+
+/**
+ * Returns true if and only if given character is an invisible formatting
+ * character.
+ * @param {number} charCode The character code under consideration.
+ * @return {boolean} True if the character is an invisible formatting character.
+ * @private
+ */
+goog.format.isInvisibleFormattingCharacter_ = function(charCode) {
+  // See: http://unicode.org/charts/PDF/U2000.pdf
+  return (charCode >= 0x200C && charCode <= 0x200F) ||
+         (charCode >= 0x202A && charCode <= 0x202E);
+};
+
+
+/**
+ * Inserts word breaks into an HTML string at a given interval.  The counter is
+ * reset if a space or a character which behaves like a space is encountered,
+ * but it isn't incremented if an invisible formatting character is encountered.
+ * WBRs aren't inserted into HTML tags or entities.  Entities count towards the
+ * character count, HTML tags do not.
+ *
+ * With common strings aliased, objects allocations are constant based on the
+ * length of the string: N + 3. This guarantee does not hold if the string
+ * contains an element >= U+0300 and hasGraphemeBreak is non-trivial.
+ *
+ * @param {string} str HTML to insert word breaks into.
+ * @param {function(number, number, boolean): boolean} hasGraphemeBreak A
+ *     function determining if there is a grapheme break between two characters,
+ *     in the same signature as goog.i18n.GraphemeBreak.hasGraphemeBreak.
+ * @param {number=} opt_maxlen Maximum length after which to ensure
+ *     there is a break.  Default is 10 characters.
+ * @return {string} The string including word breaks.
+ * @private
+ */
+goog.format.insertWordBreaksGeneric_ = function(str, hasGraphemeBreak,
+    opt_maxlen) {
+  var maxlen = opt_maxlen || 10;
+  if (maxlen > str.length) return str;
+
+  var rv = [];
+  var n = 0; // The length of the current token
+
+  // This will contain the ampersand or less-than character if one of the
+  // two has been seen; otherwise, the value is zero.
+  var nestingCharCode = 0;
+
+  // First character position from input string that has not been outputted.
+  var lastDumpPosition = 0;
+
+  var charCode = 0;
+  for (var i = 0; i < str.length; i++) {
+    // Using charCodeAt versus charAt avoids allocating new string objects.
+    var lastCharCode = charCode;
+    charCode = str.charCodeAt(i);
+
+    // Don't add a WBR before characters that might be grapheme extending.
+    var isPotentiallyGraphemeExtending =
+        charCode >= goog.format.FIRST_GRAPHEME_EXTEND_ &&
+        !hasGraphemeBreak(lastCharCode, charCode, true);
+
+    // Don't add a WBR at the end of a word. For the purposes of determining
+    // work breaks, all ASCII control characters and some commonly encountered
+    // Unicode spacing characters are treated as breaking spaces.
+    if (n >= maxlen &&
+        !goog.format.isTreatedAsBreakingSpace_(charCode) &&
+        !isPotentiallyGraphemeExtending) {
+      // Flush everything seen so far, and append a word break.
+      rv.push(str.substring(lastDumpPosition, i), goog.format.WORD_BREAK_HTML);
+      lastDumpPosition = i;
+      n = 0;
+    }
+
+    if (!nestingCharCode) {
+      // Not currently within an HTML tag or entity
+
+      if (charCode == goog.format.WbrToken_.LT ||
+          charCode == goog.format.WbrToken_.AMP) {
+
+        // Entering an HTML Entity '&' or open tag '<'
+        nestingCharCode = charCode;
+      } else if (goog.format.isTreatedAsBreakingSpace_(charCode)) {
+
+        // A space or control character -- reset the token length
+        n = 0;
+      } else if (!goog.format.isInvisibleFormattingCharacter_(charCode)) {
+
+        // A normal flow character - increment.  For grapheme extending
+        // characters, this is not *technically* a new character.  However,
+        // since the grapheme break detector might be overly conservative,
+        // we have to continue incrementing, or else we won't even be able
+        // to add breaks when we get to things like punctuation.  For the
+        // case where we have a full grapheme break detector, it is okay if
+        // we occasionally break slightly early.
+        n++;
+      }
+    } else if (charCode == goog.format.WbrToken_.GT &&
+        nestingCharCode == goog.format.WbrToken_.LT) {
+
+      // Leaving an HTML tag, treat the tag as zero-length
+      nestingCharCode = 0;
+    } else if (charCode == goog.format.WbrToken_.SEMI_COLON &&
+        nestingCharCode == goog.format.WbrToken_.AMP) {
+
+      // Leaving an HTML entity, treat it as length one
+      nestingCharCode = 0;
+      n++;
+    }
+  }
+
+  // Take care of anything we haven't flushed so far.
+  rv.push(str.substr(lastDumpPosition));
+
+  return rv.join('');
+};
+
+
+/**
+ * Inserts word breaks into an HTML string at a given interval.
+ *
+ * This method is as aggressive as possible, using a full table of Unicode
+ * characters where it is legal to insert word breaks; however, this table
+ * comes at a 2.5k pre-gzip (~1k post-gzip) size cost.  Consider using
+ * insertWordBreaksBasic to minimize the size impact.
+ *
+ * @param {string} str HTML to insert word breaks into.
+ * @param {number=} opt_maxlen Maximum length after which to ensure there is a
+ *     break.  Default is 10 characters.
+ * @return {string} The string including word breaks.
+ */
+goog.format.insertWordBreaks = function(str, opt_maxlen) {
+  return goog.format.insertWordBreaksGeneric_(str,
+      goog.i18n.GraphemeBreak.hasGraphemeBreak, opt_maxlen);
+};
+
+
+/**
+ * Determines conservatively if a character has a Grapheme break.
+ *
+ * Conforms to a similar signature as goog.i18n.GraphemeBreak, but is overly
+ * conservative, returning true only for characters in common scripts that
+ * are simple to account for.
+ *
+ * @param {number} lastCharCode The previous character code.  Ignored.
+ * @param {number} charCode The character code under consideration.  It must be
+ *     at least \u0300 as a precondition -- this case is covered by
+ *     insertWordBreaksGeneric_.
+ * @param {boolean=} opt_extended Ignored, to conform with the interface.
+ * @return {boolean} Whether it is one of the recognized subsets of characters
+ *     with a grapheme break.
+ * @private
+ */
+goog.format.conservativelyHasGraphemeBreak_ = function(
+    lastCharCode, charCode, opt_extended) {
+  // Return false for everything except the most common Cyrillic characters.
+  // Don't worry about Latin characters, because insertWordBreaksGeneric_
+  // itself already handles those.
+  // TODO(gboyer): Also account for Greek, Armenian, and Georgian if it is
+  // simple to do so.
+  return charCode >= 0x400 && charCode < 0x523;
+};
+
+
+// TODO(gboyer): Consider using a compile-time flag to switch implementations
+// rather than relying on the developers to toggle implementations.
+/**
+ * Inserts word breaks into an HTML string at a given interval.
+ *
+ * This method is less aggressive than insertWordBreaks, only inserting
+ * breaks next to punctuation and between Latin or Cyrillic characters.
+ * However, this is good enough for the common case of URLs.  It also
+ * works for all Latin and Cyrillic languages, plus CJK has no need for word
+ * breaks.  When this method is used, goog.i18n.GraphemeBreak may be dead
+ * code eliminated.
+ *
+ * @param {string} str HTML to insert word breaks into.
+ * @param {number=} opt_maxlen Maximum length after which to ensure there is a
+ *     break.  Default is 10 characters.
+ * @return {string} The string including word breaks.
+ */
+goog.format.insertWordBreaksBasic = function(str, opt_maxlen) {
+  return goog.format.insertWordBreaksGeneric_(str,
+      goog.format.conservativelyHasGraphemeBreak_, opt_maxlen);
+};
+
+
+/**
+ * True iff the current userAgent is IE8 or above.
+ * @type {boolean}
+ * @private
+ */
+goog.format.IS_IE8_OR_ABOVE_ = goog.userAgent.IE &&
+    goog.userAgent.isVersionOrHigher(8);
+
+
+/**
+ * Constant for the WBR replacement used by insertWordBreaks.  Safari requires
+ * <wbr></wbr>, Opera needs the &shy; entity, though this will give a visible
+ * hyphen at breaks.  IE8 uses a zero width space.
+ * Other browsers just use <wbr>.
+ * @type {string}
+ */
+goog.format.WORD_BREAK_HTML =
+    goog.userAgent.WEBKIT ?
+        '<wbr></wbr>' : goog.userAgent.OPERA ?
+            '&shy;' : goog.format.IS_IE8_OR_ABOVE_ ?
+                '&#8203;' : '<wbr>';
+
+
+/**
+ * Tokens used within insertWordBreaks.
+ * @private
+ * @enum {number}
+ */
+goog.format.WbrToken_ = {
+  LT: 60, // '<'.charCodeAt(0)
+  GT: 62, // '>'.charCodeAt(0)
+  AMP: 38, // '&'.charCodeAt(0)
+  SEMI_COLON: 59, // ';'.charCodeAt(0)
+  SPACE: 32 // ' '.charCodeAt(0)
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/format/htmlprettyprinter.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/format/htmlprettyprinter.js b/externs/GCL/externs/goog/format/htmlprettyprinter.js
new file mode 100644
index 0000000..86366fa
--- /dev/null
+++ b/externs/GCL/externs/goog/format/htmlprettyprinter.js
@@ -0,0 +1,408 @@
+// Copyright 2008 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 Provides functions to parse and pretty-print HTML strings.
+ *
+ */
+
+goog.provide('goog.format.HtmlPrettyPrinter');
+goog.provide('goog.format.HtmlPrettyPrinter.Buffer');
+
+goog.require('goog.dom.TagName');
+goog.require('goog.object');
+goog.require('goog.string.StringBuffer');
+
+
+
+/**
+ * This class formats HTML to be more human-readable.
+ * TODO(user): Add hierarchical indentation.
+ * @param {number=} opt_timeOutMillis Max # milliseconds to spend on #format. If
+ *     this time is exceeded, return partially formatted. 0 or negative number
+ *     indicates no timeout.
+ * @constructor
+ * @final
+ */
+goog.format.HtmlPrettyPrinter = function(opt_timeOutMillis) {
+  /**
+   * Max # milliseconds to spend on #format.
+   * @type {number}
+   * @private
+   */
+  this.timeOutMillis_ = opt_timeOutMillis && opt_timeOutMillis > 0 ?
+      opt_timeOutMillis : 0;
+};
+
+
+/**
+ * Singleton.
+ * @private {goog.format.HtmlPrettyPrinter?}
+ */
+goog.format.HtmlPrettyPrinter.instance_ = null;
+
+
+/**
+ * Singleton lazy initializer.
+ * @return {!goog.format.HtmlPrettyPrinter} Singleton.
+ * @private
+ */
+goog.format.HtmlPrettyPrinter.getInstance_ = function() {
+  if (!goog.format.HtmlPrettyPrinter.instance_) {
+    goog.format.HtmlPrettyPrinter.instance_ =
+        new goog.format.HtmlPrettyPrinter();
+  }
+  return goog.format.HtmlPrettyPrinter.instance_;
+};
+
+
+/**
+ * Static utility function. See prototype #format.
+ * @param {string} html The HTML text to pretty print.
+ * @return {string} Formatted result.
+ */
+goog.format.HtmlPrettyPrinter.format = function(html) {
+  return goog.format.HtmlPrettyPrinter.getInstance_().format(html);
+};
+
+
+/**
+ * List of patterns used to tokenize HTML for pretty printing. Cache
+ * subexpression for tag name.
+ * comment|meta-tag|tag|text|other-less-than-characters
+ * @private {!RegExp}
+ * @const
+ */
+goog.format.HtmlPrettyPrinter.TOKEN_REGEX_ =
+    /(?:<!--.*?-->|<!.*?>|<(\/?)(\w+)[^>]*>|[^<]+|<)/g;
+
+
+/**
+ * Tags whose contents we don't want pretty printed.
+ * @private {!Object}
+ * @const
+ */
+goog.format.HtmlPrettyPrinter.NON_PRETTY_PRINTED_TAGS_ = goog.object.createSet(
+    goog.dom.TagName.SCRIPT,
+    goog.dom.TagName.STYLE,
+    goog.dom.TagName.PRE,
+    'XMP');
+
+
+/**
+ * 'Block' tags. We should add newlines before and after these tags during
+ * pretty printing. Tags drawn mostly from HTML4 definitions for block and other
+ * non-online tags, excepting the ones in
+ * #goog.format.HtmlPrettyPrinter.NON_PRETTY_PRINTED_TAGS_.
+ * @private {!Object}
+ * @const
+ */
+goog.format.HtmlPrettyPrinter.BLOCK_TAGS_ = goog.object.createSet(
+    goog.dom.TagName.ADDRESS,
+    goog.dom.TagName.APPLET,
+    goog.dom.TagName.AREA,
+    goog.dom.TagName.BASE,
+    goog.dom.TagName.BASEFONT,
+    goog.dom.TagName.BLOCKQUOTE,
+    goog.dom.TagName.BODY,
+    goog.dom.TagName.CAPTION,
+    goog.dom.TagName.CENTER,
+    goog.dom.TagName.COL,
+    goog.dom.TagName.COLGROUP,
+    goog.dom.TagName.DIR,
+    goog.dom.TagName.DIV,
+    goog.dom.TagName.DL,
+    goog.dom.TagName.FIELDSET,
+    goog.dom.TagName.FORM,
+    goog.dom.TagName.FRAME,
+    goog.dom.TagName.FRAMESET,
+    goog.dom.TagName.H1,
+    goog.dom.TagName.H2,
+    goog.dom.TagName.H3,
+    goog.dom.TagName.H4,
+    goog.dom.TagName.H5,
+    goog.dom.TagName.H6,
+    goog.dom.TagName.HEAD,
+    goog.dom.TagName.HR,
+    goog.dom.TagName.HTML,
+    goog.dom.TagName.IFRAME,
+    goog.dom.TagName.ISINDEX,
+    goog.dom.TagName.LEGEND,
+    goog.dom.TagName.LINK,
+    goog.dom.TagName.MENU,
+    goog.dom.TagName.META,
+    goog.dom.TagName.NOFRAMES,
+    goog.dom.TagName.NOSCRIPT,
+    goog.dom.TagName.OL,
+    goog.dom.TagName.OPTGROUP,
+    goog.dom.TagName.OPTION,
+    goog.dom.TagName.P,
+    goog.dom.TagName.PARAM,
+    goog.dom.TagName.TABLE,
+    goog.dom.TagName.TBODY,
+    goog.dom.TagName.TD,
+    goog.dom.TagName.TFOOT,
+    goog.dom.TagName.TH,
+    goog.dom.TagName.THEAD,
+    goog.dom.TagName.TITLE,
+    goog.dom.TagName.TR,
+    goog.dom.TagName.UL);
+
+
+/**
+ * Non-block tags that break flow. We insert a line break after, but not before
+ * these. Tags drawn from HTML4 definitions.
+ * @private {!Object}
+ * @const
+ */
+goog.format.HtmlPrettyPrinter.BREAKS_FLOW_TAGS_ = goog.object.createSet(
+    goog.dom.TagName.BR,
+    goog.dom.TagName.DD,
+    goog.dom.TagName.DT,
+    goog.dom.TagName.BR,
+    goog.dom.TagName.LI,
+    goog.dom.TagName.NOFRAMES);
+
+
+/**
+ * Empty tags. These are treated as both start and end tags.
+ * @private {!Object}
+ * @const
+ */
+goog.format.HtmlPrettyPrinter.EMPTY_TAGS_ = goog.object.createSet(
+    goog.dom.TagName.BR,
+    goog.dom.TagName.HR,
+    goog.dom.TagName.ISINDEX);
+
+
+/**
+ * Breaks up HTML so it's easily readable by the user.
+ * @param {string} html The HTML text to pretty print.
+ * @return {string} Formatted result.
+ * @throws {Error} Regex error, data loss, or endless loop detected.
+ */
+goog.format.HtmlPrettyPrinter.prototype.format = function(html) {
+  // Trim leading whitespace, but preserve first indent; in other words, keep
+  // any spaces immediately before the first non-whitespace character (that's
+  // what $1 is), but remove all other leading whitespace. This adjustment
+  // historically had been made in Docs. The motivation is that some
+  // browsers prepend several line breaks in designMode.
+  html = html.replace(/^\s*?( *\S)/, '$1');
+
+  // Trim trailing whitespace.
+  html = html.replace(/\s+$/, '');
+
+  // Keep track of how much time we've used.
+  var timeOutMillis = this.timeOutMillis_;
+  var startMillis = timeOutMillis ? goog.now() : 0;
+
+  // Handles concatenation of the result and required line breaks.
+  var buffer = new goog.format.HtmlPrettyPrinter.Buffer();
+
+  // Declare these for efficiency since we access them in a loop.
+  var tokenRegex = goog.format.HtmlPrettyPrinter.TOKEN_REGEX_;
+  var nonPpTags = goog.format.HtmlPrettyPrinter.NON_PRETTY_PRINTED_TAGS_;
+  var blockTags = goog.format.HtmlPrettyPrinter.BLOCK_TAGS_;
+  var breaksFlowTags = goog.format.HtmlPrettyPrinter.BREAKS_FLOW_TAGS_;
+  var emptyTags = goog.format.HtmlPrettyPrinter.EMPTY_TAGS_;
+
+  // Used to verify we're making progress through our regex tokenization.
+  var lastIndex = 0;
+
+  // Use this to track non-pretty-printed tags and childen.
+  var nonPpTagStack = [];
+
+  // Loop through each matched token.
+  var match;
+  while (match = tokenRegex.exec(html)) {
+    // Get token.
+    var token = match[0];
+
+    // Is this token a tag? match.length == 3 for tags, 1 for all others.
+    if (match.length == 3) {
+      var tagName = match[2];
+      if (tagName) {
+        tagName = tagName.toUpperCase();
+      }
+
+      // Non-pretty-printed tags?
+      if (nonPpTags.hasOwnProperty(tagName)) {
+        // End tag?
+        if (match[1] == '/') {
+          // Do we have a matching start tag?
+          var stackSize = nonPpTagStack.length;
+          var startTagName = stackSize ? nonPpTagStack[stackSize - 1] : null;
+          if (startTagName == tagName) {
+            // End of non-pretty-printed block. Line break after.
+            nonPpTagStack.pop();
+            buffer.pushToken(false, token, !nonPpTagStack.length);
+          } else {
+            // Malformed HTML. No line breaks.
+            buffer.pushToken(false, token, false);
+          }
+        } else {
+          // Start of non-pretty-printed block. Line break before.
+          buffer.pushToken(!nonPpTagStack.length, token, false);
+          nonPpTagStack.push(tagName);
+        }
+      } else if (nonPpTagStack.length) {
+        // Inside non-pretty-printed block, no new line breaks.
+        buffer.pushToken(false, token, false);
+      } else if (blockTags.hasOwnProperty(tagName)) {
+        // Put line break before start block and after end block tags.
+        var isEmpty = emptyTags.hasOwnProperty(tagName);
+        var isEndTag = match[1] == '/';
+        buffer.pushToken(isEmpty || !isEndTag, token, isEmpty || isEndTag);
+      } else if (breaksFlowTags.hasOwnProperty(tagName)) {
+        var isEmpty = emptyTags.hasOwnProperty(tagName);
+        var isEndTag = match[1] == '/';
+        // Put line break after end flow-breaking tags.
+        buffer.pushToken(false, token, isEndTag || isEmpty);
+      } else {
+        // All other tags, no line break.
+        buffer.pushToken(false, token, false);
+      }
+    } else {
+      // Non-tags, no line break.
+      buffer.pushToken(false, token, false);
+    }
+
+    // Double check that we're making progress.
+    var newLastIndex = tokenRegex.lastIndex;
+    if (!token || newLastIndex <= lastIndex) {
+      throw Error('Regex failed to make progress through source html.');
+    }
+    lastIndex = newLastIndex;
+
+    // Out of time?
+    if (timeOutMillis) {
+      if (goog.now() - startMillis > timeOutMillis) {
+        // Push unprocessed data as one big token and reset regex object.
+        buffer.pushToken(false, html.substring(tokenRegex.lastIndex), false);
+        tokenRegex.lastIndex = 0;
+        break;
+      }
+    }
+  }
+
+  // Ensure we end in a line break.
+  buffer.lineBreak();
+
+  // Construct result string.
+  var result = String(buffer);
+
+  // Length should be original length plus # line breaks added.
+  var expectedLength = html.length + buffer.breakCount;
+  if (result.length != expectedLength) {
+    throw Error('Lost data pretty printing html.');
+  }
+
+  return result;
+};
+
+
+
+/**
+ * This class is a buffer to which we push our output. It tracks line breaks to
+ * make sure we don't add unnecessary ones.
+ * @constructor
+ * @final
+ */
+goog.format.HtmlPrettyPrinter.Buffer = function() {
+  /**
+   * Tokens to be output in #toString.
+   * @type {goog.string.StringBuffer}
+   * @private
+   */
+  this.out_ = new goog.string.StringBuffer();
+};
+
+
+/**
+ * Tracks number of line breaks added.
+ * @type {number}
+ */
+goog.format.HtmlPrettyPrinter.Buffer.prototype.breakCount = 0;
+
+
+/**
+ * Tracks if we are at the start of a new line.
+ * @type {boolean}
+ * @private
+ */
+goog.format.HtmlPrettyPrinter.Buffer.prototype.isBeginningOfNewLine_ = true;
+
+
+/**
+ * Tracks if we need a new line before the next token.
+ * @type {boolean}
+ * @private
+ */
+goog.format.HtmlPrettyPrinter.Buffer.prototype.needsNewLine_ = false;
+
+
+/**
+ * Adds token and necessary line breaks to output buffer.
+ * @param {boolean} breakBefore If true, add line break before token if
+ *     necessary.
+ * @param {string} token Token to push.
+ * @param {boolean} breakAfter If true, add line break after token if
+ *     necessary.
+ */
+goog.format.HtmlPrettyPrinter.Buffer.prototype.pushToken = function(
+    breakBefore, token, breakAfter) {
+  // If this token needs a preceeding line break, and
+  // we haven't already added a line break, and
+  // this token does not start with a line break,
+  // then add line break.
+  // Due to FF3.0 bug with lists, we don't insert a /n
+  // right before </ul>. See bug 1520665.
+  if ((this.needsNewLine_ || breakBefore) &&
+      !/^\r?\n/.test(token) &&
+      !/\/ul/i.test(token)) {
+    this.lineBreak();
+  }
+
+  // Token.
+  this.out_.append(token);
+
+  // Remember if this string ended with a line break so we know we don't have to
+  // insert another one before the next token.
+  this.isBeginningOfNewLine_ = /\r?\n$/.test(token);
+
+  // Remember if this token requires a line break after it. We don't insert it
+  // here because we might not have to if the next token starts with a line
+  // break.
+  this.needsNewLine_ = breakAfter && !this.isBeginningOfNewLine_;
+};
+
+
+/**
+ * Append line break if we need one.
+ */
+goog.format.HtmlPrettyPrinter.Buffer.prototype.lineBreak = function() {
+  if (!this.isBeginningOfNewLine_) {
+    this.out_.append('\n');
+    ++this.breakCount;
+  }
+};
+
+
+/**
+ * @return {string} String representation of tokens.
+ * @override
+ */
+goog.format.HtmlPrettyPrinter.Buffer.prototype.toString = function() {
+  return this.out_.toString();
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/format/internationalizedemailaddress.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/format/internationalizedemailaddress.js b/externs/GCL/externs/goog/format/internationalizedemailaddress.js
new file mode 100644
index 0000000..fd1dfe6
--- /dev/null
+++ b/externs/GCL/externs/goog/format/internationalizedemailaddress.js
@@ -0,0 +1,256 @@
+// Copyright 2014 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 Provides functions to parse and manipulate internationalized
+ * email addresses. This is useful in the context of Email Address
+ * Internationalization (EAI) as defined by RFC6530.
+ *
+ */
+
+goog.provide('goog.format.InternationalizedEmailAddress');
+
+goog.require('goog.format.EmailAddress');
+
+goog.require('goog.string');
+
+
+
+/**
+ * Formats an email address string for display, and allows for extraction of
+ * the individual components of the address.
+ * @param {string=} opt_address The email address.
+ * @param {string=} opt_name The name associated with the email address.
+ * @constructor
+ * @extends {goog.format.EmailAddress}
+ */
+goog.format.InternationalizedEmailAddress = function(opt_address, opt_name) {
+  goog.format.InternationalizedEmailAddress.base(
+      this, 'constructor', opt_address, opt_name);
+};
+goog.inherits(
+    goog.format.InternationalizedEmailAddress, goog.format.EmailAddress);
+
+
+/**
+ * A string representing the RegExp for the local part of an EAI email address.
+ * @private
+ */
+goog.format.InternationalizedEmailAddress.EAI_LOCAL_PART_REGEXP_STR_ =
+    '((?!\\s)[+a-zA-Z0-9_.!#$%&\'*\\/=?^`{|}~\u0080-\uFFFFFF-])+';
+
+
+/**
+ * A string representing the RegExp for a label in the domain part of an EAI
+ * email address.
+ * @private
+ */
+goog.format.InternationalizedEmailAddress.EAI_LABEL_CHAR_REGEXP_STR_ =
+    '(?!\\s)[a-zA-Z0-9\u0080-\u3001\u3003-\uFF0D\uFF0F-\uFF60\uFF62-\uFFFFFF-]';
+
+
+/**
+ * A string representing the RegExp for the domain part of an EAI email address.
+ * @private
+ */
+goog.format.InternationalizedEmailAddress.EAI_DOMAIN_PART_REGEXP_STR_ =
+    // A unicode character (ASCII or Unicode excluding periods)
+    '(' + goog.format.InternationalizedEmailAddress.EAI_LABEL_CHAR_REGEXP_STR_ +
+    // Such character 1+ times, followed by a Unicode period. All 1+ times.
+    '+[\\.\\uFF0E\\u3002\\uFF61])+' +
+    // And same thing but without a period in the end
+    goog.format.InternationalizedEmailAddress.EAI_LABEL_CHAR_REGEXP_STR_ +
+    '{2,63}';
+
+
+/**
+ * Match string for address separators. This list is the result of the
+ * discussion in b/16241003.
+ * @type {string}
+ * @private
+ */
+goog.format.InternationalizedEmailAddress.ADDRESS_SEPARATORS_ =
+    ',' + // U+002C ( , ) COMMA
+    ';' + // U+003B ( ; ) SEMICOLON
+    '\u055D' + // ( ՝ ) ARMENIAN COMMA
+    '\u060C' + // ( ، ) ARABIC COMMA
+    '\u1363' + // ( ፣ ) ETHIOPIC COMMA
+    '\u1802' + // ( ᠂ ) MONGOLIAN COMMA
+    '\u1808' + // ( ᠈ ) MONGOLIAN MANCHU COMMA
+    '\u2E41' + // ( ⹁ ) REVERSED COMMA
+    '\u3001' + // ( 、 ) IDEOGRAPHIC COMMA
+    '\uFF0C' + // ( , ) FULLWIDTH COMMA
+    '\u061B' + // ( ‎؛‎ ) ARABIC SEMICOLON
+    '\u1364' + // ( ፤ ) ETHIOPIC SEMICOLON
+    '\uFF1B' + // ( ; ) FULLWIDTH SEMICOLON
+    '\uFF64' + // ( 、 ) HALFWIDTH IDEOGRAPHIC COMMA
+    '\u104A'; // ( ၊ ) MYANMAR SIGN LITTLE SECTION
+
+
+/**
+ * Match string for characters that, when in a display name, require it to be
+ * quoted.
+ * @type {string}
+ * @private
+ */
+goog.format.InternationalizedEmailAddress.CHARS_REQUIRE_QUOTES_ =
+    goog.format.EmailAddress.SPECIAL_CHARS +
+    goog.format.InternationalizedEmailAddress.ADDRESS_SEPARATORS_;
+
+
+/**
+ * A RegExp to match the local part of an EAI email address.
+ * @private {!RegExp}
+ */
+goog.format.InternationalizedEmailAddress.EAI_LOCAL_PART_ =
+    new RegExp('^' +
+        goog.format.InternationalizedEmailAddress.EAI_LOCAL_PART_REGEXP_STR_ +
+        '$');
+
+
+/**
+ * A RegExp to match the domain part of an EAI email address.
+ * @private {!RegExp}
+ */
+goog.format.InternationalizedEmailAddress.EAI_DOMAIN_PART_ =
+    new RegExp('^' +
+        goog.format.InternationalizedEmailAddress.EAI_DOMAIN_PART_REGEXP_STR_ +
+        '$');
+
+
+/**
+ * A RegExp to match an EAI email address.
+ * @private {!RegExp}
+ */
+goog.format.InternationalizedEmailAddress.EAI_EMAIL_ADDRESS_ =
+    new RegExp('^' +
+        goog.format.InternationalizedEmailAddress.EAI_LOCAL_PART_REGEXP_STR_ +
+        '@' +
+        goog.format.InternationalizedEmailAddress.EAI_DOMAIN_PART_REGEXP_STR_ +
+        '$');
+
+
+/**
+ * Checks if the provided string is a valid local part (part before the '@') of
+ * an EAI email address.
+ * @param {string} str The local part to check.
+ * @return {boolean} Whether the provided string is a valid local part.
+ */
+goog.format.InternationalizedEmailAddress.isValidLocalPartSpec = function(str) {
+  if (!goog.isDefAndNotNull(str)) {
+    return false;
+  }
+  return goog.format.InternationalizedEmailAddress.EAI_LOCAL_PART_.test(str);
+};
+
+
+/**
+ * Checks if the provided string is a valid domain part (part after the '@') of
+ * an EAI email address.
+ * @param {string} str The domain part to check.
+ * @return {boolean} Whether the provided string is a valid domain part.
+ */
+goog.format.InternationalizedEmailAddress.isValidDomainPartSpec =
+    function(str) {
+  if (!goog.isDefAndNotNull(str)) {
+    return false;
+  }
+  return goog.format.InternationalizedEmailAddress.EAI_DOMAIN_PART_.test(str);
+};
+
+
+/** @override */
+goog.format.InternationalizedEmailAddress.prototype.isValid = function() {
+  return goog.format.InternationalizedEmailAddress.isValidAddrSpec(
+      this.address);
+};
+
+
+/**
+ * Checks if the provided string is a valid email address. Supports both
+ * simple email addresses (address specs) and addresses that contain display
+ * names.
+ * @param {string} str The email address to check.
+ * @return {boolean} Whether the provided string is a valid address.
+ */
+goog.format.InternationalizedEmailAddress.isValidAddress = function(str) {
+  if (!goog.isDefAndNotNull(str)) {
+    return false;
+  }
+  return goog.format.InternationalizedEmailAddress.parse(str).isValid();
+};
+
+
+/**
+ * Checks if the provided string is a valid address spec (local@domain.com).
+ * @param {string} str The email address to check.
+ * @return {boolean} Whether the provided string is a valid address spec.
+ */
+goog.format.InternationalizedEmailAddress.isValidAddrSpec = function(str) {
+  if (!goog.isDefAndNotNull(str)) {
+    return false;
+  }
+
+  // This is a fairly naive implementation, but it covers 99% of use cases.
+  // For more details, see http://en.wikipedia.org/wiki/Email_address#Syntax
+  return goog.format.InternationalizedEmailAddress.EAI_EMAIL_ADDRESS_.test(str);
+};
+
+
+/**
+ * Parses a string containing email addresses of the form
+ * "name" &lt;address&gt; into an array of email addresses.
+ * @param {string} str The address list.
+ * @return {!Array<!goog.format.EmailAddress>} The parsed emails.
+ */
+goog.format.InternationalizedEmailAddress.parseList = function(str) {
+  return goog.format.EmailAddress.parseListInternal(
+      str, goog.format.InternationalizedEmailAddress.parse,
+      goog.format.InternationalizedEmailAddress.isAddressSeparator);
+};
+
+
+/**
+ * Parses an email address of the form "name" &lt;address&gt; into
+ * an email address.
+ * @param {string} addr The address string.
+ * @return {!goog.format.EmailAddress} The parsed address.
+ */
+goog.format.InternationalizedEmailAddress.parse = function(addr) {
+  return goog.format.EmailAddress.parseInternal(
+      addr, goog.format.InternationalizedEmailAddress);
+};
+
+
+/**
+ * @param {string} ch The character to test.
+ * @return {boolean} Whether the provided character is an address separator.
+ */
+goog.format.InternationalizedEmailAddress.isAddressSeparator = function(ch) {
+  return goog.string.contains(
+      goog.format.InternationalizedEmailAddress.ADDRESS_SEPARATORS_, ch);
+};
+
+
+/**
+ * Return the address in a standard format:
+ *  - remove extra spaces.
+ *  - Surround name with quotes if it contains special characters.
+ * @return {string} The cleaned address.
+ * @override
+ */
+goog.format.InternationalizedEmailAddress.prototype.toString = function() {
+  return this.toStringInternal(
+      goog.format.InternationalizedEmailAddress.CHARS_REQUIRE_QUOTES_);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/format/jsonprettyprinter.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/format/jsonprettyprinter.js b/externs/GCL/externs/goog/format/jsonprettyprinter.js
new file mode 100644
index 0000000..15e2cd2
--- /dev/null
+++ b/externs/GCL/externs/goog/format/jsonprettyprinter.js
@@ -0,0 +1,414 @@
+// Copyright 2010 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 Creates a string of a JSON object, properly indented for
+ * display.
+ *
+ */
+
+goog.provide('goog.format.JsonPrettyPrinter');
+goog.provide('goog.format.JsonPrettyPrinter.HtmlDelimiters');
+goog.provide('goog.format.JsonPrettyPrinter.TextDelimiters');
+
+goog.require('goog.json');
+goog.require('goog.json.Serializer');
+goog.require('goog.string');
+goog.require('goog.string.StringBuffer');
+goog.require('goog.string.format');
+
+
+
+/**
+ * Formats a JSON object as a string, properly indented for display.  Supports
+ * displaying the string as text or html.  Users can also specify their own
+ * set of delimiters for different environments.  For example, the JSON object:
+ *
+ * <code>{"a": 1, "b": {"c": null, "d": true, "e": [1, 2]}}</code>
+ *
+ * Will be displayed like this:
+ *
+ * <code>{
+ *   "a": 1,
+ *   "b": {
+ *     "c": null,
+ *     "d": true,
+ *     "e": [
+ *       1,
+ *       2
+ *     ]
+ *   }
+ * }</code>
+ * @param {goog.format.JsonPrettyPrinter.TextDelimiters} delimiters Container
+ *     for the various strings to use to delimit objects, arrays, newlines, and
+ *     other pieces of the output.
+ * @constructor
+ */
+goog.format.JsonPrettyPrinter = function(delimiters) {
+
+  /**
+   * The set of characters to use as delimiters.
+   * @type {goog.format.JsonPrettyPrinter.TextDelimiters}
+   * @private
+   */
+  this.delimiters_ = delimiters ||
+      new goog.format.JsonPrettyPrinter.TextDelimiters();
+
+  /**
+   * Used to serialize property names and values.
+   * @type {goog.json.Serializer}
+   * @private
+   */
+  this.jsonSerializer_ = new goog.json.Serializer();
+};
+
+
+/**
+ * Formats a JSON object as a string, properly indented for display.
+ * @param {*} json The object to pretty print. It could be a JSON object, a
+ *     string representing a JSON object, or any other type.
+ * @return {string} Returns a string of the JSON object, properly indented for
+ *     display.
+ */
+goog.format.JsonPrettyPrinter.prototype.format = function(json) {
+  // If input is undefined, null, or empty, return an empty string.
+  if (!goog.isDefAndNotNull(json)) {
+    return '';
+  }
+  if (goog.isString(json)) {
+    if (goog.string.isEmptyOrWhitespace(json)) {
+      return '';
+    }
+    // Try to coerce a string into a JSON object.
+    json = goog.json.parse(json);
+  }
+  var outputBuffer = new goog.string.StringBuffer();
+  this.printObject_(json, outputBuffer, 0);
+  return outputBuffer.toString();
+};
+
+
+/**
+ * Formats a property value based on the type of the propery.
+ * @param {*} val The object to format.
+ * @param {goog.string.StringBuffer} outputBuffer The buffer to write the
+ *     response to.
+ * @param {number} indent The number of spaces to indent each line of the
+ *     output.
+ * @private
+ */
+goog.format.JsonPrettyPrinter.prototype.printObject_ = function(val,
+    outputBuffer, indent) {
+  var typeOf = goog.typeOf(val);
+  switch (typeOf) {
+    case 'null':
+    case 'boolean':
+    case 'number':
+    case 'string':
+      // "null", "boolean", "number" and "string" properties are printed
+      // directly to the output.
+      this.printValue_(
+          /** @type {null|string|boolean|number} */ (val),
+          typeOf, outputBuffer);
+      break;
+    case 'array':
+      // Example of how an array looks when formatted
+      // (using the default delimiters):
+      // [
+      //   1,
+      //   2,
+      //   3
+      // ]
+      outputBuffer.append(this.delimiters_.arrayStart);
+      var i = 0;
+      // Iterate through the array and format each element.
+      for (i = 0; i < val.length; i++) {
+        if (i > 0) {
+          // There are multiple elements, add a comma to separate them.
+          outputBuffer.append(this.delimiters_.propertySeparator);
+        }
+        outputBuffer.append(this.delimiters_.lineBreak);
+        this.printSpaces_(indent + this.delimiters_.indent, outputBuffer);
+        this.printObject_(val[i], outputBuffer,
+            indent + this.delimiters_.indent);
+      }
+      // If there are no properties in this object, don't put a line break
+      // between the beginning "[" and ending "]", so the output of an empty
+      // array looks like <code>[]</code>.
+      if (i > 0) {
+        outputBuffer.append(this.delimiters_.lineBreak);
+        this.printSpaces_(indent, outputBuffer);
+      }
+      outputBuffer.append(this.delimiters_.arrayEnd);
+      break;
+    case 'object':
+      // Example of how an object looks when formatted
+      // (using the default delimiters):
+      // {
+      //   "a": 1,
+      //   "b": 2,
+      //   "c": "3"
+      // }
+      outputBuffer.append(this.delimiters_.objectStart);
+      var propertyCount = 0;
+      // Iterate through the object and display each property.
+      for (var name in val) {
+        if (!val.hasOwnProperty(name)) {
+          continue;
+        }
+        if (propertyCount > 0) {
+          // There are multiple properties, add a comma to separate them.
+          outputBuffer.append(this.delimiters_.propertySeparator);
+        }
+        outputBuffer.append(this.delimiters_.lineBreak);
+        this.printSpaces_(indent + this.delimiters_.indent, outputBuffer);
+        this.printName_(name, outputBuffer);
+        outputBuffer.append(this.delimiters_.nameValueSeparator,
+            this.delimiters_.space);
+        this.printObject_(val[name], outputBuffer,
+            indent + this.delimiters_.indent);
+        propertyCount++;
+      }
+      // If there are no properties in this object, don't put a line break
+      // between the beginning "{" and ending "}", so the output of an empty
+      // object looks like <code>{}</code>.
+      if (propertyCount > 0) {
+        outputBuffer.append(this.delimiters_.lineBreak);
+        this.printSpaces_(indent, outputBuffer);
+      }
+      outputBuffer.append(this.delimiters_.objectEnd);
+      break;
+    // Other types, such as "function", aren't expected in JSON, and their
+    // behavior is undefined.  In these cases, just print an empty string to the
+    // output buffer.  This allows the pretty printer to continue while still
+    // outputing well-formed JSON.
+    default:
+      this.printValue_('', 'unknown', outputBuffer);
+  }
+};
+
+
+/**
+ * Prints a property name to the output.
+ * @param {string} name The property name.
+ * @param {goog.string.StringBuffer} outputBuffer The buffer to write the
+ *     response to.
+ * @private
+ */
+goog.format.JsonPrettyPrinter.prototype.printName_ = function(name,
+    outputBuffer) {
+  outputBuffer.append(this.delimiters_.preName,
+      this.jsonSerializer_.serialize(name), this.delimiters_.postName);
+};
+
+
+/**
+ * Prints a property name to the output.
+ * @param {string|boolean|number|null} val The property value.
+ * @param {string} typeOf The type of the value.  Used to customize
+ *     value-specific css in the display.  This allows clients to distinguish
+ *     between different types in css.  For example, the client may define two
+ *     classes: "goog-jsonprettyprinter-propertyvalue-string" and
+ *     "goog-jsonprettyprinter-propertyvalue-number" to assign a different color
+ *     to string and number values.
+ * @param {goog.string.StringBuffer} outputBuffer The buffer to write the
+ *     response to.
+ * @private
+ */
+goog.format.JsonPrettyPrinter.prototype.printValue_ = function(val,
+    typeOf, outputBuffer) {
+  outputBuffer.append(goog.string.format(this.delimiters_.preValue, typeOf),
+      this.jsonSerializer_.serialize(val),
+      goog.string.format(this.delimiters_.postValue, typeOf));
+};
+
+
+/**
+ * Print a number of space characters to the output.
+ * @param {number} indent The number of spaces to indent the line.
+ * @param {goog.string.StringBuffer} outputBuffer The buffer to write the
+ *     response to.
+ * @private
+ */
+goog.format.JsonPrettyPrinter.prototype.printSpaces_ = function(indent,
+    outputBuffer) {
+  outputBuffer.append(goog.string.repeat(this.delimiters_.space, indent));
+};
+
+
+
+/**
+ * A container for the delimiting characters used to display the JSON string
+ * to a text display.  Each delimiter is a publicly accessible property of
+ * the object, which makes it easy to tweak delimiters to specific environments.
+ * @constructor
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters = function() {
+};
+
+
+/**
+ * Represents a space character in the output.  Used to indent properties a
+ * certain number of spaces, and to separate property names from property
+ * values.
+ * @type {string}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.space = ' ';
+
+
+/**
+ * Represents a newline character in the output.  Used to begin a new line.
+ * @type {string}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.lineBreak = '\n';
+
+
+/**
+ * Represents the start of an object in the output.
+ * @type {string}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.objectStart = '{';
+
+
+/**
+ * Represents the end of an object in the output.
+ * @type {string}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.objectEnd = '}';
+
+
+/**
+ * Represents the start of an array in the output.
+ * @type {string}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.arrayStart = '[';
+
+
+/**
+ * Represents the end of an array in the output.
+ * @type {string}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.arrayEnd = ']';
+
+
+/**
+ * Represents the string used to separate properties in the output.
+ * @type {string}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.propertySeparator = ',';
+
+
+/**
+ * Represents the string used to separate property names from property values in
+ * the output.
+ * @type {string}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.nameValueSeparator = ':';
+
+
+/**
+ * A string that's placed before a property name in the output.  Useful for
+ * wrapping a property name in an html tag.
+ * @type {string}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.preName = '';
+
+
+/**
+ * A string that's placed after a property name in the output.  Useful for
+ * wrapping a property name in an html tag.
+ * @type {string}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.postName = '';
+
+
+/**
+ * A string that's placed before a property value in the output.  Useful for
+ * wrapping a property value in an html tag.
+ * @type {string}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.preValue = '';
+
+
+/**
+ * A string that's placed after a property value in the output.  Useful for
+ * wrapping a property value in an html tag.
+ * @type {string}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.postValue = '';
+
+
+/**
+ * Represents the number of spaces to indent each sub-property of the JSON.
+ * @type {number}
+ */
+goog.format.JsonPrettyPrinter.TextDelimiters.prototype.indent = 2;
+
+
+
+/**
+ * A container for the delimiting characters used to display the JSON string
+ * to an HTML <code>&lt;pre&gt;</code> or <code>&lt;code&gt;</code> element.
+ * @constructor
+ * @extends {goog.format.JsonPrettyPrinter.TextDelimiters}
+ * @final
+ */
+goog.format.JsonPrettyPrinter.HtmlDelimiters = function() {
+  goog.format.JsonPrettyPrinter.TextDelimiters.call(this);
+};
+goog.inherits(goog.format.JsonPrettyPrinter.HtmlDelimiters,
+    goog.format.JsonPrettyPrinter.TextDelimiters);
+
+
+/**
+ * A <code>span</code> tag thats placed before a property name.  Used to style
+ * property names with CSS.
+ * @type {string}
+ * @override
+ */
+goog.format.JsonPrettyPrinter.HtmlDelimiters.prototype.preName =
+    '<span class="' +
+    goog.getCssName('goog-jsonprettyprinter-propertyname') +
+    '">';
+
+
+/**
+ * A closing <code>span</code> tag that's placed after a property name.
+ * @type {string}
+ * @override
+ */
+goog.format.JsonPrettyPrinter.HtmlDelimiters.prototype.postName = '</span>';
+
+
+/**
+ * A <code>span</code> tag thats placed before a property value.  Used to style
+ * property value with CSS.  The span tag's class is in the format
+ * goog-jsonprettyprinter-propertyvalue-{TYPE}, where {TYPE} is the JavaScript
+ * type of the object (the {TYPE} parameter is obtained from goog.typeOf).  This
+ * can be used to style different value types.
+ * @type {string}
+ * @override
+ */
+goog.format.JsonPrettyPrinter.HtmlDelimiters.prototype.preValue =
+    '<span class="' +
+    goog.getCssName('goog-jsonprettyprinter-propertyvalue') +
+    '-%s">';
+
+
+/**
+ * A closing <code>span</code> tag that's placed after a property value.
+ * @type {string}
+ * @override
+ */
+goog.format.JsonPrettyPrinter.HtmlDelimiters.prototype.postValue = '</span>';

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/entry.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/entry.js b/externs/GCL/externs/goog/fs/entry.js
new file mode 100644
index 0000000..8143daa
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/entry.js
@@ -0,0 +1,272 @@
+// Copyright 2011 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 Wrappers for HTML5 Entry objects. These are all in the same
+ * file to avoid circular dependency issues.
+ *
+ * When adding or modifying functionality in this namespace, be sure to update
+ * the mock counterparts in goog.testing.fs.
+ *
+ */
+goog.provide('goog.fs.DirectoryEntry');
+goog.provide('goog.fs.DirectoryEntry.Behavior');
+goog.provide('goog.fs.Entry');
+goog.provide('goog.fs.FileEntry');
+
+
+
+/**
+ * The interface for entries in the filesystem.
+ * @interface
+ */
+goog.fs.Entry = function() {};
+
+
+/**
+ * @return {boolean} Whether or not this entry is a file.
+ */
+goog.fs.Entry.prototype.isFile = function() {};
+
+
+/**
+ * @return {boolean} Whether or not this entry is a directory.
+ */
+goog.fs.Entry.prototype.isDirectory = function() {};
+
+
+/**
+ * @return {string} The name of this entry.
+ */
+goog.fs.Entry.prototype.getName = function() {};
+
+
+/**
+ * @return {string} The full path to this entry.
+ */
+goog.fs.Entry.prototype.getFullPath = function() {};
+
+
+/**
+ * @return {!goog.fs.FileSystem} The filesystem backing this entry.
+ */
+goog.fs.Entry.prototype.getFileSystem = function() {};
+
+
+/**
+ * Retrieves the last modified date for this entry.
+ *
+ * @return {!goog.async.Deferred} The deferred Date for this entry. If an error
+ *     occurs, the errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.Entry.prototype.getLastModified = function() {};
+
+
+/**
+ * Retrieves the metadata for this entry.
+ *
+ * @return {!goog.async.Deferred} The deferred Metadata for this entry. If an
+ *     error occurs, the errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.Entry.prototype.getMetadata = function() {};
+
+
+/**
+ * Move this entry to a new location.
+ *
+ * @param {!goog.fs.DirectoryEntry} parent The new parent directory.
+ * @param {string=} opt_newName The new name of the entry. If omitted, the entry
+ *     retains its original name.
+ * @return {!goog.async.Deferred} The deferred {@link goog.fs.FileEntry} or
+ *     {@link goog.fs.DirectoryEntry} for the new entry. If an error occurs, the
+ *     errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.Entry.prototype.moveTo = function(parent, opt_newName) {};
+
+
+/**
+ * Copy this entry to a new location.
+ *
+ * @param {!goog.fs.DirectoryEntry} parent The new parent directory.
+ * @param {string=} opt_newName The name of the new entry. If omitted, the new
+ *     entry has the same name as the original.
+ * @return {!goog.async.Deferred} The deferred {@link goog.fs.FileEntry} or
+ *     {@link goog.fs.DirectoryEntry} for the new entry. If an error occurs, the
+ *     errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.Entry.prototype.copyTo = function(parent, opt_newName) {};
+
+
+/**
+ * Wrap an HTML5 entry object in an appropriate subclass instance.
+ *
+ * @param {!Entry} entry The underlying Entry object.
+ * @return {!goog.fs.Entry} The appropriate subclass wrapper.
+ * @protected
+ */
+goog.fs.Entry.prototype.wrapEntry = function(entry) {};
+
+
+/**
+ * Get the URL for this file.
+ *
+ * @param {string=} opt_mimeType The MIME type that will be served for the URL.
+ * @return {string} The URL.
+ */
+goog.fs.Entry.prototype.toUrl = function(opt_mimeType) {};
+
+
+/**
+ * Get the URI for this file.
+ *
+ * @deprecated Use {@link #toUrl} instead.
+ * @param {string=} opt_mimeType The MIME type that will be served for the URI.
+ * @return {string} The URI.
+ */
+goog.fs.Entry.prototype.toUri = function(opt_mimeType) {};
+
+
+/**
+ * Remove this entry.
+ *
+ * @return {!goog.async.Deferred} A deferred object. If the removal succeeds,
+ *     the callback is called with true. If an error occurs, the errback is
+ *     called a {@link goog.fs.Error}.
+ */
+goog.fs.Entry.prototype.remove = function() {};
+
+
+/**
+ * Gets the parent directory.
+ *
+ * @return {!goog.async.Deferred} The deferred {@link goog.fs.DirectoryEntry}.
+ *     If an error occurs, the errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.Entry.prototype.getParent = function() {};
+
+
+
+/**
+ * A directory in a local FileSystem.
+ *
+ * @interface
+ * @extends {goog.fs.Entry}
+ */
+goog.fs.DirectoryEntry = function() {};
+
+
+/**
+ * Behaviors for getting files and directories.
+ * @enum {number}
+ */
+goog.fs.DirectoryEntry.Behavior = {
+  /**
+   * Get the file if it exists, error out if it doesn't.
+   */
+  DEFAULT: 1,
+  /**
+   * Get the file if it exists, create it if it doesn't.
+   */
+  CREATE: 2,
+  /**
+   * Error out if the file exists, create it if it doesn't.
+   */
+  CREATE_EXCLUSIVE: 3
+};
+
+
+/**
+ * Get a file in the directory.
+ *
+ * @param {string} path The path to the file, relative to this directory.
+ * @param {goog.fs.DirectoryEntry.Behavior=} opt_behavior The behavior for
+ *     handling an existing file, or the lack thereof.
+ * @return {!goog.async.Deferred} The deferred {@link goog.fs.FileEntry}. If an
+ *     error occurs, the errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.DirectoryEntry.prototype.getFile = function(path, opt_behavior) {};
+
+
+/**
+ * Get a directory within this directory.
+ *
+ * @param {string} path The path to the directory, relative to this directory.
+ * @param {goog.fs.DirectoryEntry.Behavior=} opt_behavior The behavior for
+ *     handling an existing directory, or the lack thereof.
+ * @return {!goog.async.Deferred} The deferred {@link goog.fs.DirectoryEntry}.
+ *     If an error occurs, the errback is called a {@link goog.fs.Error}.
+ */
+goog.fs.DirectoryEntry.prototype.getDirectory = function(path, opt_behavior) {};
+
+
+/**
+ * Opens the directory for the specified path, creating the directory and any
+ * intermediate directories as necessary.
+ *
+ * @param {string} path The directory path to create. May be absolute or
+ *     relative to the current directory. The parent directory ".." and current
+ *     directory "." are supported.
+ * @return {!goog.async.Deferred} A deferred {@link goog.fs.DirectoryEntry} for
+ *     the requested path. If an error occurs, the errback is called with a
+ *     {@link goog.fs.Error}.
+ */
+goog.fs.DirectoryEntry.prototype.createPath = function(path) {};
+
+
+/**
+ * Gets a list of all entries in this directory.
+ *
+ * @return {!goog.async.Deferred} The deferred list of {@link goog.fs.Entry}
+ *     results. If an error occurs, the errback is called with a
+ *     {@link goog.fs.Error}.
+ */
+goog.fs.DirectoryEntry.prototype.listDirectory = function() {};
+
+
+/**
+ * Removes this directory and all its contents.
+ *
+ * @return {!goog.async.Deferred} A deferred object. If the removal succeeds,
+ *     the callback is called with true. If an error occurs, the errback is
+ *     called a {@link goog.fs.Error}.
+ */
+goog.fs.DirectoryEntry.prototype.removeRecursively = function() {};
+
+
+
+/**
+ * A file in a local filesystem.
+ *
+ * @interface
+ * @extends {goog.fs.Entry}
+ */
+goog.fs.FileEntry = function() {};
+
+
+/**
+ * Create a writer for writing to the file.
+ *
+ * @return {!goog.async.Deferred<!goog.fs.FileWriter>} If an error occurs, the
+ *     errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.FileEntry.prototype.createWriter = function() {};
+
+
+/**
+ * Get the file contents as a File blob.
+ *
+ * @return {!goog.async.Deferred<!File>} If an error occurs, the errback is
+ *     called with a {@link goog.fs.Error}.
+ */
+goog.fs.FileEntry.prototype.file = function() {};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/entryimpl.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/entryimpl.js b/externs/GCL/externs/goog/fs/entryimpl.js
new file mode 100644
index 0000000..a4cbe7a
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/entryimpl.js
@@ -0,0 +1,404 @@
+// Copyright 2013 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 Concrete implementations of the
+ *     goog.fs.DirectoryEntry, and goog.fs.FileEntry interfaces.
+ */
+goog.provide('goog.fs.DirectoryEntryImpl');
+goog.provide('goog.fs.EntryImpl');
+goog.provide('goog.fs.FileEntryImpl');
+
+goog.require('goog.array');
+goog.require('goog.async.Deferred');
+goog.require('goog.fs.DirectoryEntry');
+goog.require('goog.fs.Entry');
+goog.require('goog.fs.Error');
+goog.require('goog.fs.FileEntry');
+goog.require('goog.fs.FileWriter');
+goog.require('goog.functions');
+goog.require('goog.string');
+
+
+
+/**
+ * Base class for concrete implementations of goog.fs.Entry.
+ * @param {!goog.fs.FileSystem} fs The wrapped filesystem.
+ * @param {!Entry} entry The underlying Entry object.
+ * @constructor
+ * @implements {goog.fs.Entry}
+ */
+goog.fs.EntryImpl = function(fs, entry) {
+  /**
+   * The wrapped filesystem.
+   *
+   * @type {!goog.fs.FileSystem}
+   * @private
+   */
+  this.fs_ = fs;
+
+  /**
+   * The underlying Entry object.
+   *
+   * @type {!Entry}
+   * @private
+   */
+  this.entry_ = entry;
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.isFile = function() {
+  return this.entry_.isFile;
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.isDirectory = function() {
+  return this.entry_.isDirectory;
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.getName = function() {
+  return this.entry_.name;
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.getFullPath = function() {
+  return this.entry_.fullPath;
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.getFileSystem = function() {
+  return this.fs_;
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.getLastModified = function() {
+  return this.getMetadata().addCallback(function(metadata) {
+    return metadata.modificationTime;
+  });
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.getMetadata = function() {
+  var d = new goog.async.Deferred();
+
+  this.entry_.getMetadata(
+      function(metadata) { d.callback(metadata); },
+      goog.bind(function(err) {
+        var msg = 'retrieving metadata for ' + this.getFullPath();
+        d.errback(new goog.fs.Error(err, msg));
+      }, this));
+  return d;
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.moveTo = function(parent, opt_newName) {
+  var d = new goog.async.Deferred();
+  this.entry_.moveTo(
+      parent.dir_, opt_newName,
+      goog.bind(function(entry) { d.callback(this.wrapEntry(entry)); }, this),
+      goog.bind(function(err) {
+        var msg = 'moving ' + this.getFullPath() + ' into ' +
+            parent.getFullPath() +
+            (opt_newName ? ', renaming to ' + opt_newName : '');
+        d.errback(new goog.fs.Error(err, msg));
+      }, this));
+  return d;
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.copyTo = function(parent, opt_newName) {
+  var d = new goog.async.Deferred();
+  this.entry_.copyTo(
+      parent.dir_, opt_newName,
+      goog.bind(function(entry) { d.callback(this.wrapEntry(entry)); }, this),
+      goog.bind(function(err) {
+        var msg = 'copying ' + this.getFullPath() + ' into ' +
+            parent.getFullPath() +
+            (opt_newName ? ', renaming to ' + opt_newName : '');
+        d.errback(new goog.fs.Error(err, msg));
+      }, this));
+  return d;
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.wrapEntry = function(entry) {
+  return entry.isFile ?
+      new goog.fs.FileEntryImpl(this.fs_, /** @type {!FileEntry} */ (entry)) :
+      new goog.fs.DirectoryEntryImpl(
+          this.fs_, /** @type {!DirectoryEntry} */ (entry));
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.toUrl = function(opt_mimeType) {
+  return this.entry_.toURL(opt_mimeType);
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.toUri = goog.fs.EntryImpl.prototype.toUrl;
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.remove = function() {
+  var d = new goog.async.Deferred();
+  this.entry_.remove(
+      goog.bind(d.callback, d, true /* result */),
+      goog.bind(function(err) {
+        var msg = 'removing ' + this.getFullPath();
+        d.errback(new goog.fs.Error(err, msg));
+      }, this));
+  return d;
+};
+
+
+/** @override */
+goog.fs.EntryImpl.prototype.getParent = function() {
+  var d = new goog.async.Deferred();
+  this.entry_.getParent(
+      goog.bind(function(parent) {
+        d.callback(new goog.fs.DirectoryEntryImpl(this.fs_, parent));
+      }, this),
+      goog.bind(function(err) {
+        var msg = 'getting parent of ' + this.getFullPath();
+        d.errback(new goog.fs.Error(err, msg));
+      }, this));
+  return d;
+};
+
+
+
+/**
+ * A directory in a local FileSystem.
+ *
+ * This should not be instantiated directly. Instead, it should be accessed via
+ * {@link goog.fs.FileSystem#getRoot} or
+ * {@link goog.fs.DirectoryEntry#getDirectoryEntry}.
+ *
+ * @param {!goog.fs.FileSystem} fs The wrapped filesystem.
+ * @param {!DirectoryEntry} dir The underlying DirectoryEntry object.
+ * @constructor
+ * @extends {goog.fs.EntryImpl}
+ * @implements {goog.fs.DirectoryEntry}
+ * @final
+ */
+goog.fs.DirectoryEntryImpl = function(fs, dir) {
+  goog.fs.DirectoryEntryImpl.base(this, 'constructor', fs, dir);
+
+  /**
+   * The underlying DirectoryEntry object.
+   *
+   * @type {!DirectoryEntry}
+   * @private
+   */
+  this.dir_ = dir;
+};
+goog.inherits(goog.fs.DirectoryEntryImpl, goog.fs.EntryImpl);
+
+
+/** @override */
+goog.fs.DirectoryEntryImpl.prototype.getFile = function(path, opt_behavior) {
+  var d = new goog.async.Deferred();
+  this.dir_.getFile(
+      path, this.getOptions_(opt_behavior),
+      goog.bind(function(entry) {
+        d.callback(new goog.fs.FileEntryImpl(this.fs_, entry));
+      }, this),
+      goog.bind(function(err) {
+        var msg = 'loading file ' + path + ' from ' + this.getFullPath();
+        d.errback(new goog.fs.Error(err, msg));
+      }, this));
+  return d;
+};
+
+
+/** @override */
+goog.fs.DirectoryEntryImpl.prototype.getDirectory =
+    function(path, opt_behavior) {
+  var d = new goog.async.Deferred();
+  this.dir_.getDirectory(
+      path, this.getOptions_(opt_behavior),
+      goog.bind(function(entry) {
+        d.callback(new goog.fs.DirectoryEntryImpl(this.fs_, entry));
+      }, this),
+      goog.bind(function(err) {
+        var msg = 'loading directory ' + path + ' from ' + this.getFullPath();
+        d.errback(new goog.fs.Error(err, msg));
+      }, this));
+  return d;
+};
+
+
+/** @override */
+goog.fs.DirectoryEntryImpl.prototype.createPath = function(path) {
+  // If the path begins at the root, reinvoke createPath on the root directory.
+  if (goog.string.startsWith(path, '/')) {
+    var root = this.getFileSystem().getRoot();
+    if (this.getFullPath() != root.getFullPath()) {
+      return root.createPath(path);
+    }
+  }
+
+  // Filter out any empty path components caused by '//' or a leading slash.
+  var parts = goog.array.filter(path.split('/'), goog.functions.identity);
+
+  /**
+   * @param {goog.fs.DirectoryEntryImpl} dir
+   * @return {!goog.async.Deferred}
+   */
+  function getNextDirectory(dir) {
+    if (!parts.length) {
+      return goog.async.Deferred.succeed(dir);
+    }
+
+    var def;
+    var nextDir = parts.shift();
+
+    if (nextDir == '..') {
+      def = dir.getParent();
+    } else if (nextDir == '.') {
+      def = goog.async.Deferred.succeed(dir);
+    } else {
+      def = dir.getDirectory(nextDir, goog.fs.DirectoryEntry.Behavior.CREATE);
+    }
+    return def.addCallback(getNextDirectory);
+  }
+
+  return getNextDirectory(this);
+};
+
+
+/** @override */
+goog.fs.DirectoryEntryImpl.prototype.listDirectory = function() {
+  var d = new goog.async.Deferred();
+  var reader = this.dir_.createReader();
+  var results = [];
+
+  var errorCallback = goog.bind(function(err) {
+    var msg = 'listing directory ' + this.getFullPath();
+    d.errback(new goog.fs.Error(err, msg));
+  }, this);
+
+  var successCallback = goog.bind(function(entries) {
+    if (entries.length) {
+      for (var i = 0, entry; entry = entries[i]; i++) {
+        results.push(this.wrapEntry(entry));
+      }
+      reader.readEntries(successCallback, errorCallback);
+    } else {
+      d.callback(results);
+    }
+  }, this);
+
+  reader.readEntries(successCallback, errorCallback);
+  return d;
+};
+
+
+/** @override */
+goog.fs.DirectoryEntryImpl.prototype.removeRecursively = function() {
+  var d = new goog.async.Deferred();
+  this.dir_.removeRecursively(
+      goog.bind(d.callback, d, true /* result */),
+      goog.bind(function(err) {
+        var msg = 'removing ' + this.getFullPath() + ' recursively';
+        d.errback(new goog.fs.Error(err, msg));
+      }, this));
+  return d;
+};
+
+
+/**
+ * Converts a value in the Behavior enum into an options object expected by the
+ * File API.
+ *
+ * @param {goog.fs.DirectoryEntry.Behavior=} opt_behavior The behavior for
+ *     existing files.
+ * @return {!Object<boolean>} The options object expected by the File API.
+ * @private
+ */
+goog.fs.DirectoryEntryImpl.prototype.getOptions_ = function(opt_behavior) {
+  if (opt_behavior == goog.fs.DirectoryEntry.Behavior.CREATE) {
+    return {'create': true};
+  } else if (opt_behavior == goog.fs.DirectoryEntry.Behavior.CREATE_EXCLUSIVE) {
+    return {'create': true, 'exclusive': true};
+  } else {
+    return {};
+  }
+};
+
+
+
+/**
+ * A file in a local filesystem.
+ *
+ * This should not be instantiated directly. Instead, it should be accessed via
+ * {@link goog.fs.DirectoryEntry#getFile}.
+ *
+ * @param {!goog.fs.FileSystem} fs The wrapped filesystem.
+ * @param {!FileEntry} file The underlying FileEntry object.
+ * @constructor
+ * @extends {goog.fs.EntryImpl}
+ * @implements {goog.fs.FileEntry}
+ * @final
+ */
+goog.fs.FileEntryImpl = function(fs, file) {
+  goog.fs.FileEntryImpl.base(this, 'constructor', fs, file);
+
+  /**
+   * The underlying FileEntry object.
+   *
+   * @type {!FileEntry}
+   * @private
+   */
+  this.file_ = file;
+};
+goog.inherits(goog.fs.FileEntryImpl, goog.fs.EntryImpl);
+
+
+/** @override */
+goog.fs.FileEntryImpl.prototype.createWriter = function() {
+  var d = new goog.async.Deferred();
+  this.file_.createWriter(
+      function(w) { d.callback(new goog.fs.FileWriter(w)); },
+      goog.bind(function(err) {
+        var msg = 'creating writer for ' + this.getFullPath();
+        d.errback(new goog.fs.Error(err, msg));
+      }, this));
+  return d;
+};
+
+
+/** @override */
+goog.fs.FileEntryImpl.prototype.file = function() {
+  var d = new goog.async.Deferred();
+  this.file_.file(
+      function(f) { d.callback(f); },
+      goog.bind(function(err) {
+        var msg = 'getting file for ' + this.getFullPath();
+        d.errback(new goog.fs.Error(err, msg));
+      }, this));
+  return d;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/error3.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/error3.js b/externs/GCL/externs/goog/fs/error3.js
new file mode 100644
index 0000000..3a54f28
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/error3.js
@@ -0,0 +1,181 @@
+// Copyright 2011 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 wrapper for the HTML5 FileError object.
+ *
+ */
+
+goog.provide('goog.fs.Error');
+goog.provide('goog.fs.Error.ErrorCode');
+
+goog.require('goog.debug.Error');
+goog.require('goog.object');
+goog.require('goog.string');
+
+
+
+/**
+ * A filesystem error. Since the filesystem API is asynchronous, stack traces
+ * are less useful for identifying where errors come from, so this includes a
+ * large amount of metadata in the message.
+ *
+ * @param {!DOMError} error
+ * @param {string} action The action being undertaken when the error was raised.
+ * @constructor
+ * @extends {goog.debug.Error}
+ * @final
+ */
+goog.fs.Error = function(error, action) {
+  /** @type {string} */
+  this.name;
+
+  /**
+   * @type {goog.fs.Error.ErrorCode}
+   * @deprecated Use the 'name' or 'message' field instead.
+   */
+  this.code;
+
+  if (goog.isDef(error.name)) {
+    this.name = error.name;
+    // TODO(user): Remove warning suppression after JSCompiler stops
+    // firing a spurious warning here.
+    /** @suppress {deprecated} */
+    this.code = goog.fs.Error.getCodeFromName_(error.name);
+  } else {
+    this.code = error.code;
+    this.name = goog.fs.Error.getNameFromCode_(error.code);
+  }
+  goog.fs.Error.base(this, 'constructor',
+      goog.string.subs('%s %s', this.name, action));
+};
+goog.inherits(goog.fs.Error, goog.debug.Error);
+
+
+/**
+ * Names of errors that may be thrown by the File API, the File System API, or
+ * the File Writer API.
+ *
+ * @see http://dev.w3.org/2006/webapi/FileAPI/#ErrorAndException
+ * @see http://www.w3.org/TR/file-system-api/#definitions
+ * @see http://dev.w3.org/2009/dap/file-system/file-writer.html#definitions
+ * @enum {string}
+ */
+goog.fs.Error.ErrorName = {
+  ABORT: 'AbortError',
+  ENCODING: 'EncodingError',
+  INVALID_MODIFICATION: 'InvalidModificationError',
+  INVALID_STATE: 'InvalidStateError',
+  NOT_FOUND: 'NotFoundError',
+  NOT_READABLE: 'NotReadableError',
+  NO_MODIFICATION_ALLOWED: 'NoModificationAllowedError',
+  PATH_EXISTS: 'PathExistsError',
+  QUOTA_EXCEEDED: 'QuotaExceededError',
+  SECURITY: 'SecurityError',
+  SYNTAX: 'SyntaxError',
+  TYPE_MISMATCH: 'TypeMismatchError'
+};
+
+
+/**
+ * Error codes for file errors.
+ * @see http://www.w3.org/TR/file-system-api/#idl-def-FileException
+ *
+ * @enum {number}
+ * @deprecated Use the 'name' or 'message' attribute instead.
+ */
+goog.fs.Error.ErrorCode = {
+  NOT_FOUND: 1,
+  SECURITY: 2,
+  ABORT: 3,
+  NOT_READABLE: 4,
+  ENCODING: 5,
+  NO_MODIFICATION_ALLOWED: 6,
+  INVALID_STATE: 7,
+  SYNTAX: 8,
+  INVALID_MODIFICATION: 9,
+  QUOTA_EXCEEDED: 10,
+  TYPE_MISMATCH: 11,
+  PATH_EXISTS: 12
+};
+
+
+/**
+ * @param {goog.fs.Error.ErrorCode} code
+ * @return {string} name
+ * @private
+ */
+goog.fs.Error.getNameFromCode_ = function(code) {
+  var name = goog.object.findKey(goog.fs.Error.NameToCodeMap_, function(c) {
+    return code == c;
+  });
+  if (!goog.isDef(name)) {
+    throw new Error('Invalid code: ' + code);
+  }
+  return name;
+};
+
+
+/**
+ * Returns the code that corresponds to the given name.
+ * @param {string} name
+ * @return {goog.fs.Error.ErrorCode} code
+ * @private
+ */
+goog.fs.Error.getCodeFromName_ = function(name) {
+  return goog.fs.Error.NameToCodeMap_[name];
+};
+
+
+/**
+ * Mapping from error names to values from the ErrorCode enum.
+ * @see http://www.w3.org/TR/file-system-api/#definitions.
+ * @private {!Object<string, goog.fs.Error.ErrorCode>}
+ */
+goog.fs.Error.NameToCodeMap_ = goog.object.create(
+    goog.fs.Error.ErrorName.ABORT,
+    goog.fs.Error.ErrorCode.ABORT,
+
+    goog.fs.Error.ErrorName.ENCODING,
+    goog.fs.Error.ErrorCode.ENCODING,
+
+    goog.fs.Error.ErrorName.INVALID_MODIFICATION,
+    goog.fs.Error.ErrorCode.INVALID_MODIFICATION,
+
+    goog.fs.Error.ErrorName.INVALID_STATE,
+    goog.fs.Error.ErrorCode.INVALID_STATE,
+
+    goog.fs.Error.ErrorName.NOT_FOUND,
+    goog.fs.Error.ErrorCode.NOT_FOUND,
+
+    goog.fs.Error.ErrorName.NOT_READABLE,
+    goog.fs.Error.ErrorCode.NOT_READABLE,
+
+    goog.fs.Error.ErrorName.NO_MODIFICATION_ALLOWED,
+    goog.fs.Error.ErrorCode.NO_MODIFICATION_ALLOWED,
+
+    goog.fs.Error.ErrorName.PATH_EXISTS,
+    goog.fs.Error.ErrorCode.PATH_EXISTS,
+
+    goog.fs.Error.ErrorName.QUOTA_EXCEEDED,
+    goog.fs.Error.ErrorCode.QUOTA_EXCEEDED,
+
+    goog.fs.Error.ErrorName.SECURITY,
+    goog.fs.Error.ErrorCode.SECURITY,
+
+    goog.fs.Error.ErrorName.SYNTAX,
+    goog.fs.Error.ErrorCode.SYNTAX,
+
+    goog.fs.Error.ErrorName.TYPE_MISMATCH,
+    goog.fs.Error.ErrorCode.TYPE_MISMATCH);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/filereader.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/filereader.js b/externs/GCL/externs/goog/fs/filereader.js
new file mode 100644
index 0000000..14d5245
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/filereader.js
@@ -0,0 +1,288 @@
+// Copyright 2011 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 wrapper for the HTML5 FileReader object.
+ *
+ */
+
+goog.provide('goog.fs.FileReader');
+goog.provide('goog.fs.FileReader.EventType');
+goog.provide('goog.fs.FileReader.ReadyState');
+
+goog.require('goog.async.Deferred');
+goog.require('goog.events.EventTarget');
+goog.require('goog.fs.Error');
+goog.require('goog.fs.ProgressEvent');
+
+
+
+/**
+ * An object for monitoring the reading of files. This emits ProgressEvents of
+ * the types listed in {@link goog.fs.FileReader.EventType}.
+ *
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @final
+ */
+goog.fs.FileReader = function() {
+  goog.fs.FileReader.base(this, 'constructor');
+
+  /**
+   * The underlying FileReader object.
+   *
+   * @type {!FileReader}
+   * @private
+   */
+  this.reader_ = new FileReader();
+
+  this.reader_.onloadstart = goog.bind(this.dispatchProgressEvent_, this);
+  this.reader_.onprogress = goog.bind(this.dispatchProgressEvent_, this);
+  this.reader_.onload = goog.bind(this.dispatchProgressEvent_, this);
+  this.reader_.onabort = goog.bind(this.dispatchProgressEvent_, this);
+  this.reader_.onerror = goog.bind(this.dispatchProgressEvent_, this);
+  this.reader_.onloadend = goog.bind(this.dispatchProgressEvent_, this);
+};
+goog.inherits(goog.fs.FileReader, goog.events.EventTarget);
+
+
+/**
+ * Possible states for a FileReader.
+ *
+ * @enum {number}
+ */
+goog.fs.FileReader.ReadyState = {
+  /**
+   * The object has been constructed, but there is no pending read.
+   */
+  INIT: 0,
+  /**
+   * Data is being read.
+   */
+  LOADING: 1,
+  /**
+   * The data has been read from the file, the read was aborted, or an error
+   * occurred.
+   */
+  DONE: 2
+};
+
+
+/**
+ * Events emitted by a FileReader.
+ *
+ * @enum {string}
+ */
+goog.fs.FileReader.EventType = {
+  /**
+   * Emitted when the reading begins. readyState will be LOADING.
+   */
+  LOAD_START: 'loadstart',
+  /**
+   * Emitted when progress has been made in reading the file. readyState will be
+   * LOADING.
+   */
+  PROGRESS: 'progress',
+  /**
+   * Emitted when the data has been successfully read. readyState will be
+   * LOADING.
+   */
+  LOAD: 'load',
+  /**
+   * Emitted when the reading has been aborted. readyState will be LOADING.
+   */
+  ABORT: 'abort',
+  /**
+   * Emitted when an error is encountered or the reading has been aborted.
+   * readyState will be LOADING.
+   */
+  ERROR: 'error',
+  /**
+   * Emitted when the reading is finished, whether successfully or not.
+   * readyState will be DONE.
+   */
+  LOAD_END: 'loadend'
+};
+
+
+/**
+ * Abort the reading of the file.
+ */
+goog.fs.FileReader.prototype.abort = function() {
+  try {
+    this.reader_.abort();
+  } catch (e) {
+    throw new goog.fs.Error(e, 'aborting read');
+  }
+};
+
+
+/**
+ * @return {goog.fs.FileReader.ReadyState} The current state of the FileReader.
+ */
+goog.fs.FileReader.prototype.getReadyState = function() {
+  return /** @type {goog.fs.FileReader.ReadyState} */ (this.reader_.readyState);
+};
+
+
+/**
+ * @return {*} The result of the file read.
+ */
+goog.fs.FileReader.prototype.getResult = function() {
+  return this.reader_.result;
+};
+
+
+/**
+ * @return {goog.fs.Error} The error encountered while reading, if any.
+ */
+goog.fs.FileReader.prototype.getError = function() {
+  return this.reader_.error &&
+      new goog.fs.Error(this.reader_.error, 'reading file');
+};
+
+
+/**
+ * Wrap a progress event emitted by the underlying file reader and re-emit it.
+ *
+ * @param {!ProgressEvent} event The underlying event.
+ * @private
+ */
+goog.fs.FileReader.prototype.dispatchProgressEvent_ = function(event) {
+  this.dispatchEvent(new goog.fs.ProgressEvent(event, this));
+};
+
+
+/** @override */
+goog.fs.FileReader.prototype.disposeInternal = function() {
+  goog.fs.FileReader.base(this, 'disposeInternal');
+  delete this.reader_;
+};
+
+
+/**
+ * Starts reading a blob as a binary string.
+ * @param {!Blob} blob The blob to read.
+ */
+goog.fs.FileReader.prototype.readAsBinaryString = function(blob) {
+  this.reader_.readAsBinaryString(blob);
+};
+
+
+/**
+ * Reads a blob as a binary string.
+ * @param {!Blob} blob The blob to read.
+ * @return {!goog.async.Deferred} The deferred Blob contents as a binary string.
+ *     If an error occurs, the errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.FileReader.readAsBinaryString = function(blob) {
+  var reader = new goog.fs.FileReader();
+  var d = goog.fs.FileReader.createDeferred_(reader);
+  reader.readAsBinaryString(blob);
+  return d;
+};
+
+
+/**
+ * Starts reading a blob as an array buffer.
+ * @param {!Blob} blob The blob to read.
+ */
+goog.fs.FileReader.prototype.readAsArrayBuffer = function(blob) {
+  this.reader_.readAsArrayBuffer(blob);
+};
+
+
+/**
+ * Reads a blob as an array buffer.
+ * @param {!Blob} blob The blob to read.
+ * @return {!goog.async.Deferred} The deferred Blob contents as an array buffer.
+ *     If an error occurs, the errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.FileReader.readAsArrayBuffer = function(blob) {
+  var reader = new goog.fs.FileReader();
+  var d = goog.fs.FileReader.createDeferred_(reader);
+  reader.readAsArrayBuffer(blob);
+  return d;
+};
+
+
+/**
+ * Starts reading a blob as text.
+ * @param {!Blob} blob The blob to read.
+ * @param {string=} opt_encoding The name of the encoding to use.
+ */
+goog.fs.FileReader.prototype.readAsText = function(blob, opt_encoding) {
+  this.reader_.readAsText(blob, opt_encoding);
+};
+
+
+/**
+ * Reads a blob as text.
+ * @param {!Blob} blob The blob to read.
+ * @param {string=} opt_encoding The name of the encoding to use.
+ * @return {!goog.async.Deferred} The deferred Blob contents as text.
+ *     If an error occurs, the errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.FileReader.readAsText = function(blob, opt_encoding) {
+  var reader = new goog.fs.FileReader();
+  var d = goog.fs.FileReader.createDeferred_(reader);
+  reader.readAsText(blob, opt_encoding);
+  return d;
+};
+
+
+/**
+ * Starts reading a blob as a data URL.
+ * @param {!Blob} blob The blob to read.
+ */
+goog.fs.FileReader.prototype.readAsDataUrl = function(blob) {
+  this.reader_.readAsDataURL(blob);
+};
+
+
+/**
+ * Reads a blob as a data URL.
+ * @param {!Blob} blob The blob to read.
+ * @return {!goog.async.Deferred} The deferred Blob contents as a data URL.
+ *     If an error occurs, the errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.FileReader.readAsDataUrl = function(blob) {
+  var reader = new goog.fs.FileReader();
+  var d = goog.fs.FileReader.createDeferred_(reader);
+  reader.readAsDataUrl(blob);
+  return d;
+};
+
+
+/**
+ * Creates a new deferred object for the results of a read method.
+ * @param {goog.fs.FileReader} reader The reader to create a deferred for.
+ * @return {!goog.async.Deferred} The deferred results.
+ * @private
+ */
+goog.fs.FileReader.createDeferred_ = function(reader) {
+  var deferred = new goog.async.Deferred();
+  reader.listen(goog.fs.FileReader.EventType.LOAD_END,
+      goog.partial(function(d, r, e) {
+        var result = r.getResult();
+        var error = r.getError();
+        if (result != null && !error) {
+          d.callback(result);
+        } else {
+          d.errback(error);
+        }
+        r.dispose();
+      }, deferred, reader));
+  return deferred;
+};


[48/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/asserts/asserts.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/asserts/asserts.js b/externs/GCL/externs/goog/asserts/asserts.js
new file mode 100644
index 0000000..95513d1
--- /dev/null
+++ b/externs/GCL/externs/goog/asserts/asserts.js
@@ -0,0 +1,365 @@
+// Copyright 2008 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 to check the preconditions, postconditions and
+ * invariants runtime.
+ *
+ * Methods in this package should be given special treatment by the compiler
+ * for type-inference. For example, <code>goog.asserts.assert(foo)</code>
+ * will restrict <code>foo</code> to a truthy value.
+ *
+ * The compiler has an option to disable asserts. So code like:
+ * <code>
+ * var x = goog.asserts.assert(foo()); goog.asserts.assert(bar());
+ * </code>
+ * will be transformed into:
+ * <code>
+ * var x = foo();
+ * </code>
+ * The compiler will leave in foo() (because its return value is used),
+ * but it will remove bar() because it assumes it does not have side-effects.
+ *
+ * @author agrieve@google.com (Andrew Grieve)
+ */
+
+goog.provide('goog.asserts');
+goog.provide('goog.asserts.AssertionError');
+
+goog.require('goog.debug.Error');
+goog.require('goog.dom.NodeType');
+goog.require('goog.string');
+
+
+/**
+ * @define {boolean} Whether to strip out asserts or to leave them in.
+ */
+goog.define('goog.asserts.ENABLE_ASSERTS', goog.DEBUG);
+
+
+
+/**
+ * Error object for failed assertions.
+ * @param {string} messagePattern The pattern that was used to form message.
+ * @param {!Array<*>} messageArgs The items to substitute into the pattern.
+ * @constructor
+ * @extends {goog.debug.Error}
+ * @final
+ */
+goog.asserts.AssertionError = function(messagePattern, messageArgs) {
+  messageArgs.unshift(messagePattern);
+  goog.debug.Error.call(this, goog.string.subs.apply(null, messageArgs));
+  // Remove the messagePattern afterwards to avoid permenantly modifying the
+  // passed in array.
+  messageArgs.shift();
+
+  /**
+   * The message pattern used to format the error message. Error handlers can
+   * use this to uniquely identify the assertion.
+   * @type {string}
+   */
+  this.messagePattern = messagePattern;
+};
+goog.inherits(goog.asserts.AssertionError, goog.debug.Error);
+
+
+/** @override */
+goog.asserts.AssertionError.prototype.name = 'AssertionError';
+
+
+/**
+ * The default error handler.
+ * @param {!goog.asserts.AssertionError} e The exception to be handled.
+ */
+goog.asserts.DEFAULT_ERROR_HANDLER = function(e) { throw e; };
+
+
+/**
+ * The handler responsible for throwing or logging assertion errors.
+ * @private {function(!goog.asserts.AssertionError)}
+ */
+goog.asserts.errorHandler_ = goog.asserts.DEFAULT_ERROR_HANDLER;
+
+
+/**
+ * Throws an exception with the given message and "Assertion failed" prefixed
+ * onto it.
+ * @param {string} defaultMessage The message to use if givenMessage is empty.
+ * @param {Array<*>} defaultArgs The substitution arguments for defaultMessage.
+ * @param {string|undefined} givenMessage Message supplied by the caller.
+ * @param {Array<*>} givenArgs The substitution arguments for givenMessage.
+ * @throws {goog.asserts.AssertionError} When the value is not a number.
+ * @private
+ */
+goog.asserts.doAssertFailure_ =
+    function(defaultMessage, defaultArgs, givenMessage, givenArgs) {
+  var message = 'Assertion failed';
+  if (givenMessage) {
+    message += ': ' + givenMessage;
+    var args = givenArgs;
+  } else if (defaultMessage) {
+    message += ': ' + defaultMessage;
+    args = defaultArgs;
+  }
+  // The '' + works around an Opera 10 bug in the unit tests. Without it,
+  // a stack trace is added to var message above. With this, a stack trace is
+  // not added until this line (it causes the extra garbage to be added after
+  // the assertion message instead of in the middle of it).
+  var e = new goog.asserts.AssertionError('' + message, args || []);
+  goog.asserts.errorHandler_(e);
+};
+
+
+/**
+ * Sets a custom error handler that can be used to customize the behavior of
+ * assertion failures, for example by turning all assertion failures into log
+ * messages.
+ * @param {function(!goog.asserts.AssertionError)} errorHandler
+ */
+goog.asserts.setErrorHandler = function(errorHandler) {
+  if (goog.asserts.ENABLE_ASSERTS) {
+    goog.asserts.errorHandler_ = errorHandler;
+  }
+};
+
+
+/**
+ * Checks if the condition evaluates to true if goog.asserts.ENABLE_ASSERTS is
+ * true.
+ * @template T
+ * @param {T} condition The condition to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {T} The value of the condition.
+ * @throws {goog.asserts.AssertionError} When the condition evaluates to false.
+ */
+goog.asserts.assert = function(condition, opt_message, var_args) {
+  if (goog.asserts.ENABLE_ASSERTS && !condition) {
+    goog.asserts.doAssertFailure_('', null, opt_message,
+        Array.prototype.slice.call(arguments, 2));
+  }
+  return condition;
+};
+
+
+/**
+ * Fails if goog.asserts.ENABLE_ASSERTS is true. This function is useful in case
+ * when we want to add a check in the unreachable area like switch-case
+ * statement:
+ *
+ * <pre>
+ *  switch(type) {
+ *    case FOO: doSomething(); break;
+ *    case BAR: doSomethingElse(); break;
+ *    default: goog.assert.fail('Unrecognized type: ' + type);
+ *      // We have only 2 types - "default:" section is unreachable code.
+ *  }
+ * </pre>
+ *
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @throws {goog.asserts.AssertionError} Failure.
+ */
+goog.asserts.fail = function(opt_message, var_args) {
+  if (goog.asserts.ENABLE_ASSERTS) {
+    goog.asserts.errorHandler_(new goog.asserts.AssertionError(
+        'Failure' + (opt_message ? ': ' + opt_message : ''),
+        Array.prototype.slice.call(arguments, 1)));
+  }
+};
+
+
+/**
+ * Checks if the value is a number if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {number} The value, guaranteed to be a number when asserts enabled.
+ * @throws {goog.asserts.AssertionError} When the value is not a number.
+ */
+goog.asserts.assertNumber = function(value, opt_message, var_args) {
+  if (goog.asserts.ENABLE_ASSERTS && !goog.isNumber(value)) {
+    goog.asserts.doAssertFailure_('Expected number but got %s: %s.',
+        [goog.typeOf(value), value], opt_message,
+        Array.prototype.slice.call(arguments, 2));
+  }
+  return /** @type {number} */ (value);
+};
+
+
+/**
+ * Checks if the value is a string if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {string} The value, guaranteed to be a string when asserts enabled.
+ * @throws {goog.asserts.AssertionError} When the value is not a string.
+ */
+goog.asserts.assertString = function(value, opt_message, var_args) {
+  if (goog.asserts.ENABLE_ASSERTS && !goog.isString(value)) {
+    goog.asserts.doAssertFailure_('Expected string but got %s: %s.',
+        [goog.typeOf(value), value], opt_message,
+        Array.prototype.slice.call(arguments, 2));
+  }
+  return /** @type {string} */ (value);
+};
+
+
+/**
+ * Checks if the value is a function if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {!Function} The value, guaranteed to be a function when asserts
+ *     enabled.
+ * @throws {goog.asserts.AssertionError} When the value is not a function.
+ */
+goog.asserts.assertFunction = function(value, opt_message, var_args) {
+  if (goog.asserts.ENABLE_ASSERTS && !goog.isFunction(value)) {
+    goog.asserts.doAssertFailure_('Expected function but got %s: %s.',
+        [goog.typeOf(value), value], opt_message,
+        Array.prototype.slice.call(arguments, 2));
+  }
+  return /** @type {!Function} */ (value);
+};
+
+
+/**
+ * Checks if the value is an Object if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {!Object} The value, guaranteed to be a non-null object.
+ * @throws {goog.asserts.AssertionError} When the value is not an object.
+ */
+goog.asserts.assertObject = function(value, opt_message, var_args) {
+  if (goog.asserts.ENABLE_ASSERTS && !goog.isObject(value)) {
+    goog.asserts.doAssertFailure_('Expected object but got %s: %s.',
+        [goog.typeOf(value), value],
+        opt_message, Array.prototype.slice.call(arguments, 2));
+  }
+  return /** @type {!Object} */ (value);
+};
+
+
+/**
+ * Checks if the value is an Array if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {!Array<?>} The value, guaranteed to be a non-null array.
+ * @throws {goog.asserts.AssertionError} When the value is not an array.
+ */
+goog.asserts.assertArray = function(value, opt_message, var_args) {
+  if (goog.asserts.ENABLE_ASSERTS && !goog.isArray(value)) {
+    goog.asserts.doAssertFailure_('Expected array but got %s: %s.',
+        [goog.typeOf(value), value], opt_message,
+        Array.prototype.slice.call(arguments, 2));
+  }
+  return /** @type {!Array<?>} */ (value);
+};
+
+
+/**
+ * Checks if the value is a boolean if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {boolean} The value, guaranteed to be a boolean when asserts are
+ *     enabled.
+ * @throws {goog.asserts.AssertionError} When the value is not a boolean.
+ */
+goog.asserts.assertBoolean = function(value, opt_message, var_args) {
+  if (goog.asserts.ENABLE_ASSERTS && !goog.isBoolean(value)) {
+    goog.asserts.doAssertFailure_('Expected boolean but got %s: %s.',
+        [goog.typeOf(value), value], opt_message,
+        Array.prototype.slice.call(arguments, 2));
+  }
+  return /** @type {boolean} */ (value);
+};
+
+
+/**
+ * Checks if the value is a DOM Element if goog.asserts.ENABLE_ASSERTS is true.
+ * @param {*} value The value to check.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @return {!Element} The value, likely to be a DOM Element when asserts are
+ *     enabled.
+ * @throws {goog.asserts.AssertionError} When the value is not an Element.
+ */
+goog.asserts.assertElement = function(value, opt_message, var_args) {
+  if (goog.asserts.ENABLE_ASSERTS && (!goog.isObject(value) ||
+      value.nodeType != goog.dom.NodeType.ELEMENT)) {
+    goog.asserts.doAssertFailure_('Expected Element but got %s: %s.',
+        [goog.typeOf(value), value], opt_message,
+        Array.prototype.slice.call(arguments, 2));
+  }
+  return /** @type {!Element} */ (value);
+};
+
+
+/**
+ * Checks if the value is an instance of the user-defined type if
+ * goog.asserts.ENABLE_ASSERTS is true.
+ *
+ * The compiler may tighten the type returned by this function.
+ *
+ * @param {*} value The value to check.
+ * @param {function(new: T, ...)} type A user-defined constructor.
+ * @param {string=} opt_message Error message in case of failure.
+ * @param {...*} var_args The items to substitute into the failure message.
+ * @throws {goog.asserts.AssertionError} When the value is not an instance of
+ *     type.
+ * @return {T}
+ * @template T
+ */
+goog.asserts.assertInstanceof = function(value, type, opt_message, var_args) {
+  if (goog.asserts.ENABLE_ASSERTS && !(value instanceof type)) {
+    goog.asserts.doAssertFailure_('Expected instanceof %s but got %s.',
+        [goog.asserts.getType_(type), goog.asserts.getType_(value)],
+        opt_message, Array.prototype.slice.call(arguments, 3));
+  }
+  return value;
+};
+
+
+/**
+ * Checks that no enumerable keys are present in Object.prototype. Such keys
+ * would break most code that use {@code for (var ... in ...)} loops.
+ */
+goog.asserts.assertObjectPrototypeIsIntact = function() {
+  for (var key in Object.prototype) {
+    goog.asserts.fail(key + ' should not be enumerable in Object.prototype.');
+  }
+};
+
+
+/**
+ * Returns the type of a value. If a constructor is passed, and a suitable
+ * string cannot be found, 'unknown type name' will be returned.
+ * @param {*} value A constructor, object, or primitive.
+ * @return {string} The best display name for the value, or 'unknown type name'.
+ * @private
+ */
+goog.asserts.getType_ = function(value) {
+  if (value instanceof Function) {
+    return value.displayName || value.name || 'unknown type name';
+  } else if (value instanceof Object) {
+    return value.constructor.displayName || value.constructor.name ||
+        Object.prototype.toString.call(value);
+  } else {
+    return value === null ? 'null' : typeof value;
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/async/animationdelay.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/async/animationdelay.js b/externs/GCL/externs/goog/async/animationdelay.js
new file mode 100644
index 0000000..1e24b34
--- /dev/null
+++ b/externs/GCL/externs/goog/async/animationdelay.js
@@ -0,0 +1,267 @@
+// 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 delayed callback that pegs to the next animation frame
+ * instead of a user-configurable timeout.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.async.AnimationDelay');
+
+goog.require('goog.Disposable');
+goog.require('goog.events');
+goog.require('goog.functions');
+
+
+
+// TODO(nicksantos): Should we factor out the common code between this and
+// goog.async.Delay? I'm not sure if there's enough code for this to really
+// make sense. Subclassing seems like the wrong approach for a variety of
+// reasons. Maybe there should be a common interface?
+
+
+
+/**
+ * A delayed callback that pegs to the next animation frame
+ * instead of a user configurable timeout. By design, this should have
+ * the same interface as goog.async.Delay.
+ *
+ * Uses requestAnimationFrame and friends when available, but falls
+ * back to a timeout of goog.async.AnimationDelay.TIMEOUT.
+ *
+ * For more on requestAnimationFrame and how you can use it to create smoother
+ * animations, see:
+ * @see http://paulirish.com/2011/requestanimationframe-for-smart-animating/
+ *
+ * @param {function(number)} listener Function to call when the delay completes.
+ *     Will be passed the timestamp when it's called, in unix ms.
+ * @param {Window=} opt_window The window object to execute the delay in.
+ *     Defaults to the global object.
+ * @param {Object=} opt_handler The object scope to invoke the function in.
+ * @constructor
+ * @struct
+ * @suppress {checkStructDictInheritance}
+ * @extends {goog.Disposable}
+ * @final
+ */
+goog.async.AnimationDelay = function(listener, opt_window, opt_handler) {
+  goog.async.AnimationDelay.base(this, 'constructor');
+
+  /**
+   * Identifier of the active delay timeout, or event listener,
+   * or null when inactive.
+   * @private {goog.events.Key|number}
+   */
+  this.id_ = null;
+
+  /**
+   * If we're using dom listeners.
+   * @private {?boolean}
+   */
+  this.usingListeners_ = false;
+
+  /**
+   * The function that will be invoked after a delay.
+   * @private {function(number)}
+   */
+  this.listener_ = listener;
+
+  /**
+   * The object context to invoke the callback in.
+   * @private {Object|undefined}
+   */
+  this.handler_ = opt_handler;
+
+  /**
+   * @private {Window}
+   */
+  this.win_ = opt_window || window;
+
+  /**
+   * Cached callback function invoked when the delay finishes.
+   * @private {function()}
+   */
+  this.callback_ = goog.bind(this.doAction_, this);
+};
+goog.inherits(goog.async.AnimationDelay, goog.Disposable);
+
+
+/**
+ * Default wait timeout for animations (in milliseconds).  Only used for timed
+ * animation, which uses a timer (setTimeout) to schedule animation.
+ *
+ * @type {number}
+ * @const
+ */
+goog.async.AnimationDelay.TIMEOUT = 20;
+
+
+/**
+ * Name of event received from the requestAnimationFrame in Firefox.
+ *
+ * @type {string}
+ * @const
+ * @private
+ */
+goog.async.AnimationDelay.MOZ_BEFORE_PAINT_EVENT_ = 'MozBeforePaint';
+
+
+/**
+ * Starts the delay timer. The provided listener function will be called
+ * before the next animation frame.
+ */
+goog.async.AnimationDelay.prototype.start = function() {
+  this.stop();
+  this.usingListeners_ = false;
+
+  var raf = this.getRaf_();
+  var cancelRaf = this.getCancelRaf_();
+  if (raf && !cancelRaf && this.win_.mozRequestAnimationFrame) {
+    // Because Firefox (Gecko) runs animation in separate threads, it also saves
+    // time by running the requestAnimationFrame callbacks in that same thread.
+    // Sadly this breaks the assumption of implicit thread-safety in JS, and can
+    // thus create thread-based inconsistencies on counters etc.
+    //
+    // Calling cycleAnimations_ using the MozBeforePaint event instead of as
+    // callback fixes this.
+    //
+    // Trigger this condition only if the mozRequestAnimationFrame is available,
+    // but not the W3C requestAnimationFrame function (as in draft) or the
+    // equivalent cancel functions.
+    this.id_ = goog.events.listen(
+        this.win_,
+        goog.async.AnimationDelay.MOZ_BEFORE_PAINT_EVENT_,
+        this.callback_);
+    this.win_.mozRequestAnimationFrame(null);
+    this.usingListeners_ = true;
+  } else if (raf && cancelRaf) {
+    this.id_ = raf.call(this.win_, this.callback_);
+  } else {
+    this.id_ = this.win_.setTimeout(
+        // Prior to Firefox 13, Gecko passed a non-standard parameter
+        // to the callback that we want to ignore.
+        goog.functions.lock(this.callback_),
+        goog.async.AnimationDelay.TIMEOUT);
+  }
+};
+
+
+/**
+ * Stops the delay timer if it is active. No action is taken if the timer is not
+ * in use.
+ */
+goog.async.AnimationDelay.prototype.stop = function() {
+  if (this.isActive()) {
+    var raf = this.getRaf_();
+    var cancelRaf = this.getCancelRaf_();
+    if (raf && !cancelRaf && this.win_.mozRequestAnimationFrame) {
+      goog.events.unlistenByKey(this.id_);
+    } else if (raf && cancelRaf) {
+      cancelRaf.call(this.win_, /** @type {number} */ (this.id_));
+    } else {
+      this.win_.clearTimeout(/** @type {number} */ (this.id_));
+    }
+  }
+  this.id_ = null;
+};
+
+
+/**
+ * Fires delay's action even if timer has already gone off or has not been
+ * started yet; guarantees action firing. Stops the delay timer.
+ */
+goog.async.AnimationDelay.prototype.fire = function() {
+  this.stop();
+  this.doAction_();
+};
+
+
+/**
+ * Fires delay's action only if timer is currently active. Stops the delay
+ * timer.
+ */
+goog.async.AnimationDelay.prototype.fireIfActive = function() {
+  if (this.isActive()) {
+    this.fire();
+  }
+};
+
+
+/**
+ * @return {boolean} True if the delay is currently active, false otherwise.
+ */
+goog.async.AnimationDelay.prototype.isActive = function() {
+  return this.id_ != null;
+};
+
+
+/**
+ * Invokes the callback function after the delay successfully completes.
+ * @private
+ */
+goog.async.AnimationDelay.prototype.doAction_ = function() {
+  if (this.usingListeners_ && this.id_) {
+    goog.events.unlistenByKey(this.id_);
+  }
+  this.id_ = null;
+
+  // We are not using the timestamp returned by requestAnimationFrame
+  // because it may be either a Date.now-style time or a
+  // high-resolution time (depending on browser implementation). Using
+  // goog.now() will ensure that the timestamp used is consistent and
+  // compatible with goog.fx.Animation.
+  this.listener_.call(this.handler_, goog.now());
+};
+
+
+/** @override */
+goog.async.AnimationDelay.prototype.disposeInternal = function() {
+  this.stop();
+  goog.async.AnimationDelay.base(this, 'disposeInternal');
+};
+
+
+/**
+ * @return {?function(function(number)): number} The requestAnimationFrame
+ *     function, or null if not available on this browser.
+ * @private
+ */
+goog.async.AnimationDelay.prototype.getRaf_ = function() {
+  var win = this.win_;
+  return win.requestAnimationFrame ||
+      win.webkitRequestAnimationFrame ||
+      win.mozRequestAnimationFrame ||
+      win.oRequestAnimationFrame ||
+      win.msRequestAnimationFrame ||
+      null;
+};
+
+
+/**
+ * @return {?function(number): number} The cancelAnimationFrame function,
+ *     or null if not available on this browser.
+ * @private
+ */
+goog.async.AnimationDelay.prototype.getCancelRaf_ = function() {
+  var win = this.win_;
+  return win.cancelAnimationFrame ||
+      win.cancelRequestAnimationFrame ||
+      win.webkitCancelRequestAnimationFrame ||
+      win.mozCancelRequestAnimationFrame ||
+      win.oCancelRequestAnimationFrame ||
+      win.msCancelRequestAnimationFrame ||
+      null;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/async/conditionaldelay.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/async/conditionaldelay.js b/externs/GCL/externs/goog/async/conditionaldelay.js
new file mode 100644
index 0000000..c5ff892
--- /dev/null
+++ b/externs/GCL/externs/goog/async/conditionaldelay.js
@@ -0,0 +1,228 @@
+// Copyright 2008 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 Defines a class useful for handling functions that must be
+ * invoked later when some condition holds. Examples include deferred function
+ * calls that return a boolean flag whether it succedeed or not.
+ *
+ * Example:
+ *
+ *  function deferred() {
+ *     var succeeded = false;
+ *     // ... custom code
+ *     return succeeded;
+ *  }
+ *
+ *  var deferredCall = new goog.async.ConditionalDelay(deferred);
+ *  deferredCall.onSuccess = function() {
+ *    alert('Success: The deferred function has been successfully executed.');
+ *  }
+ *  deferredCall.onFailure = function() {
+ *    alert('Failure: Time limit exceeded.');
+ *  }
+ *
+ *  // Call the deferred() every 100 msec until it returns true,
+ *  // or 5 seconds pass.
+ *  deferredCall.start(100, 5000);
+ *
+ *  // Stop the deferred function call (does nothing if it's not active).
+ *  deferredCall.stop();
+ *
+ */
+
+
+goog.provide('goog.async.ConditionalDelay');
+
+goog.require('goog.Disposable');
+goog.require('goog.async.Delay');
+
+
+
+/**
+ * A ConditionalDelay object invokes the associated function after a specified
+ * interval delay and checks its return value. If the function returns
+ * {@code true} the conditional delay is cancelled and {@see #onSuccess}
+ * is called. Otherwise this object keeps to invoke the deferred function until
+ * either it returns {@code true} or the timeout is exceeded. In the latter case
+ * the {@see #onFailure} method will be called.
+ *
+ * The interval duration and timeout can be specified each time the delay is
+ * started. Calling start on an active delay will reset the timer.
+ *
+ * @param {function():boolean} listener Function to call when the delay
+ *     completes. Should return a value that type-converts to {@code true} if
+ *     the call succeeded and this delay should be stopped.
+ * @param {Object=} opt_handler The object scope to invoke the function in.
+ * @constructor
+ * @struct
+ * @suppress {checkStructDictInheritance}
+ * @extends {goog.Disposable}
+ */
+goog.async.ConditionalDelay = function(listener, opt_handler) {
+  goog.async.ConditionalDelay.base(this, 'constructor');
+
+  /**
+   * The delay interval in milliseconds to between the calls to the callback.
+   * Note, that the callback may be invoked earlier than this interval if the
+   * timeout is exceeded.
+   * @private {number}
+   */
+  this.interval_ = 0;
+
+  /**
+   * The timeout timestamp until which the delay is to be executed.
+   * A negative value means no timeout.
+   * @private {number}
+   */
+  this.runUntil_ = 0;
+
+  /**
+   * True if the listener has been executed, and it returned {@code true}.
+   * @private {boolean}
+   */
+  this.isDone_ = false;
+
+  /**
+   * The function that will be invoked after a delay.
+   * @private {function():boolean}
+   */
+  this.listener_ = listener;
+
+  /**
+   * The object context to invoke the callback in.
+   * @private {Object|undefined}
+   */
+  this.handler_ = opt_handler;
+
+  /**
+   * The underlying goog.async.Delay delegate object.
+   * @private {goog.async.Delay}
+   */
+  this.delay_ = new goog.async.Delay(
+      goog.bind(this.onTick_, this), 0 /*interval*/, this /*scope*/);
+};
+goog.inherits(goog.async.ConditionalDelay, goog.Disposable);
+
+
+/** @override */
+goog.async.ConditionalDelay.prototype.disposeInternal = function() {
+  this.delay_.dispose();
+  delete this.listener_;
+  delete this.handler_;
+  goog.async.ConditionalDelay.superClass_.disposeInternal.call(this);
+};
+
+
+/**
+ * Starts the delay timer. The provided listener function will be called
+ * repeatedly after the specified interval until the function returns
+ * {@code true} or the timeout is exceeded. Calling start on an active timer
+ * will stop the timer first.
+ * @param {number=} opt_interval The time interval between the function
+ *     invocations (in milliseconds). Default is 0.
+ * @param {number=} opt_timeout The timeout interval (in milliseconds). Takes
+ *     precedence over the {@code opt_interval}, i.e. if the timeout is less
+ *     than the invocation interval, the function will be called when the
+ *     timeout is exceeded. A negative value means no timeout. Default is 0.
+ */
+goog.async.ConditionalDelay.prototype.start = function(opt_interval,
+                                                       opt_timeout) {
+  this.stop();
+  this.isDone_ = false;
+
+  var timeout = opt_timeout || 0;
+  this.interval_ = Math.max(opt_interval || 0, 0);
+  this.runUntil_ = timeout < 0 ? -1 : (goog.now() + timeout);
+  this.delay_.start(
+      timeout < 0 ? this.interval_ : Math.min(this.interval_, timeout));
+};
+
+
+/**
+ * Stops the delay timer if it is active. No action is taken if the timer is not
+ * in use.
+ */
+goog.async.ConditionalDelay.prototype.stop = function() {
+  this.delay_.stop();
+};
+
+
+/**
+ * @return {boolean} True if the delay is currently active, false otherwise.
+ */
+goog.async.ConditionalDelay.prototype.isActive = function() {
+  return this.delay_.isActive();
+};
+
+
+/**
+ * @return {boolean} True if the listener has been executed and returned
+ *     {@code true} since the last call to {@see #start}.
+ */
+goog.async.ConditionalDelay.prototype.isDone = function() {
+  return this.isDone_;
+};
+
+
+/**
+ * Called when the listener has been successfully executed and returned
+ * {@code true}. The {@see #isDone} method should return {@code true} by now.
+ * Designed for inheritance, should be overridden by subclasses or on the
+ * instances if they care.
+ */
+goog.async.ConditionalDelay.prototype.onSuccess = function() {
+  // Do nothing by default.
+};
+
+
+/**
+ * Called when this delayed call is cancelled because the timeout has been
+ * exceeded, and the listener has never returned {@code true}.
+ * Designed for inheritance, should be overridden by subclasses or on the
+ * instances if they care.
+ */
+goog.async.ConditionalDelay.prototype.onFailure = function() {
+  // Do nothing by default.
+};
+
+
+/**
+ * A callback function for the underlying {@code goog.async.Delay} object. When
+ * executed the listener function is called, and if it returns {@code true}
+ * the delay is stopped and the {@see #onSuccess} method is invoked.
+ * If the timeout is exceeded the delay is stopped and the
+ * {@see #onFailure} method is called.
+ * @private
+ */
+goog.async.ConditionalDelay.prototype.onTick_ = function() {
+  var successful = this.listener_.call(this.handler_);
+  if (successful) {
+    this.isDone_ = true;
+    this.onSuccess();
+  } else {
+    // Try to reschedule the task.
+    if (this.runUntil_ < 0) {
+      // No timeout.
+      this.delay_.start(this.interval_);
+    } else {
+      var timeLeft = this.runUntil_ - goog.now();
+      if (timeLeft <= 0) {
+        this.onFailure();
+      } else {
+        this.delay_.start(Math.min(this.interval_, timeLeft));
+      }
+    }
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/async/delay.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/async/delay.js b/externs/GCL/externs/goog/async/delay.js
new file mode 100644
index 0000000..0b8225d
--- /dev/null
+++ b/externs/GCL/externs/goog/async/delay.js
@@ -0,0 +1,182 @@
+// 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 Defines a class useful for handling functions that must be
+ * invoked after a delay, especially when that delay is frequently restarted.
+ * Examples include delaying before displaying a tooltip, menu hysteresis,
+ * idle timers, etc.
+ * @author brenneman@google.com (Shawn Brenneman)
+ * @see ../demos/timers.html
+ */
+
+
+goog.provide('goog.Delay');
+goog.provide('goog.async.Delay');
+
+goog.require('goog.Disposable');
+goog.require('goog.Timer');
+
+
+
+/**
+ * A Delay object invokes the associated function after a specified delay. The
+ * interval duration can be specified once in the constructor, or can be defined
+ * each time the delay is started. Calling start on an active delay will reset
+ * the timer.
+ *
+ * @param {function(this:THIS)} listener Function to call when the
+ *     delay completes.
+ * @param {number=} opt_interval The default length of the invocation delay (in
+ *     milliseconds).
+ * @param {THIS=} opt_handler The object scope to invoke the function in.
+ * @template THIS
+ * @constructor
+ * @struct
+ * @suppress {checkStructDictInheritance}
+ * @extends {goog.Disposable}
+ * @final
+ */
+goog.async.Delay = function(listener, opt_interval, opt_handler) {
+  goog.async.Delay.base(this, 'constructor');
+
+  /**
+   * The function that will be invoked after a delay.
+   * @private {function(this:THIS)}
+   */
+  this.listener_ = listener;
+
+  /**
+   * The default amount of time to delay before invoking the callback.
+   * @type {number}
+   * @private
+   */
+  this.interval_ = opt_interval || 0;
+
+  /**
+   * The object context to invoke the callback in.
+   * @type {Object|undefined}
+   * @private
+   */
+  this.handler_ = opt_handler;
+
+
+  /**
+   * Cached callback function invoked when the delay finishes.
+   * @type {Function}
+   * @private
+   */
+  this.callback_ = goog.bind(this.doAction_, this);
+};
+goog.inherits(goog.async.Delay, goog.Disposable);
+
+
+
+/**
+ * A deprecated alias.
+ * @deprecated Use goog.async.Delay instead.
+ * @constructor
+ * @final
+ */
+goog.Delay = goog.async.Delay;
+
+
+/**
+ * Identifier of the active delay timeout, or 0 when inactive.
+ * @type {number}
+ * @private
+ */
+goog.async.Delay.prototype.id_ = 0;
+
+
+/**
+ * Disposes of the object, cancelling the timeout if it is still outstanding and
+ * removing all object references.
+ * @override
+ * @protected
+ */
+goog.async.Delay.prototype.disposeInternal = function() {
+  goog.async.Delay.base(this, 'disposeInternal');
+  this.stop();
+  delete this.listener_;
+  delete this.handler_;
+};
+
+
+/**
+ * Starts the delay timer. The provided listener function will be called after
+ * the specified interval. Calling start on an active timer will reset the
+ * delay interval.
+ * @param {number=} opt_interval If specified, overrides the object's default
+ *     interval with this one (in milliseconds).
+ */
+goog.async.Delay.prototype.start = function(opt_interval) {
+  this.stop();
+  this.id_ = goog.Timer.callOnce(
+      this.callback_,
+      goog.isDef(opt_interval) ? opt_interval : this.interval_);
+};
+
+
+/**
+ * Stops the delay timer if it is active. No action is taken if the timer is not
+ * in use.
+ */
+goog.async.Delay.prototype.stop = function() {
+  if (this.isActive()) {
+    goog.Timer.clear(this.id_);
+  }
+  this.id_ = 0;
+};
+
+
+/**
+ * Fires delay's action even if timer has already gone off or has not been
+ * started yet; guarantees action firing. Stops the delay timer.
+ */
+goog.async.Delay.prototype.fire = function() {
+  this.stop();
+  this.doAction_();
+};
+
+
+/**
+ * Fires delay's action only if timer is currently active. Stops the delay
+ * timer.
+ */
+goog.async.Delay.prototype.fireIfActive = function() {
+  if (this.isActive()) {
+    this.fire();
+  }
+};
+
+
+/**
+ * @return {boolean} True if the delay is currently active, false otherwise.
+ */
+goog.async.Delay.prototype.isActive = function() {
+  return this.id_ != 0;
+};
+
+
+/**
+ * Invokes the callback function after the delay successfully completes.
+ * @private
+ */
+goog.async.Delay.prototype.doAction_ = function() {
+  this.id_ = 0;
+  if (this.listener_) {
+    this.listener_.call(this.handler_);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/async/freelist.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/async/freelist.js b/externs/GCL/externs/goog/async/freelist.js
new file mode 100644
index 0000000..d0331f2
--- /dev/null
+++ b/externs/GCL/externs/goog/async/freelist.js
@@ -0,0 +1,88 @@
+// Copyright 2015 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 Simple freelist.
+ *
+ * An anterative to goog.structs.SimplePool, it imposes the requirement that the
+ * objects in the list contain a "next" property that can be used to maintain
+ * the pool.
+ */
+
+goog.provide('goog.async.FreeList');
+
+
+/**
+ * @template ITEM
+ */
+goog.async.FreeList = goog.defineClass(null, {
+  /**
+   * @param {function():ITEM} create
+   * @param {function(ITEM):void} reset
+   * @param {number} limit
+   */
+  constructor: function(create, reset, limit) {
+    /** @const {number} */
+    this.limit_ = limit;
+    /** @const {function()} */
+    this.create_ = create;
+    /** @const {function(ITEM):void} */
+    this.reset_ = reset;
+
+    /** @type {number} */
+    this.occupants_ = 0;
+    /** @type {ITEM} */
+    this.head_ = null;
+  },
+
+  /**
+   * @return {ITEM}
+   */
+  get: function() {
+    var item;
+    if (this.occupants_ > 0) {
+      this.occupants_--;
+      item = this.head_;
+      this.head_ = item.next;
+      item.next = null;
+    } else {
+      item = this.create_();
+    }
+    return item;
+  },
+
+  /**
+   * @param {ITEM} item An item available for possible future reuse.
+   */
+  put: function(item) {
+    this.reset_(item);
+    if (this.occupants_ < this.limit_) {
+      this.occupants_++;
+      item.next = this.head_;
+      this.head_ = item;
+    }
+  },
+
+  /**
+   * Visible for testing.
+   * @package
+   * @return {number}
+   */
+  occupants: function() {
+    return this.occupants_;
+  }
+});
+
+
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/async/nexttick.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/async/nexttick.js b/externs/GCL/externs/goog/async/nexttick.js
new file mode 100644
index 0000000..bdbad6b
--- /dev/null
+++ b/externs/GCL/externs/goog/async/nexttick.js
@@ -0,0 +1,241 @@
+// Copyright 2013 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 Provides a function to schedule running a function as soon
+ * as possible after the current JS execution stops and yields to the event
+ * loop.
+ *
+ */
+
+goog.provide('goog.async.nextTick');
+goog.provide('goog.async.throwException');
+
+goog.require('goog.debug.entryPointRegistry');
+goog.require('goog.dom.TagName');
+goog.require('goog.functions');
+goog.require('goog.labs.userAgent.browser');
+goog.require('goog.labs.userAgent.engine');
+
+
+/**
+ * Throw an item without interrupting the current execution context.  For
+ * example, if processing a group of items in a loop, sometimes it is useful
+ * to report an error while still allowing the rest of the batch to be
+ * processed.
+ * @param {*} exception
+ */
+goog.async.throwException = function(exception) {
+  // Each throw needs to be in its own context.
+  goog.global.setTimeout(function() { throw exception; }, 0);
+};
+
+
+/**
+ * Fires the provided callbacks as soon as possible after the current JS
+ * execution context. setTimeout(…, 0) takes at least 4ms when called from
+ * within another setTimeout(…, 0) for legacy reasons.
+ *
+ * This will not schedule the callback as a microtask (i.e. a task that can
+ * preempt user input or networking callbacks). It is meant to emulate what
+ * setTimeout(_, 0) would do if it were not throttled. If you desire microtask
+ * behavior, use {@see goog.Promise} instead.
+ *
+ * @param {function(this:SCOPE)} callback Callback function to fire as soon as
+ *     possible.
+ * @param {SCOPE=} opt_context Object in whose scope to call the listener.
+ * @param {boolean=} opt_useSetImmediate Avoid the IE workaround that
+ *     ensures correctness at the cost of speed. See comments for details.
+ * @template SCOPE
+ */
+goog.async.nextTick = function(callback, opt_context, opt_useSetImmediate) {
+  var cb = callback;
+  if (opt_context) {
+    cb = goog.bind(callback, opt_context);
+  }
+  cb = goog.async.nextTick.wrapCallback_(cb);
+  // window.setImmediate was introduced and currently only supported by IE10+,
+  // but due to a bug in the implementation it is not guaranteed that
+  // setImmediate is faster than setTimeout nor that setImmediate N is before
+  // setImmediate N+1. That is why we do not use the native version if
+  // available. We do, however, call setImmediate if it is a normal function
+  // because that indicates that it has been replaced by goog.testing.MockClock
+  // which we do want to support.
+  // See
+  // http://connect.microsoft.com/IE/feedback/details/801823/setimmediate-and-messagechannel-are-broken-in-ie10
+  //
+  // Note we do allow callers to also request setImmediate if they are willing
+  // to accept the possible tradeoffs of incorrectness in exchange for speed.
+  // The IE fallback of readystate change is much slower.
+  if (goog.isFunction(goog.global.setImmediate) &&
+      // Opt in.
+      (opt_useSetImmediate ||
+      // or it isn't a browser or the environment is weird
+      !goog.global.Window || !goog.global.Window.prototype ||
+      // or something redefined setImmediate in which case we (YOLO) decide
+      // to use it (This is so that we use the mockClock setImmediate. sigh).
+      goog.global.Window.prototype.setImmediate != goog.global.setImmediate)) {
+    goog.global.setImmediate(cb);
+    return;
+  }
+
+  // Look for and cache the custom fallback version of setImmediate.
+  if (!goog.async.nextTick.setImmediate_) {
+    goog.async.nextTick.setImmediate_ =
+        goog.async.nextTick.getSetImmediateEmulator_();
+  }
+  goog.async.nextTick.setImmediate_(cb);
+};
+
+
+/**
+ * Cache for the setImmediate implementation.
+ * @type {function(function())}
+ * @private
+ */
+goog.async.nextTick.setImmediate_;
+
+
+/**
+ * Determines the best possible implementation to run a function as soon as
+ * the JS event loop is idle.
+ * @return {function(function())} The "setImmediate" implementation.
+ * @private
+ */
+goog.async.nextTick.getSetImmediateEmulator_ = function() {
+  // Create a private message channel and use it to postMessage empty messages
+  // to ourselves.
+  var Channel = goog.global['MessageChannel'];
+  // If MessageChannel is not available and we are in a browser, implement
+  // an iframe based polyfill in browsers that have postMessage and
+  // document.addEventListener. The latter excludes IE8 because it has a
+  // synchronous postMessage implementation.
+  if (typeof Channel === 'undefined' && typeof window !== 'undefined' &&
+      window.postMessage && window.addEventListener &&
+      // Presto (The old pre-blink Opera engine) has problems with iframes
+      // and contentWindow.
+      !goog.labs.userAgent.engine.isPresto()) {
+    /** @constructor */
+    Channel = function() {
+      // Make an empty, invisible iframe.
+      var iframe = document.createElement(goog.dom.TagName.IFRAME);
+      iframe.style.display = 'none';
+      iframe.src = '';
+      document.documentElement.appendChild(iframe);
+      var win = iframe.contentWindow;
+      var doc = win.document;
+      doc.open();
+      doc.write('');
+      doc.close();
+      // Do not post anything sensitive over this channel, as the workaround for
+      // pages with file: origin could allow that information to be modified or
+      // intercepted.
+      var message = 'callImmediate' + Math.random();
+      // The same origin policy rejects attempts to postMessage from file: urls
+      // unless the origin is '*'.
+      // TODO(b/16335441): Use '*' origin for data: and other similar protocols.
+      var origin = win.location.protocol == 'file:' ?
+          '*' : win.location.protocol + '//' + win.location.host;
+      var onmessage = goog.bind(function(e) {
+        // Validate origin and message to make sure that this message was
+        // intended for us. If the origin is set to '*' (see above) only the
+        // message needs to match since, for example, '*' != 'file://'. Allowing
+        // the wildcard is ok, as we are not concerned with security here.
+        if ((origin != '*' && e.origin != origin) || e.data != message) {
+          return;
+        }
+        this['port1'].onmessage();
+      }, this);
+      win.addEventListener('message', onmessage, false);
+      this['port1'] = {};
+      this['port2'] = {
+        postMessage: function() {
+          win.postMessage(message, origin);
+        }
+      };
+    };
+  }
+  if (typeof Channel !== 'undefined' &&
+      (!goog.labs.userAgent.browser.isIE())) {
+    // Exclude all of IE due to
+    // http://codeforhire.com/2013/09/21/setimmediate-and-messagechannel-broken-on-internet-explorer-10/
+    // which allows starving postMessage with a busy setTimeout loop.
+    // This currently affects IE10 and IE11 which would otherwise be able
+    // to use the postMessage based fallbacks.
+    var channel = new Channel();
+    // Use a fifo linked list to call callbacks in the right order.
+    var head = {};
+    var tail = head;
+    channel['port1'].onmessage = function() {
+      if (goog.isDef(head.next)) {
+        head = head.next;
+        var cb = head.cb;
+        head.cb = null;
+        cb();
+      }
+    };
+    return function(cb) {
+      tail.next = {
+        cb: cb
+      };
+      tail = tail.next;
+      channel['port2'].postMessage(0);
+    };
+  }
+  // Implementation for IE6+: Script elements fire an asynchronous
+  // onreadystatechange event when inserted into the DOM.
+  if (typeof document !== 'undefined' && 'onreadystatechange' in
+      document.createElement(goog.dom.TagName.SCRIPT)) {
+    return function(cb) {
+      var script = document.createElement(goog.dom.TagName.SCRIPT);
+      script.onreadystatechange = function() {
+        // Clean up and call the callback.
+        script.onreadystatechange = null;
+        script.parentNode.removeChild(script);
+        script = null;
+        cb();
+        cb = null;
+      };
+      document.documentElement.appendChild(script);
+    };
+  }
+  // Fall back to setTimeout with 0. In browsers this creates a delay of 5ms
+  // or more.
+  return function(cb) {
+    goog.global.setTimeout(cb, 0);
+  };
+};
+
+
+/**
+ * Helper function that is overrided to protect callbacks with entry point
+ * monitor if the application monitors entry points.
+ * @param {function()} callback Callback function to fire as soon as possible.
+ * @return {function()} The wrapped callback.
+ * @private
+ */
+goog.async.nextTick.wrapCallback_ = goog.functions.identity;
+
+
+// Register the callback function as an entry point, so that it can be
+// monitored for exception handling, etc. This has to be done in this file
+// since it requires special code to handle all browsers.
+goog.debug.entryPointRegistry.register(
+    /**
+     * @param {function(!Function): !Function} transformer The transforming
+     *     function.
+     */
+    function(transformer) {
+      goog.async.nextTick.wrapCallback_ = transformer;
+    });

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/async/run.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/async/run.js b/externs/GCL/externs/goog/async/run.js
new file mode 100644
index 0000000..b621477
--- /dev/null
+++ b/externs/GCL/externs/goog/async/run.js
@@ -0,0 +1,130 @@
+// Copyright 2013 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.
+
+goog.provide('goog.async.run');
+
+goog.require('goog.async.WorkQueue');
+goog.require('goog.async.nextTick');
+goog.require('goog.async.throwException');
+goog.require('goog.testing.watchers');
+
+
+/**
+ * Fires the provided callback just before the current callstack unwinds, or as
+ * soon as possible after the current JS execution context.
+ * @param {function(this:THIS)} callback
+ * @param {THIS=} opt_context Object to use as the "this value" when calling
+ *     the provided function.
+ * @template THIS
+ */
+goog.async.run = function(callback, opt_context) {
+  if (!goog.async.run.schedule_) {
+    goog.async.run.initializeRunner_();
+  }
+  if (!goog.async.run.workQueueScheduled_) {
+    // Nothing is currently scheduled, schedule it now.
+    goog.async.run.schedule_();
+    goog.async.run.workQueueScheduled_ = true;
+  }
+
+  goog.async.run.workQueue_.add(callback, opt_context);
+};
+
+
+/**
+ * Initializes the function to use to process the work queue.
+ * @private
+ */
+goog.async.run.initializeRunner_ = function() {
+  // If native Promises are available in the browser, just schedule the callback
+  // on a fulfilled promise, which is specified to be async, but as fast as
+  // possible.
+  if (goog.global.Promise && goog.global.Promise.resolve) {
+    var promise = goog.global.Promise.resolve();
+    goog.async.run.schedule_ = function() {
+      promise.then(goog.async.run.processWorkQueue);
+    };
+  } else {
+    goog.async.run.schedule_ = function() {
+      goog.async.nextTick(goog.async.run.processWorkQueue);
+    };
+  }
+};
+
+
+/**
+ * Forces goog.async.run to use nextTick instead of Promise.
+ *
+ * This should only be done in unit tests. It's useful because MockClock
+ * replaces nextTick, but not the browser Promise implementation, so it allows
+ * Promise-based code to be tested with MockClock.
+ */
+goog.async.run.forceNextTick = function() {
+  goog.async.run.schedule_ = function() {
+    goog.async.nextTick(goog.async.run.processWorkQueue);
+  };
+};
+
+
+/**
+ * The function used to schedule work asynchronousely.
+ * @private {function()}
+ */
+goog.async.run.schedule_;
+
+
+/** @private {boolean} */
+goog.async.run.workQueueScheduled_ = false;
+
+
+/** @private {!goog.async.WorkQueue} */
+goog.async.run.workQueue_ = new goog.async.WorkQueue();
+
+
+if (goog.DEBUG) {
+  /**
+   * Reset the work queue.
+   * @private
+   */
+  goog.async.run.resetQueue_ = function() {
+    goog.async.run.workQueueScheduled_ = false;
+    goog.async.run.workQueue_ = new goog.async.WorkQueue();
+  };
+
+  // If there is a clock implemenation in use for testing
+  // and it is reset, reset the queue.
+  goog.testing.watchers.watchClockReset(goog.async.run.resetQueue_);
+}
+
+
+/**
+ * Run any pending goog.async.run work items. This function is not intended
+ * for general use, but for use by entry point handlers to run items ahead of
+ * goog.async.nextTick.
+ */
+goog.async.run.processWorkQueue = function() {
+  // NOTE: additional work queue items may be added while processing.
+  var item = null;
+  while (item = goog.async.run.workQueue_.remove()) {
+    try {
+      item.fn.call(item.scope);
+    } catch (e) {
+      goog.async.throwException(e);
+    }
+    goog.async.run.workQueue_.returnUnused(item);
+  }
+
+  // There are no more work items, allow processing to be scheduled again.
+  goog.async.run.workQueueScheduled_ = false;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/async/throttle.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/async/throttle.js b/externs/GCL/externs/goog/async/throttle.js
new file mode 100644
index 0000000..2efa119
--- /dev/null
+++ b/externs/GCL/externs/goog/async/throttle.js
@@ -0,0 +1,195 @@
+// 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 goog.async.Throttle class.
+ *
+ * @see ../demos/timers.html
+ */
+
+goog.provide('goog.Throttle');
+goog.provide('goog.async.Throttle');
+
+goog.require('goog.Disposable');
+goog.require('goog.Timer');
+
+
+
+/**
+ * Throttle will perform an action that is passed in no more than once
+ * per interval (specified in milliseconds). If it gets multiple signals
+ * to perform the action while it is waiting, it will only perform the action
+ * once at the end of the interval.
+ * @param {function(this: T)} listener Function to callback when the action is
+ *     triggered.
+ * @param {number} interval Interval over which to throttle. The listener can
+ *     only be called once per interval.
+ * @param {T=} opt_handler Object in whose scope to call the listener.
+ * @constructor
+ * @struct
+ * @suppress {checkStructDictInheritance}
+ * @extends {goog.Disposable}
+ * @final
+ * @template T
+ */
+goog.async.Throttle = function(listener, interval, opt_handler) {
+  goog.async.Throttle.base(this, 'constructor');
+
+  /**
+   * Function to callback
+   * @type {function(this: T)}
+   * @private
+   */
+  this.listener_ = listener;
+
+  /**
+   * Interval for the throttle time
+   * @type {number}
+   * @private
+   */
+  this.interval_ = interval;
+
+  /**
+   * "this" context for the listener
+   * @type {Object|undefined}
+   * @private
+   */
+  this.handler_ = opt_handler;
+
+  /**
+   * Cached callback function invoked after the throttle timeout completes
+   * @type {Function}
+   * @private
+   */
+  this.callback_ = goog.bind(this.onTimer_, this);
+};
+goog.inherits(goog.async.Throttle, goog.Disposable);
+
+
+
+/**
+ * A deprecated alias.
+ * @deprecated Use goog.async.Throttle instead.
+ * @constructor
+ * @final
+ */
+goog.Throttle = goog.async.Throttle;
+
+
+/**
+ * Indicates that the action is pending and needs to be fired.
+ * @type {boolean}
+ * @private
+ */
+goog.async.Throttle.prototype.shouldFire_ = false;
+
+
+/**
+ * Indicates the count of nested pauses currently in effect on the throttle.
+ * When this count is not zero, fired actions will be postponed until the
+ * throttle is resumed enough times to drop the pause count to zero.
+ * @type {number}
+ * @private
+ */
+goog.async.Throttle.prototype.pauseCount_ = 0;
+
+
+/**
+ * Timer for scheduling the next callback
+ * @type {?number}
+ * @private
+ */
+goog.async.Throttle.prototype.timer_ = null;
+
+
+/**
+ * Notifies the throttle that the action has happened. It will throttle the call
+ * so that the callback is not called too often according to the interval
+ * parameter passed to the constructor.
+ */
+goog.async.Throttle.prototype.fire = function() {
+  if (!this.timer_ && !this.pauseCount_) {
+    this.doAction_();
+  } else {
+    this.shouldFire_ = true;
+  }
+};
+
+
+/**
+ * Cancels any pending action callback. The throttle can be restarted by
+ * calling {@link #fire}.
+ */
+goog.async.Throttle.prototype.stop = function() {
+  if (this.timer_) {
+    goog.Timer.clear(this.timer_);
+    this.timer_ = null;
+    this.shouldFire_ = false;
+  }
+};
+
+
+/**
+ * Pauses the throttle.  All pending and future action callbacks will be
+ * delayed until the throttle is resumed.  Pauses can be nested.
+ */
+goog.async.Throttle.prototype.pause = function() {
+  this.pauseCount_++;
+};
+
+
+/**
+ * Resumes the throttle.  If doing so drops the pausing count to zero, pending
+ * action callbacks will be executed as soon as possible, but still no sooner
+ * than an interval's delay after the previous call.  Future action callbacks
+ * will be executed as normal.
+ */
+goog.async.Throttle.prototype.resume = function() {
+  this.pauseCount_--;
+  if (!this.pauseCount_ && this.shouldFire_ && !this.timer_) {
+    this.shouldFire_ = false;
+    this.doAction_();
+  }
+};
+
+
+/** @override */
+goog.async.Throttle.prototype.disposeInternal = function() {
+  goog.async.Throttle.base(this, 'disposeInternal');
+  this.stop();
+};
+
+
+/**
+ * Handler for the timer to fire the throttle
+ * @private
+ */
+goog.async.Throttle.prototype.onTimer_ = function() {
+  this.timer_ = null;
+
+  if (this.shouldFire_ && !this.pauseCount_) {
+    this.shouldFire_ = false;
+    this.doAction_();
+  }
+};
+
+
+/**
+ * Calls the callback
+ * @private
+ */
+goog.async.Throttle.prototype.doAction_ = function() {
+  this.timer_ = goog.Timer.callOnce(this.callback_, this.interval_);
+  this.listener_.call(this.handler_);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/async/workqueue.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/async/workqueue.js b/externs/GCL/externs/goog/async/workqueue.js
new file mode 100644
index 0000000..2d86c89
--- /dev/null
+++ b/externs/GCL/externs/goog/async/workqueue.js
@@ -0,0 +1,139 @@
+// Copyright 2015 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.
+
+goog.provide('goog.async.WorkItem');
+goog.provide('goog.async.WorkQueue');
+
+goog.require('goog.asserts');
+goog.require('goog.async.FreeList');
+
+
+// TODO(johnlenz): generalize the WorkQueue if this is used by more
+// than goog.async.run.
+
+
+
+/**
+ * A low GC workqueue. The key elements of this design:
+ *   - avoids the need for goog.bind or equivalent by carrying scope
+ *   - avoids the need for array reallocation by using a linked list
+ *   - minimizes work entry objects allocation by recycling objects
+ * @constructor
+ * @final
+ * @struct
+ */
+goog.async.WorkQueue = function() {
+  this.workHead_ = null;
+  this.workTail_ = null;
+};
+
+
+/** @define {number} The maximum number of entries to keep for recycling. */
+goog.define('goog.async.WorkQueue.DEFAULT_MAX_UNUSED', 100);
+
+
+/** @const @private {goog.async.FreeList<goog.async.WorkItem>} */
+goog.async.WorkQueue.freelist_ = new goog.async.FreeList(
+    function() {return new goog.async.WorkItem(); },
+    function(item) {item.reset()},
+    goog.async.WorkQueue.DEFAULT_MAX_UNUSED);
+
+
+/**
+ * @param {function()} fn
+ * @param {Object|null|undefined} scope
+ */
+goog.async.WorkQueue.prototype.add = function(fn, scope) {
+  var item = this.getUnusedItem_();
+  item.set(fn, scope);
+
+  if (this.workTail_) {
+    this.workTail_.next = item;
+    this.workTail_ = item;
+  } else {
+    goog.asserts.assert(!this.workHead_);
+    this.workHead_ = item;
+    this.workTail_ = item;
+  }
+};
+
+
+/**
+ * @return {goog.async.WorkItem}
+ */
+goog.async.WorkQueue.prototype.remove = function() {
+  var item = null;
+
+  if (this.workHead_) {
+    item = this.workHead_;
+    this.workHead_ = this.workHead_.next;
+    if (!this.workHead_) {
+      this.workTail_ = null;
+    }
+    item.next = null;
+  }
+  return item;
+};
+
+
+/**
+ * @param {goog.async.WorkItem} item
+ */
+goog.async.WorkQueue.prototype.returnUnused = function(item) {
+  goog.async.WorkQueue.freelist_.put(item);
+};
+
+
+/**
+ * @return {goog.async.WorkItem}
+ * @private
+ */
+goog.async.WorkQueue.prototype.getUnusedItem_ = function() {
+  return goog.async.WorkQueue.freelist_.get();
+};
+
+
+
+/**
+ * @constructor
+ * @final
+ * @struct
+ */
+goog.async.WorkItem = function() {
+  /** @type {?function()} */
+  this.fn = null;
+  /** @type {Object|null|undefined} */
+  this.scope = null;
+  /** @type {?goog.async.WorkItem} */
+  this.next = null;
+};
+
+
+/**
+ * @param {function()} fn
+ * @param {Object|null|undefined} scope
+ */
+goog.async.WorkItem.prototype.set = function(fn, scope) {
+  this.fn = fn;
+  this.scope = scope;
+  this.next = null;
+};
+
+
+/** Reset the work item so they don't prevent GC before reuse */
+goog.async.WorkItem.prototype.reset = function() {
+  this.fn = null;
+  this.scope = null;
+  this.next = null;
+};


[17/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/listenable.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/listenable.js b/externs/GCL/externs/goog/events/listenable.js
new file mode 100644
index 0000000..a05b348
--- /dev/null
+++ b/externs/GCL/externs/goog/events/listenable.js
@@ -0,0 +1,335 @@
+// 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 An interface for a listenable JavaScript object.
+ * @author chrishenry@google.com (Chris Henry)
+ */
+
+goog.provide('goog.events.Listenable');
+goog.provide('goog.events.ListenableKey');
+
+/** @suppress {extraRequire} */
+goog.require('goog.events.EventId');
+
+
+
+/**
+ * A listenable interface. A listenable is an object with the ability
+ * to dispatch/broadcast events to "event listeners" registered via
+ * listen/listenOnce.
+ *
+ * The interface allows for an event propagation mechanism similar
+ * to one offered by native browser event targets, such as
+ * capture/bubble mechanism, stopping propagation, and preventing
+ * default actions. Capture/bubble mechanism depends on the ancestor
+ * tree constructed via {@code #getParentEventTarget}; this tree
+ * must be directed acyclic graph. The meaning of default action(s)
+ * in preventDefault is specific to a particular use case.
+ *
+ * Implementations that do not support capture/bubble or can not have
+ * a parent listenable can simply not implement any ability to set the
+ * parent listenable (and have {@code #getParentEventTarget} return
+ * null).
+ *
+ * Implementation of this class can be used with or independently from
+ * goog.events.
+ *
+ * Implementation must call {@code #addImplementation(implClass)}.
+ *
+ * @interface
+ * @see goog.events
+ * @see http://www.w3.org/TR/DOM-Level-2-Events/events.html
+ */
+goog.events.Listenable = function() {};
+
+
+/**
+ * An expando property to indicate that an object implements
+ * goog.events.Listenable.
+ *
+ * See addImplementation/isImplementedBy.
+ *
+ * @type {string}
+ * @const
+ */
+goog.events.Listenable.IMPLEMENTED_BY_PROP =
+    'closure_listenable_' + ((Math.random() * 1e6) | 0);
+
+
+/**
+ * Marks a given class (constructor) as an implementation of
+ * Listenable, do that we can query that fact at runtime. The class
+ * must have already implemented the interface.
+ * @param {!Function} cls The class constructor. The corresponding
+ *     class must have already implemented the interface.
+ */
+goog.events.Listenable.addImplementation = function(cls) {
+  cls.prototype[goog.events.Listenable.IMPLEMENTED_BY_PROP] = true;
+};
+
+
+/**
+ * @param {Object} obj The object to check.
+ * @return {boolean} Whether a given instance implements Listenable. The
+ *     class/superclass of the instance must call addImplementation.
+ */
+goog.events.Listenable.isImplementedBy = function(obj) {
+  return !!(obj && obj[goog.events.Listenable.IMPLEMENTED_BY_PROP]);
+};
+
+
+/**
+ * Adds an event listener. A listener can only be added once to an
+ * object and if it is added again the key for the listener is
+ * returned. Note that if the existing listener is a one-off listener
+ * (registered via listenOnce), it will no longer be a one-off
+ * listener after a call to listen().
+ *
+ * @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
+ * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
+ *     method.
+ * @param {boolean=} opt_useCapture Whether to fire in capture phase
+ *     (defaults to false).
+ * @param {SCOPE=} opt_listenerScope Object in whose scope to call the
+ *     listener.
+ * @return {goog.events.ListenableKey} Unique key for the listener.
+ * @template SCOPE,EVENTOBJ
+ */
+goog.events.Listenable.prototype.listen;
+
+
+/**
+ * Adds an event listener that is removed automatically after the
+ * listener fired once.
+ *
+ * If an existing listener already exists, listenOnce will do
+ * nothing. In particular, if the listener was previously registered
+ * via listen(), listenOnce() will not turn the listener into a
+ * one-off listener. Similarly, if there is already an existing
+ * one-off listener, listenOnce does not modify the listeners (it is
+ * still a once listener).
+ *
+ * @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
+ * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
+ *     method.
+ * @param {boolean=} opt_useCapture Whether to fire in capture phase
+ *     (defaults to false).
+ * @param {SCOPE=} opt_listenerScope Object in whose scope to call the
+ *     listener.
+ * @return {goog.events.ListenableKey} Unique key for the listener.
+ * @template SCOPE,EVENTOBJ
+ */
+goog.events.Listenable.prototype.listenOnce;
+
+
+/**
+ * Removes an event listener which was added with listen() or listenOnce().
+ *
+ * @param {string|!goog.events.EventId<EVENTOBJ>} type The event type id.
+ * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener Callback
+ *     method.
+ * @param {boolean=} opt_useCapture Whether to fire in capture phase
+ *     (defaults to false).
+ * @param {SCOPE=} opt_listenerScope Object in whose scope to call
+ *     the listener.
+ * @return {boolean} Whether any listener was removed.
+ * @template SCOPE,EVENTOBJ
+ */
+goog.events.Listenable.prototype.unlisten;
+
+
+/**
+ * Removes an event listener which was added with listen() by the key
+ * returned by listen().
+ *
+ * @param {goog.events.ListenableKey} key The key returned by
+ *     listen() or listenOnce().
+ * @return {boolean} Whether any listener was removed.
+ */
+goog.events.Listenable.prototype.unlistenByKey;
+
+
+/**
+ * Dispatches an event (or event like object) and calls all listeners
+ * listening for events of this type. The type of the event is decided by the
+ * type property on the event object.
+ *
+ * If any of the listeners returns false OR calls preventDefault then this
+ * function will return false.  If one of the capture listeners calls
+ * stopPropagation, then the bubble listeners won't fire.
+ *
+ * @param {goog.events.EventLike} e Event object.
+ * @return {boolean} If anyone called preventDefault on the event object (or
+ *     if any of the listeners returns false) this will also return false.
+ */
+goog.events.Listenable.prototype.dispatchEvent;
+
+
+/**
+ * Removes all listeners from this listenable. If type is specified,
+ * it will only remove listeners of the particular type. otherwise all
+ * registered listeners will be removed.
+ *
+ * @param {string=} opt_type Type of event to remove, default is to
+ *     remove all types.
+ * @return {number} Number of listeners removed.
+ */
+goog.events.Listenable.prototype.removeAllListeners;
+
+
+/**
+ * Returns the parent of this event target to use for capture/bubble
+ * mechanism.
+ *
+ * NOTE(chrishenry): The name reflects the original implementation of
+ * custom event target ({@code goog.events.EventTarget}). We decided
+ * that changing the name is not worth it.
+ *
+ * @return {goog.events.Listenable} The parent EventTarget or null if
+ *     there is no parent.
+ */
+goog.events.Listenable.prototype.getParentEventTarget;
+
+
+/**
+ * Fires all registered listeners in this listenable for the given
+ * type and capture mode, passing them the given eventObject. This
+ * does not perform actual capture/bubble. Only implementors of the
+ * interface should be using this.
+ *
+ * @param {string|!goog.events.EventId<EVENTOBJ>} type The type of the
+ *     listeners to fire.
+ * @param {boolean} capture The capture mode of the listeners to fire.
+ * @param {EVENTOBJ} eventObject The event object to fire.
+ * @return {boolean} Whether all listeners succeeded without
+ *     attempting to prevent default behavior. If any listener returns
+ *     false or called goog.events.Event#preventDefault, this returns
+ *     false.
+ * @template EVENTOBJ
+ */
+goog.events.Listenable.prototype.fireListeners;
+
+
+/**
+ * Gets all listeners in this listenable for the given type and
+ * capture mode.
+ *
+ * @param {string|!goog.events.EventId} type The type of the listeners to fire.
+ * @param {boolean} capture The capture mode of the listeners to fire.
+ * @return {!Array<goog.events.ListenableKey>} An array of registered
+ *     listeners.
+ * @template EVENTOBJ
+ */
+goog.events.Listenable.prototype.getListeners;
+
+
+/**
+ * Gets the goog.events.ListenableKey for the event or null if no such
+ * listener is in use.
+ *
+ * @param {string|!goog.events.EventId<EVENTOBJ>} type The name of the event
+ *     without the 'on' prefix.
+ * @param {function(this:SCOPE, EVENTOBJ):(boolean|undefined)} listener The
+ *     listener function to get.
+ * @param {boolean} capture Whether the listener is a capturing listener.
+ * @param {SCOPE=} opt_listenerScope Object in whose scope to call the
+ *     listener.
+ * @return {goog.events.ListenableKey} the found listener or null if not found.
+ * @template SCOPE,EVENTOBJ
+ */
+goog.events.Listenable.prototype.getListener;
+
+
+/**
+ * Whether there is any active listeners matching the specified
+ * signature. If either the type or capture parameters are
+ * unspecified, the function will match on the remaining criteria.
+ *
+ * @param {string|!goog.events.EventId<EVENTOBJ>=} opt_type Event type.
+ * @param {boolean=} opt_capture Whether to check for capture or bubble
+ *     listeners.
+ * @return {boolean} Whether there is any active listeners matching
+ *     the requested type and/or capture phase.
+ * @template EVENTOBJ
+ */
+goog.events.Listenable.prototype.hasListener;
+
+
+
+/**
+ * An interface that describes a single registered listener.
+ * @interface
+ */
+goog.events.ListenableKey = function() {};
+
+
+/**
+ * Counter used to create a unique key
+ * @type {number}
+ * @private
+ */
+goog.events.ListenableKey.counter_ = 0;
+
+
+/**
+ * Reserves a key to be used for ListenableKey#key field.
+ * @return {number} A number to be used to fill ListenableKey#key
+ *     field.
+ */
+goog.events.ListenableKey.reserveKey = function() {
+  return ++goog.events.ListenableKey.counter_;
+};
+
+
+/**
+ * The source event target.
+ * @type {!(Object|goog.events.Listenable|goog.events.EventTarget)}
+ */
+goog.events.ListenableKey.prototype.src;
+
+
+/**
+ * The event type the listener is listening to.
+ * @type {string}
+ */
+goog.events.ListenableKey.prototype.type;
+
+
+/**
+ * The listener function.
+ * @type {function(?):?|{handleEvent:function(?):?}|null}
+ */
+goog.events.ListenableKey.prototype.listener;
+
+
+/**
+ * Whether the listener works on capture phase.
+ * @type {boolean}
+ */
+goog.events.ListenableKey.prototype.capture;
+
+
+/**
+ * The 'this' object for the listener function's scope.
+ * @type {Object}
+ */
+goog.events.ListenableKey.prototype.handler;
+
+
+/**
+ * A globally unique number to identify the key.
+ * @type {number}
+ */
+goog.events.ListenableKey.prototype.key;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/listener.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/listener.js b/externs/GCL/externs/goog/events/listener.js
new file mode 100644
index 0000000..60c7370
--- /dev/null
+++ b/externs/GCL/externs/goog/events/listener.js
@@ -0,0 +1,131 @@
+// Copyright 2005 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 Listener object.
+ * @see ../demos/events.html
+ */
+
+goog.provide('goog.events.Listener');
+
+goog.require('goog.events.ListenableKey');
+
+
+
+/**
+ * Simple class that stores information about a listener
+ * @param {!Function} listener Callback function.
+ * @param {Function} proxy Wrapper for the listener that patches the event.
+ * @param {EventTarget|goog.events.Listenable} src Source object for
+ *     the event.
+ * @param {string} type Event type.
+ * @param {boolean} capture Whether in capture or bubble phase.
+ * @param {Object=} opt_handler Object in whose context to execute the callback.
+ * @implements {goog.events.ListenableKey}
+ * @constructor
+ */
+goog.events.Listener = function(
+    listener, proxy, src, type, capture, opt_handler) {
+  if (goog.events.Listener.ENABLE_MONITORING) {
+    this.creationStack = new Error().stack;
+  }
+
+  /**
+   * Callback function.
+   * @type {Function}
+   */
+  this.listener = listener;
+
+  /**
+   * A wrapper over the original listener. This is used solely to
+   * handle native browser events (it is used to simulate the capture
+   * phase and to patch the event object).
+   * @type {Function}
+   */
+  this.proxy = proxy;
+
+  /**
+   * Object or node that callback is listening to
+   * @type {EventTarget|goog.events.Listenable}
+   */
+  this.src = src;
+
+  /**
+   * The event type.
+   * @const {string}
+   */
+  this.type = type;
+
+  /**
+   * Whether the listener is being called in the capture or bubble phase
+   * @const {boolean}
+   */
+  this.capture = !!capture;
+
+  /**
+   * Optional object whose context to execute the listener in
+   * @type {Object|undefined}
+   */
+  this.handler = opt_handler;
+
+  /**
+   * The key of the listener.
+   * @const {number}
+   * @override
+   */
+  this.key = goog.events.ListenableKey.reserveKey();
+
+  /**
+   * Whether to remove the listener after it has been called.
+   * @type {boolean}
+   */
+  this.callOnce = false;
+
+  /**
+   * Whether the listener has been removed.
+   * @type {boolean}
+   */
+  this.removed = false;
+};
+
+
+/**
+ * @define {boolean} Whether to enable the monitoring of the
+ *     goog.events.Listener instances. Switching on the monitoring is only
+ *     recommended for debugging because it has a significant impact on
+ *     performance and memory usage. If switched off, the monitoring code
+ *     compiles down to 0 bytes.
+ */
+goog.define('goog.events.Listener.ENABLE_MONITORING', false);
+
+
+/**
+ * If monitoring the goog.events.Listener instances is enabled, stores the
+ * creation stack trace of the Disposable instance.
+ * @type {string}
+ */
+goog.events.Listener.prototype.creationStack;
+
+
+/**
+ * Marks this listener as removed. This also remove references held by
+ * this listener object (such as listener and event source).
+ */
+goog.events.Listener.prototype.markAsRemoved = function() {
+  this.removed = true;
+  this.listener = null;
+  this.proxy = null;
+  this.src = null;
+  this.handler = null;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/listenermap.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/listenermap.js b/externs/GCL/externs/goog/events/listenermap.js
new file mode 100644
index 0000000..c20cdb9
--- /dev/null
+++ b/externs/GCL/externs/goog/events/listenermap.js
@@ -0,0 +1,308 @@
+// Copyright 2013 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 map of listeners that provides utility functions to
+ * deal with listeners on an event target. Used by
+ * {@code goog.events.EventTarget}.
+ *
+ * WARNING: Do not use this class from outside goog.events package.
+ *
+ * @visibility {//closure/goog/bin/sizetests:__pkg__}
+ * @visibility {//closure/goog/events:__pkg__}
+ * @visibility {//closure/goog/labs/events:__pkg__}
+ */
+
+goog.provide('goog.events.ListenerMap');
+
+goog.require('goog.array');
+goog.require('goog.events.Listener');
+goog.require('goog.object');
+
+
+
+/**
+ * Creates a new listener map.
+ * @param {EventTarget|goog.events.Listenable} src The src object.
+ * @constructor
+ * @final
+ */
+goog.events.ListenerMap = function(src) {
+  /** @type {EventTarget|goog.events.Listenable} */
+  this.src = src;
+
+  /**
+   * Maps of event type to an array of listeners.
+   * @type {Object<string, !Array<!goog.events.Listener>>}
+   */
+  this.listeners = {};
+
+  /**
+   * The count of types in this map that have registered listeners.
+   * @private {number}
+   */
+  this.typeCount_ = 0;
+};
+
+
+/**
+ * @return {number} The count of event types in this map that actually
+ *     have registered listeners.
+ */
+goog.events.ListenerMap.prototype.getTypeCount = function() {
+  return this.typeCount_;
+};
+
+
+/**
+ * @return {number} Total number of registered listeners.
+ */
+goog.events.ListenerMap.prototype.getListenerCount = function() {
+  var count = 0;
+  for (var type in this.listeners) {
+    count += this.listeners[type].length;
+  }
+  return count;
+};
+
+
+/**
+ * Adds an event listener. A listener can only be added once to an
+ * object and if it is added again the key for the listener is
+ * returned.
+ *
+ * Note that a one-off listener will not change an existing listener,
+ * if any. On the other hand a normal listener will change existing
+ * one-off listener to become a normal listener.
+ *
+ * @param {string|!goog.events.EventId} type The listener event type.
+ * @param {!Function} listener This listener callback method.
+ * @param {boolean} callOnce Whether the listener is a one-off
+ *     listener.
+ * @param {boolean=} opt_useCapture The capture mode of the listener.
+ * @param {Object=} opt_listenerScope Object in whose scope to call the
+ *     listener.
+ * @return {goog.events.ListenableKey} Unique key for the listener.
+ */
+goog.events.ListenerMap.prototype.add = function(
+    type, listener, callOnce, opt_useCapture, opt_listenerScope) {
+  var typeStr = type.toString();
+  var listenerArray = this.listeners[typeStr];
+  if (!listenerArray) {
+    listenerArray = this.listeners[typeStr] = [];
+    this.typeCount_++;
+  }
+
+  var listenerObj;
+  var index = goog.events.ListenerMap.findListenerIndex_(
+      listenerArray, listener, opt_useCapture, opt_listenerScope);
+  if (index > -1) {
+    listenerObj = listenerArray[index];
+    if (!callOnce) {
+      // Ensure that, if there is an existing callOnce listener, it is no
+      // longer a callOnce listener.
+      listenerObj.callOnce = false;
+    }
+  } else {
+    listenerObj = new goog.events.Listener(
+        listener, null, this.src, typeStr, !!opt_useCapture, opt_listenerScope);
+    listenerObj.callOnce = callOnce;
+    listenerArray.push(listenerObj);
+  }
+  return listenerObj;
+};
+
+
+/**
+ * Removes a matching listener.
+ * @param {string|!goog.events.EventId} type The listener event type.
+ * @param {!Function} listener This listener callback method.
+ * @param {boolean=} opt_useCapture The capture mode of the listener.
+ * @param {Object=} opt_listenerScope Object in whose scope to call the
+ *     listener.
+ * @return {boolean} Whether any listener was removed.
+ */
+goog.events.ListenerMap.prototype.remove = function(
+    type, listener, opt_useCapture, opt_listenerScope) {
+  var typeStr = type.toString();
+  if (!(typeStr in this.listeners)) {
+    return false;
+  }
+
+  var listenerArray = this.listeners[typeStr];
+  var index = goog.events.ListenerMap.findListenerIndex_(
+      listenerArray, listener, opt_useCapture, opt_listenerScope);
+  if (index > -1) {
+    var listenerObj = listenerArray[index];
+    listenerObj.markAsRemoved();
+    goog.array.removeAt(listenerArray, index);
+    if (listenerArray.length == 0) {
+      delete this.listeners[typeStr];
+      this.typeCount_--;
+    }
+    return true;
+  }
+  return false;
+};
+
+
+/**
+ * Removes the given listener object.
+ * @param {goog.events.ListenableKey} listener The listener to remove.
+ * @return {boolean} Whether the listener is removed.
+ */
+goog.events.ListenerMap.prototype.removeByKey = function(listener) {
+  var type = listener.type;
+  if (!(type in this.listeners)) {
+    return false;
+  }
+
+  var removed = goog.array.remove(this.listeners[type], listener);
+  if (removed) {
+    listener.markAsRemoved();
+    if (this.listeners[type].length == 0) {
+      delete this.listeners[type];
+      this.typeCount_--;
+    }
+  }
+  return removed;
+};
+
+
+/**
+ * Removes all listeners from this map. If opt_type is provided, only
+ * listeners that match the given type are removed.
+ * @param {string|!goog.events.EventId=} opt_type Type of event to remove.
+ * @return {number} Number of listeners removed.
+ */
+goog.events.ListenerMap.prototype.removeAll = function(opt_type) {
+  var typeStr = opt_type && opt_type.toString();
+  var count = 0;
+  for (var type in this.listeners) {
+    if (!typeStr || type == typeStr) {
+      var listenerArray = this.listeners[type];
+      for (var i = 0; i < listenerArray.length; i++) {
+        ++count;
+        listenerArray[i].markAsRemoved();
+      }
+      delete this.listeners[type];
+      this.typeCount_--;
+    }
+  }
+  return count;
+};
+
+
+/**
+ * Gets all listeners that match the given type and capture mode. The
+ * returned array is a copy (but the listener objects are not).
+ * @param {string|!goog.events.EventId} type The type of the listeners
+ *     to retrieve.
+ * @param {boolean} capture The capture mode of the listeners to retrieve.
+ * @return {!Array<goog.events.ListenableKey>} An array of matching
+ *     listeners.
+ */
+goog.events.ListenerMap.prototype.getListeners = function(type, capture) {
+  var listenerArray = this.listeners[type.toString()];
+  var rv = [];
+  if (listenerArray) {
+    for (var i = 0; i < listenerArray.length; ++i) {
+      var listenerObj = listenerArray[i];
+      if (listenerObj.capture == capture) {
+        rv.push(listenerObj);
+      }
+    }
+  }
+  return rv;
+};
+
+
+/**
+ * Gets the goog.events.ListenableKey for the event or null if no such
+ * listener is in use.
+ *
+ * @param {string|!goog.events.EventId} type The type of the listener
+ *     to retrieve.
+ * @param {!Function} listener The listener function to get.
+ * @param {boolean} capture Whether the listener is a capturing listener.
+ * @param {Object=} opt_listenerScope Object in whose scope to call the
+ *     listener.
+ * @return {goog.events.ListenableKey} the found listener or null if not found.
+ */
+goog.events.ListenerMap.prototype.getListener = function(
+    type, listener, capture, opt_listenerScope) {
+  var listenerArray = this.listeners[type.toString()];
+  var i = -1;
+  if (listenerArray) {
+    i = goog.events.ListenerMap.findListenerIndex_(
+        listenerArray, listener, capture, opt_listenerScope);
+  }
+  return i > -1 ? listenerArray[i] : null;
+};
+
+
+/**
+ * Whether there is a matching listener. If either the type or capture
+ * parameters are unspecified, the function will match on the
+ * remaining criteria.
+ *
+ * @param {string|!goog.events.EventId=} opt_type The type of the listener.
+ * @param {boolean=} opt_capture The capture mode of the listener.
+ * @return {boolean} Whether there is an active listener matching
+ *     the requested type and/or capture phase.
+ */
+goog.events.ListenerMap.prototype.hasListener = function(
+    opt_type, opt_capture) {
+  var hasType = goog.isDef(opt_type);
+  var typeStr = hasType ? opt_type.toString() : '';
+  var hasCapture = goog.isDef(opt_capture);
+
+  return goog.object.some(
+      this.listeners, function(listenerArray, type) {
+        for (var i = 0; i < listenerArray.length; ++i) {
+          if ((!hasType || listenerArray[i].type == typeStr) &&
+              (!hasCapture || listenerArray[i].capture == opt_capture)) {
+            return true;
+          }
+        }
+
+        return false;
+      });
+};
+
+
+/**
+ * Finds the index of a matching goog.events.Listener in the given
+ * listenerArray.
+ * @param {!Array<!goog.events.Listener>} listenerArray Array of listener.
+ * @param {!Function} listener The listener function.
+ * @param {boolean=} opt_useCapture The capture flag for the listener.
+ * @param {Object=} opt_listenerScope The listener scope.
+ * @return {number} The index of the matching listener within the
+ *     listenerArray.
+ * @private
+ */
+goog.events.ListenerMap.findListenerIndex_ = function(
+    listenerArray, listener, opt_useCapture, opt_listenerScope) {
+  for (var i = 0; i < listenerArray.length; ++i) {
+    var listenerObj = listenerArray[i];
+    if (!listenerObj.removed &&
+        listenerObj.listener == listener &&
+        listenerObj.capture == !!opt_useCapture &&
+        listenerObj.handler == opt_listenerScope) {
+      return i;
+    }
+  }
+  return -1;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/mousewheelhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/mousewheelhandler.js b/externs/GCL/externs/goog/events/mousewheelhandler.js
new file mode 100644
index 0000000..6729064
--- /dev/null
+++ b/externs/GCL/externs/goog/events/mousewheelhandler.js
@@ -0,0 +1,296 @@
+// 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 This event wrapper will dispatch an event when the user uses
+ * the mouse wheel to scroll an element. You can get the direction by checking
+ * the deltaX and deltaY properties of the event.
+ *
+ * This class aims to smooth out inconsistencies between browser platforms with
+ * regards to mousewheel events, but we do not cover every possible
+ * software/hardware combination out there, some of which occasionally produce
+ * very large deltas in mousewheel events. If your application wants to guard
+ * against extremely large deltas, use the setMaxDeltaX and setMaxDeltaY APIs
+ * to set maximum values that make sense for your application.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/mousewheelhandler.html
+ */
+
+goog.provide('goog.events.MouseWheelEvent');
+goog.provide('goog.events.MouseWheelHandler');
+goog.provide('goog.events.MouseWheelHandler.EventType');
+
+goog.require('goog.dom');
+goog.require('goog.events');
+goog.require('goog.events.BrowserEvent');
+goog.require('goog.events.EventTarget');
+goog.require('goog.math');
+goog.require('goog.style');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * This event handler allows you to catch mouse wheel events in a consistent
+ * manner.
+ * @param {Element|Document} element The element to listen to the mouse wheel
+ *     event on.
+ * @param {boolean=} opt_capture Whether to handle the mouse wheel event in
+ *     capture phase.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.events.MouseWheelHandler = function(element, opt_capture) {
+  goog.events.EventTarget.call(this);
+
+  /**
+   * This is the element that we will listen to the real mouse wheel events on.
+   * @type {Element|Document}
+   * @private
+   */
+  this.element_ = element;
+
+  var rtlElement = goog.dom.isElement(this.element_) ?
+      /** @type {Element} */ (this.element_) :
+      (this.element_ ? /** @type {Document} */ (this.element_).body : null);
+
+  /**
+   * True if the element exists and is RTL, false otherwise.
+   * @type {boolean}
+   * @private
+   */
+  this.isRtl_ = !!rtlElement && goog.style.isRightToLeft(rtlElement);
+
+  var type = goog.userAgent.GECKO ? 'DOMMouseScroll' : 'mousewheel';
+
+  /**
+   * The key returned from the goog.events.listen.
+   * @type {goog.events.Key}
+   * @private
+   */
+  this.listenKey_ = goog.events.listen(this.element_, type, this, opt_capture);
+};
+goog.inherits(goog.events.MouseWheelHandler, goog.events.EventTarget);
+
+
+/**
+ * Enum type for the events fired by the mouse wheel handler.
+ * @enum {string}
+ */
+goog.events.MouseWheelHandler.EventType = {
+  MOUSEWHEEL: 'mousewheel'
+};
+
+
+/**
+ * Optional maximum magnitude for x delta on each mousewheel event.
+ * @type {number|undefined}
+ * @private
+ */
+goog.events.MouseWheelHandler.prototype.maxDeltaX_;
+
+
+/**
+ * Optional maximum magnitude for y delta on each mousewheel event.
+ * @type {number|undefined}
+ * @private
+ */
+goog.events.MouseWheelHandler.prototype.maxDeltaY_;
+
+
+/**
+ * @param {number} maxDeltaX Maximum magnitude for x delta on each mousewheel
+ *     event. Should be non-negative.
+ */
+goog.events.MouseWheelHandler.prototype.setMaxDeltaX = function(maxDeltaX) {
+  this.maxDeltaX_ = maxDeltaX;
+};
+
+
+/**
+ * @param {number} maxDeltaY Maximum magnitude for y delta on each mousewheel
+ *     event. Should be non-negative.
+ */
+goog.events.MouseWheelHandler.prototype.setMaxDeltaY = function(maxDeltaY) {
+  this.maxDeltaY_ = maxDeltaY;
+};
+
+
+/**
+ * Handles the events on the element.
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ */
+goog.events.MouseWheelHandler.prototype.handleEvent = function(e) {
+  var deltaX = 0;
+  var deltaY = 0;
+  var detail = 0;
+  var be = e.getBrowserEvent();
+  if (be.type == 'mousewheel') {
+    var wheelDeltaScaleFactor = 1;
+    if (goog.userAgent.IE ||
+        goog.userAgent.WEBKIT &&
+        (goog.userAgent.WINDOWS || goog.userAgent.isVersionOrHigher('532.0'))) {
+      // In IE we get a multiple of 120; we adjust to a multiple of 3 to
+      // represent number of lines scrolled (like Gecko).
+      // Newer versions of Webkit match IE behavior, and WebKit on
+      // Windows also matches IE behavior.
+      // See bug https://bugs.webkit.org/show_bug.cgi?id=24368
+      wheelDeltaScaleFactor = 40;
+    }
+
+    detail = goog.events.MouseWheelHandler.smartScale_(
+        -be.wheelDelta, wheelDeltaScaleFactor);
+    if (goog.isDef(be.wheelDeltaX)) {
+      // Webkit has two properties to indicate directional scroll, and
+      // can scroll both directions at once.
+      deltaX = goog.events.MouseWheelHandler.smartScale_(
+          -be.wheelDeltaX, wheelDeltaScaleFactor);
+      deltaY = goog.events.MouseWheelHandler.smartScale_(
+          -be.wheelDeltaY, wheelDeltaScaleFactor);
+    } else {
+      deltaY = detail;
+    }
+
+    // Historical note: Opera (pre 9.5) used to negate the detail value.
+  } else { // Gecko
+    // Gecko returns multiple of 3 (representing the number of lines scrolled)
+    detail = be.detail;
+
+    // Gecko sometimes returns really big values if the user changes settings to
+    // scroll a whole page per scroll
+    if (detail > 100) {
+      detail = 3;
+    } else if (detail < -100) {
+      detail = -3;
+    }
+
+    // Firefox 3.1 adds an axis field to the event to indicate direction of
+    // scroll.  See https://developer.mozilla.org/en/Gecko-Specific_DOM_Events
+    if (goog.isDef(be.axis) && be.axis === be.HORIZONTAL_AXIS) {
+      deltaX = detail;
+    } else {
+      deltaY = detail;
+    }
+  }
+
+  if (goog.isNumber(this.maxDeltaX_)) {
+    deltaX = goog.math.clamp(deltaX, -this.maxDeltaX_, this.maxDeltaX_);
+  }
+  if (goog.isNumber(this.maxDeltaY_)) {
+    deltaY = goog.math.clamp(deltaY, -this.maxDeltaY_, this.maxDeltaY_);
+  }
+  // Don't clamp 'detail', since it could be ambiguous which axis it refers to
+  // and because it's informally deprecated anyways.
+
+  // For horizontal scrolling we need to flip the value for RTL grids.
+  if (this.isRtl_) {
+    deltaX = -deltaX;
+  }
+  var newEvent = new goog.events.MouseWheelEvent(detail, be, deltaX, deltaY);
+  this.dispatchEvent(newEvent);
+};
+
+
+/**
+ * Helper for scaling down a mousewheel delta by a scale factor, if appropriate.
+ * @param {number} mouseWheelDelta Delta from a mouse wheel event. Expected to
+ *     be an integer.
+ * @param {number} scaleFactor Factor to scale the delta down by. Expected to
+ *     be an integer.
+ * @return {number} Scaled-down delta value, or the original delta if the
+ *     scaleFactor does not appear to be applicable.
+ * @private
+ */
+goog.events.MouseWheelHandler.smartScale_ = function(mouseWheelDelta,
+    scaleFactor) {
+  // The basic problem here is that in Webkit on Mac and Linux, we can get two
+  // very different types of mousewheel events: from continuous devices
+  // (touchpads, Mighty Mouse) or non-continuous devices (normal wheel mice).
+  //
+  // Non-continuous devices in Webkit get their wheel deltas scaled up to
+  // behave like IE. Continuous devices return much smaller unscaled values
+  // (which most of the time will not be cleanly divisible by the IE scale
+  // factor), so we should not try to normalize them down.
+  //
+  // Detailed discussion:
+  //   https://bugs.webkit.org/show_bug.cgi?id=29601
+  //   http://trac.webkit.org/browser/trunk/WebKit/chromium/src/mac/WebInputEventFactory.mm#L1063
+  if (goog.userAgent.WEBKIT &&
+      (goog.userAgent.MAC || goog.userAgent.LINUX) &&
+      (mouseWheelDelta % scaleFactor) != 0) {
+    return mouseWheelDelta;
+  } else {
+    return mouseWheelDelta / scaleFactor;
+  }
+};
+
+
+/** @override */
+goog.events.MouseWheelHandler.prototype.disposeInternal = function() {
+  goog.events.MouseWheelHandler.superClass_.disposeInternal.call(this);
+  goog.events.unlistenByKey(this.listenKey_);
+  this.listenKey_ = null;
+};
+
+
+
+/**
+ * A base class for mouse wheel events. This is used with the
+ * MouseWheelHandler.
+ *
+ * @param {number} detail The number of rows the user scrolled.
+ * @param {Event} browserEvent Browser event object.
+ * @param {number} deltaX The number of rows the user scrolled in the X
+ *     direction.
+ * @param {number} deltaY The number of rows the user scrolled in the Y
+ *     direction.
+ * @constructor
+ * @extends {goog.events.BrowserEvent}
+ * @final
+ */
+goog.events.MouseWheelEvent = function(detail, browserEvent, deltaX, deltaY) {
+  goog.events.BrowserEvent.call(this, browserEvent);
+
+  this.type = goog.events.MouseWheelHandler.EventType.MOUSEWHEEL;
+
+  /**
+   * The number of lines the user scrolled
+   * @type {number}
+   * NOTE: Informally deprecated. Use deltaX and deltaY instead, they provide
+   * more information.
+   */
+  this.detail = detail;
+
+  /**
+   * The number of "lines" scrolled in the X direction.
+   *
+   * Note that not all browsers provide enough information to distinguish
+   * horizontal and vertical scroll events, so for these unsupported browsers,
+   * we will always have a deltaX of 0, even if the user scrolled their mouse
+   * wheel or trackpad sideways.
+   *
+   * Currently supported browsers are Webkit and Firefox 3.1 or later.
+   *
+   * @type {number}
+   */
+  this.deltaX = deltaX;
+
+  /**
+   * The number of lines scrolled in the Y direction.
+   * @type {number}
+   */
+  this.deltaY = deltaY;
+};
+goog.inherits(goog.events.MouseWheelEvent, goog.events.BrowserEvent);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/onlinehandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/onlinehandler.js b/externs/GCL/externs/goog/events/onlinehandler.js
new file mode 100644
index 0000000..5c9fb16
--- /dev/null
+++ b/externs/GCL/externs/goog/events/onlinehandler.js
@@ -0,0 +1,159 @@
+// Copyright 2008 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 This event handler will dispatch events when
+ * {@code navigator.onLine} changes.  HTML5 defines two events, online and
+ * offline that is fired on the window.  As of today 3 browsers support these
+ * events: Firefox 3 (Gecko 1.9), Opera 9.5, and IE8.  If we have any of these
+ * we listen to the 'online' and 'offline' events on the current window
+ * object.  Otherwise we poll the navigator.onLine property to detect changes.
+ *
+ * Note that this class only reflects what the browser tells us and this usually
+ * only reflects changes to the File -> Work Offline menu item.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/onlinehandler.html
+ */
+
+// TODO(arv): We should probably implement some kind of polling service and/or
+// a poll for changes event handler that can be used to fire events when a state
+// changes.
+
+goog.provide('goog.events.OnlineHandler');
+goog.provide('goog.events.OnlineHandler.EventType');
+
+goog.require('goog.Timer');
+goog.require('goog.events.BrowserFeature');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.net.NetworkStatusMonitor');
+
+
+
+/**
+ * Basic object for detecting whether the online state changes.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @implements {goog.net.NetworkStatusMonitor}
+ */
+goog.events.OnlineHandler = function() {
+  goog.events.OnlineHandler.base(this, 'constructor');
+
+  /**
+   * @private {goog.events.EventHandler<!goog.events.OnlineHandler>}
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+  // Some browsers do not support navigator.onLine and therefore we don't
+  // bother setting up events or timers.
+  if (!goog.events.BrowserFeature.HAS_NAVIGATOR_ONLINE_PROPERTY) {
+    return;
+  }
+
+  if (goog.events.BrowserFeature.HAS_HTML5_NETWORK_EVENT_SUPPORT) {
+    var target =
+        goog.events.BrowserFeature.HTML5_NETWORK_EVENTS_FIRE_ON_BODY ?
+        document.body : window;
+    this.eventHandler_.listen(target,
+        [goog.events.EventType.ONLINE, goog.events.EventType.OFFLINE],
+        this.handleChange_);
+  } else {
+    this.online_ = this.isOnline();
+    this.timer_ = new goog.Timer(goog.events.OnlineHandler.POLL_INTERVAL_);
+    this.eventHandler_.listen(this.timer_, goog.Timer.TICK, this.handleTick_);
+    this.timer_.start();
+  }
+};
+goog.inherits(goog.events.OnlineHandler, goog.events.EventTarget);
+
+
+/**
+ * Enum for the events dispatched by the OnlineHandler.
+ * @enum {string}
+ * @deprecated Use goog.net.NetworkStatusMonitor.EventType instead.
+ */
+goog.events.OnlineHandler.EventType = goog.net.NetworkStatusMonitor.EventType;
+
+
+/**
+ * The time to wait before checking the {@code navigator.onLine} again.
+ * @type {number}
+ * @private
+ */
+goog.events.OnlineHandler.POLL_INTERVAL_ = 250;
+
+
+/**
+ * Stores the last value of the online state so we can detect if this has
+ * changed.
+ * @type {boolean}
+ * @private
+ */
+goog.events.OnlineHandler.prototype.online_;
+
+
+/**
+ * The timer object used to poll the online state.
+ * @type {goog.Timer}
+ * @private
+ */
+goog.events.OnlineHandler.prototype.timer_;
+
+
+/** @override */
+goog.events.OnlineHandler.prototype.isOnline = function() {
+  return goog.events.BrowserFeature.HAS_NAVIGATOR_ONLINE_PROPERTY ?
+      navigator.onLine : true;
+};
+
+
+/**
+ * Called every time the timer ticks to see if the state has changed and when
+ * the online state changes the method handleChange_ is called.
+ * @private
+ */
+goog.events.OnlineHandler.prototype.handleTick_ = function() {
+  var online = this.isOnline();
+  if (online != this.online_) {
+    this.online_ = online;
+    this.handleChange_();
+  }
+};
+
+
+/**
+ * Called when the online state changes.  This dispatches the
+ * {@code ONLINE} and {@code OFFLINE} events respectively.
+ * @private
+ */
+goog.events.OnlineHandler.prototype.handleChange_ = function() {
+  var type = this.isOnline() ?
+      goog.net.NetworkStatusMonitor.EventType.ONLINE :
+      goog.net.NetworkStatusMonitor.EventType.OFFLINE;
+  this.dispatchEvent(type);
+};
+
+
+/** @override */
+goog.events.OnlineHandler.prototype.disposeInternal = function() {
+  goog.events.OnlineHandler.base(this, 'disposeInternal');
+  this.eventHandler_.dispose();
+  this.eventHandler_ = null;
+  if (this.timer_) {
+    this.timer_.dispose();
+    this.timer_ = null;
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/pastehandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/pastehandler.js b/externs/GCL/externs/goog/events/pastehandler.js
new file mode 100644
index 0000000..4992ff0
--- /dev/null
+++ b/externs/GCL/externs/goog/events/pastehandler.js
@@ -0,0 +1,517 @@
+// 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 Provides a 'paste' event detector that works consistently
+ * across different browsers.
+ *
+ * IE5, IE6, IE7, Safari3.0 and FF3.0 all fire 'paste' events on textareas.
+ * FF2 doesn't. This class uses 'paste' events when they are available
+ * and uses heuristics to detect the 'paste' event when they are not available.
+ *
+ * Known issue: will not detect paste events in FF2 if you pasted exactly the
+ * same existing text.
+ * Known issue: Opera + Mac doesn't work properly because of the meta key. We
+ * can probably fix that. TODO(user): {@link KeyboardShortcutHandler} does not
+ * work either very well with opera + mac. fix that.
+ *
+ * @supported IE5, IE6, IE7, Safari3.0, Chrome, FF2.0 (linux) and FF3.0 and
+ * Opera (mac and windows).
+ *
+ * @see ../demos/pastehandler.html
+ */
+
+goog.provide('goog.events.PasteHandler');
+goog.provide('goog.events.PasteHandler.EventType');
+goog.provide('goog.events.PasteHandler.State');
+
+goog.require('goog.Timer');
+goog.require('goog.async.ConditionalDelay');
+goog.require('goog.events.BrowserEvent');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.log');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * A paste event detector. Gets an {@code element} as parameter and fires
+ * {@code goog.events.PasteHandler.EventType.PASTE} events when text is
+ * pasted in the {@code element}. Uses heuristics to detect paste events in FF2.
+ * See more details of the heuristic on {@link #handleEvent_}.
+ *
+ * @param {Element} element The textarea element we are listening on.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.events.PasteHandler = function(element) {
+  goog.events.EventTarget.call(this);
+
+  /**
+   * The element that you want to listen for paste events on.
+   * @type {Element}
+   * @private
+   */
+  this.element_ = element;
+
+  /**
+   * The last known value of the element. Kept to check if things changed. See
+   * more details on {@link #handleEvent_}.
+   * @type {string}
+   * @private
+   */
+  this.oldValue_ = this.element_.value;
+
+  /**
+   * Handler for events.
+   * @type {goog.events.EventHandler<!goog.events.PasteHandler>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+  /**
+   * The last time an event occurred on the element. Kept to check whether the
+   * last event was generated by two input events or by multiple fast key events
+   * that got swallowed. See more details on {@link #handleEvent_}.
+   * @type {number}
+   * @private
+   */
+  this.lastTime_ = goog.now();
+
+  if (goog.userAgent.WEBKIT ||
+      goog.userAgent.IE ||
+      goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9')) {
+    // Most modern browsers support the paste event.
+    this.eventHandler_.listen(element, goog.events.EventType.PASTE,
+        this.dispatch_);
+  } else {
+    // But FF2 and Opera doesn't. we listen for a series of events to try to
+    // find out if a paste occurred. We enumerate and cover all known ways to
+    // paste text on textareas.  See more details on {@link #handleEvent_}.
+    var events = [
+      goog.events.EventType.KEYDOWN,
+      goog.events.EventType.BLUR,
+      goog.events.EventType.FOCUS,
+      goog.events.EventType.MOUSEOVER,
+      'input'
+    ];
+    this.eventHandler_.listen(element, events, this.handleEvent_);
+  }
+
+  /**
+   * ConditionalDelay used to poll for changes in the text element once users
+   * paste text. Browsers fire paste events BEFORE the text is actually present
+   * in the element.value property.
+   * @type {goog.async.ConditionalDelay}
+   * @private
+   */
+  this.delay_ = new goog.async.ConditionalDelay(
+      goog.bind(this.checkUpdatedText_, this));
+
+};
+goog.inherits(goog.events.PasteHandler, goog.events.EventTarget);
+
+
+/**
+ * The types of events fired by this class.
+ * @enum {string}
+ */
+goog.events.PasteHandler.EventType = {
+  /**
+   * Dispatched as soon as the paste event is detected, but before the pasted
+   * text has been added to the text element we're listening to.
+   */
+  PASTE: 'paste',
+
+  /**
+   * Dispatched after detecting a change to the value of text element
+   * (within 200msec of receiving the PASTE event).
+   */
+  AFTER_PASTE: 'after_paste'
+};
+
+
+/**
+ * The mandatory delay we expect between two {@code input} events, used to
+ * differentiated between non key paste events and key events.
+ * @type {number}
+ */
+goog.events.PasteHandler.MANDATORY_MS_BETWEEN_INPUT_EVENTS_TIE_BREAKER =
+    400;
+
+
+/**
+ * The period between each time we check whether the pasted text appears in the
+ * text element or not.
+ * @type {number}
+ * @private
+ */
+goog.events.PasteHandler.PASTE_POLLING_PERIOD_MS_ = 50;
+
+
+/**
+ * The maximum amount of time we want to poll for changes.
+ * @type {number}
+ * @private
+ */
+goog.events.PasteHandler.PASTE_POLLING_TIMEOUT_MS_ = 200;
+
+
+/**
+ * The states that this class can be found, on the paste detection algorithm.
+ * @enum {string}
+ */
+goog.events.PasteHandler.State = {
+  INIT: 'init',
+  FOCUSED: 'focused',
+  TYPING: 'typing'
+};
+
+
+/**
+ * The initial state of the paste detection algorithm.
+ * @type {goog.events.PasteHandler.State}
+ * @private
+ */
+goog.events.PasteHandler.prototype.state_ =
+    goog.events.PasteHandler.State.INIT;
+
+
+/**
+ * The previous event that caused us to be on the current state.
+ * @type {?string}
+ * @private
+ */
+goog.events.PasteHandler.prototype.previousEvent_;
+
+
+/**
+ * A logger, used to help us debug the algorithm.
+ * @type {goog.log.Logger}
+ * @private
+ */
+goog.events.PasteHandler.prototype.logger_ =
+    goog.log.getLogger('goog.events.PasteHandler');
+
+
+/** @override */
+goog.events.PasteHandler.prototype.disposeInternal = function() {
+  goog.events.PasteHandler.superClass_.disposeInternal.call(this);
+  this.eventHandler_.dispose();
+  this.eventHandler_ = null;
+  this.delay_.dispose();
+  this.delay_ = null;
+};
+
+
+/**
+ * Returns the current state of the paste detection algorithm. Used mostly for
+ * testing.
+ * @return {goog.events.PasteHandler.State} The current state of the class.
+ */
+goog.events.PasteHandler.prototype.getState = function() {
+  return this.state_;
+};
+
+
+/**
+ * Returns the event handler.
+ * @return {goog.events.EventHandler<T>} The event handler.
+ * @protected
+ * @this T
+ * @template T
+ */
+goog.events.PasteHandler.prototype.getEventHandler = function() {
+  return this.eventHandler_;
+};
+
+
+/**
+ * Checks whether the element.value property was updated, and if so, dispatches
+ * the event that let clients know that the text is available.
+ * @return {boolean} Whether the polling should stop or not, based on whether
+ *     we found a text change or not.
+ * @private
+ */
+goog.events.PasteHandler.prototype.checkUpdatedText_ = function() {
+  if (this.oldValue_ == this.element_.value) {
+    return false;
+  }
+  goog.log.info(this.logger_, 'detected textchange after paste');
+  this.dispatchEvent(goog.events.PasteHandler.EventType.AFTER_PASTE);
+  return true;
+};
+
+
+/**
+ * Dispatches the paste event.
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ * @private
+ */
+goog.events.PasteHandler.prototype.dispatch_ = function(e) {
+  var event = new goog.events.BrowserEvent(e.getBrowserEvent());
+  event.type = goog.events.PasteHandler.EventType.PASTE;
+  this.dispatchEvent(event);
+
+  // Starts polling for updates in the element.value property so we can tell
+  // when do dispatch the AFTER_PASTE event. (We do an initial check after an
+  // async delay of 0 msec since some browsers update the text right away and
+  // our poller will always wait one period before checking).
+  goog.Timer.callOnce(function() {
+    if (!this.checkUpdatedText_()) {
+      this.delay_.start(
+          goog.events.PasteHandler.PASTE_POLLING_PERIOD_MS_,
+          goog.events.PasteHandler.PASTE_POLLING_TIMEOUT_MS_);
+    }
+  }, 0, this);
+};
+
+
+/**
+ * The main event handler which implements a state machine.
+ *
+ * To handle FF2, we enumerate and cover all the known ways a user can paste:
+ *
+ * 1) ctrl+v, shift+insert, cmd+v
+ * 2) right click -> paste
+ * 3) edit menu -> paste
+ * 4) drag and drop
+ * 5) middle click
+ *
+ * (1) is easy and can be detected by listening for key events and finding out
+ * which keys are pressed. (2), (3), (4) and (5) do not generate a key event,
+ * so we need to listen for more than that. (2-5) all generate 'input' events,
+ * but so does key events. So we need to have some sort of 'how did the input
+ * event was generated' history algorithm.
+ *
+ * (2) is an interesting case in Opera on a Mac: since Macs does not have two
+ * buttons, right clicking involves pressing the CTRL key. Even more interesting
+ * is the fact that opera does NOT set the e.ctrlKey bit. Instead, it sets
+ * e.keyCode = 0.
+ * {@link http://www.quirksmode.org/js/keys.html}
+ *
+ * (1) is also an interesting case in Opera on a Mac: Opera is the only browser
+ * covered by this class that can detect the cmd key (FF2 can't apparently). And
+ * it fires e.keyCode = 17, which is the CTRL key code.
+ * {@link http://www.quirksmode.org/js/keys.html}
+ *
+ * NOTE(user, pbarry): There is an interesting thing about (5): on Linux, (5)
+ * pastes the last thing that you highlighted, not the last thing that you
+ * ctrl+c'ed. This code will still generate a {@code PASTE} event though.
+ *
+ * We enumerate all the possible steps a user can take to paste text and we
+ * implemented the transition between the steps in a state machine. The
+ * following is the design of the state machine:
+ *
+ * matching paths:
+ *
+ * (1) happens on INIT -> FOCUSED -> TYPING -> [e.ctrlKey & e.keyCode = 'v']
+ * (2-3) happens on INIT -> FOCUSED -> [input event happened]
+ * (4) happens on INIT -> [mouseover && text changed]
+ *
+ * non matching paths:
+ *
+ * user is typing normally
+ * INIT -> FOCUS -> TYPING -> INPUT -> INIT
+ *
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ * @private
+ */
+goog.events.PasteHandler.prototype.handleEvent_ = function(e) {
+  // transition between states happen at each browser event, and depend on the
+  // current state, the event that led to this state, and the event input.
+  switch (this.state_) {
+    case goog.events.PasteHandler.State.INIT: {
+      this.handleUnderInit_(e);
+      break;
+    }
+    case goog.events.PasteHandler.State.FOCUSED: {
+      this.handleUnderFocused_(e);
+      break;
+    }
+    case goog.events.PasteHandler.State.TYPING: {
+      this.handleUnderTyping_(e);
+      break;
+    }
+    default: {
+      goog.log.error(this.logger_, 'invalid ' + this.state_ + ' state');
+    }
+  }
+  this.lastTime_ = goog.now();
+  this.oldValue_ = this.element_.value;
+  goog.log.info(this.logger_, e.type + ' -> ' + this.state_);
+  this.previousEvent_ = e.type;
+};
+
+
+/**
+ * {@code goog.events.PasteHandler.EventType.INIT} is the first initial state
+ * the textarea is found. You can only leave this state by setting focus on the
+ * textarea, which is how users will input text. You can also paste things using
+ * drag and drop, which will not generate a {@code goog.events.EventType.FOCUS}
+ * event, but will generate a {@code goog.events.EventType.MOUSEOVER}.
+ *
+ * For browsers that support the 'paste' event, we match it and stay on the same
+ * state.
+ *
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ * @private
+ */
+goog.events.PasteHandler.prototype.handleUnderInit_ = function(e) {
+  switch (e.type) {
+    case goog.events.EventType.BLUR: {
+      this.state_ = goog.events.PasteHandler.State.INIT;
+      break;
+    }
+    case goog.events.EventType.FOCUS: {
+      this.state_ = goog.events.PasteHandler.State.FOCUSED;
+      break;
+    }
+    case goog.events.EventType.MOUSEOVER: {
+      this.state_ = goog.events.PasteHandler.State.INIT;
+      if (this.element_.value != this.oldValue_) {
+        goog.log.info(this.logger_, 'paste by dragdrop while on init!');
+        this.dispatch_(e);
+      }
+      break;
+    }
+    default: {
+      goog.log.error(this.logger_,
+          'unexpected event ' + e.type + 'during init');
+    }
+  }
+};
+
+
+/**
+ * {@code goog.events.PasteHandler.EventType.FOCUSED} is typically the second
+ * state the textarea will be, which is followed by the {@code INIT} state. On
+ * this state, users can paste in three different ways: edit -> paste,
+ * right click -> paste and drag and drop.
+ *
+ * The latter will generate a {@code goog.events.EventType.MOUSEOVER} event,
+ * which we match by making sure the textarea text changed. The first two will
+ * generate an 'input', which we match by making sure it was NOT generated by a
+ * key event (which also generates an 'input' event).
+ *
+ * Unfortunately, in Firefox, if you type fast, some KEYDOWN events are
+ * swallowed but an INPUT event may still happen. That means we need to
+ * differentiate between two consecutive INPUT events being generated either by
+ * swallowed key events OR by a valid edit -> paste -> edit -> paste action. We
+ * do this by checking a minimum time between the two events. This heuristic
+ * seems to work well, but it is obviously a heuristic :).
+ *
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ * @private
+ */
+goog.events.PasteHandler.prototype.handleUnderFocused_ = function(e) {
+  switch (e.type) {
+    case 'input' : {
+      // there are two different events that happen in practice that involves
+      // consecutive 'input' events. we use a heuristic to differentiate
+      // between the one that generates a valid paste action and the one that
+      // doesn't.
+      // @see testTypingReallyFastDispatchesTwoInputEventsBeforeTheKEYDOWNEvent
+      // and
+      // @see testRightClickRightClickAlsoDispatchesTwoConsecutiveInputEvents
+      // Notice that an 'input' event may be also triggered by a 'middle click'
+      // paste event, which is described in
+      // @see testMiddleClickWithoutFocusTriggersPasteEvent
+      var minimumMilisecondsBetweenInputEvents = this.lastTime_ +
+          goog.events.PasteHandler.
+              MANDATORY_MS_BETWEEN_INPUT_EVENTS_TIE_BREAKER;
+      if (goog.now() > minimumMilisecondsBetweenInputEvents ||
+          this.previousEvent_ == goog.events.EventType.FOCUS) {
+        goog.log.info(this.logger_, 'paste by textchange while focused!');
+        this.dispatch_(e);
+      }
+      break;
+    }
+    case goog.events.EventType.BLUR: {
+      this.state_ = goog.events.PasteHandler.State.INIT;
+      break;
+    }
+    case goog.events.EventType.KEYDOWN: {
+      goog.log.info(this.logger_, 'key down ... looking for ctrl+v');
+      // Opera + MAC does not set e.ctrlKey. Instead, it gives me e.keyCode = 0.
+      // http://www.quirksmode.org/js/keys.html
+      if (goog.userAgent.MAC && goog.userAgent.OPERA && e.keyCode == 0 ||
+          goog.userAgent.MAC && goog.userAgent.OPERA && e.keyCode == 17) {
+        break;
+      }
+      this.state_ = goog.events.PasteHandler.State.TYPING;
+      break;
+    }
+    case goog.events.EventType.MOUSEOVER: {
+      if (this.element_.value != this.oldValue_) {
+        goog.log.info(this.logger_, 'paste by dragdrop while focused!');
+        this.dispatch_(e);
+      }
+      break;
+    }
+    default: {
+      goog.log.error(this.logger_,
+          'unexpected event ' + e.type + ' during focused');
+    }
+  }
+};
+
+
+/**
+ * {@code goog.events.PasteHandler.EventType.TYPING} is the third state
+ * this class can be. It exists because each KEYPRESS event will ALSO generate
+ * an INPUT event (because the textarea value changes), and we need to
+ * differentiate between an INPUT event generated by a key event and an INPUT
+ * event generated by edit -> paste actions.
+ *
+ * This is the state that we match the ctrl+v pattern.
+ *
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ * @private
+ */
+goog.events.PasteHandler.prototype.handleUnderTyping_ = function(e) {
+  switch (e.type) {
+    case 'input' : {
+      this.state_ = goog.events.PasteHandler.State.FOCUSED;
+      break;
+    }
+    case goog.events.EventType.BLUR: {
+      this.state_ = goog.events.PasteHandler.State.INIT;
+      break;
+    }
+    case goog.events.EventType.KEYDOWN: {
+      if (e.ctrlKey && e.keyCode == goog.events.KeyCodes.V ||
+          e.shiftKey && e.keyCode == goog.events.KeyCodes.INSERT ||
+          e.metaKey && e.keyCode == goog.events.KeyCodes.V) {
+        goog.log.info(this.logger_, 'paste by ctrl+v while keypressed!');
+        this.dispatch_(e);
+      }
+      break;
+    }
+    case goog.events.EventType.MOUSEOVER: {
+      if (this.element_.value != this.oldValue_) {
+        goog.log.info(this.logger_, 'paste by dragdrop while keypressed!');
+        this.dispatch_(e);
+      }
+      break;
+    }
+    default: {
+      goog.log.error(this.logger_,
+          'unexpected event ' + e.type + ' during keypressed');
+    }
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/wheelevent.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/wheelevent.js b/externs/GCL/externs/goog/events/wheelevent.js
new file mode 100644
index 0000000..1f172eb
--- /dev/null
+++ b/externs/GCL/externs/goog/events/wheelevent.js
@@ -0,0 +1,169 @@
+// Copyright 2014 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 This class aims to smooth out inconsistencies between browser
+ * handling of wheel events by providing an event that is similar to that
+ * defined in the standard, but also easier to consume.
+ *
+ * It is based upon the WheelEvent, which allows for up to 3 dimensional
+ * scrolling events that come in units of either pixels, lines or pages.
+ * http://www.w3.org/TR/2014/WD-DOM-Level-3-Events-20140925/#interface-WheelEvent
+ *
+ * The significant difference here is that it also provides reasonable pixel
+ * deltas for clients that do not want to treat line and page scrolling events
+ * specially.
+ *
+ * Clients of this code should be aware that some input devices only fire a few
+ * discrete events (such as a mouse wheel without acceleration) whereas some can
+ * generate a large number of events for a single interaction (such as a
+ * touchpad with acceleration). There is no signal in the events to reliably
+ * distinguish between these.
+ *
+ * @see ../demos/wheelhandler.html
+ */
+
+goog.provide('goog.events.WheelEvent');
+
+goog.require('goog.asserts');
+goog.require('goog.events.BrowserEvent');
+
+
+
+/**
+ * A common class for wheel events. This is used with the WheelHandler.
+ *
+ * @param {Event} browserEvent Browser event object.
+ * @param {goog.events.WheelEvent.DeltaMode} deltaMode The delta mode units of
+ *     the wheel event.
+ * @param {number} deltaX The number of delta units the user in the X axis.
+ * @param {number} deltaY The number of delta units the user in the Y axis.
+ * @param {number} deltaZ The number of delta units the user in the Z axis.
+ * @constructor
+ * @extends {goog.events.BrowserEvent}
+ * @final
+ */
+goog.events.WheelEvent = function(
+    browserEvent, deltaMode, deltaX, deltaY, deltaZ) {
+  goog.events.WheelEvent.base(this, 'constructor', browserEvent);
+  goog.asserts.assert(browserEvent, 'Expecting a non-null browserEvent');
+
+  /** @type {goog.events.WheelEvent.EventType} */
+  this.type = goog.events.WheelEvent.EventType.WHEEL;
+
+  /**
+   * An enum corresponding to the units of this event.
+   * @type {goog.events.WheelEvent.DeltaMode}
+   */
+  this.deltaMode = deltaMode;
+
+  /**
+   * The number of delta units in the X axis.
+   * @type {number}
+   */
+  this.deltaX = deltaX;
+
+  /**
+   * The number of delta units in the Y axis.
+   * @type {number}
+   */
+  this.deltaY = deltaY;
+
+  /**
+   * The number of delta units in the Z axis.
+   * @type {number}
+   */
+  this.deltaZ = deltaZ;
+
+  // Ratio between delta and pixel values.
+  var pixelRatio = 1;  // Value for DeltaMode.PIXEL
+  switch (deltaMode) {
+    case goog.events.WheelEvent.DeltaMode.PAGE:
+      pixelRatio *= goog.events.WheelEvent.PIXELS_PER_PAGE_;
+      break;
+    case goog.events.WheelEvent.DeltaMode.LINE:
+      pixelRatio *= goog.events.WheelEvent.PIXELS_PER_LINE_;
+      break;
+  }
+
+  /**
+   * The number of delta pixels in the X axis. Code that doesn't want to handle
+   * different deltaMode units can just look here.
+   * @type {number}
+   */
+  this.pixelDeltaX = this.deltaX * pixelRatio;
+
+  /**
+   * The number of pixels in the Y axis. Code that doesn't want to
+   * handle different deltaMode units can just look here.
+   * @type {number}
+   */
+  this.pixelDeltaY = this.deltaY * pixelRatio;
+
+  /**
+   * The number of pixels scrolled in the Z axis. Code that doesn't want to
+   * handle different deltaMode units can just look here.
+   * @type {number}
+   */
+  this.pixelDeltaZ = this.deltaZ * pixelRatio;
+};
+goog.inherits(goog.events.WheelEvent, goog.events.BrowserEvent);
+
+
+/**
+ * Enum type for the events fired by the wheel handler.
+ * @enum {string}
+ */
+goog.events.WheelEvent.EventType = {
+  /** The user has provided wheel-based input. */
+  WHEEL: 'wheel'
+};
+
+
+/**
+ * Units for the deltas in a WheelEvent.
+ * @enum {number}
+ */
+goog.events.WheelEvent.DeltaMode = {
+  /** The units are in pixels. From DOM_DELTA_PIXEL. */
+  PIXEL: 0,
+  /** The units are in lines. From DOM_DELTA_LINE. */
+  LINE: 1,
+  /** The units are in pages. From DOM_DELTA_PAGE. */
+  PAGE: 2
+};
+
+
+/**
+ * A conversion number between line scroll units and pixel scroll units. The
+ * actual value per line can vary a lot between devices and font sizes. This
+ * number can not be perfect, but it should be reasonable for converting lines
+ * scroll events into pixels.
+ * @const {number}
+ * @private
+ */
+goog.events.WheelEvent.PIXELS_PER_LINE_ = 15;
+
+
+/**
+ * A conversion number between page scroll units and pixel scroll units. The
+ * actual value per page can vary a lot as many different devices have different
+ * screen sizes, and the window might not be taking up the full screen. This
+ * number can not be perfect, but it should be reasonable for converting page
+ * scroll events into pixels.
+ * @const {number}
+ * @private
+ */
+goog.events.WheelEvent.PIXELS_PER_PAGE_ = 30 *
+    goog.events.WheelEvent.PIXELS_PER_LINE_;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/wheelhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/wheelhandler.js b/externs/GCL/externs/goog/events/wheelhandler.js
new file mode 100644
index 0000000..9d0f1e3
--- /dev/null
+++ b/externs/GCL/externs/goog/events/wheelhandler.js
@@ -0,0 +1,159 @@
+// Copyright 2014 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 This event wrapper will dispatch an event when the user uses
+ * the wheel on an element. The event provides details of the unit type (pixel /
+ * line / page) and deltas in those units in up to 3 dimensions. Additionally,
+ * simplified pixel deltas are provided for code that doesn't need to handle the
+ * different units differently. This is not to be confused with the scroll
+ * event, where an element in the dom can report that it was scrolled.
+ *
+ * This class aims to smooth out inconsistencies between browser platforms with
+ * regards to wheel events, but we do not cover every possible software/hardware
+ * combination out there, some of which occasionally produce very large deltas
+ * in wheel events, especially when the device supports acceleration.
+ *
+ * Relevant standard:
+ * http://www.w3.org/TR/2014/WD-DOM-Level-3-Events-20140925/#interface-WheelEvent
+ *
+ * Clients of this code should be aware that some input devices only fire a few
+ * discrete events (such as a mouse wheel without acceleration) whereas some can
+ * generate a large number of events for a single interaction (such as a
+ * touchpad with acceleration). There is no signal in the events to reliably
+ * distinguish between these.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/wheelhandler.html
+ */
+
+goog.provide('goog.events.WheelHandler');
+
+goog.require('goog.dom');
+goog.require('goog.events');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.WheelEvent');
+goog.require('goog.style');
+goog.require('goog.userAgent');
+goog.require('goog.userAgent.product');
+goog.require('goog.userAgent.product.isVersion');
+
+
+
+/**
+ * This event handler allows you to catch wheel events in a consistent manner.
+ * @param {!Element|!Document} element The element to listen to the wheel event
+ *     on.
+ * @param {boolean=} opt_capture Whether to handle the wheel event in capture
+ *     phase.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.events.WheelHandler = function(element, opt_capture) {
+  goog.events.WheelHandler.base(this, 'constructor');
+
+  /**
+   * This is the element that we will listen to the real wheel events on.
+   * @private {!Element|!Document}
+   */
+  this.element_ = element;
+
+  var rtlElement = goog.dom.isElement(this.element_) ?
+      /** @type {!Element} */ (this.element_) :
+      /** @type {!Document} */ (this.element_).body;
+
+  /**
+   * True if the element exists and is RTL, false otherwise.
+   * @private {boolean}
+   */
+  this.isRtl_ = !!rtlElement && goog.style.isRightToLeft(rtlElement);
+
+  /**
+   * The key returned from the goog.events.listen.
+   * @private {goog.events.Key}
+   */
+  this.listenKey_ = goog.events.listen(
+      this.element_, goog.events.WheelHandler.getDomEventType(),
+      this, opt_capture);
+};
+goog.inherits(goog.events.WheelHandler, goog.events.EventTarget);
+
+
+/**
+ * Returns the dom event type.
+ * @return {string} The dom event type.
+ */
+goog.events.WheelHandler.getDomEventType = function() {
+  // Prefer to use wheel events whenever supported.
+  if (goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher(17) ||
+      goog.userAgent.IE && goog.userAgent.isVersionOrHigher(9) ||
+      goog.userAgent.product.CHROME && goog.userAgent.product.isVersion(31)) {
+    return 'wheel';
+  }
+
+  // Legacy events. Still the best we have on Opera and Safari.
+  return goog.userAgent.GECKO ? 'DOMMouseScroll' : 'mousewheel';
+};
+
+
+/**
+ * Handles the events on the element.
+ * @param {!goog.events.BrowserEvent} e The underlying browser event.
+ */
+goog.events.WheelHandler.prototype.handleEvent = function(e) {
+  var deltaMode = goog.events.WheelEvent.DeltaMode.PIXEL;
+  var deltaX = 0;
+  var deltaY = 0;
+  var deltaZ = 0;
+  var be = e.getBrowserEvent();
+  if (be.type == 'wheel') {
+    deltaMode = be.deltaMode;
+    deltaX = be.deltaX;
+    deltaY = be.deltaY;
+    deltaZ = be.deltaZ;
+  } else if (be.type == 'mousewheel') {
+    // Assume that these are still comparable to pixels. This may not be true
+    // for all old browsers.
+    if (goog.isDef(be.wheelDeltaX)) {
+      deltaX = -be.wheelDeltaX;
+      deltaY = -be.wheelDeltaY;
+    } else {
+      deltaY = -be.wheelDelta;
+    }
+  } else { // Historical Gecko
+    // Gecko returns multiple of 3 (representing the number of lines)
+    deltaMode = goog.events.WheelEvent.DeltaMode.LINE;
+    // Firefox 3.1 adds an axis field to the event to indicate axis.
+    if (goog.isDef(be.axis) && be.axis === be.HORIZONTAL_AXIS) {
+      deltaX = be.detail;
+    } else {
+      deltaY = be.detail;
+    }
+  }
+  // For horizontal deltas we need to flip the value for RTL grids.
+  if (this.isRtl_) {
+    deltaX = -deltaX;
+  }
+  var newEvent = new goog.events.WheelEvent(
+      be, deltaMode, deltaX, deltaY, deltaZ);
+  this.dispatchEvent(newEvent);
+};
+
+
+/** @override */
+goog.events.WheelHandler.prototype.disposeInternal = function() {
+  goog.events.WheelHandler.superClass_.disposeInternal.call(this);
+  goog.events.unlistenByKey(this.listenKey_);
+  this.listenKey_ = null;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/format/emailaddress.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/format/emailaddress.js b/externs/GCL/externs/goog/format/emailaddress.js
new file mode 100644
index 0000000..670bc33
--- /dev/null
+++ b/externs/GCL/externs/goog/format/emailaddress.js
@@ -0,0 +1,499 @@
+// Copyright 2010 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 Provides functions to parse and manipulate email addresses.
+ *
+ */
+
+goog.provide('goog.format.EmailAddress');
+
+goog.require('goog.string');
+
+
+
+/**
+ * Formats an email address string for display, and allows for extraction of
+ * the individual components of the address.
+ * @param {string=} opt_address The email address.
+ * @param {string=} opt_name The name associated with the email address.
+ * @constructor
+ */
+goog.format.EmailAddress = function(opt_address, opt_name) {
+  /**
+   * The name or personal string associated with the address.
+   * @type {string}
+   * @private
+   */
+  this.name_ = opt_name || '';
+
+  /**
+   * The email address.
+   * @type {string}
+   * @protected
+   */
+  this.address = opt_address || '';
+};
+
+
+/**
+ * Match string for opening tokens.
+ * @type {string}
+ * @private
+ */
+goog.format.EmailAddress.OPENERS_ = '"<([';
+
+
+/**
+ * Match string for closing tokens.
+ * @type {string}
+ * @private
+ */
+goog.format.EmailAddress.CLOSERS_ = '">)]';
+
+
+/**
+ * Match string for characters that require display names to be quoted and are
+ * not address separators.
+ * @type {string}
+ * @const
+ * @package
+ */
+goog.format.EmailAddress.SPECIAL_CHARS = '()<>@:\\\".[]';
+
+
+/**
+ * Match string for address separators.
+ * @type {string}
+ * @const
+ * @private
+ */
+goog.format.EmailAddress.ADDRESS_SEPARATORS_ = ',;';
+
+
+/**
+ * Match string for characters that, when in a display name, require it to be
+ * quoted.
+ * @type {string}
+ * @const
+ * @private
+ */
+goog.format.EmailAddress.CHARS_REQUIRE_QUOTES_ =
+    goog.format.EmailAddress.SPECIAL_CHARS +
+    goog.format.EmailAddress.ADDRESS_SEPARATORS_;
+
+
+/**
+ * A RegExp to match all double quotes.  Used in cleanAddress().
+ * @type {RegExp}
+ * @private
+ */
+goog.format.EmailAddress.ALL_DOUBLE_QUOTES_ = /\"/g;
+
+
+/**
+ * A RegExp to match escaped double quotes.  Used in parse().
+ * @type {RegExp}
+ * @private
+ */
+goog.format.EmailAddress.ESCAPED_DOUBLE_QUOTES_ = /\\\"/g;
+
+
+/**
+ * A RegExp to match all backslashes.  Used in cleanAddress().
+ * @type {RegExp}
+ * @private
+ */
+goog.format.EmailAddress.ALL_BACKSLASHES_ = /\\/g;
+
+
+/**
+ * A RegExp to match escaped backslashes.  Used in parse().
+ * @type {RegExp}
+ * @private
+ */
+goog.format.EmailAddress.ESCAPED_BACKSLASHES_ = /\\\\/g;
+
+
+/**
+ * A string representing the RegExp for the local part of an email address.
+ * @private {string}
+ */
+goog.format.EmailAddress.LOCAL_PART_REGEXP_STR_ =
+    '[+a-zA-Z0-9_.!#$%&\'*\\/=?^`{|}~-]+';
+
+
+/**
+ * A string representing the RegExp for the domain part of an email address.
+ * @private {string}
+ */
+goog.format.EmailAddress.DOMAIN_PART_REGEXP_STR_ =
+    '([a-zA-Z0-9-]+\\.)+[a-zA-Z0-9]{2,63}';
+
+
+/**
+ * A RegExp to match the local part of an email address.
+ * @private {!RegExp}
+ */
+goog.format.EmailAddress.LOCAL_PART_ =
+    new RegExp('^' + goog.format.EmailAddress.LOCAL_PART_REGEXP_STR_ + '$');
+
+
+/**
+ * A RegExp to match the domain part of an email address.
+ * @private {!RegExp}
+ */
+goog.format.EmailAddress.DOMAIN_PART_ =
+    new RegExp('^' + goog.format.EmailAddress.DOMAIN_PART_REGEXP_STR_ + '$');
+
+
+/**
+ * A RegExp to match an email address.
+ * @private {!RegExp}
+ */
+goog.format.EmailAddress.EMAIL_ADDRESS_ =
+    new RegExp('^' + goog.format.EmailAddress.LOCAL_PART_REGEXP_STR_ + '@' +
+        goog.format.EmailAddress.DOMAIN_PART_REGEXP_STR_ + '$');
+
+
+/**
+ * Get the name associated with the email address.
+ * @return {string} The name or personal portion of the address.
+ * @final
+ */
+goog.format.EmailAddress.prototype.getName = function() {
+  return this.name_;
+};
+
+
+/**
+ * Get the email address.
+ * @return {string} The email address.
+ * @final
+ */
+goog.format.EmailAddress.prototype.getAddress = function() {
+  return this.address;
+};
+
+
+/**
+ * Set the name associated with the email address.
+ * @param {string} name The name to associate.
+ * @final
+ */
+goog.format.EmailAddress.prototype.setName = function(name) {
+  this.name_ = name;
+};
+
+
+/**
+ * Set the email address.
+ * @param {string} address The email address.
+ * @final
+ */
+goog.format.EmailAddress.prototype.setAddress = function(address) {
+  this.address = address;
+};
+
+
+/**
+ * Return the address in a standard format:
+ *  - remove extra spaces.
+ *  - Surround name with quotes if it contains special characters.
+ * @return {string} The cleaned address.
+ * @override
+ */
+goog.format.EmailAddress.prototype.toString = function() {
+  return this.toStringInternal(
+      goog.format.EmailAddress.CHARS_REQUIRE_QUOTES_);
+};
+
+
+/**
+ * Check if a display name requires quoting.
+ * @param {string} name The display name
+ * @param {string} specialChars String that contains the characters that require
+ *  the display name to be quoted. This may change based in whereas we are
+ *  in EAI context or not.
+ * @return {boolean}
+ * @private
+ */
+goog.format.EmailAddress.isQuoteNeeded_ = function(name, specialChars) {
+  for (var i = 0; i < specialChars.length; i++) {
+    var specialChar = specialChars[i];
+    if (goog.string.contains(name, specialChar)) {
+      return true;
+    }
+  }
+  return false;
+};
+
+
+/**
+ * Return the address in a standard format:
+ *  - remove extra spaces.
+ *  - Surround name with quotes if it contains special characters.
+ * @param {string} specialChars String that contains the characters that require
+ *  the display name to be quoted.
+ * @return {string} The cleaned address.
+ * @protected
+ */
+goog.format.EmailAddress.prototype.toStringInternal = function(specialChars) {
+  var name = this.getName();
+
+  // We intentionally remove double quotes in the name because escaping
+  // them to \" looks ugly.
+  name = name.replace(goog.format.EmailAddress.ALL_DOUBLE_QUOTES_, '');
+
+  // If the name has special characters, we need to quote it and escape \'s.
+  if (goog.format.EmailAddress.isQuoteNeeded_(name, specialChars)) {
+    name = '"' +
+        name.replace(goog.format.EmailAddress.ALL_BACKSLASHES_, '\\\\') + '"';
+  }
+
+  if (name == '') {
+    return this.address;
+  }
+  if (this.address == '') {
+    return name;
+  }
+  return name + ' <' + this.address + '>';
+};
+
+
+/**
+ * Determines is the current object is a valid email address.
+ * @return {boolean} Whether the email address is valid.
+ */
+goog.format.EmailAddress.prototype.isValid = function() {
+  return goog.format.EmailAddress.isValidAddrSpec(this.address);
+};
+
+
+/**
+ * Checks if the provided string is a valid email address. Supports both
+ * simple email addresses (address specs) and addresses that contain display
+ * names.
+ * @param {string} str The email address to check.
+ * @return {boolean} Whether the provided string is a valid address.
+ */
+goog.format.EmailAddress.isValidAddress = function(str) {
+  return goog.format.EmailAddress.parse(str).isValid();
+};
+
+
+/**
+ * Checks if the provided string is a valid address spec (local@domain.com).
+ * @param {string} str The email address to check.
+ * @return {boolean} Whether the provided string is a valid address spec.
+ */
+goog.format.EmailAddress.isValidAddrSpec = function(str) {
+  // This is a fairly naive implementation, but it covers 99% of use cases.
+  // For more details, see http://en.wikipedia.org/wiki/Email_address#Syntax
+  return goog.format.EmailAddress.EMAIL_ADDRESS_.test(str);
+};
+
+
+/**
+ * Checks if the provided string is a valid local part (part before the '@') of
+ * an email address.
+ * @param {string} str The local part to check.
+ * @return {boolean} Whether the provided string is a valid local part.
+ */
+goog.format.EmailAddress.isValidLocalPartSpec = function(str) {
+  return goog.format.EmailAddress.LOCAL_PART_.test(str);
+};
+
+
+/**
+ * Checks if the provided string is a valid domain part (part after the '@') of
+ * an email address.
+ * @param {string} str The domain part to check.
+ * @return {boolean} Whether the provided string is a valid domain part.
+ */
+goog.format.EmailAddress.isValidDomainPartSpec = function(str) {
+  return goog.format.EmailAddress.DOMAIN_PART_.test(str);
+};
+
+
+/**
+ * Parses an email address of the form "name" &lt;address&gt; ("name" is
+ * optional) into an email address.
+ * @param {string} addr The address string.
+ * @param {function(new: goog.format.EmailAddress, string=,string=)} ctor
+ *     EmailAddress constructor to instantiate the output address.
+ * @return {!goog.format.EmailAddress} The parsed address.
+ * @protected
+ */
+goog.format.EmailAddress.parseInternal = function(addr, ctor) {
+  // TODO(ecattell): Strip bidi markers.
+  var name = '';
+  var address = '';
+  for (var i = 0; i < addr.length;) {
+    var token = goog.format.EmailAddress.getToken_(addr, i);
+    if (token.charAt(0) == '<' && token.indexOf('>') != -1) {
+      var end = token.indexOf('>');
+      address = token.substring(1, end);
+    } else if (address == '') {
+      name += token;
+    }
+    i += token.length;
+  }
+
+  // Check if it's a simple email address of the form "jlim@google.com".
+  if (address == '' && name.indexOf('@') != -1) {
+    address = name;
+    name = '';
+  }
+
+  name = goog.string.collapseWhitespace(name);
+  name = goog.string.stripQuotes(name, '\'');
+  name = goog.string.stripQuotes(name, '"');
+  // Replace escaped quotes and slashes.
+  name = name.replace(goog.format.EmailAddress.ESCAPED_DOUBLE_QUOTES_, '"');
+  name = name.replace(goog.format.EmailAddress.ESCAPED_BACKSLASHES_, '\\');
+  address = goog.string.collapseWhitespace(address);
+  return new ctor(address, name);
+};
+
+
+/**
+ * Parses an email address of the form "name" &lt;address&gt; into
+ * an email address.
+ * @param {string} addr The address string.
+ * @return {!goog.format.EmailAddress} The parsed address.
+ */
+goog.format.EmailAddress.parse = function(addr) {
+  return goog.format.EmailAddress.parseInternal(
+      addr, goog.format.EmailAddress);
+};
+
+
+/**
+ * Parse a string containing email addresses of the form
+ * "name" &lt;address&gt; into an array of email addresses.
+ * @param {string} str The address list.
+ * @param {function(string)} parser The parser to employ.
+ * @param {function(string):boolean} separatorChecker Accepts a character and
+ *    returns whether it should be considered an address separator.
+ * @return {!Array<!goog.format.EmailAddress>} The parsed emails.
+ * @protected
+ */
+goog.format.EmailAddress.parseListInternal = function(
+    str, parser, separatorChecker) {
+  var result = [];
+  var email = '';
+  var token;
+
+  // Remove non-UNIX-style newlines that would otherwise cause getToken_ to
+  // choke. Remove multiple consecutive whitespace characters for the same
+  // reason.
+  str = goog.string.collapseWhitespace(str);
+
+  for (var i = 0; i < str.length; ) {
+    token = goog.format.EmailAddress.getToken_(str, i);
+    if (separatorChecker(token) ||
+        (token == ' ' && parser(email).isValid())) {
+      if (!goog.string.isEmptyOrWhitespace(email)) {
+        result.push(parser(email));
+      }
+      email = '';
+      i++;
+      continue;
+    }
+    email += token;
+    i += token.length;
+  }
+
+  // Add the final token.
+  if (!goog.string.isEmptyOrWhitespace(email)) {
+    result.push(parser(email));
+  }
+  return result;
+};
+
+
+/**
+ * Parses a string containing email addresses of the form
+ * "name" &lt;address&gt; into an array of email addresses.
+ * @param {string} str The address list.
+ * @return {!Array<!goog.format.EmailAddress>} The parsed emails.
+ */
+goog.format.EmailAddress.parseList = function(str) {
+  return goog.format.EmailAddress.parseListInternal(
+      str, goog.format.EmailAddress.parse,
+      goog.format.EmailAddress.isAddressSeparator);
+};
+
+
+/**
+ * Get the next token from a position in an address string.
+ * @param {string} str the string.
+ * @param {number} pos the position.
+ * @return {string} the token.
+ * @private
+ */
+goog.format.EmailAddress.getToken_ = function(str, pos) {
+  var ch = str.charAt(pos);
+  var p = goog.format.EmailAddress.OPENERS_.indexOf(ch);
+  if (p == -1) {
+    return ch;
+  }
+  if (goog.format.EmailAddress.isEscapedDlQuote_(str, pos)) {
+
+    // If an opener is an escaped quote we do not treat it as a real opener
+    // and keep accumulating the token.
+    return ch;
+  }
+  var closerChar = goog.format.EmailAddress.CLOSERS_.charAt(p);
+  var endPos = str.indexOf(closerChar, pos + 1);
+
+  // If the closer is a quote we go forward skipping escaped quotes until we
+  // hit the real closing one.
+  while (endPos >= 0 &&
+         goog.format.EmailAddress.isEscapedDlQuote_(str, endPos)) {
+    endPos = str.indexOf(closerChar, endPos + 1);
+  }
+  var token = (endPos >= 0) ? str.substring(pos, endPos + 1) : ch;
+  return token;
+};
+
+
+/**
+ * Checks if the character in the current position is an escaped double quote
+ * ( \" ).
+ * @param {string} str the string.
+ * @param {number} pos the position.
+ * @return {boolean} true if the char is escaped double quote.
+ * @private
+ */
+goog.format.EmailAddress.isEscapedDlQuote_ = function(str, pos) {
+  if (str.charAt(pos) != '"') {
+    return false;
+  }
+  var slashCount = 0;
+  for (var idx = pos - 1; idx >= 0 && str.charAt(idx) == '\\'; idx--) {
+    slashCount++;
+  }
+  return ((slashCount % 2) != 0);
+};
+
+
+/**
+ * @param {string} ch The character to test.
+ * @return {boolean} Whether the provided character is an address separator.
+ */
+goog.format.EmailAddress.isAddressSeparator = function(ch) {
+  return goog.string.contains(goog.format.EmailAddress.ADDRESS_SEPARATORS_, ch);
+};


[15/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/filesaver.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/filesaver.js b/externs/GCL/externs/goog/fs/filesaver.js
new file mode 100644
index 0000000..8d441c4
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/filesaver.js
@@ -0,0 +1,166 @@
+// Copyright 2011 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 wrapper for the HTML5 FileSaver object.
+ *
+ */
+
+goog.provide('goog.fs.FileSaver');
+goog.provide('goog.fs.FileSaver.EventType');
+goog.provide('goog.fs.FileSaver.ReadyState');
+
+goog.require('goog.events.EventTarget');
+goog.require('goog.fs.Error');
+goog.require('goog.fs.ProgressEvent');
+
+
+
+/**
+ * An object for monitoring the saving of files. This emits ProgressEvents of
+ * the types listed in {@link goog.fs.FileSaver.EventType}.
+ *
+ * This should not be instantiated directly. Instead, its subclass
+ * {@link goog.fs.FileWriter} should be accessed via
+ * {@link goog.fs.FileEntry#createWriter}.
+ *
+ * @param {!FileSaver} fileSaver The underlying FileSaver object.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.fs.FileSaver = function(fileSaver) {
+  goog.fs.FileSaver.base(this, 'constructor');
+
+  /**
+   * The underlying FileSaver object.
+   *
+   * @type {!FileSaver}
+   * @private
+   */
+  this.saver_ = fileSaver;
+
+  this.saver_.onwritestart = goog.bind(this.dispatchProgressEvent_, this);
+  this.saver_.onprogress = goog.bind(this.dispatchProgressEvent_, this);
+  this.saver_.onwrite = goog.bind(this.dispatchProgressEvent_, this);
+  this.saver_.onabort = goog.bind(this.dispatchProgressEvent_, this);
+  this.saver_.onerror = goog.bind(this.dispatchProgressEvent_, this);
+  this.saver_.onwriteend = goog.bind(this.dispatchProgressEvent_, this);
+};
+goog.inherits(goog.fs.FileSaver, goog.events.EventTarget);
+
+
+/**
+ * Possible states for a FileSaver.
+ *
+ * @enum {number}
+ */
+goog.fs.FileSaver.ReadyState = {
+  /**
+   * The object has been constructed, but there is no pending write.
+   */
+  INIT: 0,
+  /**
+   * Data is being written.
+   */
+  WRITING: 1,
+  /**
+   * The data has been written to the file, the write was aborted, or an error
+   * occurred.
+   */
+  DONE: 2
+};
+
+
+/**
+ * Events emitted by a FileSaver.
+ *
+ * @enum {string}
+ */
+goog.fs.FileSaver.EventType = {
+  /**
+   * Emitted when the writing begins. readyState will be WRITING.
+   */
+  WRITE_START: 'writestart',
+  /**
+   * Emitted when progress has been made in saving the file. readyState will be
+   * WRITING.
+   */
+  PROGRESS: 'progress',
+  /**
+   * Emitted when the data has been successfully written. readyState will be
+   * WRITING.
+   */
+  WRITE: 'write',
+  /**
+   * Emitted when the writing has been aborted. readyState will be WRITING.
+   */
+  ABORT: 'abort',
+  /**
+   * Emitted when an error is encountered or the writing has been aborted.
+   * readyState will be WRITING.
+   */
+  ERROR: 'error',
+  /**
+   * Emitted when the writing is finished, whether successfully or not.
+   * readyState will be DONE.
+   */
+  WRITE_END: 'writeend'
+};
+
+
+/**
+ * Abort the writing of the file.
+ */
+goog.fs.FileSaver.prototype.abort = function() {
+  try {
+    this.saver_.abort();
+  } catch (e) {
+    throw new goog.fs.Error(e, 'aborting save');
+  }
+};
+
+
+/**
+ * @return {goog.fs.FileSaver.ReadyState} The current state of the FileSaver.
+ */
+goog.fs.FileSaver.prototype.getReadyState = function() {
+  return /** @type {goog.fs.FileSaver.ReadyState} */ (this.saver_.readyState);
+};
+
+
+/**
+ * @return {goog.fs.Error} The error encountered while writing, if any.
+ */
+goog.fs.FileSaver.prototype.getError = function() {
+  return this.saver_.error &&
+      new goog.fs.Error(this.saver_.error, 'saving file');
+};
+
+
+/**
+ * Wrap a progress event emitted by the underlying file saver and re-emit it.
+ *
+ * @param {!ProgressEvent} event The underlying event.
+ * @private
+ */
+goog.fs.FileSaver.prototype.dispatchProgressEvent_ = function(event) {
+  this.dispatchEvent(new goog.fs.ProgressEvent(event, this));
+};
+
+
+/** @override */
+goog.fs.FileSaver.prototype.disposeInternal = function() {
+  delete this.saver_;
+  goog.fs.FileSaver.base(this, 'disposeInternal');
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/filesystem.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/filesystem.js b/externs/GCL/externs/goog/fs/filesystem.js
new file mode 100644
index 0000000..b120b92
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/filesystem.js
@@ -0,0 +1,41 @@
+// Copyright 2011 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 wrapper for the HTML5 FileSystem object.
+ *
+ */
+
+goog.provide('goog.fs.FileSystem');
+
+
+
+/**
+ * A local filesystem.
+ *
+ * @interface
+ */
+goog.fs.FileSystem = function() {};
+
+
+/**
+ * @return {string} The name of the filesystem.
+ */
+goog.fs.FileSystem.prototype.getName = function() {};
+
+
+/**
+ * @return {!goog.fs.DirectoryEntry} The root directory of the filesystem.
+ */
+goog.fs.FileSystem.prototype.getRoot = function() {};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/filesystemimpl.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/filesystemimpl.js b/externs/GCL/externs/goog/fs/filesystemimpl.js
new file mode 100644
index 0000000..b5ebb33
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/filesystemimpl.js
@@ -0,0 +1,65 @@
+// Copyright 2013 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 Concrete implementation of the goog.fs.FileSystem interface
+ *     using an HTML FileSystem object.
+ */
+goog.provide('goog.fs.FileSystemImpl');
+
+goog.require('goog.fs.DirectoryEntryImpl');
+goog.require('goog.fs.FileSystem');
+
+
+
+/**
+ * A local filesystem.
+ *
+ * This shouldn't be instantiated directly. Instead, it should be accessed via
+ * {@link goog.fs.getTemporary} or {@link goog.fs.getPersistent}.
+ *
+ * @param {!FileSystem} fs The underlying FileSystem object.
+ * @constructor
+ * @implements {goog.fs.FileSystem}
+ * @final
+ */
+goog.fs.FileSystemImpl = function(fs) {
+  /**
+   * The underlying FileSystem object.
+   *
+   * @type {!FileSystem}
+   * @private
+   */
+  this.fs_ = fs;
+};
+
+
+/** @override */
+goog.fs.FileSystemImpl.prototype.getName = function() {
+  return this.fs_.name;
+};
+
+
+/** @override */
+goog.fs.FileSystemImpl.prototype.getRoot = function() {
+  return new goog.fs.DirectoryEntryImpl(this, this.fs_.root);
+};
+
+
+/**
+ * @return {!FileSystem} The underlying FileSystem object.
+ */
+goog.fs.FileSystemImpl.prototype.getBrowserFileSystem = function() {
+  return this.fs_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/filewriter.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/filewriter.js b/externs/GCL/externs/goog/fs/filewriter.js
new file mode 100644
index 0000000..1709846
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/filewriter.js
@@ -0,0 +1,111 @@
+// Copyright 2011 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 wrapper for the HTML5 FileWriter object.
+ *
+ * When adding or modifying functionality in this namespace, be sure to update
+ * the mock counterparts in goog.testing.fs.
+ *
+ */
+
+goog.provide('goog.fs.FileWriter');
+
+goog.require('goog.fs.Error');
+goog.require('goog.fs.FileSaver');
+
+
+
+/**
+ * An object for monitoring the saving of files, as well as other fine-grained
+ * writing operations.
+ *
+ * This should not be instantiated directly. Instead, it should be accessed via
+ * {@link goog.fs.FileEntry#createWriter}.
+ *
+ * @param {!FileWriter} writer The underlying FileWriter object.
+ * @constructor
+ * @extends {goog.fs.FileSaver}
+ * @final
+ */
+goog.fs.FileWriter = function(writer) {
+  goog.fs.FileWriter.base(this, 'constructor', writer);
+
+  /**
+   * The underlying FileWriter object.
+   *
+   * @type {!FileWriter}
+   * @private
+   */
+  this.writer_ = writer;
+};
+goog.inherits(goog.fs.FileWriter, goog.fs.FileSaver);
+
+
+/**
+ * @return {number} The byte offset at which the next write will occur.
+ */
+goog.fs.FileWriter.prototype.getPosition = function() {
+  return this.writer_.position;
+};
+
+
+/**
+ * @return {number} The length of the file.
+ */
+goog.fs.FileWriter.prototype.getLength = function() {
+  return this.writer_.length;
+};
+
+
+/**
+ * Write data to the file.
+ *
+ * @param {!Blob} blob The data to write.
+ */
+goog.fs.FileWriter.prototype.write = function(blob) {
+  try {
+    this.writer_.write(blob);
+  } catch (e) {
+    throw new goog.fs.Error(e, 'writing file');
+  }
+};
+
+
+/**
+ * Set the file position at which the next write will occur.
+ *
+ * @param {number} offset An absolute byte offset into the file.
+ */
+goog.fs.FileWriter.prototype.seek = function(offset) {
+  try {
+    this.writer_.seek(offset);
+  } catch (e) {
+    throw new goog.fs.Error(e, 'seeking in file');
+  }
+};
+
+
+/**
+ * Changes the length of the file to that specified.
+ *
+ * @param {number} size The new size of the file, in bytes.
+ */
+goog.fs.FileWriter.prototype.truncate = function(size) {
+  try {
+    this.writer_.truncate(size);
+  } catch (e) {
+    throw new goog.fs.Error(e, 'truncating file');
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/fs.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/fs.js b/externs/GCL/externs/goog/fs/fs.js
new file mode 100644
index 0000000..6081f6e
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/fs.js
@@ -0,0 +1,278 @@
+// Copyright 2011 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 Wrappers for the HTML5 File API. These wrappers closely mirror
+ * the underlying APIs, but use Closure-style events and Deferred return values.
+ * Their existence also makes it possible to mock the FileSystem API for testing
+ * in browsers that don't support it natively.
+ *
+ * When adding public functions to anything under this namespace, be sure to add
+ * its mock counterpart to goog.testing.fs.
+ *
+ */
+
+goog.provide('goog.fs');
+
+goog.require('goog.array');
+goog.require('goog.async.Deferred');
+goog.require('goog.fs.Error');
+goog.require('goog.fs.FileReader');
+goog.require('goog.fs.FileSystemImpl');
+goog.require('goog.fs.url');
+goog.require('goog.userAgent');
+
+
+/**
+ * Get a wrapped FileSystem object.
+ *
+ * @param {goog.fs.FileSystemType_} type The type of the filesystem to get.
+ * @param {number} size The size requested for the filesystem, in bytes.
+ * @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an
+ *     error occurs, the errback is called with a {@link goog.fs.Error}.
+ * @private
+ */
+goog.fs.get_ = function(type, size) {
+  var requestFileSystem = goog.global.requestFileSystem ||
+      goog.global.webkitRequestFileSystem;
+
+  if (!goog.isFunction(requestFileSystem)) {
+    return goog.async.Deferred.fail(new Error('File API unsupported'));
+  }
+
+  var d = new goog.async.Deferred();
+  requestFileSystem(type, size, function(fs) {
+    d.callback(new goog.fs.FileSystemImpl(fs));
+  }, function(err) {
+    d.errback(new goog.fs.Error(err, 'requesting filesystem'));
+  });
+  return d;
+};
+
+
+/**
+ * The two types of filesystem.
+ *
+ * @enum {number}
+ * @private
+ */
+goog.fs.FileSystemType_ = {
+  /**
+   * A temporary filesystem may be deleted by the user agent at its discretion.
+   */
+  TEMPORARY: 0,
+  /**
+   * A persistent filesystem will never be deleted without the user's or
+   * application's authorization.
+   */
+  PERSISTENT: 1
+};
+
+
+/**
+ * Returns a temporary FileSystem object. A temporary filesystem may be deleted
+ * by the user agent at its discretion.
+ *
+ * @param {number} size The size requested for the filesystem, in bytes.
+ * @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an
+ *     error occurs, the errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.getTemporary = function(size) {
+  return goog.fs.get_(goog.fs.FileSystemType_.TEMPORARY, size);
+};
+
+
+/**
+ * Returns a persistent FileSystem object. A persistent filesystem will never be
+ * deleted without the user's or application's authorization.
+ *
+ * @param {number} size The size requested for the filesystem, in bytes.
+ * @return {!goog.async.Deferred} The deferred {@link goog.fs.FileSystem}. If an
+ *     error occurs, the errback is called with a {@link goog.fs.Error}.
+ */
+goog.fs.getPersistent = function(size) {
+  return goog.fs.get_(goog.fs.FileSystemType_.PERSISTENT, size);
+};
+
+
+/**
+ * Creates a blob URL for a blob object.
+ * Throws an error if the browser does not support Object Urls.
+ *
+ * TODO(user): Update references to this method to use
+ * goog.fs.url.createObjectUrl instead.
+ *
+ * @param {!Blob} blob The object for which to create the URL.
+ * @return {string} The URL for the object.
+ */
+goog.fs.createObjectUrl = function(blob) {
+  return goog.fs.url.createObjectUrl(blob);
+};
+
+
+/**
+ * Revokes a URL created by {@link goog.fs.createObjectUrl}.
+ * Throws an error if the browser does not support Object Urls.
+ *
+ * TODO(user): Update references to this method to use
+ * goog.fs.url.revokeObjectUrl instead.
+ *
+ * @param {string} url The URL to revoke.
+ */
+goog.fs.revokeObjectUrl = function(url) {
+  goog.fs.url.revokeObjectUrl(url);
+};
+
+
+/**
+ * Checks whether this browser supports Object Urls. If not, calls to
+ * createObjectUrl and revokeObjectUrl will result in an error.
+ *
+ * TODO(user): Update references to this method to use
+ * goog.fs.url.browserSupportsObjectUrls instead.
+ *
+ * @return {boolean} True if this browser supports Object Urls.
+ */
+goog.fs.browserSupportsObjectUrls = function() {
+  return goog.fs.url.browserSupportsObjectUrls();
+};
+
+
+/**
+ * Concatenates one or more values together and converts them to a Blob.
+ *
+ * @param {...(string|!Blob|!ArrayBuffer)} var_args The values that will make up
+ *     the resulting blob.
+ * @return {!Blob} The blob.
+ */
+goog.fs.getBlob = function(var_args) {
+  var BlobBuilder = goog.global.BlobBuilder || goog.global.WebKitBlobBuilder;
+
+  if (goog.isDef(BlobBuilder)) {
+    var bb = new BlobBuilder();
+    for (var i = 0; i < arguments.length; i++) {
+      bb.append(arguments[i]);
+    }
+    return bb.getBlob();
+  } else {
+    return goog.fs.getBlobWithProperties(goog.array.toArray(arguments));
+  }
+};
+
+
+/**
+ * Creates a blob with the given properties.
+ * See https://developer.mozilla.org/en-US/docs/Web/API/Blob for more details.
+ *
+ * @param {Array<string|!Blob>} parts The values that will make up the
+ *     resulting blob.
+ * @param {string=} opt_type The MIME type of the Blob.
+ * @param {string=} opt_endings Specifies how strings containing newlines are to
+ *     be written out.
+ * @return {!Blob} The blob.
+ */
+goog.fs.getBlobWithProperties = function(parts, opt_type, opt_endings) {
+  var BlobBuilder = goog.global.BlobBuilder || goog.global.WebKitBlobBuilder;
+
+  if (goog.isDef(BlobBuilder)) {
+    var bb = new BlobBuilder();
+    for (var i = 0; i < parts.length; i++) {
+      bb.append(parts[i], opt_endings);
+    }
+    return bb.getBlob(opt_type);
+  } else if (goog.isDef(goog.global.Blob)) {
+    var properties = {};
+    if (opt_type) {
+      properties['type'] = opt_type;
+    }
+    if (opt_endings) {
+      properties['endings'] = opt_endings;
+    }
+    return new Blob(parts, properties);
+  } else {
+    throw Error('This browser doesn\'t seem to support creating Blobs');
+  }
+};
+
+
+/**
+ * Converts a Blob or a File into a string. This should only be used when the
+ * blob is known to be small.
+ *
+ * @param {!Blob} blob The blob to convert.
+ * @param {string=} opt_encoding The name of the encoding to use.
+ * @return {!goog.async.Deferred} The deferred string. If an error occurrs, the
+ *     errback is called with a {@link goog.fs.Error}.
+ * @deprecated Use {@link goog.fs.FileReader.readAsText} instead.
+ */
+goog.fs.blobToString = function(blob, opt_encoding) {
+  return goog.fs.FileReader.readAsText(blob, opt_encoding);
+};
+
+
+/**
+ * Slices the blob. The returned blob contains data from the start byte
+ * (inclusive) till the end byte (exclusive). Negative indices can be used
+ * to count bytes from the end of the blob (-1 == blob.size - 1). Indices
+ * are always clamped to blob range. If end is omitted, all the data till
+ * the end of the blob is taken.
+ *
+ * @param {!Blob} blob The blob to be sliced.
+ * @param {number} start Index of the starting byte.
+ * @param {number=} opt_end Index of the ending byte.
+ * @return {Blob} The blob slice or null if not supported.
+ */
+goog.fs.sliceBlob = function(blob, start, opt_end) {
+  if (!goog.isDef(opt_end)) {
+    opt_end = blob.size;
+  }
+  if (blob.webkitSlice) {
+    // Natively accepts negative indices, clamping to the blob range and
+    // range end is optional. See http://trac.webkit.org/changeset/83873
+    return blob.webkitSlice(start, opt_end);
+  } else if (blob.mozSlice) {
+    // Natively accepts negative indices, clamping to the blob range and
+    // range end is optional. See https://developer.mozilla.org/en/DOM/Blob
+    // and http://hg.mozilla.org/mozilla-central/rev/dae833f4d934
+    return blob.mozSlice(start, opt_end);
+  } else if (blob.slice) {
+    // Old versions of Firefox and Chrome use the original specification.
+    // Negative indices are not accepted, only range end is clamped and
+    // range end specification is obligatory.
+    // See http://www.w3.org/TR/2009/WD-FileAPI-20091117/
+    if ((goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('13.0')) ||
+        (goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('537.1'))) {
+      if (start < 0) {
+        start += blob.size;
+      }
+      if (start < 0) {
+        start = 0;
+      }
+      if (opt_end < 0) {
+        opt_end += blob.size;
+      }
+      if (opt_end < start) {
+        opt_end = start;
+      }
+      return blob.slice(start, opt_end - start);
+    }
+    // IE and the latest versions of Firefox and Chrome use the new
+    // specification. Natively accepts negative indices, clamping to the blob
+    // range and range end is optional.
+    // See http://dev.w3.org/2006/webapi/FileAPI/
+    return blob.slice(start, opt_end);
+  }
+  return null;
+};
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/progressevent.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/progressevent.js b/externs/GCL/externs/goog/fs/progressevent.js
new file mode 100644
index 0000000..b0695be
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/progressevent.js
@@ -0,0 +1,69 @@
+// Copyright 2011 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 wrapper for the HTML5 File ProgressEvent objects.
+ *
+ */
+goog.provide('goog.fs.ProgressEvent');
+
+goog.require('goog.events.Event');
+
+
+
+/**
+ * A wrapper for the progress events emitted by the File APIs.
+ *
+ * @param {!ProgressEvent} event The underlying event object.
+ * @param {!Object} target The file access object emitting the event.
+ * @extends {goog.events.Event}
+ * @constructor
+ * @final
+ */
+goog.fs.ProgressEvent = function(event, target) {
+  goog.fs.ProgressEvent.base(this, 'constructor', event.type, target);
+
+  /**
+   * The underlying event object.
+   * @type {!ProgressEvent}
+   * @private
+   */
+  this.event_ = event;
+};
+goog.inherits(goog.fs.ProgressEvent, goog.events.Event);
+
+
+/**
+ * @return {boolean} Whether or not the total size of the of the file being
+ *     saved is known.
+ */
+goog.fs.ProgressEvent.prototype.isLengthComputable = function() {
+  return this.event_.lengthComputable;
+};
+
+
+/**
+ * @return {number} The number of bytes saved so far.
+ */
+goog.fs.ProgressEvent.prototype.getLoaded = function() {
+  return this.event_.loaded;
+};
+
+
+/**
+ * @return {number} The total number of bytes in the file being saved.
+ */
+goog.fs.ProgressEvent.prototype.getTotal = function() {
+  return this.event_.total;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fs/url.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fs/url.js b/externs/GCL/externs/goog/fs/url.js
new file mode 100644
index 0000000..083c066
--- /dev/null
+++ b/externs/GCL/externs/goog/fs/url.js
@@ -0,0 +1,105 @@
+// Copyright 2015 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 Wrapper for URL and its createObjectUrl and revokeObjectUrl
+ * methods that are part of the HTML5 File API.
+ */
+
+goog.provide('goog.fs.url');
+
+
+/**
+ * Creates a blob URL for a blob object.
+ * Throws an error if the browser does not support Object Urls.
+ *
+ * @param {!Blob} blob The object for which to create the URL.
+ * @return {string} The URL for the object.
+ */
+goog.fs.url.createObjectUrl = function(blob) {
+  return goog.fs.url.getUrlObject_().createObjectURL(blob);
+};
+
+
+/**
+ * Revokes a URL created by {@link goog.fs.url.createObjectUrl}.
+ * Throws an error if the browser does not support Object Urls.
+ *
+ * @param {string} url The URL to revoke.
+ */
+goog.fs.url.revokeObjectUrl = function(url) {
+  goog.fs.url.getUrlObject_().revokeObjectURL(url);
+};
+
+
+/**
+ * @typedef {{createObjectURL: (function(!Blob): string),
+ *            revokeObjectURL: function(string): void}}
+ */
+goog.fs.url.UrlObject_;
+
+
+/**
+ * Get the object that has the createObjectURL and revokeObjectURL functions for
+ * this browser.
+ *
+ * @return {goog.fs.url.UrlObject_} The object for this browser.
+ * @private
+ */
+goog.fs.url.getUrlObject_ = function() {
+  var urlObject = goog.fs.url.findUrlObject_();
+  if (urlObject != null) {
+    return urlObject;
+  } else {
+    throw Error('This browser doesn\'t seem to support blob URLs');
+  }
+};
+
+
+/**
+ * Finds the object that has the createObjectURL and revokeObjectURL functions
+ * for this browser.
+ *
+ * @return {?goog.fs.url.UrlObject_} The object for this browser or null if the
+ *     browser does not support Object Urls.
+ * @private
+ */
+goog.fs.url.findUrlObject_ = function() {
+  // This is what the spec says to do
+  // http://dev.w3.org/2006/webapi/FileAPI/#dfn-createObjectURL
+  if (goog.isDef(goog.global.URL) &&
+      goog.isDef(goog.global.URL.createObjectURL)) {
+    return /** @type {goog.fs.url.UrlObject_} */ (goog.global.URL);
+  // This is what Chrome does (as of 10.0.648.6 dev)
+  } else if (goog.isDef(goog.global.webkitURL) &&
+             goog.isDef(goog.global.webkitURL.createObjectURL)) {
+    return /** @type {goog.fs.url.UrlObject_} */ (goog.global.webkitURL);
+  // This is what the spec used to say to do
+  } else if (goog.isDef(goog.global.createObjectURL)) {
+    return /** @type {goog.fs.url.UrlObject_} */ (goog.global);
+  } else {
+    return null;
+  }
+};
+
+
+/**
+ * Checks whether this browser supports Object Urls. If not, calls to
+ * createObjectUrl and revokeObjectUrl will result in an error.
+ *
+ * @return {boolean} True if this browser supports Object Urls.
+ */
+goog.fs.url.browserSupportsObjectUrls = function() {
+  return goog.fs.url.findUrlObject_() != null;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/functions/functions.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/functions/functions.js b/externs/GCL/externs/goog/functions/functions.js
new file mode 100644
index 0000000..d7ccf40
--- /dev/null
+++ b/externs/GCL/externs/goog/functions/functions.js
@@ -0,0 +1,332 @@
+// Copyright 2008 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 creating functions. Loosely inspired by the
+ * java classes: http://goo.gl/GM0Hmu and http://goo.gl/6k7nI8.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+
+goog.provide('goog.functions');
+
+
+/**
+ * Creates a function that always returns the same value.
+ * @param {T} retValue The value to return.
+ * @return {function():T} The new function.
+ * @template T
+ */
+goog.functions.constant = function(retValue) {
+  return function() {
+    return retValue;
+  };
+};
+
+
+/**
+ * Always returns false.
+ * @type {function(...): boolean}
+ */
+goog.functions.FALSE = goog.functions.constant(false);
+
+
+/**
+ * Always returns true.
+ * @type {function(...): boolean}
+ */
+goog.functions.TRUE = goog.functions.constant(true);
+
+
+/**
+ * Always returns NULL.
+ * @type {function(...): null}
+ */
+goog.functions.NULL = goog.functions.constant(null);
+
+
+/**
+ * A simple function that returns the first argument of whatever is passed
+ * into it.
+ * @param {T=} opt_returnValue The single value that will be returned.
+ * @param {...*} var_args Optional trailing arguments. These are ignored.
+ * @return {T} The first argument passed in, or undefined if nothing was passed.
+ * @template T
+ */
+goog.functions.identity = function(opt_returnValue, var_args) {
+  return opt_returnValue;
+};
+
+
+/**
+ * Creates a function that always throws an error with the given message.
+ * @param {string} message The error message.
+ * @return {!Function} The error-throwing function.
+ */
+goog.functions.error = function(message) {
+  return function() {
+    throw Error(message);
+  };
+};
+
+
+/**
+ * Creates a function that throws the given object.
+ * @param {*} err An object to be thrown.
+ * @return {!Function} The error-throwing function.
+ */
+goog.functions.fail = function(err) {
+  return function() {
+    throw err;
+  }
+};
+
+
+/**
+ * Given a function, create a function that keeps opt_numArgs arguments and
+ * silently discards all additional arguments.
+ * @param {Function} f The original function.
+ * @param {number=} opt_numArgs The number of arguments to keep. Defaults to 0.
+ * @return {!Function} A version of f that only keeps the first opt_numArgs
+ *     arguments.
+ */
+goog.functions.lock = function(f, opt_numArgs) {
+  opt_numArgs = opt_numArgs || 0;
+  return function() {
+    return f.apply(this, Array.prototype.slice.call(arguments, 0, opt_numArgs));
+  };
+};
+
+
+/**
+ * Creates a function that returns its nth argument.
+ * @param {number} n The position of the return argument.
+ * @return {!Function} A new function.
+ */
+goog.functions.nth = function(n) {
+  return function() {
+    return arguments[n];
+  };
+};
+
+
+/**
+ * Given a function, create a new function that swallows its return value
+ * and replaces it with a new one.
+ * @param {Function} f A function.
+ * @param {T} retValue A new return value.
+ * @return {function(...?):T} A new function.
+ * @template T
+ */
+goog.functions.withReturnValue = function(f, retValue) {
+  return goog.functions.sequence(f, goog.functions.constant(retValue));
+};
+
+
+/**
+ * Creates a function that returns whether its arguement equals the given value.
+ *
+ * Example:
+ * var key = goog.object.findKey(obj, goog.functions.equalTo('needle'));
+ *
+ * @param {*} value The value to compare to.
+ * @param {boolean=} opt_useLooseComparison Whether to use a loose (==)
+ *     comparison rather than a strict (===) one. Defaults to false.
+ * @return {function(*):boolean} The new function.
+ */
+goog.functions.equalTo = function(value, opt_useLooseComparison) {
+  return function(other) {
+    return opt_useLooseComparison ? (value == other) : (value === other);
+  };
+};
+
+
+/**
+ * Creates the composition of the functions passed in.
+ * For example, (goog.functions.compose(f, g))(a) is equivalent to f(g(a)).
+ * @param {function(...?):T} fn The final function.
+ * @param {...Function} var_args A list of functions.
+ * @return {function(...?):T} The composition of all inputs.
+ * @template T
+ */
+goog.functions.compose = function(fn, var_args) {
+  var functions = arguments;
+  var length = functions.length;
+  return function() {
+    var result;
+    if (length) {
+      result = functions[length - 1].apply(this, arguments);
+    }
+
+    for (var i = length - 2; i >= 0; i--) {
+      result = functions[i].call(this, result);
+    }
+    return result;
+  };
+};
+
+
+/**
+ * Creates a function that calls the functions passed in in sequence, and
+ * returns the value of the last function. For example,
+ * (goog.functions.sequence(f, g))(x) is equivalent to f(x),g(x).
+ * @param {...Function} var_args A list of functions.
+ * @return {!Function} A function that calls all inputs in sequence.
+ */
+goog.functions.sequence = function(var_args) {
+  var functions = arguments;
+  var length = functions.length;
+  return function() {
+    var result;
+    for (var i = 0; i < length; i++) {
+      result = functions[i].apply(this, arguments);
+    }
+    return result;
+  };
+};
+
+
+/**
+ * Creates a function that returns true if each of its components evaluates
+ * to true. The components are evaluated in order, and the evaluation will be
+ * short-circuited as soon as a function returns false.
+ * For example, (goog.functions.and(f, g))(x) is equivalent to f(x) && g(x).
+ * @param {...Function} var_args A list of functions.
+ * @return {function(...?):boolean} A function that ANDs its component
+ *      functions.
+ */
+goog.functions.and = function(var_args) {
+  var functions = arguments;
+  var length = functions.length;
+  return function() {
+    for (var i = 0; i < length; i++) {
+      if (!functions[i].apply(this, arguments)) {
+        return false;
+      }
+    }
+    return true;
+  };
+};
+
+
+/**
+ * Creates a function that returns true if any of its components evaluates
+ * to true. The components are evaluated in order, and the evaluation will be
+ * short-circuited as soon as a function returns true.
+ * For example, (goog.functions.or(f, g))(x) is equivalent to f(x) || g(x).
+ * @param {...Function} var_args A list of functions.
+ * @return {function(...?):boolean} A function that ORs its component
+ *    functions.
+ */
+goog.functions.or = function(var_args) {
+  var functions = arguments;
+  var length = functions.length;
+  return function() {
+    for (var i = 0; i < length; i++) {
+      if (functions[i].apply(this, arguments)) {
+        return true;
+      }
+    }
+    return false;
+  };
+};
+
+
+/**
+ * Creates a function that returns the Boolean opposite of a provided function.
+ * For example, (goog.functions.not(f))(x) is equivalent to !f(x).
+ * @param {!Function} f The original function.
+ * @return {function(...?):boolean} A function that delegates to f and returns
+ * opposite.
+ */
+goog.functions.not = function(f) {
+  return function() {
+    return !f.apply(this, arguments);
+  };
+};
+
+
+/**
+ * Generic factory function to construct an object given the constructor
+ * and the arguments. Intended to be bound to create object factories.
+ *
+ * Example:
+ *
+ * var factory = goog.partial(goog.functions.create, Class);
+ *
+ * @param {function(new:T, ...)} constructor The constructor for the Object.
+ * @param {...*} var_args The arguments to be passed to the constructor.
+ * @return {T} A new instance of the class given in {@code constructor}.
+ * @template T
+ */
+goog.functions.create = function(constructor, var_args) {
+  /**
+   * @constructor
+   * @final
+   */
+  var temp = function() {};
+  temp.prototype = constructor.prototype;
+
+  // obj will have constructor's prototype in its chain and
+  // 'obj instanceof constructor' will be true.
+  var obj = new temp();
+
+  // obj is initialized by constructor.
+  // arguments is only array-like so lacks shift(), but can be used with
+  // the Array prototype function.
+  constructor.apply(obj, Array.prototype.slice.call(arguments, 1));
+  return obj;
+};
+
+
+/**
+ * @define {boolean} Whether the return value cache should be used.
+ *    This should only be used to disable caches when testing.
+ */
+goog.define('goog.functions.CACHE_RETURN_VALUE', true);
+
+
+/**
+ * Gives a wrapper function that caches the return value of a parameterless
+ * function when first called.
+ *
+ * When called for the first time, the given function is called and its
+ * return value is cached (thus this is only appropriate for idempotent
+ * functions).  Subsequent calls will return the cached return value. This
+ * allows the evaluation of expensive functions to be delayed until first used.
+ *
+ * To cache the return values of functions with parameters, see goog.memoize.
+ *
+ * @param {!function():T} fn A function to lazily evaluate.
+ * @return {!function():T} A wrapped version the function.
+ * @template T
+ */
+goog.functions.cacheReturnValue = function(fn) {
+  var called = false;
+  var value;
+
+  return function() {
+    if (!goog.functions.CACHE_RETURN_VALUE) {
+      return fn();
+    }
+
+    if (!called) {
+      value = fn();
+      called = true;
+    }
+
+    return value;
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/abstractdragdrop.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/abstractdragdrop.js b/externs/GCL/externs/goog/fx/abstractdragdrop.js
new file mode 100644
index 0000000..afd4af8
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/abstractdragdrop.js
@@ -0,0 +1,1540 @@
+// 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 Abstract Base Class for Drag and Drop.
+ *
+ * Provides functionality for implementing drag and drop classes. Also provides
+ * support classes and events.
+ *
+ * @author eae@google.com (Emil A Eklund)
+ */
+
+goog.provide('goog.fx.AbstractDragDrop');
+goog.provide('goog.fx.AbstractDragDrop.EventType');
+goog.provide('goog.fx.DragDropEvent');
+goog.provide('goog.fx.DragDropItem');
+
+goog.require('goog.asserts');
+goog.require('goog.dom');
+goog.require('goog.dom.classlist');
+goog.require('goog.events');
+goog.require('goog.events.Event');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.fx.Dragger');
+goog.require('goog.math.Box');
+goog.require('goog.math.Coordinate');
+goog.require('goog.style');
+
+
+
+/**
+ * Abstract class that provides reusable functionality for implementing drag
+ * and drop functionality.
+ *
+ * This class also allows clients to define their own subtargeting function
+ * so that drop areas can have finer granularity then a singe element. This is
+ * accomplished by using a client provided function to map from element and
+ * coordinates to a subregion id.
+ *
+ * This class can also be made aware of scrollable containers that contain
+ * drop targets by calling addScrollableContainer. This will cause dnd to
+ * take changing scroll positions into account while a drag is occuring.
+ *
+ * @extends {goog.events.EventTarget}
+ * @constructor
+ */
+goog.fx.AbstractDragDrop = function() {
+  goog.fx.AbstractDragDrop.base(this, 'constructor');
+
+  /**
+   * List of items that makes up the drag source or drop target.
+   * @type {Array<goog.fx.DragDropItem>}
+   * @protected
+   * @suppress {underscore|visibility}
+   */
+  this.items_ = [];
+
+  /**
+   * List of associated drop targets.
+   * @type {Array<goog.fx.AbstractDragDrop>}
+   * @private
+   */
+  this.targets_ = [];
+
+  /**
+   * Scrollable containers to account for during drag
+   * @type {Array<goog.fx.ScrollableContainer_>}
+   * @private
+   */
+  this.scrollableContainers_ = [];
+
+};
+goog.inherits(goog.fx.AbstractDragDrop, goog.events.EventTarget);
+
+
+/**
+ * Minimum size (in pixels) for a dummy target. If the box for the target is
+ * less than the specified size it's not created.
+ * @type {number}
+ * @private
+ */
+goog.fx.AbstractDragDrop.DUMMY_TARGET_MIN_SIZE_ = 10;
+
+
+/**
+ * Flag indicating if it's a drag source, set by addTarget.
+ * @type {boolean}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.isSource_ = false;
+
+
+/**
+ * Flag indicating if it's a drop target, set when added as target to another
+ * DragDrop object.
+ * @type {boolean}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.isTarget_ = false;
+
+
+/**
+ * Subtargeting function accepting args:
+ * (goog.fx.DragDropItem, goog.math.Box, number, number)
+ * @type {Function}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.subtargetFunction_;
+
+
+/**
+ * Last active subtarget.
+ * @type {Object}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.activeSubtarget_;
+
+
+/**
+ * Class name to add to source elements being dragged. Set by setDragClass.
+ * @type {?string}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.dragClass_;
+
+
+/**
+ * Class name to add to source elements. Set by setSourceClass.
+ * @type {?string}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.sourceClass_;
+
+
+/**
+ * Class name to add to target elements. Set by setTargetClass.
+ * @type {?string}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.targetClass_;
+
+
+/**
+ * The SCROLL event target used to make drag element follow scrolling.
+ * @type {EventTarget}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.scrollTarget_;
+
+
+/**
+ * Dummy target, {@see maybeCreateDummyTargetForPosition_}.
+ * @type {goog.fx.ActiveDropTarget_}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.dummyTarget_;
+
+
+/**
+ * Whether the object has been initialized.
+ * @type {boolean}
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.initialized_ = false;
+
+
+/**
+ * Constants for event names
+ * @const
+ */
+goog.fx.AbstractDragDrop.EventType = {
+  DRAGOVER: 'dragover',
+  DRAGOUT: 'dragout',
+  DRAG: 'drag',
+  DROP: 'drop',
+  DRAGSTART: 'dragstart',
+  DRAGEND: 'dragend'
+};
+
+
+/**
+ * Constant for distance threshold, in pixels, an element has to be moved to
+ * initiate a drag operation.
+ * @type {number}
+ */
+goog.fx.AbstractDragDrop.initDragDistanceThreshold = 5;
+
+
+/**
+ * Set class to add to source elements being dragged.
+ *
+ * @param {string} className Class to be added.  Must be a single, valid
+ *     classname.
+ */
+goog.fx.AbstractDragDrop.prototype.setDragClass = function(className) {
+  this.dragClass_ = className;
+};
+
+
+/**
+ * Set class to add to source elements.
+ *
+ * @param {string} className Class to be added.  Must be a single, valid
+ *     classname.
+ */
+goog.fx.AbstractDragDrop.prototype.setSourceClass = function(className) {
+  this.sourceClass_ = className;
+};
+
+
+/**
+ * Set class to add to target elements.
+ *
+ * @param {string} className Class to be added.  Must be a single, valid
+ *     classname.
+ */
+goog.fx.AbstractDragDrop.prototype.setTargetClass = function(className) {
+  this.targetClass_ = className;
+};
+
+
+/**
+ * Whether the control has been initialized.
+ *
+ * @return {boolean} True if it's been initialized.
+ */
+goog.fx.AbstractDragDrop.prototype.isInitialized = function() {
+  return this.initialized_;
+};
+
+
+/**
+ * Add item to drag object.
+ *
+ * @param {Element|string} element Dom Node, or string representation of node
+ *     id, to be used as drag source/drop target.
+ * @throws Error Thrown if called on instance of abstract class
+ */
+goog.fx.AbstractDragDrop.prototype.addItem = goog.abstractMethod;
+
+
+/**
+ * Associate drop target with drag element.
+ *
+ * @param {goog.fx.AbstractDragDrop} target Target to add.
+ */
+goog.fx.AbstractDragDrop.prototype.addTarget = function(target) {
+  this.targets_.push(target);
+  target.isTarget_ = true;
+  this.isSource_ = true;
+};
+
+
+/**
+ * Sets the SCROLL event target to make drag element follow scrolling.
+ *
+ * @param {EventTarget} scrollTarget The element that dispatches SCROLL events.
+ */
+goog.fx.AbstractDragDrop.prototype.setScrollTarget = function(scrollTarget) {
+  this.scrollTarget_ = scrollTarget;
+};
+
+
+/**
+ * Initialize drag and drop functionality for sources/targets already added.
+ * Sources/targets added after init has been called will initialize themselves
+ * one by one.
+ */
+goog.fx.AbstractDragDrop.prototype.init = function() {
+  if (this.initialized_) {
+    return;
+  }
+  for (var item, i = 0; item = this.items_[i]; i++) {
+    this.initItem(item);
+  }
+
+  this.initialized_ = true;
+};
+
+
+/**
+ * Initializes a single item.
+ *
+ * @param {goog.fx.DragDropItem} item Item to initialize.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.initItem = function(item) {
+  if (this.isSource_) {
+    goog.events.listen(item.element, goog.events.EventType.MOUSEDOWN,
+                       item.mouseDown_, false, item);
+    if (this.sourceClass_) {
+      goog.dom.classlist.add(
+          goog.asserts.assert(item.element), this.sourceClass_);
+    }
+  }
+
+  if (this.isTarget_ && this.targetClass_) {
+    goog.dom.classlist.add(
+        goog.asserts.assert(item.element), this.targetClass_);
+  }
+};
+
+
+/**
+ * Called when removing an item. Removes event listeners and classes.
+ *
+ * @param {goog.fx.DragDropItem} item Item to dispose.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.disposeItem = function(item) {
+  if (this.isSource_) {
+    goog.events.unlisten(item.element, goog.events.EventType.MOUSEDOWN,
+                         item.mouseDown_, false, item);
+    if (this.sourceClass_) {
+      goog.dom.classlist.remove(
+          goog.asserts.assert(item.element), this.sourceClass_);
+    }
+  }
+  if (this.isTarget_ && this.targetClass_) {
+    goog.dom.classlist.remove(
+        goog.asserts.assert(item.element), this.targetClass_);
+  }
+  item.dispose();
+};
+
+
+/**
+ * Removes all items.
+ */
+goog.fx.AbstractDragDrop.prototype.removeItems = function() {
+  for (var item, i = 0; item = this.items_[i]; i++) {
+    this.disposeItem(item);
+  }
+  this.items_.length = 0;
+};
+
+
+/**
+ * Starts a drag event for an item if the mouse button stays pressed and the
+ * cursor moves a few pixels. Allows dragging of items without first having to
+ * register them with addItem.
+ *
+ * @param {goog.events.BrowserEvent} event Mouse down event.
+ * @param {goog.fx.DragDropItem} item Item that's being dragged.
+ */
+goog.fx.AbstractDragDrop.prototype.maybeStartDrag = function(event, item) {
+  item.maybeStartDrag_(event, item.element);
+};
+
+
+/**
+ * Event handler that's used to start drag.
+ *
+ * @param {goog.events.BrowserEvent} event Mouse move event.
+ * @param {goog.fx.DragDropItem} item Item that's being dragged.
+ */
+goog.fx.AbstractDragDrop.prototype.startDrag = function(event, item) {
+
+  // Prevent a new drag operation from being started if another one is already
+  // in progress (could happen if the mouse was released outside of the
+  // document).
+  if (this.dragItem_) {
+    return;
+  }
+
+  this.dragItem_ = item;
+
+  // Dispatch DRAGSTART event
+  var dragStartEvent = new goog.fx.DragDropEvent(
+      goog.fx.AbstractDragDrop.EventType.DRAGSTART, this, this.dragItem_);
+  if (this.dispatchEvent(dragStartEvent) == false) {
+    this.dragItem_ = null;
+    return;
+  }
+
+  // Get the source element and create a drag element for it.
+  var el = item.getCurrentDragElement();
+  this.dragEl_ = this.createDragElement(el);
+  var doc = goog.dom.getOwnerDocument(el);
+  doc.body.appendChild(this.dragEl_);
+
+  this.dragger_ = this.createDraggerFor(el, this.dragEl_, event);
+  this.dragger_.setScrollTarget(this.scrollTarget_);
+
+  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.DRAG,
+                     this.moveDrag_, false, this);
+
+  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.END,
+                     this.endDrag, false, this);
+
+  // IE may issue a 'selectstart' event when dragging over an iframe even when
+  // default mousemove behavior is suppressed. If the default selectstart
+  // behavior is not suppressed, elements dragged over will show as selected.
+  goog.events.listen(doc.body, goog.events.EventType.SELECTSTART,
+                     this.suppressSelect_);
+
+  this.recalculateDragTargets();
+  this.recalculateScrollableContainers();
+  this.activeTarget_ = null;
+  this.initScrollableContainerListeners_();
+  this.dragger_.startDrag(event);
+
+  event.preventDefault();
+};
+
+
+/**
+ * Recalculates the geometry of this source's drag targets.  Call this
+ * if the position or visibility of a drag target has changed during
+ * a drag, or if targets are added or removed.
+ *
+ * TODO(user): this is an expensive operation;  more efficient APIs
+ * may be necessary.
+ */
+goog.fx.AbstractDragDrop.prototype.recalculateDragTargets = function() {
+  this.targetList_ = [];
+  for (var target, i = 0; target = this.targets_[i]; i++) {
+    for (var itm, j = 0; itm = target.items_[j]; j++) {
+      this.addDragTarget_(target, itm);
+    }
+  }
+  if (!this.targetBox_) {
+    this.targetBox_ = new goog.math.Box(0, 0, 0, 0);
+  }
+};
+
+
+/**
+ * Recalculates the current scroll positions of scrollable containers and
+ * allocates targets. Call this if the position of a container changed or if
+ * targets are added or removed.
+ */
+goog.fx.AbstractDragDrop.prototype.recalculateScrollableContainers =
+    function() {
+  var container, i, j, target;
+  for (i = 0; container = this.scrollableContainers_[i]; i++) {
+    container.containedTargets_ = [];
+    container.savedScrollLeft_ = container.element_.scrollLeft;
+    container.savedScrollTop_ = container.element_.scrollTop;
+    var pos = goog.style.getPageOffset(container.element_);
+    var size = goog.style.getSize(container.element_);
+    container.box_ = new goog.math.Box(pos.y, pos.x + size.width,
+                                       pos.y + size.height, pos.x);
+  }
+
+  for (i = 0; target = this.targetList_[i]; i++) {
+    for (j = 0; container = this.scrollableContainers_[j]; j++) {
+      if (goog.dom.contains(container.element_, target.element_)) {
+        container.containedTargets_.push(target);
+        target.scrollableContainer_ = container;
+      }
+    }
+  }
+};
+
+
+/**
+ * Creates the Dragger for the drag element.
+ * @param {Element} sourceEl Drag source element.
+ * @param {Element} el the element created by createDragElement().
+ * @param {goog.events.BrowserEvent} event Mouse down event for start of drag.
+ * @return {!goog.fx.Dragger} The new Dragger.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.createDraggerFor =
+    function(sourceEl, el, event) {
+  // Position the drag element.
+  var pos = this.getDragElementPosition(sourceEl, el, event);
+  el.style.position = 'absolute';
+  el.style.left = pos.x + 'px';
+  el.style.top = pos.y + 'px';
+  return new goog.fx.Dragger(el);
+};
+
+
+/**
+ * Event handler that's used to stop drag. Fires a drop event if over a valid
+ * target.
+ *
+ * @param {goog.fx.DragEvent} event Drag event.
+ */
+goog.fx.AbstractDragDrop.prototype.endDrag = function(event) {
+  var activeTarget = event.dragCanceled ? null : this.activeTarget_;
+  if (activeTarget && activeTarget.target_) {
+    var clientX = event.clientX;
+    var clientY = event.clientY;
+    var scroll = this.getScrollPos();
+    var x = clientX + scroll.x;
+    var y = clientY + scroll.y;
+
+    var subtarget;
+    // If a subtargeting function is enabled get the current subtarget
+    if (this.subtargetFunction_) {
+      subtarget = this.subtargetFunction_(activeTarget.item_,
+          activeTarget.box_, x, y);
+    }
+
+    var dragEvent = new goog.fx.DragDropEvent(
+        goog.fx.AbstractDragDrop.EventType.DRAG, this, this.dragItem_,
+        activeTarget.target_, activeTarget.item_, activeTarget.element_,
+        clientX, clientY, x, y);
+    this.dispatchEvent(dragEvent);
+
+    var dropEvent = new goog.fx.DragDropEvent(
+        goog.fx.AbstractDragDrop.EventType.DROP, this, this.dragItem_,
+        activeTarget.target_, activeTarget.item_, activeTarget.element_,
+        clientX, clientY, x, y, subtarget);
+    activeTarget.target_.dispatchEvent(dropEvent);
+  }
+
+  var dragEndEvent = new goog.fx.DragDropEvent(
+      goog.fx.AbstractDragDrop.EventType.DRAGEND, this, this.dragItem_);
+  this.dispatchEvent(dragEndEvent);
+
+  goog.events.unlisten(this.dragger_, goog.fx.Dragger.EventType.DRAG,
+                       this.moveDrag_, false, this);
+  goog.events.unlisten(this.dragger_, goog.fx.Dragger.EventType.END,
+                       this.endDrag, false, this);
+  var doc = goog.dom.getOwnerDocument(this.dragItem_.getCurrentDragElement());
+  goog.events.unlisten(doc.body, goog.events.EventType.SELECTSTART,
+                       this.suppressSelect_);
+
+
+  this.afterEndDrag(this.activeTarget_ ? this.activeTarget_.item_ : null);
+};
+
+
+/**
+ * Called after a drag operation has finished.
+ *
+ * @param {goog.fx.DragDropItem=} opt_dropTarget Target for successful drop.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.afterEndDrag = function(opt_dropTarget) {
+  this.disposeDrag();
+};
+
+
+/**
+ * Called once a drag operation has finished. Removes event listeners and
+ * elements.
+ *
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.disposeDrag = function() {
+  this.disposeScrollableContainerListeners_();
+  this.dragger_.dispose();
+
+  goog.dom.removeNode(this.dragEl_);
+  delete this.dragItem_;
+  delete this.dragEl_;
+  delete this.dragger_;
+  delete this.targetList_;
+  delete this.activeTarget_;
+};
+
+
+/**
+ * Event handler for drag events. Determines the active drop target, if any, and
+ * fires dragover and dragout events appropriately.
+ *
+ * @param {goog.fx.DragEvent} event Drag event.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.moveDrag_ = function(event) {
+  var position = this.getEventPosition(event);
+  var x = position.x;
+  var y = position.y;
+
+  // Check if we're still inside the bounds of the active target, if not fire
+  // a dragout event and proceed to find a new target.
+  var activeTarget = this.activeTarget_;
+
+  var subtarget;
+  if (activeTarget) {
+    // If a subtargeting function is enabled get the current subtarget
+    if (this.subtargetFunction_ && activeTarget.target_) {
+      subtarget = this.subtargetFunction_(activeTarget.item_,
+          activeTarget.box_, x, y);
+    }
+
+    if (activeTarget.box_.contains(position) &&
+        subtarget == this.activeSubtarget_) {
+      return;
+    }
+
+    if (activeTarget.target_) {
+      var sourceDragOutEvent = new goog.fx.DragDropEvent(
+          goog.fx.AbstractDragDrop.EventType.DRAGOUT, this, this.dragItem_,
+          activeTarget.target_, activeTarget.item_, activeTarget.element_);
+      this.dispatchEvent(sourceDragOutEvent);
+
+      // The event should be dispatched the by target DragDrop so that the
+      // target DragDrop can manage these events without having to know what
+      // sources this is a target for.
+      var targetDragOutEvent = new goog.fx.DragDropEvent(
+          goog.fx.AbstractDragDrop.EventType.DRAGOUT,
+          this,
+          this.dragItem_,
+          activeTarget.target_,
+          activeTarget.item_,
+          activeTarget.element_,
+          undefined,
+          undefined,
+          undefined,
+          undefined,
+          this.activeSubtarget_);
+      activeTarget.target_.dispatchEvent(targetDragOutEvent);
+    }
+    this.activeSubtarget_ = subtarget;
+    this.activeTarget_ = null;
+  }
+
+  // Check if inside target box
+  if (this.targetBox_.contains(position)) {
+    // Search for target and fire a dragover event if found
+    activeTarget = this.activeTarget_ = this.getTargetFromPosition_(position);
+    if (activeTarget && activeTarget.target_) {
+      // If a subtargeting function is enabled get the current subtarget
+      if (this.subtargetFunction_) {
+        subtarget = this.subtargetFunction_(activeTarget.item_,
+            activeTarget.box_, x, y);
+      }
+      var sourceDragOverEvent = new goog.fx.DragDropEvent(
+          goog.fx.AbstractDragDrop.EventType.DRAGOVER, this, this.dragItem_,
+          activeTarget.target_, activeTarget.item_, activeTarget.element_);
+      sourceDragOverEvent.subtarget = subtarget;
+      this.dispatchEvent(sourceDragOverEvent);
+
+      // The event should be dispatched by the target DragDrop so that the
+      // target DragDrop can manage these events without having to know what
+      // sources this is a target for.
+      var targetDragOverEvent = new goog.fx.DragDropEvent(
+          goog.fx.AbstractDragDrop.EventType.DRAGOVER, this, this.dragItem_,
+          activeTarget.target_, activeTarget.item_, activeTarget.element_,
+          event.clientX, event.clientY, undefined, undefined, subtarget);
+      activeTarget.target_.dispatchEvent(targetDragOverEvent);
+
+    } else if (!activeTarget) {
+      // If no target was found create a dummy one so we won't have to iterate
+      // over all possible targets for every move event.
+      this.activeTarget_ = this.maybeCreateDummyTargetForPosition_(x, y);
+    }
+  }
+};
+
+
+/**
+ * Event handler for suppressing selectstart events. Selecting should be
+ * disabled while dragging.
+ *
+ * @param {goog.events.Event} event The selectstart event to suppress.
+ * @return {boolean} Whether to perform default behavior.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.suppressSelect_ = function(event) {
+  return false;
+};
+
+
+/**
+ * Sets up listeners for the scrollable containers that keep track of their
+ * scroll positions.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.initScrollableContainerListeners_ =
+    function() {
+  var container, i;
+  for (i = 0; container = this.scrollableContainers_[i]; i++) {
+    goog.events.listen(container.element_, goog.events.EventType.SCROLL,
+        this.containerScrollHandler_, false, this);
+  }
+};
+
+
+/**
+ * Cleans up the scrollable container listeners.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.disposeScrollableContainerListeners_ =
+    function() {
+  for (var i = 0, container; container = this.scrollableContainers_[i]; i++) {
+    goog.events.unlisten(container.element_, 'scroll',
+        this.containerScrollHandler_, false, this);
+    container.containedTargets_ = [];
+  }
+};
+
+
+/**
+ * Makes drag and drop aware of a target container that could scroll mid drag.
+ * @param {Element} element The scroll container.
+ */
+goog.fx.AbstractDragDrop.prototype.addScrollableContainer = function(element) {
+  this.scrollableContainers_.push(new goog.fx.ScrollableContainer_(element));
+};
+
+
+/**
+ * Removes all scrollable containers.
+ */
+goog.fx.AbstractDragDrop.prototype.removeAllScrollableContainers = function() {
+  this.disposeScrollableContainerListeners_();
+  this.scrollableContainers_ = [];
+};
+
+
+/**
+ * Event handler for containers scrolling.
+ * @param {goog.events.Event} e The event.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.containerScrollHandler_ = function(e) {
+  for (var i = 0, container; container = this.scrollableContainers_[i]; i++) {
+    if (e.target == container.element_) {
+      var deltaTop = container.savedScrollTop_ - container.element_.scrollTop;
+      var deltaLeft =
+          container.savedScrollLeft_ - container.element_.scrollLeft;
+      container.savedScrollTop_ = container.element_.scrollTop;
+      container.savedScrollLeft_ = container.element_.scrollLeft;
+
+      // When the container scrolls, it's possible that one of the targets will
+      // move to the region contained by the dummy target. Since we don't know
+      // which sides (if any) of the dummy target are defined by targets
+      // contained by this container, we are conservative and just shrink it.
+      if (this.dummyTarget_ && this.activeTarget_ == this.dummyTarget_) {
+        if (deltaTop > 0) {
+          this.dummyTarget_.box_.top += deltaTop;
+        } else {
+          this.dummyTarget_.box_.bottom += deltaTop;
+        }
+        if (deltaLeft > 0) {
+          this.dummyTarget_.box_.left += deltaLeft;
+        } else {
+          this.dummyTarget_.box_.right += deltaLeft;
+        }
+      }
+      for (var j = 0, target; target = container.containedTargets_[j]; j++) {
+        var box = target.box_;
+        box.top += deltaTop;
+        box.left += deltaLeft;
+        box.bottom += deltaTop;
+        box.right += deltaLeft;
+
+        this.calculateTargetBox_(box);
+      }
+    }
+  }
+  this.dragger_.onScroll_(e);
+};
+
+
+/**
+ * Set a function that provides subtargets. A subtargeting function
+ * returns an arbitrary identifier for each subtarget of an element.
+ * DnD code will generate additional drag over / out events when
+ * switching from subtarget to subtarget. This is useful for instance
+ * if you are interested if you are on the top half or the bottom half
+ * of the element.
+ * The provided function will be given the DragDropItem, box, x, y
+ * box is the current window coordinates occupied by element
+ * x, y is the mouse position in window coordinates
+ *
+ * @param {Function} f The new subtarget function.
+ */
+goog.fx.AbstractDragDrop.prototype.setSubtargetFunction = function(f) {
+  this.subtargetFunction_ = f;
+};
+
+
+/**
+ * Creates an element for the item being dragged.
+ *
+ * @param {Element} sourceEl Drag source element.
+ * @return {Element} The new drag element.
+ */
+goog.fx.AbstractDragDrop.prototype.createDragElement = function(sourceEl) {
+  var dragEl = this.createDragElementInternal(sourceEl);
+  goog.asserts.assert(dragEl);
+  if (this.dragClass_) {
+    goog.dom.classlist.add(dragEl, this.dragClass_);
+  }
+
+  return dragEl;
+};
+
+
+/**
+ * Returns the position for the drag element.
+ *
+ * @param {Element} el Drag source element.
+ * @param {Element} dragEl The dragged element created by createDragElement().
+ * @param {goog.events.BrowserEvent} event Mouse down event for start of drag.
+ * @return {!goog.math.Coordinate} The position for the drag element.
+ */
+goog.fx.AbstractDragDrop.prototype.getDragElementPosition =
+    function(el, dragEl, event) {
+  var pos = goog.style.getPageOffset(el);
+
+  // Subtract margin from drag element position twice, once to adjust the
+  // position given by the original node and once for the drag node.
+  var marginBox = goog.style.getMarginBox(el);
+  pos.x -= (marginBox.left || 0) * 2;
+  pos.y -= (marginBox.top || 0) * 2;
+
+  return pos;
+};
+
+
+/**
+ * Returns the dragger object.
+ *
+ * @return {goog.fx.Dragger} The dragger object used by this drag and drop
+ *     instance.
+ */
+goog.fx.AbstractDragDrop.prototype.getDragger = function() {
+  return this.dragger_;
+};
+
+
+/**
+ * Creates copy of node being dragged.
+ *
+ * @param {Element} sourceEl Element to copy.
+ * @return {!Element} The clone of {@code sourceEl}.
+ * @deprecated Use goog.fx.Dragger.cloneNode().
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.cloneNode_ = function(sourceEl) {
+  return goog.fx.Dragger.cloneNode(sourceEl);
+};
+
+
+/**
+ * Generates an element to follow the cursor during dragging, given a drag
+ * source element.  The default behavior is simply to clone the source element,
+ * but this may be overridden in subclasses.  This method is called by
+ * {@code createDragElement()} before the drag class is added.
+ *
+ * @param {Element} sourceEl Drag source element.
+ * @return {!Element} The new drag element.
+ * @protected
+ * @suppress {deprecated}
+ */
+goog.fx.AbstractDragDrop.prototype.createDragElementInternal =
+    function(sourceEl) {
+  return this.cloneNode_(sourceEl);
+};
+
+
+/**
+ * Add possible drop target for current drag operation.
+ *
+ * @param {goog.fx.AbstractDragDrop} target Drag handler.
+ * @param {goog.fx.DragDropItem} item Item that's being dragged.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.addDragTarget_ = function(target, item) {
+
+  // Get all the draggable elements and add each one.
+  var draggableElements = item.getDraggableElements();
+  var targetList = this.targetList_;
+  for (var i = 0; i < draggableElements.length; i++) {
+    var draggableElement = draggableElements[i];
+
+    // Determine target position and dimension
+    var box = this.getElementBox(item, draggableElement);
+
+    targetList.push(
+        new goog.fx.ActiveDropTarget_(box, target, item, draggableElement));
+
+    this.calculateTargetBox_(box);
+  }
+};
+
+
+/**
+ * Calculates the position and dimension of a draggable element.
+ *
+ * @param {goog.fx.DragDropItem} item Item that's being dragged.
+ * @param {Element} element The element to calculate the box.
+ *
+ * @return {!goog.math.Box} Box describing the position and dimension
+ *     of element.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.getElementBox = function(item, element) {
+  var pos = goog.style.getPageOffset(element);
+  var size = goog.style.getSize(element);
+  return new goog.math.Box(pos.y, pos.x + size.width, pos.y + size.height,
+      pos.x);
+};
+
+
+/**
+ * Calculate the outer bounds (the region all targets are inside).
+ *
+ * @param {goog.math.Box} box Box describing the position and dimension
+ *     of a drag target.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.calculateTargetBox_ = function(box) {
+  if (this.targetList_.length == 1) {
+    this.targetBox_ = new goog.math.Box(box.top, box.right,
+                                        box.bottom, box.left);
+  } else {
+    var tb = this.targetBox_;
+    tb.left = Math.min(box.left, tb.left);
+    tb.right = Math.max(box.right, tb.right);
+    tb.top = Math.min(box.top, tb.top);
+    tb.bottom = Math.max(box.bottom, tb.bottom);
+  }
+};
+
+
+/**
+ * Creates a dummy target for the given cursor position. The assumption is to
+ * create as big dummy target box as possible, the only constraints are:
+ * - The dummy target box cannot overlap any of real target boxes.
+ * - The dummy target has to contain a point with current mouse coordinates.
+ *
+ * NOTE: For performance reasons the box construction algorithm is kept simple
+ * and it is not optimal (see example below). Currently it is O(n) in regard to
+ * the number of real drop target boxes, but its result depends on the order
+ * of those boxes being processed (the order in which they're added to the
+ * targetList_ collection).
+ *
+ * The algorithm.
+ * a) Assumptions
+ * - Mouse pointer is in the bounding box of real target boxes.
+ * - None of the boxes have negative coordinate values.
+ * - Mouse pointer is not contained by any of "real target" boxes.
+ * - For targets inside a scrollable container, the box used is the
+ *   intersection of the scrollable container's box and the target's box.
+ *   This is because the part of the target that extends outside the scrollable
+ *   container should not be used in the clipping calculations.
+ *
+ * b) Outline
+ * - Initialize the fake target to the bounding box of real targets.
+ * - For each real target box - clip the fake target box so it does not contain
+ *   that target box, but does contain the mouse pointer.
+ *   -- Project the real target box, mouse pointer and fake target box onto
+ *      both axes and calculate the clipping coordinates.
+ *   -- Only one coordinate is used to clip the fake target box to keep the
+ *      fake target as big as possible.
+ *   -- If the projection of the real target box contains the mouse pointer,
+ *      clipping for a given axis is not possible.
+ *   -- If both clippings are possible, the clipping more distant from the
+ *      mouse pointer is selected to keep bigger fake target area.
+ * - Save the created fake target only if it has a big enough area.
+ *
+ *
+ * c) Example
+ * <pre>
+ *        Input:           Algorithm created box:        Maximum box:
+ * +---------------------+ +---------------------+ +---------------------+
+ * | B1      |        B2 | | B1               B2 | | B1               B2 |
+ * |         |           | |   +-------------+   | |+-------------------+|
+ * |---------x-----------| |   |             |   | ||                   ||
+ * |         |           | |   |             |   | ||                   ||
+ * |         |           | |   |             |   | ||                   ||
+ * |         |           | |   |             |   | ||                   ||
+ * |         |           | |   |             |   | ||                   ||
+ * |         |           | |   +-------------+   | |+-------------------+|
+ * | B4      |        B3 | | B4               B3 | | B4               B3 |
+ * +---------------------+ +---------------------+ +---------------------+
+ * </pre>
+ *
+ * @param {number} x Cursor position on the x-axis.
+ * @param {number} y Cursor position on the y-axis.
+ * @return {goog.fx.ActiveDropTarget_} Dummy drop target.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.maybeCreateDummyTargetForPosition_ =
+    function(x, y) {
+  if (!this.dummyTarget_) {
+    this.dummyTarget_ = new goog.fx.ActiveDropTarget_(this.targetBox_.clone());
+  }
+  var fakeTargetBox = this.dummyTarget_.box_;
+
+  // Initialize the fake target box to the bounding box of DnD targets.
+  fakeTargetBox.top = this.targetBox_.top;
+  fakeTargetBox.right = this.targetBox_.right;
+  fakeTargetBox.bottom = this.targetBox_.bottom;
+  fakeTargetBox.left = this.targetBox_.left;
+
+  // Clip the fake target based on mouse position and DnD target boxes.
+  for (var i = 0, target; target = this.targetList_[i]; i++) {
+    var box = target.box_;
+
+    if (target.scrollableContainer_) {
+      // If the target has a scrollable container, use the intersection of that
+      // container's box and the target's box.
+      var scrollBox = target.scrollableContainer_.box_;
+
+      box = new goog.math.Box(
+          Math.max(box.top, scrollBox.top),
+          Math.min(box.right, scrollBox.right),
+          Math.min(box.bottom, scrollBox.bottom),
+          Math.max(box.left, scrollBox.left));
+    }
+
+    // Calculate clipping coordinates for horizontal and vertical axis.
+    // The clipping coordinate is calculated by projecting fake target box,
+    // the mouse pointer and DnD target box onto an axis and checking how
+    // box projections overlap and if the projected DnD target box contains
+    // mouse pointer. The clipping coordinate cannot be computed and is set to
+    // a negative value if the projected DnD target contains the mouse pointer.
+
+    var horizontalClip = null; // Assume mouse is above or below the DnD box.
+    if (x >= box.right) { // Mouse is to the right of the DnD box.
+      // Clip the fake box only if the DnD box overlaps it.
+      horizontalClip = box.right > fakeTargetBox.left ?
+          box.right : fakeTargetBox.left;
+    } else if (x < box.left) { // Mouse is to the left of the DnD box.
+      // Clip the fake box only if the DnD box overlaps it.
+      horizontalClip = box.left < fakeTargetBox.right ?
+          box.left : fakeTargetBox.right;
+    }
+    var verticalClip = null;
+    if (y >= box.bottom) {
+      verticalClip = box.bottom > fakeTargetBox.top ?
+          box.bottom : fakeTargetBox.top;
+    } else if (y < box.top) {
+      verticalClip = box.top < fakeTargetBox.bottom ?
+          box.top : fakeTargetBox.bottom;
+    }
+
+    // If both clippings are possible, choose one that gives us larger distance
+    // to mouse pointer (mark the shorter clipping as impossible, by setting it
+    // to null).
+    if (!goog.isNull(horizontalClip) && !goog.isNull(verticalClip)) {
+      if (Math.abs(horizontalClip - x) > Math.abs(verticalClip - y)) {
+        verticalClip = null;
+      } else {
+        horizontalClip = null;
+      }
+    }
+
+    // Clip none or one of fake target box sides (at most one clipping
+    // coordinate can be active).
+    if (!goog.isNull(horizontalClip)) {
+      if (horizontalClip <= x) {
+        fakeTargetBox.left = horizontalClip;
+      } else {
+        fakeTargetBox.right = horizontalClip;
+      }
+    } else if (!goog.isNull(verticalClip)) {
+      if (verticalClip <= y) {
+        fakeTargetBox.top = verticalClip;
+      } else {
+        fakeTargetBox.bottom = verticalClip;
+      }
+    }
+  }
+
+  // Only return the new fake target if it is big enough.
+  return (fakeTargetBox.right - fakeTargetBox.left) *
+         (fakeTargetBox.bottom - fakeTargetBox.top) >=
+         goog.fx.AbstractDragDrop.DUMMY_TARGET_MIN_SIZE_ ?
+      this.dummyTarget_ : null;
+};
+
+
+/**
+ * Returns the target for a given cursor position.
+ *
+ * @param {goog.math.Coordinate} position Cursor position.
+ * @return {Object} Target for position or null if no target was defined
+ *     for the given position.
+ * @private
+ */
+goog.fx.AbstractDragDrop.prototype.getTargetFromPosition_ = function(position) {
+  for (var target, i = 0; target = this.targetList_[i]; i++) {
+    if (target.box_.contains(position)) {
+      if (target.scrollableContainer_) {
+        // If we have a scrollable container we will need to make sure
+        // we account for clipping of the scroll area
+        var box = target.scrollableContainer_.box_;
+        if (box.contains(position)) {
+          return target;
+        }
+      } else {
+        return target;
+      }
+    }
+  }
+
+  return null;
+};
+
+
+/**
+ * Checks whatever a given point is inside a given box.
+ *
+ * @param {number} x Cursor position on the x-axis.
+ * @param {number} y Cursor position on the y-axis.
+ * @param {goog.math.Box} box Box to check position against.
+ * @return {boolean} Whether the given point is inside {@code box}.
+ * @protected
+ * @deprecated Use goog.math.Box.contains.
+ */
+goog.fx.AbstractDragDrop.prototype.isInside = function(x, y, box) {
+  return x >= box.left &&
+         x < box.right &&
+         y >= box.top &&
+         y < box.bottom;
+};
+
+
+/**
+ * Gets the scroll distance as a coordinate object, using
+ * the window of the current drag element's dom.
+ * @return {!goog.math.Coordinate} Object with scroll offsets 'x' and 'y'.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.getScrollPos = function() {
+  return goog.dom.getDomHelper(this.dragEl_).getDocumentScroll();
+};
+
+
+/**
+ * Get the position of a drag event.
+ * @param {goog.fx.DragEvent} event Drag event.
+ * @return {!goog.math.Coordinate} Position of the event.
+ * @protected
+ */
+goog.fx.AbstractDragDrop.prototype.getEventPosition = function(event) {
+  var scroll = this.getScrollPos();
+  return new goog.math.Coordinate(event.clientX + scroll.x,
+                                  event.clientY + scroll.y);
+};
+
+
+/** @override */
+goog.fx.AbstractDragDrop.prototype.disposeInternal = function() {
+  goog.fx.AbstractDragDrop.base(this, 'disposeInternal');
+  this.removeItems();
+};
+
+
+
+/**
+ * Object representing a drag and drop event.
+ *
+ * @param {string} type Event type.
+ * @param {goog.fx.AbstractDragDrop} source Source drag drop object.
+ * @param {goog.fx.DragDropItem} sourceItem Source item.
+ * @param {goog.fx.AbstractDragDrop=} opt_target Target drag drop object.
+ * @param {goog.fx.DragDropItem=} opt_targetItem Target item.
+ * @param {Element=} opt_targetElement Target element.
+ * @param {number=} opt_clientX X-Position relative to the screen.
+ * @param {number=} opt_clientY Y-Position relative to the screen.
+ * @param {number=} opt_x X-Position relative to the viewport.
+ * @param {number=} opt_y Y-Position relative to the viewport.
+ * @param {Object=} opt_subtarget The currently active subtarget.
+ * @extends {goog.events.Event}
+ * @constructor
+ */
+goog.fx.DragDropEvent = function(type, source, sourceItem,
+                                 opt_target, opt_targetItem, opt_targetElement,
+                                 opt_clientX, opt_clientY, opt_x, opt_y,
+                                 opt_subtarget) {
+  // TODO(eae): Get rid of all the optional parameters and have the caller set
+  // the fields directly instead.
+  goog.fx.DragDropEvent.base(this, 'constructor', type);
+
+  /**
+   * Reference to the source goog.fx.AbstractDragDrop object.
+   * @type {goog.fx.AbstractDragDrop}
+   */
+  this.dragSource = source;
+
+  /**
+   * Reference to the source goog.fx.DragDropItem object.
+   * @type {goog.fx.DragDropItem}
+   */
+  this.dragSourceItem = sourceItem;
+
+  /**
+   * Reference to the target goog.fx.AbstractDragDrop object.
+   * @type {goog.fx.AbstractDragDrop|undefined}
+   */
+  this.dropTarget = opt_target;
+
+  /**
+   * Reference to the target goog.fx.DragDropItem object.
+   * @type {goog.fx.DragDropItem|undefined}
+   */
+  this.dropTargetItem = opt_targetItem;
+
+  /**
+   * The actual element of the drop target that is the target for this event.
+   * @type {Element|undefined}
+   */
+  this.dropTargetElement = opt_targetElement;
+
+  /**
+   * X-Position relative to the screen.
+   * @type {number|undefined}
+   */
+  this.clientX = opt_clientX;
+
+  /**
+   * Y-Position relative to the screen.
+   * @type {number|undefined}
+   */
+  this.clientY = opt_clientY;
+
+  /**
+   * X-Position relative to the viewport.
+   * @type {number|undefined}
+   */
+  this.viewportX = opt_x;
+
+  /**
+   * Y-Position relative to the viewport.
+   * @type {number|undefined}
+   */
+  this.viewportY = opt_y;
+
+  /**
+   * The subtarget that is currently active if a subtargeting function
+   * is supplied.
+   * @type {Object|undefined}
+   */
+  this.subtarget = opt_subtarget;
+};
+goog.inherits(goog.fx.DragDropEvent, goog.events.Event);
+
+
+
+/**
+ * Class representing a source or target element for drag and drop operations.
+ *
+ * @param {Element|string} element Dom Node, or string representation of node
+ *     id, to be used as drag source/drop target.
+ * @param {Object=} opt_data Data associated with the source/target.
+ * @throws Error If no element argument is provided or if the type is invalid
+ * @extends {goog.events.EventTarget}
+ * @constructor
+ */
+goog.fx.DragDropItem = function(element, opt_data) {
+  goog.fx.DragDropItem.base(this, 'constructor');
+
+  /**
+   * Reference to drag source/target element
+   * @type {Element}
+   */
+  this.element = goog.dom.getElement(element);
+
+  /**
+   * Data associated with element.
+   * @type {Object|undefined}
+   */
+  this.data = opt_data;
+
+  /**
+   * Drag object the item belongs to.
+   * @type {goog.fx.AbstractDragDrop?}
+   * @private
+   */
+  this.parent_ = null;
+
+  /**
+   * Event handler for listeners on events that can initiate a drag.
+   * @type {!goog.events.EventHandler<!goog.fx.DragDropItem>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+  this.registerDisposable(this.eventHandler_);
+
+  if (!this.element) {
+    throw Error('Invalid argument');
+  }
+};
+goog.inherits(goog.fx.DragDropItem, goog.events.EventTarget);
+
+
+/**
+ * The current element being dragged. This is needed because a DragDropItem can
+ * have multiple elements that can be dragged.
+ * @type {Element}
+ * @private
+ */
+goog.fx.DragDropItem.prototype.currentDragElement_ = null;
+
+
+/**
+ * Get the data associated with the source/target.
+ * @return {Object|null|undefined} Data associated with the source/target.
+ */
+goog.fx.DragDropItem.prototype.getData = function() {
+  return this.data;
+};
+
+
+/**
+ * Gets the element that is actually draggable given that the given target was
+ * attempted to be dragged. This should be overriden when the element that was
+ * given actually contains many items that can be dragged. From the target, you
+ * can determine what element should actually be dragged.
+ *
+ * @param {Element} target The target that was attempted to be dragged.
+ * @return {Element} The element that is draggable given the target. If
+ *     none are draggable, this will return null.
+ */
+goog.fx.DragDropItem.prototype.getDraggableElement = function(target) {
+  return target;
+};
+
+
+/**
+ * Gets the element that is currently being dragged.
+ *
+ * @return {Element} The element that is currently being dragged.
+ */
+goog.fx.DragDropItem.prototype.getCurrentDragElement = function() {
+  return this.currentDragElement_;
+};
+
+
+/**
+ * Gets all the elements of this item that are potentially draggable/
+ *
+ * @return {!Array<Element>} The draggable elements.
+ */
+goog.fx.DragDropItem.prototype.getDraggableElements = function() {
+  return [this.element];
+};
+
+
+/**
+ * Event handler for mouse down.
+ *
+ * @param {goog.events.BrowserEvent} event Mouse down event.
+ * @private
+ */
+goog.fx.DragDropItem.prototype.mouseDown_ = function(event) {
+  if (!event.isMouseActionButton()) {
+    return;
+  }
+
+  // Get the draggable element for the target.
+  var element = this.getDraggableElement(/** @type {Element} */ (event.target));
+  if (element) {
+    this.maybeStartDrag_(event, element);
+  }
+};
+
+
+/**
+ * Sets the dragdrop to which this item belongs.
+ * @param {goog.fx.AbstractDragDrop} parent The parent dragdrop.
+ */
+goog.fx.DragDropItem.prototype.setParent = function(parent) {
+  this.parent_ = parent;
+};
+
+
+/**
+ * Adds mouse move, mouse out and mouse up handlers.
+ *
+ * @param {goog.events.BrowserEvent} event Mouse down event.
+ * @param {Element} element Element.
+ * @private
+ */
+goog.fx.DragDropItem.prototype.maybeStartDrag_ = function(event, element) {
+  var eventType = goog.events.EventType;
+  this.eventHandler_.
+      listen(element, eventType.MOUSEMOVE, this.mouseMove_, false).
+      listen(element, eventType.MOUSEOUT, this.mouseMove_, false);
+
+  // Capture the MOUSEUP on the document to ensure that we cancel the start
+  // drag handlers even if the mouse up occurs on some other element. This can
+  // happen for instance when the mouse down changes the geometry of the element
+  // clicked on (e.g. through changes in activation styling) such that the mouse
+  // up occurs outside the original element.
+  var doc = goog.dom.getOwnerDocument(element);
+  this.eventHandler_.listen(doc, eventType.MOUSEUP, this.mouseUp_, true);
+
+  this.currentDragElement_ = element;
+
+  this.startPosition_ = new goog.math.Coordinate(
+      event.clientX, event.clientY);
+
+  event.preventDefault();
+};
+
+
+/**
+ * Event handler for mouse move. Starts drag operation if moved more than the
+ * threshold value.
+ *
+ * @param {goog.events.BrowserEvent} event Mouse move or mouse out event.
+ * @private
+ */
+goog.fx.DragDropItem.prototype.mouseMove_ = function(event) {
+  var distance = Math.abs(event.clientX - this.startPosition_.x) +
+      Math.abs(event.clientY - this.startPosition_.y);
+  // Fire dragStart event if the drag distance exceeds the threshold or if the
+  // mouse leave the dragged element.
+  // TODO(user): Consider using the goog.fx.Dragger to track the distance
+  // even after the mouse leaves the dragged element.
+  var currentDragElement = this.currentDragElement_;
+  var distanceAboveThreshold =
+      distance > goog.fx.AbstractDragDrop.initDragDistanceThreshold;
+  var mouseOutOnDragElement = event.type == goog.events.EventType.MOUSEOUT &&
+      event.target == currentDragElement;
+  if (distanceAboveThreshold || mouseOutOnDragElement) {
+    this.eventHandler_.removeAll();
+    this.parent_.startDrag(event, this);
+  }
+};
+
+
+/**
+ * Event handler for mouse up. Removes mouse move, mouse out and mouse up event
+ * handlers.
+ *
+ * @param {goog.events.BrowserEvent} event Mouse up event.
+ * @private
+ */
+goog.fx.DragDropItem.prototype.mouseUp_ = function(event) {
+  this.eventHandler_.removeAll();
+  delete this.startPosition_;
+  this.currentDragElement_ = null;
+};
+
+
+
+/**
+ * Class representing an active drop target
+ *
+ * @param {goog.math.Box} box Box describing the position and dimension of the
+ *     target item.
+ * @param {goog.fx.AbstractDragDrop=} opt_target Target that contains the item
+       associated with position.
+ * @param {goog.fx.DragDropItem=} opt_item Item associated with position.
+ * @param {Element=} opt_element Element of item associated with position.
+ * @constructor
+ * @private
+ */
+goog.fx.ActiveDropTarget_ = function(box, opt_target, opt_item, opt_element) {
+
+  /**
+   * Box describing the position and dimension of the target item
+   * @type {goog.math.Box}
+   * @private
+   */
+  this.box_ = box;
+
+  /**
+   * Target that contains the item associated with position
+   * @type {goog.fx.AbstractDragDrop|undefined}
+   * @private
+   */
+  this.target_ = opt_target;
+
+  /**
+   * Item associated with position
+   * @type {goog.fx.DragDropItem|undefined}
+   * @private
+   */
+  this.item_ = opt_item;
+
+  /**
+   * The draggable element of the item associated with position.
+   * @type {Element|undefined}
+   * @private
+   */
+  this.element_ = opt_element;
+};
+
+
+/**
+ * If this target is in a scrollable container this is it.
+ * @type {goog.fx.ScrollableContainer_}
+ * @private
+ */
+goog.fx.ActiveDropTarget_.prototype.scrollableContainer_ = null;
+
+
+
+/**
+ * Class for representing a scrollable container
+ * @param {Element} element the scrollable element.
+ * @constructor
+ * @private
+ */
+goog.fx.ScrollableContainer_ = function(element) {
+
+  /**
+   * The targets that lie within this container.
+   * @type {Array<goog.fx.ActiveDropTarget_>}
+   * @private
+   */
+  this.containedTargets_ = [];
+
+  /**
+   * The element that is this container
+   * @type {Element}
+   * @private
+   */
+  this.element_ = element;
+
+  /**
+   * The saved scroll left location for calculating deltas.
+   * @type {number}
+   * @private
+   */
+  this.savedScrollLeft_ = 0;
+
+  /**
+   * The saved scroll top location for calculating deltas.
+   * @type {number}
+   * @private
+   */
+  this.savedScrollTop_ = 0;
+
+  /**
+   * The space occupied by the container.
+   * @type {goog.math.Box}
+   * @private
+   */
+  this.box_ = null;
+};


[37/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/errorreporter.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/errorreporter.js b/externs/GCL/externs/goog/debug/errorreporter.js
new file mode 100644
index 0000000..e869792
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/errorreporter.js
@@ -0,0 +1,434 @@
+// 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 ErrorReporter class, which creates an error
+ * handler that reports any errors raised to a URL.
+ *
+ */
+
+goog.provide('goog.debug.ErrorReporter');
+goog.provide('goog.debug.ErrorReporter.ExceptionEvent');
+
+goog.require('goog.asserts');
+goog.require('goog.debug');
+goog.require('goog.debug.Error');
+goog.require('goog.debug.ErrorHandler');
+goog.require('goog.debug.entryPointRegistry');
+goog.require('goog.events');
+goog.require('goog.events.Event');
+goog.require('goog.events.EventTarget');
+goog.require('goog.log');
+goog.require('goog.net.XhrIo');
+goog.require('goog.object');
+goog.require('goog.string');
+goog.require('goog.uri.utils');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Constructs an error reporter. Internal Use Only. To install an error
+ * reporter see the {@see #install} method below.
+ *
+ * @param {string} handlerUrl The URL to which all errors will be reported.
+ * @param {function(!Error, !Object<string, string>)=}
+ *     opt_contextProvider When a report is to be sent to the server,
+ *     this method will be called, and given an opportunity to modify the
+ *     context object before submission to the server.
+ * @param {boolean=} opt_noAutoProtect Whether to automatically add handlers for
+ *     onerror and to protect entry points.  If apps have other error reporting
+ *     facilities, it may make sense for them to set these up themselves and use
+ *     the ErrorReporter just for transmission of reports.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.debug.ErrorReporter = function(
+    handlerUrl, opt_contextProvider, opt_noAutoProtect) {
+  goog.debug.ErrorReporter.base(this, 'constructor');
+
+  /**
+   * Context provider, if one was provided.
+   * @type {?function(!Error, !Object<string, string>)}
+   * @private
+   */
+  this.contextProvider_ = opt_contextProvider || null;
+
+  /**
+   * The string prefix of any optional context parameters logged with the error.
+   * @private {string}
+   */
+  this.contextPrefix_ = 'context.';
+
+  /**
+   * The number of bytes after which the ErrorReporter truncates the POST body.
+   * If null, the ErrorReporter won't truncate the body.
+   * @private {?number}
+   */
+  this.truncationLimit_ = null;
+
+  /**
+   * Additional arguments to append to URL before sending XHR.
+   * @private {!Object<string,string>}
+   */
+  this.additionalArguments_ = {};
+
+  /**
+   * XHR sender.
+   * @type {function(string, string, string, (Object|goog.structs.Map)=)}
+   * @private
+   */
+  this.xhrSender_ = goog.debug.ErrorReporter.defaultXhrSender;
+
+  /**
+   * The URL at which all errors caught by this handler will be logged.
+   *
+   * @type {string}
+   * @private
+   */
+  this.handlerUrl_ = handlerUrl;
+
+  if (goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT) {
+    if (!opt_noAutoProtect) {
+      /**
+       * The internal error handler used to catch all errors.
+       *
+       * @private {goog.debug.ErrorHandler}
+       */
+      this.errorHandler_ = null;
+
+      this.setup_();
+    }
+  } else if (!opt_noAutoProtect) {
+    goog.asserts.fail(
+        'opt_noAutoProtect cannot be false while ' +
+        'goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT is false.  Setting ' +
+        'ALLOW_AUTO_PROTECT to false removes the necessary auto-protect code ' +
+        'in compiled/optimized mode.');
+  }
+};
+goog.inherits(goog.debug.ErrorReporter, goog.events.EventTarget);
+
+
+/**
+ * @define {boolean} If true, the code that provides additional entry point
+ *     protection and setup is exposed in this file.  Set to false to avoid
+ *     bringing in a lot of code from ErrorHandler and entryPointRegistry in
+ *     compiled mode.
+ */
+goog.define('goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT', true);
+
+
+
+/**
+ * Event broadcast when an exception is logged.
+ * @param {Error} error The exception that was was reported.
+ * @param {!Object<string, string>} context The context values sent to the
+ *     server alongside this error.
+ * @constructor
+ * @extends {goog.events.Event}
+ * @final
+ */
+goog.debug.ErrorReporter.ExceptionEvent = function(error, context) {
+  goog.events.Event.call(this, goog.debug.ErrorReporter.ExceptionEvent.TYPE);
+
+  /**
+   * The error that was reported.
+   * @type {Error}
+   */
+  this.error = error;
+
+  /**
+   * Context values sent to the server alongside this report.
+   * @type {!Object<string, string>}
+   */
+  this.context = context;
+};
+goog.inherits(goog.debug.ErrorReporter.ExceptionEvent, goog.events.Event);
+
+
+/**
+ * Event type for notifying of a logged exception.
+ * @type {string}
+ */
+goog.debug.ErrorReporter.ExceptionEvent.TYPE =
+    goog.events.getUniqueId('exception');
+
+
+/**
+ * Extra headers for the error-reporting XHR.
+ * @type {Object|goog.structs.Map|undefined}
+ * @private
+ */
+goog.debug.ErrorReporter.prototype.extraHeaders_;
+
+
+/**
+ * Logging object.
+ *
+ * @type {goog.log.Logger}
+ * @private
+ */
+goog.debug.ErrorReporter.logger_ =
+    goog.log.getLogger('goog.debug.ErrorReporter');
+
+
+/**
+ * Installs an error reporter to catch all JavaScript errors raised.
+ *
+ * @param {string} loggingUrl The URL to which the errors caught will be
+ *     reported.
+ * @param {function(!Error, !Object<string, string>)=}
+ *     opt_contextProvider When a report is to be sent to the server,
+ *     this method will be called, and given an opportunity to modify the
+ *     context object before submission to the server.
+ * @param {boolean=} opt_noAutoProtect Whether to automatically add handlers for
+ *     onerror and to protect entry points.  If apps have other error reporting
+ *     facilities, it may make sense for them to set these up themselves and use
+ *     the ErrorReporter just for transmission of reports.
+ * @return {!goog.debug.ErrorReporter} The error reporter.
+ */
+goog.debug.ErrorReporter.install = function(
+    loggingUrl, opt_contextProvider, opt_noAutoProtect) {
+  var instance = new goog.debug.ErrorReporter(
+      loggingUrl, opt_contextProvider, opt_noAutoProtect);
+  return instance;
+};
+
+
+/**
+ * Default implementation of XHR sender interface.
+ *
+ * @param {string} uri URI to make request to.
+ * @param {string} method Send method.
+ * @param {string} content Post data.
+ * @param {Object|goog.structs.Map=} opt_headers Map of headers to add to the
+ *     request.
+ */
+goog.debug.ErrorReporter.defaultXhrSender = function(uri, method, content,
+    opt_headers) {
+  goog.net.XhrIo.send(uri, null, method, content, opt_headers);
+};
+
+
+/**
+ * Installs exception protection for an entry point function in addition
+ * to those that are protected by default.
+ * Has no effect in IE because window.onerror is used for reporting
+ * exceptions in that case.
+ *
+ * @this {goog.debug.ErrorReporter}
+ * @param {Function} fn An entry point function to be protected.
+ * @return {Function} A protected wrapper function that calls the entry point
+ *     function or null if the entry point could not be protected.
+ */
+goog.debug.ErrorReporter.prototype.protectAdditionalEntryPoint =
+    goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT ?
+    function(fn) {
+      if (this.errorHandler_) {
+        return this.errorHandler_.protectEntryPoint(fn);
+      }
+      return null;
+    } :
+    function(fn) {
+      goog.asserts.fail(
+          'Cannot call protectAdditionalEntryPoint while ALLOW_AUTO_PROTECT ' +
+          'is false.  If ALLOW_AUTO_PROTECT is false, the necessary ' +
+          'auto-protect code in compiled/optimized mode is removed.');
+      return null;
+    };
+
+
+if (goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT) {
+  /**
+   * Sets up the error reporter.
+   *
+   * @private
+   */
+  goog.debug.ErrorReporter.prototype.setup_ = function() {
+    if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('10')) {
+      // Use "onerror" because caught exceptions in IE don't provide line
+      // number.
+      goog.debug.catchErrors(
+          goog.bind(this.handleException, this), false, null);
+    } else {
+      // "onerror" doesn't work with FF2 or Chrome
+      this.errorHandler_ = new goog.debug.ErrorHandler(
+          goog.bind(this.handleException, this));
+
+      this.errorHandler_.protectWindowSetTimeout();
+      this.errorHandler_.protectWindowSetInterval();
+      this.errorHandler_.protectWindowRequestAnimationFrame();
+      goog.debug.entryPointRegistry.monitorAll(this.errorHandler_);
+    }
+  };
+}
+
+
+/**
+ * Add headers to the logging url.
+ * @param {Object|goog.structs.Map} loggingHeaders Extra headers to send
+ *     to the logging URL.
+ */
+goog.debug.ErrorReporter.prototype.setLoggingHeaders =
+    function(loggingHeaders) {
+  this.extraHeaders_ = loggingHeaders;
+};
+
+
+/**
+ * Set the function used to send error reports to the server.
+ * @param {function(string, string, string, (Object|goog.structs.Map)=)}
+ *     xhrSender If provided, this will be used to send a report to the
+ *     server instead of the default method. The function will be given the URI,
+ *     HTTP method request content, and (optionally) request headers to be
+ *     added.
+ */
+goog.debug.ErrorReporter.prototype.setXhrSender = function(xhrSender) {
+  this.xhrSender_ = xhrSender;
+};
+
+
+/**
+ * Handler for caught exceptions. Sends report to the LoggingServlet and
+ * notifies any listeners.
+ *
+ * @param {Object} e The exception.
+ * @param {!Object<string, string>=} opt_context Context values to optionally
+ *     include in the error report.
+ */
+goog.debug.ErrorReporter.prototype.handleException = function(e,
+    opt_context) {
+  var error = /** @type {!Error} */ (goog.debug.normalizeErrorObject(e));
+
+  // Construct the context, possibly from the one provided in the argument, and
+  // pass it to the context provider if there is one.
+  var context = opt_context ? goog.object.clone(opt_context) : {};
+  if (this.contextProvider_) {
+    try {
+      this.contextProvider_(error, context);
+    } catch (err) {
+      goog.log.error(goog.debug.ErrorReporter.logger_,
+          'Context provider threw an exception: ' + err.message);
+    }
+  }
+  // Truncate message to a reasonable length, since it will be sent in the URL.
+  // The entire URL length historically needed to be 2,083 or less, so leave
+  // some room for the rest of the URL.
+  var message = error.message.substring(0, 1900);
+  if (!(e instanceof goog.debug.Error) || e.reportErrorToServer) {
+    this.sendErrorReport(message, error.fileName, error.lineNumber, error.stack,
+        context);
+  }
+
+  try {
+    this.dispatchEvent(
+        new goog.debug.ErrorReporter.ExceptionEvent(error, context));
+  } catch (ex) {
+    // Swallow exception to avoid infinite recursion.
+  }
+};
+
+
+/**
+ * Sends an error report to the logging URL.  This will not consult the context
+ * provider, the report will be sent exactly as specified.
+ *
+ * @param {string} message Error description.
+ * @param {string} fileName URL of the JavaScript file with the error.
+ * @param {number} line Line number of the error.
+ * @param {string=} opt_trace Call stack trace of the error.
+ * @param {!Object<string, string>=} opt_context Context information to include
+ *     in the request.
+ */
+goog.debug.ErrorReporter.prototype.sendErrorReport =
+    function(message, fileName, line, opt_trace, opt_context) {
+  try {
+    // Create the logging URL.
+    var requestUrl = goog.uri.utils.appendParams(this.handlerUrl_,
+        'script', fileName, 'error', message, 'line', line);
+
+    if (!goog.object.isEmpty(this.additionalArguments_)) {
+      requestUrl = goog.uri.utils.appendParamsFromMap(requestUrl,
+          this.additionalArguments_);
+    }
+
+    var queryMap = {};
+    queryMap['trace'] = opt_trace;
+
+    // Copy context into query data map
+    if (opt_context) {
+      for (var entry in opt_context) {
+        queryMap[this.contextPrefix_ + entry] = opt_context[entry];
+      }
+    }
+
+    // Copy query data map into request.
+    var queryData = goog.uri.utils.buildQueryDataFromMap(queryMap);
+
+    // Truncate if truncationLimit set.
+    if (goog.isNumber(this.truncationLimit_)) {
+      queryData = queryData.substring(0, this.truncationLimit_);
+    }
+
+    // Send the request with the contents of the error.
+    this.xhrSender_(requestUrl, 'POST', queryData, this.extraHeaders_);
+  } catch (e) {
+    var logMessage = goog.string.buildString(
+        'Error occurred in sending an error report.\n\n',
+        'script:', fileName, '\n',
+        'line:', line, '\n',
+        'error:', message, '\n',
+        'trace:', opt_trace);
+    goog.log.info(goog.debug.ErrorReporter.logger_, logMessage);
+  }
+};
+
+
+/**
+ * @param {string} prefix The prefix to appear prepended to all context
+ *     variables in the error report body.
+ */
+goog.debug.ErrorReporter.prototype.setContextPrefix = function(prefix) {
+  this.contextPrefix_ = prefix;
+};
+
+
+/**
+ * @param {?number} limit Size in bytes to begin truncating POST body.  Set to
+ *     null to prevent truncation.  The limit must be >= 0.
+ */
+goog.debug.ErrorReporter.prototype.setTruncationLimit = function(limit) {
+  goog.asserts.assert(!goog.isNumber(limit) || limit >= 0,
+      'Body limit must be valid number >= 0 or null');
+  this.truncationLimit_ = limit;
+};
+
+
+/**
+ * @param {!Object<string,string>} urlArgs Set of key-value pairs to append
+ *     to handlerUrl_ before sending XHR.
+ */
+goog.debug.ErrorReporter.prototype.setAdditionalArguments = function(urlArgs) {
+  this.additionalArguments_ = urlArgs;
+};
+
+
+/** @override */
+goog.debug.ErrorReporter.prototype.disposeInternal = function() {
+  if (goog.debug.ErrorReporter.ALLOW_AUTO_PROTECT) {
+    goog.dispose(this.errorHandler_);
+  }
+  goog.debug.ErrorReporter.base(this, 'disposeInternal');
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/fancywindow.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/fancywindow.js b/externs/GCL/externs/goog/debug/fancywindow.js
new file mode 100644
index 0000000..d9aea26
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/fancywindow.js
@@ -0,0 +1,385 @@
+// 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 Definition of the FancyWindow class. Please minimize
+ * dependencies this file has on other closure classes as any dependency it
+ * takes won't be able to use the logging infrastructure.
+ *
+ * This is a pretty hacky implementation, aimed at making debugging of large
+ * applications more manageable.
+ *
+ * @see ../demos/debug.html
+ */
+
+
+goog.provide('goog.debug.FancyWindow');
+
+goog.require('goog.array');
+goog.require('goog.debug.DebugWindow');
+goog.require('goog.debug.LogManager');
+goog.require('goog.debug.Logger');
+goog.require('goog.dom.DomHelper');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.safe');
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.SafeStyleSheet');
+goog.require('goog.object');
+goog.require('goog.string');
+goog.require('goog.string.Const');
+goog.require('goog.userAgent');
+
+
+
+// TODO(user): Introduce goog.scope for goog.html.SafeHtml once b/12014412
+// is fixed.
+/**
+ * Provides a Fancy extension to the DebugWindow class.  Allows filtering based
+ * on loggers and levels.
+ *
+ * @param {string=} opt_identifier Idenitifier for this logging class.
+ * @param {string=} opt_prefix Prefix pre-pended to messages.
+ * @constructor
+ * @extends {goog.debug.DebugWindow}
+ */
+goog.debug.FancyWindow = function(opt_identifier, opt_prefix) {
+  this.readOptionsFromLocalStorage_();
+  goog.debug.FancyWindow.base(this, 'constructor', opt_identifier, opt_prefix);
+  /** @private {goog.dom.DomHelper} */
+  this.dh_ = null;
+};
+goog.inherits(goog.debug.FancyWindow, goog.debug.DebugWindow);
+
+
+/**
+ * Constant indicating if we are able to use localStorage to persist filters
+ * @type {boolean}
+ */
+goog.debug.FancyWindow.HAS_LOCAL_STORE = (function() {
+  /** @preserveTry */
+  try {
+    return !!window['localStorage'].getItem;
+  } catch (e) {}
+  return false;
+})();
+
+
+/**
+ * Constant defining the prefix to use when storing log levels
+ * @type {string}
+ */
+goog.debug.FancyWindow.LOCAL_STORE_PREFIX = 'fancywindow.sel.';
+
+
+/** @override */
+goog.debug.FancyWindow.prototype.writeBufferToLog = function() {
+  this.lastCall = goog.now();
+  if (this.hasActiveWindow()) {
+    var logel = this.dh_.getElement('log');
+
+    // Work out if scrolling is needed before we add the content
+    var scroll =
+        logel.scrollHeight - (logel.scrollTop + logel.offsetHeight) <= 100;
+
+    for (var i = 0; i < this.outputBuffer.length; i++) {
+      var div = this.dh_.createDom(goog.dom.TagName.DIV, 'logmsg');
+      goog.dom.safe.setInnerHtml(div, this.outputBuffer[i]);
+      logel.appendChild(div);
+    }
+    this.outputBuffer.length = 0;
+    this.resizeStuff_();
+
+    if (scroll) {
+      logel.scrollTop = logel.scrollHeight;
+    }
+  }
+};
+
+
+/** @override */
+goog.debug.FancyWindow.prototype.writeInitialDocument = function() {
+  if (!this.hasActiveWindow()) {
+    return;
+  }
+
+  var doc = this.win.document;
+  doc.open();
+  goog.dom.safe.documentWrite(doc, this.getHtml_());
+  doc.close();
+
+  (goog.userAgent.IE ? doc.body : this.win).onresize =
+      goog.bind(this.resizeStuff_, this);
+
+  // Create a dom helper for the logging window
+  this.dh_ = new goog.dom.DomHelper(doc);
+
+  // Don't use events system to reduce dependencies
+  this.dh_.getElement('openbutton').onclick =
+      goog.bind(this.openOptions_, this);
+  this.dh_.getElement('closebutton').onclick =
+      goog.bind(this.closeOptions_, this);
+  this.dh_.getElement('clearbutton').onclick =
+      goog.bind(this.clear, this);
+  this.dh_.getElement('exitbutton').onclick =
+      goog.bind(this.exit_, this);
+
+  this.writeSavedMessages();
+};
+
+
+/**
+ * Show the options menu.
+ * @return {boolean} false.
+ * @private
+ */
+goog.debug.FancyWindow.prototype.openOptions_ = function() {
+  var el = goog.asserts.assert(this.dh_.getElement('optionsarea'));
+  goog.dom.safe.setInnerHtml(el, goog.html.SafeHtml.EMPTY);
+
+  var loggers = goog.debug.FancyWindow.getLoggers_();
+  var dh = this.dh_;
+  for (var i = 0; i < loggers.length; i++) {
+    var logger = loggers[i];
+    var curlevel = logger.getLevel() ? logger.getLevel().name : 'INHERIT';
+    var div = dh.createDom(goog.dom.TagName.DIV, {},
+        this.getDropDown_('sel' + logger.getName(), curlevel),
+        dh.createDom(goog.dom.TagName.SPAN, {}, logger.getName() || '(root)'));
+    el.appendChild(div);
+  }
+
+  this.dh_.getElement('options').style.display = 'block';
+  return false;
+};
+
+
+/**
+ * Make a drop down for the log levels.
+ * @param {string} id Logger id.
+ * @param {string} selected What log level is currently selected.
+ * @return {Element} The newly created 'select' DOM element.
+ * @private
+ */
+goog.debug.FancyWindow.prototype.getDropDown_ = function(id, selected) {
+  var dh = this.dh_;
+  var sel = dh.createDom(goog.dom.TagName.SELECT, {'id': id});
+  var levels = goog.debug.Logger.Level.PREDEFINED_LEVELS;
+  for (var i = 0; i < levels.length; i++) {
+    var level = levels[i];
+    var option = dh.createDom(goog.dom.TagName.OPTION, {}, level.name);
+    if (selected == level.name) {
+      option.selected = true;
+    }
+    sel.appendChild(option);
+  }
+  sel.appendChild(dh.createDom(goog.dom.TagName.OPTION,
+      {'selected': selected == 'INHERIT'}, 'INHERIT'));
+  return sel;
+};
+
+
+/**
+ * Close the options menu.
+ * @return {boolean} The value false.
+ * @private
+ */
+goog.debug.FancyWindow.prototype.closeOptions_ = function() {
+  this.dh_.getElement('options').style.display = 'none';
+  var loggers = goog.debug.FancyWindow.getLoggers_();
+  var dh = this.dh_;
+  for (var i = 0; i < loggers.length; i++) {
+    var logger = loggers[i];
+    var sel = dh.getElement('sel' + logger.getName());
+    var level = sel.options[sel.selectedIndex].text;
+    if (level == 'INHERIT') {
+      logger.setLevel(null);
+    } else {
+      logger.setLevel(goog.debug.Logger.Level.getPredefinedLevel(level));
+    }
+  }
+  this.writeOptionsToLocalStorage_();
+  return false;
+};
+
+
+/**
+ * Resizes the log elements
+ * @private
+ */
+goog.debug.FancyWindow.prototype.resizeStuff_ = function() {
+  var dh = this.dh_;
+  var logel = dh.getElement('log');
+  var headel = dh.getElement('head');
+  logel.style.top = headel.offsetHeight + 'px';
+  logel.style.height = (dh.getDocument().body.offsetHeight -
+      headel.offsetHeight - (goog.userAgent.IE ? 4 : 0)) + 'px';
+};
+
+
+/**
+ * Handles the user clicking the exit button, disabled the debug window and
+ * closes the popup.
+ * @param {Event} e Event object.
+ * @private
+ */
+goog.debug.FancyWindow.prototype.exit_ = function(e) {
+  this.setEnabled(false);
+  if (this.win) {
+    this.win.close();
+  }
+};
+
+
+/** @override */
+goog.debug.FancyWindow.prototype.getStyleRules = function() {
+  var baseRules = goog.debug.FancyWindow.base(this, 'getStyleRules');
+  var extraRules = goog.html.SafeStyleSheet.fromConstant(goog.string.Const.from(
+      'html,body{height:100%;width:100%;margin:0px;padding:0px;' +
+      'background-color:#FFF;overflow:hidden}' +
+      '*{}' +
+      '.logmsg{border-bottom:1px solid #CCC;padding:2px;font:90% monospace}' +
+      '#head{position:absolute;width:100%;font:x-small arial;' +
+      'border-bottom:2px solid #999;background-color:#EEE;}' +
+      '#head p{margin:0px 5px;}' +
+      '#log{position:absolute;width:100%;background-color:#FFF;}' +
+      '#options{position:absolute;right:0px;width:50%;height:100%;' +
+      'border-left:1px solid #999;background-color:#DDD;display:none;' +
+      'padding-left: 5px;font:normal small arial;overflow:auto;}' +
+      '#openbutton,#closebutton{text-decoration:underline;color:#00F;cursor:' +
+      'pointer;position:absolute;top:0px;right:5px;font:x-small arial;}' +
+      '#clearbutton{text-decoration:underline;color:#00F;cursor:' +
+      'pointer;position:absolute;top:0px;right:80px;font:x-small arial;}' +
+      '#exitbutton{text-decoration:underline;color:#00F;cursor:' +
+      'pointer;position:absolute;top:0px;right:50px;font:x-small arial;}' +
+      'select{font:x-small arial;margin-right:10px;}' +
+      'hr{border:0;height:5px;background-color:#8c8;color:#8c8;}'));
+  return goog.html.SafeStyleSheet.concat(baseRules, extraRules);
+};
+
+
+/**
+ * Return the default HTML for the debug window
+ * @return {!goog.html.SafeHtml} Html.
+ * @private
+ */
+goog.debug.FancyWindow.prototype.getHtml_ = function() {
+  var SafeHtml = goog.html.SafeHtml;
+  var head = SafeHtml.create('head', {}, SafeHtml.concat(
+      SafeHtml.create('title', {}, 'Logging: ' + this.identifier),
+      SafeHtml.createStyle(this.getStyleRules())));
+
+  var body = SafeHtml.create('body', {}, SafeHtml.concat(
+      SafeHtml.create('div',
+          {'id': 'log', 'style': goog.string.Const.from('overflow:auto')}),
+      SafeHtml.create('div', {'id': 'head'}, SafeHtml.concat(
+          SafeHtml.create('p', {},
+              SafeHtml.create('b', {}, 'Logging: ' + this.identifier)),
+          SafeHtml.create('p', {}, this.welcomeMessage),
+          SafeHtml.create('span', {'id': 'clearbutton'}, 'clear'),
+          SafeHtml.create('span', {'id': 'exitbutton'}, 'exit'),
+          SafeHtml.create('span', {'id': 'openbutton'}, 'options'))),
+      SafeHtml.create('div', {'id': 'options'}, SafeHtml.concat(
+          SafeHtml.create('big', {},
+              SafeHtml.create('b', {}, 'Options:')),
+          SafeHtml.create('div', {'id': 'optionsarea'}),
+          SafeHtml.create('span', {'id': 'closebutton'}, 'save and close')))));
+
+  return SafeHtml.create('html', {}, SafeHtml.concat(head, body));
+};
+
+
+/**
+ * Write logger levels to localStorage if possible.
+ * @private
+ */
+goog.debug.FancyWindow.prototype.writeOptionsToLocalStorage_ = function() {
+  if (!goog.debug.FancyWindow.HAS_LOCAL_STORE) {
+    return;
+  }
+  var loggers = goog.debug.FancyWindow.getLoggers_();
+  var storedKeys = goog.debug.FancyWindow.getStoredKeys_();
+  for (var i = 0; i < loggers.length; i++) {
+    var key = goog.debug.FancyWindow.LOCAL_STORE_PREFIX + loggers[i].getName();
+    var level = loggers[i].getLevel();
+    if (key in storedKeys) {
+      if (!level) {
+        window.localStorage.removeItem(key);
+      } else if (window.localStorage.getItem(key) != level.name) {
+        window.localStorage.setItem(key, level.name);
+      }
+    } else if (level) {
+      window.localStorage.setItem(key, level.name);
+    }
+  }
+};
+
+
+/**
+ * Sync logger levels with any values stored in localStorage.
+ * @private
+ */
+goog.debug.FancyWindow.prototype.readOptionsFromLocalStorage_ = function() {
+  if (!goog.debug.FancyWindow.HAS_LOCAL_STORE) {
+    return;
+  }
+  var storedKeys = goog.debug.FancyWindow.getStoredKeys_();
+  for (var key in storedKeys) {
+    var loggerName = key.replace(goog.debug.FancyWindow.LOCAL_STORE_PREFIX, '');
+    var logger = goog.debug.LogManager.getLogger(loggerName);
+    var curLevel = logger.getLevel();
+    var storedLevel = window.localStorage.getItem(key).toString();
+    if (!curLevel || curLevel.toString() != storedLevel) {
+      logger.setLevel(goog.debug.Logger.Level.getPredefinedLevel(storedLevel));
+    }
+  }
+};
+
+
+/**
+ * Helper function to create a list of locally stored keys. Used to avoid
+ * expensive localStorage.getItem() calls.
+ * @return {!Object} List of keys.
+ * @private
+ */
+goog.debug.FancyWindow.getStoredKeys_ = function() {
+  var storedKeys = {};
+  for (var i = 0, len = window.localStorage.length; i < len; i++) {
+    var key = window.localStorage.key(i);
+    if (key != null && goog.string.startsWith(
+        key, goog.debug.FancyWindow.LOCAL_STORE_PREFIX)) {
+      storedKeys[key] = true;
+    }
+  }
+  return storedKeys;
+};
+
+
+/**
+ * Gets a sorted array of all the loggers registered.
+ * @return {!Array<!goog.debug.Logger>} Array of logger instances.
+ * @private
+ */
+goog.debug.FancyWindow.getLoggers_ = function() {
+  var loggers = goog.object.getValues(goog.debug.LogManager.getLoggers());
+
+  /**
+   * @param {!goog.debug.Logger} a
+   * @param {!goog.debug.Logger} b
+   * @return {number}
+   */
+  var loggerSort = function(a, b) {
+    return goog.array.defaultCompare(a.getName(), b.getName());
+  };
+  goog.array.sort(loggers, loggerSort);
+  return loggers;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/formatter.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/formatter.js b/externs/GCL/externs/goog/debug/formatter.js
new file mode 100644
index 0000000..949a652
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/formatter.js
@@ -0,0 +1,387 @@
+// 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 Definition of various formatters for logging. Please minimize
+ * dependencies this file has on other closure classes as any dependency it
+ * takes won't be able to use the logging infrastructure.
+ *
+ */
+
+goog.provide('goog.debug.Formatter');
+goog.provide('goog.debug.HtmlFormatter');
+goog.provide('goog.debug.TextFormatter');
+
+goog.require('goog.debug');
+goog.require('goog.debug.Logger');
+goog.require('goog.debug.RelativeTimeProvider');
+goog.require('goog.html.SafeHtml');
+
+
+
+/**
+ * Base class for Formatters. A Formatter is used to format a LogRecord into
+ * something that can be displayed to the user.
+ *
+ * @param {string=} opt_prefix The prefix to place before text records.
+ * @constructor
+ */
+goog.debug.Formatter = function(opt_prefix) {
+  this.prefix_ = opt_prefix || '';
+
+  /**
+   * A provider that returns the relative start time.
+   * @type {goog.debug.RelativeTimeProvider}
+   * @private
+   */
+  this.startTimeProvider_ =
+      goog.debug.RelativeTimeProvider.getDefaultInstance();
+};
+
+
+/**
+ * Whether to append newlines to the end of formatted log records.
+ * @type {boolean}
+ */
+goog.debug.Formatter.prototype.appendNewline = true;
+
+
+/**
+ * Whether to show absolute time in the DebugWindow.
+ * @type {boolean}
+ */
+goog.debug.Formatter.prototype.showAbsoluteTime = true;
+
+
+/**
+ * Whether to show relative time in the DebugWindow.
+ * @type {boolean}
+ */
+goog.debug.Formatter.prototype.showRelativeTime = true;
+
+
+/**
+ * Whether to show the logger name in the DebugWindow.
+ * @type {boolean}
+ */
+goog.debug.Formatter.prototype.showLoggerName = true;
+
+
+/**
+ * Whether to show the logger exception text.
+ * @type {boolean}
+ */
+goog.debug.Formatter.prototype.showExceptionText = false;
+
+
+/**
+ * Whether to show the severity level.
+ * @type {boolean}
+ */
+goog.debug.Formatter.prototype.showSeverityLevel = false;
+
+
+/**
+ * Formats a record.
+ * @param {goog.debug.LogRecord} logRecord the logRecord to format.
+ * @return {string} The formatted string.
+ */
+goog.debug.Formatter.prototype.formatRecord = goog.abstractMethod;
+
+
+/**
+ * Formats a record as SafeHtml.
+ * @param {goog.debug.LogRecord} logRecord the logRecord to format.
+ * @return {!goog.html.SafeHtml} The formatted string as SafeHtml.
+ */
+goog.debug.Formatter.prototype.formatRecordAsHtml = goog.abstractMethod;
+
+
+/**
+ * Sets the start time provider. By default, this is the default instance
+ * but can be changed.
+ * @param {goog.debug.RelativeTimeProvider} provider The provider to use.
+ */
+goog.debug.Formatter.prototype.setStartTimeProvider = function(provider) {
+  this.startTimeProvider_ = provider;
+};
+
+
+/**
+ * Returns the start time provider. By default, this is the default instance
+ * but can be changed.
+ * @return {goog.debug.RelativeTimeProvider} The start time provider.
+ */
+goog.debug.Formatter.prototype.getStartTimeProvider = function() {
+  return this.startTimeProvider_;
+};
+
+
+/**
+ * Resets the start relative time.
+ */
+goog.debug.Formatter.prototype.resetRelativeTimeStart = function() {
+  this.startTimeProvider_.reset();
+};
+
+
+/**
+ * Returns a string for the time/date of the LogRecord.
+ * @param {goog.debug.LogRecord} logRecord The record to get a time stamp for.
+ * @return {string} A string representation of the time/date of the LogRecord.
+ * @private
+ */
+goog.debug.Formatter.getDateTimeStamp_ = function(logRecord) {
+  var time = new Date(logRecord.getMillis());
+  return goog.debug.Formatter.getTwoDigitString_((time.getFullYear() - 2000)) +
+         goog.debug.Formatter.getTwoDigitString_((time.getMonth() + 1)) +
+         goog.debug.Formatter.getTwoDigitString_(time.getDate()) + ' ' +
+         goog.debug.Formatter.getTwoDigitString_(time.getHours()) + ':' +
+         goog.debug.Formatter.getTwoDigitString_(time.getMinutes()) + ':' +
+         goog.debug.Formatter.getTwoDigitString_(time.getSeconds()) + '.' +
+         goog.debug.Formatter.getTwoDigitString_(
+             Math.floor(time.getMilliseconds() / 10));
+};
+
+
+/**
+ * Returns the number as a two-digit string, meaning it prepends a 0 if the
+ * number if less than 10.
+ * @param {number} n The number to format.
+ * @return {string} A two-digit string representation of {@code n}.
+ * @private
+ */
+goog.debug.Formatter.getTwoDigitString_ = function(n) {
+  if (n < 10) {
+    return '0' + n;
+  }
+  return String(n);
+};
+
+
+/**
+ * Returns a string for the number of seconds relative to the start time.
+ * Prepads with spaces so that anything less than 1000 seconds takes up the
+ * same number of characters for better formatting.
+ * @param {goog.debug.LogRecord} logRecord The log to compare time to.
+ * @param {number} relativeTimeStart The start time to compare to.
+ * @return {string} The number of seconds of the LogRecord relative to the
+ *     start time.
+ * @private
+ */
+goog.debug.Formatter.getRelativeTime_ = function(logRecord,
+                                                 relativeTimeStart) {
+  var ms = logRecord.getMillis() - relativeTimeStart;
+  var sec = ms / 1000;
+  var str = sec.toFixed(3);
+
+  var spacesToPrepend = 0;
+  if (sec < 1) {
+    spacesToPrepend = 2;
+  } else {
+    while (sec < 100) {
+      spacesToPrepend++;
+      sec *= 10;
+    }
+  }
+  while (spacesToPrepend-- > 0) {
+    str = ' ' + str;
+  }
+  return str;
+};
+
+
+
+/**
+ * Formatter that returns formatted html. See formatRecord for the classes
+ * it uses for various types of formatted output.
+ *
+ * @param {string=} opt_prefix The prefix to place before text records.
+ * @constructor
+ * @extends {goog.debug.Formatter}
+ */
+goog.debug.HtmlFormatter = function(opt_prefix) {
+  goog.debug.Formatter.call(this, opt_prefix);
+};
+goog.inherits(goog.debug.HtmlFormatter, goog.debug.Formatter);
+
+
+/**
+ * Whether to show the logger exception text
+ * @type {boolean}
+ * @override
+ */
+goog.debug.HtmlFormatter.prototype.showExceptionText = true;
+
+
+/**
+ * Formats a record
+ * @param {goog.debug.LogRecord} logRecord the logRecord to format.
+ * @return {string} The formatted string as html.
+ * @override
+ */
+goog.debug.HtmlFormatter.prototype.formatRecord = function(logRecord) {
+  if (!logRecord) {
+    return '';
+  }
+  // OK not to use goog.html.SafeHtml.unwrap() here.
+  return this.formatRecordAsHtml(logRecord).getTypedStringValue();
+};
+
+
+/**
+ * Formats a record.
+ * @param {goog.debug.LogRecord} logRecord the logRecord to format.
+ * @return {!goog.html.SafeHtml} The formatted string as SafeHtml.
+ * @override
+ */
+goog.debug.HtmlFormatter.prototype.formatRecordAsHtml = function(logRecord) {
+  if (!logRecord) {
+    return goog.html.SafeHtml.EMPTY;
+  }
+
+  var className;
+  switch (logRecord.getLevel().value) {
+    case goog.debug.Logger.Level.SHOUT.value:
+      className = 'dbg-sh';
+      break;
+    case goog.debug.Logger.Level.SEVERE.value:
+      className = 'dbg-sev';
+      break;
+    case goog.debug.Logger.Level.WARNING.value:
+      className = 'dbg-w';
+      break;
+    case goog.debug.Logger.Level.INFO.value:
+      className = 'dbg-i';
+      break;
+    case goog.debug.Logger.Level.FINE.value:
+    default:
+      className = 'dbg-f';
+      break;
+  }
+
+  // HTML for user defined prefix, time, logger name, and severity.
+  var sb = [];
+  sb.push(this.prefix_, ' ');
+  if (this.showAbsoluteTime) {
+    sb.push('[', goog.debug.Formatter.getDateTimeStamp_(logRecord), '] ');
+  }
+  if (this.showRelativeTime) {
+    sb.push('[',
+        goog.debug.Formatter.getRelativeTime_(
+            logRecord, this.startTimeProvider_.get()),
+        's] ');
+  }
+  if (this.showLoggerName) {
+    sb.push('[', logRecord.getLoggerName(), '] ');
+  }
+  if (this.showSeverityLevel) {
+    sb.push('[', logRecord.getLevel().name, '] ');
+  }
+  var fullPrefixHtml =
+      goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(sb.join(''));
+
+  // HTML for exception text and log record.
+  var exceptionHtml = goog.html.SafeHtml.EMPTY;
+  if (this.showExceptionText && logRecord.getException()) {
+    exceptionHtml = goog.html.SafeHtml.concat(
+        goog.html.SafeHtml.create('br'),
+        goog.debug.exposeExceptionAsHtml(logRecord.getException()));
+  }
+  var logRecordHtml = goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(
+      logRecord.getMessage());
+  var recordAndExceptionHtml = goog.html.SafeHtml.create(
+      'span',
+      {'class': className},
+      goog.html.SafeHtml.concat(logRecordHtml, exceptionHtml));
+
+
+  // Combine both pieces of HTML and, if needed, append a final newline.
+  var html;
+  if (this.appendNewline) {
+    html = goog.html.SafeHtml.concat(fullPrefixHtml, recordAndExceptionHtml,
+        goog.html.SafeHtml.create('br'));
+  } else {
+    html = goog.html.SafeHtml.concat(fullPrefixHtml, recordAndExceptionHtml);
+  }
+  return html;
+};
+
+
+
+/**
+ * Formatter that returns formatted plain text
+ *
+ * @param {string=} opt_prefix The prefix to place before text records.
+ * @constructor
+ * @extends {goog.debug.Formatter}
+ * @final
+ */
+goog.debug.TextFormatter = function(opt_prefix) {
+  goog.debug.Formatter.call(this, opt_prefix);
+};
+goog.inherits(goog.debug.TextFormatter, goog.debug.Formatter);
+
+
+/**
+ * Formats a record as text
+ * @param {goog.debug.LogRecord} logRecord the logRecord to format.
+ * @return {string} The formatted string.
+ * @override
+ */
+goog.debug.TextFormatter.prototype.formatRecord = function(logRecord) {
+  var sb = [];
+  sb.push(this.prefix_, ' ');
+  if (this.showAbsoluteTime) {
+    sb.push('[', goog.debug.Formatter.getDateTimeStamp_(logRecord), '] ');
+  }
+  if (this.showRelativeTime) {
+    sb.push('[', goog.debug.Formatter.getRelativeTime_(logRecord,
+        this.startTimeProvider_.get()), 's] ');
+  }
+
+  if (this.showLoggerName) {
+    sb.push('[', logRecord.getLoggerName(), '] ');
+  }
+  if (this.showSeverityLevel) {
+    sb.push('[', logRecord.getLevel().name, '] ');
+  }
+  sb.push(logRecord.getMessage());
+  if (this.showExceptionText) {
+    var exception = logRecord.getException();
+    if (exception) {
+      var exceptionText = exception instanceof Error ?
+          exception.message :
+          exception.toString();
+      sb.push('\n', exceptionText);
+    }
+  }
+  if (this.appendNewline) {
+    sb.push('\n');
+  }
+  return sb.join('');
+};
+
+
+/**
+ * Formats a record as text
+ * @param {goog.debug.LogRecord} logRecord the logRecord to format.
+ * @return {!goog.html.SafeHtml} The formatted string as SafeHtml. This is
+ *     just an HTML-escaped version of the text obtained from formatRecord().
+ * @override
+ */
+goog.debug.TextFormatter.prototype.formatRecordAsHtml = function(logRecord) {
+  return goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces(
+      goog.debug.TextFormatter.prototype.formatRecord(logRecord));
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/fpsdisplay.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/fpsdisplay.js b/externs/GCL/externs/goog/debug/fpsdisplay.js
new file mode 100644
index 0000000..f8f525f
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/fpsdisplay.js
@@ -0,0 +1,165 @@
+// Copyright 2011 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 Displays frames per second (FPS) for the current window.
+ * Only supported in browsers that support requestAnimationFrame.
+ * See: https://developer.mozilla.org/en/DOM/window.requestAnimationFrame.
+ *
+ * @see ../demos/fpsdisplay.html
+ */
+
+goog.provide('goog.debug.FpsDisplay');
+
+goog.require('goog.asserts');
+goog.require('goog.async.AnimationDelay');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.ui.Component');
+
+
+
+/**
+ * Displays frames per seconds that the window this component is
+ * rendered in is animating at.
+ *
+ * @param {goog.dom.DomHelper=} opt_domHelper An optional dom helper.
+ * @constructor
+ * @extends {goog.ui.Component}
+ * @final
+ */
+goog.debug.FpsDisplay = function(opt_domHelper) {
+  goog.debug.FpsDisplay.base(this, 'constructor', opt_domHelper);
+};
+goog.inherits(goog.debug.FpsDisplay, goog.ui.Component);
+
+
+/**
+ * CSS class for the FPS display.
+ */
+goog.debug.FpsDisplay.CSS = goog.getCssName('goog-fps-display');
+
+
+/**
+ * The number of samples per FPS report.
+ */
+goog.debug.FpsDisplay.SAMPLES = 10;
+
+
+/**
+ * The current animation.
+ * @type {goog.debug.FpsDisplay.FpsAnimation_}
+ * @private
+ */
+goog.debug.FpsDisplay.prototype.animation_ = null;
+
+
+/** @override */
+goog.debug.FpsDisplay.prototype.createDom = function() {
+  this.setElementInternal(this.getDomHelper().createDom(
+      goog.dom.TagName.DIV, goog.debug.FpsDisplay.CSS));
+};
+
+
+/** @override */
+goog.debug.FpsDisplay.prototype.enterDocument = function() {
+  goog.debug.FpsDisplay.base(this, 'enterDocument');
+  this.animation_ = new goog.debug.FpsDisplay.FpsAnimation_(this.getElement());
+  this.delay_ = new goog.async.AnimationDelay(
+      this.handleDelay_, this.getDomHelper().getWindow(), this);
+  this.delay_.start();
+};
+
+
+/**
+ * @param {number} now The current time.
+ * @private
+ */
+goog.debug.FpsDisplay.prototype.handleDelay_ = function(now) {
+  if (this.isInDocument()) {
+    this.animation_.onAnimationFrame(now);
+    this.delay_.start();
+  }
+};
+
+
+/** @override */
+goog.debug.FpsDisplay.prototype.exitDocument = function() {
+  goog.debug.FpsDisplay.base(this, 'exitDocument');
+  this.animation_ = null;
+  goog.dispose(this.delay_);
+};
+
+
+/**
+ * @return {number} The average frames per second.
+ */
+goog.debug.FpsDisplay.prototype.getFps = function() {
+  goog.asserts.assert(
+      this.isInDocument(), 'Render the FPS display before querying FPS');
+  return this.animation_.lastFps_;
+};
+
+
+
+/**
+ * @param {Element} elem An element to hold the FPS count.
+ * @constructor
+ * @private
+ */
+goog.debug.FpsDisplay.FpsAnimation_ = function(elem) {
+  /**
+   * An element to hold the current FPS rate.
+   * @type {Element}
+   * @private
+   */
+  this.element_ = elem;
+
+  /**
+   * The number of frames observed so far.
+   * @type {number}
+   * @private
+   */
+  this.frameNumber_ = 0;
+};
+
+
+/**
+ * The last time which we reported FPS at.
+ * @type {number}
+ * @private
+ */
+goog.debug.FpsDisplay.FpsAnimation_.prototype.lastTime_ = 0;
+
+
+/**
+ * The last average FPS.
+ * @type {number}
+ * @private
+ */
+goog.debug.FpsDisplay.FpsAnimation_.prototype.lastFps_ = -1;
+
+
+/**
+ * @param {number} now The current time.
+ */
+goog.debug.FpsDisplay.FpsAnimation_.prototype.onAnimationFrame = function(now) {
+  var SAMPLES = goog.debug.FpsDisplay.SAMPLES;
+  if (this.frameNumber_ % SAMPLES == 0) {
+    this.lastFps_ = Math.round((1000 * SAMPLES) / (now - this.lastTime_));
+    goog.dom.setTextContent(this.element_, this.lastFps_);
+    this.lastTime_ = now;
+  }
+  this.frameNumber_++;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/gcdiagnostics.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/gcdiagnostics.js b/externs/GCL/externs/goog/debug/gcdiagnostics.js
new file mode 100644
index 0000000..5e5ba9a
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/gcdiagnostics.js
@@ -0,0 +1,143 @@
+// 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 GcDiagnostics class.
+ *
+ */
+
+goog.provide('goog.debug.GcDiagnostics');
+
+goog.require('goog.debug.Trace');
+goog.require('goog.log');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Class used for singleton goog.debug.GcDiagnostics.  Used to hook into
+ * the L2 ActiveX controller to profile garbage collection information in IE.
+ * Can be used in combination with tracers (goog.debug.Trace), to provide object
+ * allocation counts from within the tracers or used alone by invoking start and
+ * stop.
+ *
+ * See http://go/l2binary for the install.
+ * TODO(user): Move the L2 installer somewhere more general.
+ * @constructor
+ * @private
+ */
+goog.debug.GcDiagnostics_ = function() {};
+
+
+/**
+ * Install the GcDiagnostics tool.
+ */
+goog.debug.GcDiagnostics_.prototype.install = function() {
+  if (goog.userAgent.IE) {
+    /** @preserveTry */
+    try {
+      var l2Helper = new ActiveXObject('L2.NativeHelper');
+
+      // If using tracers, use the higher precision timer provided by L2.
+      if (goog.debug.Trace_) {
+        goog.debug.Trace_.now = function() {
+          return l2Helper['getMilliSeconds']();
+        };
+      }
+
+      if (l2Helper['gcTracer']) {
+        l2Helper['gcTracer']['installGcTracing']();
+        this.gcTracer_ = l2Helper['gcTracer'];
+        if (goog.debug.Trace) {
+          // If tracers are in use, register the gcTracer so that per tracer
+          // allocations are recorded.
+          goog.debug.Trace.setGcTracer(this.gcTracer_);
+        }
+      }
+      goog.log.info(this.logger_, 'Installed L2 native helper');
+    } catch (e) {
+      goog.log.info(this.logger_, 'Failed to install L2 native helper: ' + e);
+    }
+  }
+};
+
+
+/**
+ * Logger for the gcDiagnotics
+ * @type {goog.log.Logger}
+ * @private
+ */
+goog.debug.GcDiagnostics_.prototype.logger_ =
+    goog.log.getLogger('goog.debug.GcDiagnostics');
+
+
+/**
+ * Starts recording garbage collection information.  If a trace is already in
+ * progress, it is ended.
+ */
+goog.debug.GcDiagnostics_.prototype.start = function() {
+  if (this.gcTracer_) {
+    if (this.gcTracer_['isTracing']()) {
+      this.gcTracer_['endGcTracing']();
+    }
+    this.gcTracer_['startGcTracing']();
+  }
+};
+
+
+/**
+ * Stops recording garbage collection information.  Logs details on the garbage
+ * collections that occurred between start and stop.  If tracers are in use,
+ * adds comments where each GC occurs.
+ */
+goog.debug.GcDiagnostics_.prototype.stop = function() {
+  if (this.gcTracer_ && this.gcTracer_['isTracing']()) {
+    var gcTracer = this.gcTracer_;
+    this.gcTracer_['endGcTracing']();
+
+    var numGCs = gcTracer['getNumTraces']();
+    goog.log.info(this.logger_, '*********GC TRACE*********');
+    goog.log.info(this.logger_, 'GC ran ' + numGCs + ' times.');
+    var totalTime = 0;
+    for (var i = 0; i < numGCs; i++) {
+      var trace = gcTracer['getTrace'](i);
+
+      var msStart = trace['gcStartTime'];
+      var msElapsed = trace['gcElapsedTime'];
+
+      var msRounded = Math.round(msElapsed * 10) / 10;
+      var s = 'GC ' + i + ': ' + msRounded + ' ms, ' +
+          'numVValAlloc=' + trace['numVValAlloc'] + ', ' +
+          'numVarAlloc=' + trace['numVarAlloc'] + ', ' +
+          'numBytesSysAlloc=' + trace['numBytesSysAlloc'];
+      if (goog.debug.Trace) {
+        goog.debug.Trace.addComment(s, null, msStart);
+      }
+      goog.log.info(this.logger_, s);
+      totalTime += msElapsed;
+    }
+    if (goog.debug.Trace) {
+      goog.debug.Trace.addComment('Total GC time was ' + totalTime + ' ms.');
+    }
+    goog.log.info(this.logger_, 'Total GC time was ' + totalTime + ' ms.');
+    goog.log.info(this.logger_, '*********GC TRACE*********');
+  }
+};
+
+
+/**
+ * Singleton GcDiagnostics object
+ * @type {goog.debug.GcDiagnostics_}
+ */
+goog.debug.GcDiagnostics = new goog.debug.GcDiagnostics_();

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/logbuffer.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/logbuffer.js b/externs/GCL/externs/goog/debug/logbuffer.js
new file mode 100644
index 0000000..7e3de4b
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/logbuffer.js
@@ -0,0 +1,148 @@
+// Copyright 2010 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 buffer for log records. The purpose of this is to improve
+ * logging performance by re-using old objects when the buffer becomes full and
+ * to eliminate the need for each app to implement their own log buffer. The
+ * disadvantage to doing this is that log handlers cannot maintain references to
+ * log records and expect that they are not overwriten at a later point.
+ *
+ * @author agrieve@google.com (Andrew Grieve)
+ */
+
+goog.provide('goog.debug.LogBuffer');
+
+goog.require('goog.asserts');
+goog.require('goog.debug.LogRecord');
+
+
+
+/**
+ * Creates the log buffer.
+ * @constructor
+ * @final
+ */
+goog.debug.LogBuffer = function() {
+  goog.asserts.assert(goog.debug.LogBuffer.isBufferingEnabled(),
+      'Cannot use goog.debug.LogBuffer without defining ' +
+      'goog.debug.LogBuffer.CAPACITY.');
+  this.clear();
+};
+
+
+/**
+ * A static method that always returns the same instance of LogBuffer.
+ * @return {!goog.debug.LogBuffer} The LogBuffer singleton instance.
+ */
+goog.debug.LogBuffer.getInstance = function() {
+  if (!goog.debug.LogBuffer.instance_) {
+    // This function is written with the return statement after the assignment
+    // to avoid the jscompiler StripCode bug described in http://b/2608064.
+    // After that bug is fixed this can be refactored.
+    goog.debug.LogBuffer.instance_ = new goog.debug.LogBuffer();
+  }
+  return goog.debug.LogBuffer.instance_;
+};
+
+
+/**
+ * @define {number} The number of log records to buffer. 0 means disable
+ * buffering.
+ */
+goog.define('goog.debug.LogBuffer.CAPACITY', 0);
+
+
+/**
+ * The array to store the records.
+ * @type {!Array<!goog.debug.LogRecord|undefined>}
+ * @private
+ */
+goog.debug.LogBuffer.prototype.buffer_;
+
+
+/**
+ * The index of the most recently added record or -1 if there are no records.
+ * @type {number}
+ * @private
+ */
+goog.debug.LogBuffer.prototype.curIndex_;
+
+
+/**
+ * Whether the buffer is at capacity.
+ * @type {boolean}
+ * @private
+ */
+goog.debug.LogBuffer.prototype.isFull_;
+
+
+/**
+ * Adds a log record to the buffer, possibly overwriting the oldest record.
+ * @param {goog.debug.Logger.Level} level One of the level identifiers.
+ * @param {string} msg The string message.
+ * @param {string} loggerName The name of the source logger.
+ * @return {!goog.debug.LogRecord} The log record.
+ */
+goog.debug.LogBuffer.prototype.addRecord = function(level, msg, loggerName) {
+  var curIndex = (this.curIndex_ + 1) % goog.debug.LogBuffer.CAPACITY;
+  this.curIndex_ = curIndex;
+  if (this.isFull_) {
+    var ret = this.buffer_[curIndex];
+    ret.reset(level, msg, loggerName);
+    return ret;
+  }
+  this.isFull_ = curIndex == goog.debug.LogBuffer.CAPACITY - 1;
+  return this.buffer_[curIndex] =
+      new goog.debug.LogRecord(level, msg, loggerName);
+};
+
+
+/**
+ * @return {boolean} Whether the log buffer is enabled.
+ */
+goog.debug.LogBuffer.isBufferingEnabled = function() {
+  return goog.debug.LogBuffer.CAPACITY > 0;
+};
+
+
+/**
+ * Removes all buffered log records.
+ */
+goog.debug.LogBuffer.prototype.clear = function() {
+  this.buffer_ = new Array(goog.debug.LogBuffer.CAPACITY);
+  this.curIndex_ = -1;
+  this.isFull_ = false;
+};
+
+
+/**
+ * Calls the given function for each buffered log record, starting with the
+ * oldest one.
+ * @param {function(!goog.debug.LogRecord)} func The function to call.
+ */
+goog.debug.LogBuffer.prototype.forEachRecord = function(func) {
+  var buffer = this.buffer_;
+  // Corner case: no records.
+  if (!buffer[0]) {
+    return;
+  }
+  var curIndex = this.curIndex_;
+  var i = this.isFull_ ? curIndex : -1;
+  do {
+    i = (i + 1) % goog.debug.LogBuffer.CAPACITY;
+    func(/** @type {!goog.debug.LogRecord} */ (buffer[i]));
+  } while (i != curIndex);
+};
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/logger.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/logger.js b/externs/GCL/externs/goog/debug/logger.js
new file mode 100644
index 0000000..5ced90a
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/logger.js
@@ -0,0 +1,873 @@
+// 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 Definition of the Logger class. Please minimize dependencies
+ * this file has on other closure classes as any dependency it takes won't be
+ * able to use the logging infrastructure.
+ *
+ * @see ../demos/debug.html
+ */
+
+goog.provide('goog.debug.LogManager');
+goog.provide('goog.debug.Loggable');
+goog.provide('goog.debug.Logger');
+goog.provide('goog.debug.Logger.Level');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.debug');
+goog.require('goog.debug.LogBuffer');
+goog.require('goog.debug.LogRecord');
+
+
+/**
+ * A message value that can be handled by a Logger.
+ *
+ * Functions are treated like callbacks, but are only called when the event's
+ * log level is enabled. This is useful for logging messages that are expensive
+ * to construct.
+ *
+ * @typedef {string|function(): string}
+ */
+goog.debug.Loggable;
+
+
+
+/**
+ * The Logger is an object used for logging debug messages. Loggers are
+ * normally named, using a hierarchical dot-separated namespace. Logger names
+ * can be arbitrary strings, but they should normally be based on the package
+ * name or class name of the logged component, such as goog.net.BrowserChannel.
+ *
+ * The Logger object is loosely based on the java class
+ * java.util.logging.Logger. It supports different levels of filtering for
+ * different loggers.
+ *
+ * The logger object should never be instantiated by application code. It
+ * should always use the goog.debug.Logger.getLogger function.
+ *
+ * @constructor
+ * @param {string} name The name of the Logger.
+ * @final
+ */
+goog.debug.Logger = function(name) {
+  /**
+   * Name of the Logger. Generally a dot-separated namespace
+   * @private {string}
+   */
+  this.name_ = name;
+
+  /**
+   * Parent Logger.
+   * @private {goog.debug.Logger}
+   */
+  this.parent_ = null;
+
+  /**
+   * Level that this logger only filters above. Null indicates it should
+   * inherit from the parent.
+   * @private {goog.debug.Logger.Level}
+   */
+  this.level_ = null;
+
+  /**
+   * Map of children loggers. The keys are the leaf names of the children and
+   * the values are the child loggers.
+   * @private {Object}
+   */
+  this.children_ = null;
+
+  /**
+   * Handlers that are listening to this logger.
+   * @private {Array<Function>}
+   */
+  this.handlers_ = null;
+};
+
+
+/** @const */
+goog.debug.Logger.ROOT_LOGGER_NAME = '';
+
+
+/**
+ * @define {boolean} Toggles whether loggers other than the root logger can have
+ *     log handlers attached to them and whether they can have their log level
+ *     set. Logging is a bit faster when this is set to false.
+ */
+goog.define('goog.debug.Logger.ENABLE_HIERARCHY', true);
+
+
+if (!goog.debug.Logger.ENABLE_HIERARCHY) {
+  /**
+   * @type {!Array<Function>}
+   * @private
+   */
+  goog.debug.Logger.rootHandlers_ = [];
+
+
+  /**
+   * @type {goog.debug.Logger.Level}
+   * @private
+   */
+  goog.debug.Logger.rootLevel_;
+}
+
+
+
+/**
+ * The Level class defines a set of standard logging levels that
+ * can be used to control logging output.  The logging Level objects
+ * are ordered and are specified by ordered integers.  Enabling logging
+ * at a given level also enables logging at all higher levels.
+ * <p>
+ * Clients should normally use the predefined Level constants such
+ * as Level.SEVERE.
+ * <p>
+ * The levels in descending order are:
+ * <ul>
+ * <li>SEVERE (highest value)
+ * <li>WARNING
+ * <li>INFO
+ * <li>CONFIG
+ * <li>FINE
+ * <li>FINER
+ * <li>FINEST  (lowest value)
+ * </ul>
+ * In addition there is a level OFF that can be used to turn
+ * off logging, and a level ALL that can be used to enable
+ * logging of all messages.
+ *
+ * @param {string} name The name of the level.
+ * @param {number} value The numeric value of the level.
+ * @constructor
+ * @final
+ */
+goog.debug.Logger.Level = function(name, value) {
+  /**
+   * The name of the level
+   * @type {string}
+   */
+  this.name = name;
+
+  /**
+   * The numeric value of the level
+   * @type {number}
+   */
+  this.value = value;
+};
+
+
+/**
+ * @return {string} String representation of the logger level.
+ * @override
+ */
+goog.debug.Logger.Level.prototype.toString = function() {
+  return this.name;
+};
+
+
+/**
+ * OFF is a special level that can be used to turn off logging.
+ * This level is initialized to <CODE>Infinity</CODE>.
+ * @type {!goog.debug.Logger.Level}
+ */
+goog.debug.Logger.Level.OFF =
+    new goog.debug.Logger.Level('OFF', Infinity);
+
+
+/**
+ * SHOUT is a message level for extra debugging loudness.
+ * This level is initialized to <CODE>1200</CODE>.
+ * @type {!goog.debug.Logger.Level}
+ */
+goog.debug.Logger.Level.SHOUT = new goog.debug.Logger.Level('SHOUT', 1200);
+
+
+/**
+ * SEVERE is a message level indicating a serious failure.
+ * This level is initialized to <CODE>1000</CODE>.
+ * @type {!goog.debug.Logger.Level}
+ */
+goog.debug.Logger.Level.SEVERE = new goog.debug.Logger.Level('SEVERE', 1000);
+
+
+/**
+ * WARNING is a message level indicating a potential problem.
+ * This level is initialized to <CODE>900</CODE>.
+ * @type {!goog.debug.Logger.Level}
+ */
+goog.debug.Logger.Level.WARNING = new goog.debug.Logger.Level('WARNING', 900);
+
+
+/**
+ * INFO is a message level for informational messages.
+ * This level is initialized to <CODE>800</CODE>.
+ * @type {!goog.debug.Logger.Level}
+ */
+goog.debug.Logger.Level.INFO = new goog.debug.Logger.Level('INFO', 800);
+
+
+/**
+ * CONFIG is a message level for static configuration messages.
+ * This level is initialized to <CODE>700</CODE>.
+ * @type {!goog.debug.Logger.Level}
+ */
+goog.debug.Logger.Level.CONFIG = new goog.debug.Logger.Level('CONFIG', 700);
+
+
+/**
+ * FINE is a message level providing tracing information.
+ * This level is initialized to <CODE>500</CODE>.
+ * @type {!goog.debug.Logger.Level}
+ */
+goog.debug.Logger.Level.FINE = new goog.debug.Logger.Level('FINE', 500);
+
+
+/**
+ * FINER indicates a fairly detailed tracing message.
+ * This level is initialized to <CODE>400</CODE>.
+ * @type {!goog.debug.Logger.Level}
+ */
+goog.debug.Logger.Level.FINER = new goog.debug.Logger.Level('FINER', 400);
+
+/**
+ * FINEST indicates a highly detailed tracing message.
+ * This level is initialized to <CODE>300</CODE>.
+ * @type {!goog.debug.Logger.Level}
+ */
+
+goog.debug.Logger.Level.FINEST = new goog.debug.Logger.Level('FINEST', 300);
+
+
+/**
+ * ALL indicates that all messages should be logged.
+ * This level is initialized to <CODE>0</CODE>.
+ * @type {!goog.debug.Logger.Level}
+ */
+goog.debug.Logger.Level.ALL = new goog.debug.Logger.Level('ALL', 0);
+
+
+/**
+ * The predefined levels.
+ * @type {!Array<!goog.debug.Logger.Level>}
+ * @final
+ */
+goog.debug.Logger.Level.PREDEFINED_LEVELS = [
+  goog.debug.Logger.Level.OFF,
+  goog.debug.Logger.Level.SHOUT,
+  goog.debug.Logger.Level.SEVERE,
+  goog.debug.Logger.Level.WARNING,
+  goog.debug.Logger.Level.INFO,
+  goog.debug.Logger.Level.CONFIG,
+  goog.debug.Logger.Level.FINE,
+  goog.debug.Logger.Level.FINER,
+  goog.debug.Logger.Level.FINEST,
+  goog.debug.Logger.Level.ALL];
+
+
+/**
+ * A lookup map used to find the level object based on the name or value of
+ * the level object.
+ * @type {Object}
+ * @private
+ */
+goog.debug.Logger.Level.predefinedLevelsCache_ = null;
+
+
+/**
+ * Creates the predefined levels cache and populates it.
+ * @private
+ */
+goog.debug.Logger.Level.createPredefinedLevelsCache_ = function() {
+  goog.debug.Logger.Level.predefinedLevelsCache_ = {};
+  for (var i = 0, level; level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i];
+       i++) {
+    goog.debug.Logger.Level.predefinedLevelsCache_[level.value] = level;
+    goog.debug.Logger.Level.predefinedLevelsCache_[level.name] = level;
+  }
+};
+
+
+/**
+ * Gets the predefined level with the given name.
+ * @param {string} name The name of the level.
+ * @return {goog.debug.Logger.Level} The level, or null if none found.
+ */
+goog.debug.Logger.Level.getPredefinedLevel = function(name) {
+  if (!goog.debug.Logger.Level.predefinedLevelsCache_) {
+    goog.debug.Logger.Level.createPredefinedLevelsCache_();
+  }
+
+  return goog.debug.Logger.Level.predefinedLevelsCache_[name] || null;
+};
+
+
+/**
+ * Gets the highest predefined level <= #value.
+ * @param {number} value Level value.
+ * @return {goog.debug.Logger.Level} The level, or null if none found.
+ */
+goog.debug.Logger.Level.getPredefinedLevelByValue = function(value) {
+  if (!goog.debug.Logger.Level.predefinedLevelsCache_) {
+    goog.debug.Logger.Level.createPredefinedLevelsCache_();
+  }
+
+  if (value in goog.debug.Logger.Level.predefinedLevelsCache_) {
+    return goog.debug.Logger.Level.predefinedLevelsCache_[value];
+  }
+
+  for (var i = 0; i < goog.debug.Logger.Level.PREDEFINED_LEVELS.length; ++i) {
+    var level = goog.debug.Logger.Level.PREDEFINED_LEVELS[i];
+    if (level.value <= value) {
+      return level;
+    }
+  }
+  return null;
+};
+
+
+/**
+ * Finds or creates a logger for a named subsystem. If a logger has already been
+ * created with the given name it is returned. Otherwise a new logger is
+ * created. If a new logger is created its log level will be configured based
+ * on the LogManager configuration and it will configured to also send logging
+ * output to its parent's handlers. It will be registered in the LogManager
+ * global namespace.
+ *
+ * @param {string} name A name for the logger. This should be a dot-separated
+ * name and should normally be based on the package name or class name of the
+ * subsystem, such as goog.net.BrowserChannel.
+ * @return {!goog.debug.Logger} The named logger.
+ * @deprecated use goog.log instead. http://go/goog-debug-logger-deprecated
+ */
+goog.debug.Logger.getLogger = function(name) {
+  return goog.debug.LogManager.getLogger(name);
+};
+
+
+/**
+ * Logs a message to profiling tools, if available.
+ * {@see https://developers.google.com/web-toolkit/speedtracer/logging-api}
+ * {@see http://msdn.microsoft.com/en-us/library/dd433074(VS.85).aspx}
+ * @param {string} msg The message to log.
+ */
+goog.debug.Logger.logToProfilers = function(msg) {
+  // Using goog.global, as loggers might be used in window-less contexts.
+  if (goog.global['console']) {
+    if (goog.global['console']['timeStamp']) {
+      // Logs a message to Firebug, Web Inspector, SpeedTracer, etc.
+      goog.global['console']['timeStamp'](msg);
+    } else if (goog.global['console']['markTimeline']) {
+      // TODO(user): markTimeline is deprecated. Drop this else clause entirely
+      // after Chrome M14 hits stable.
+      goog.global['console']['markTimeline'](msg);
+    }
+  }
+
+  if (goog.global['msWriteProfilerMark']) {
+    // Logs a message to the Microsoft profiler
+    goog.global['msWriteProfilerMark'](msg);
+  }
+};
+
+
+/**
+ * Gets the name of this logger.
+ * @return {string} The name of this logger.
+ */
+goog.debug.Logger.prototype.getName = function() {
+  return this.name_;
+};
+
+
+/**
+ * Adds a handler to the logger. This doesn't use the event system because
+ * we want to be able to add logging to the event system.
+ * @param {Function} handler Handler function to add.
+ */
+goog.debug.Logger.prototype.addHandler = function(handler) {
+  if (goog.debug.LOGGING_ENABLED) {
+    if (goog.debug.Logger.ENABLE_HIERARCHY) {
+      if (!this.handlers_) {
+        this.handlers_ = [];
+      }
+      this.handlers_.push(handler);
+    } else {
+      goog.asserts.assert(!this.name_,
+          'Cannot call addHandler on a non-root logger when ' +
+          'goog.debug.Logger.ENABLE_HIERARCHY is false.');
+      goog.debug.Logger.rootHandlers_.push(handler);
+    }
+  }
+};
+
+
+/**
+ * Removes a handler from the logger. This doesn't use the event system because
+ * we want to be able to add logging to the event system.
+ * @param {Function} handler Handler function to remove.
+ * @return {boolean} Whether the handler was removed.
+ */
+goog.debug.Logger.prototype.removeHandler = function(handler) {
+  if (goog.debug.LOGGING_ENABLED) {
+    var handlers = goog.debug.Logger.ENABLE_HIERARCHY ? this.handlers_ :
+        goog.debug.Logger.rootHandlers_;
+    return !!handlers && goog.array.remove(handlers, handler);
+  } else {
+    return false;
+  }
+};
+
+
+/**
+ * Returns the parent of this logger.
+ * @return {goog.debug.Logger} The parent logger or null if this is the root.
+ */
+goog.debug.Logger.prototype.getParent = function() {
+  return this.parent_;
+};
+
+
+/**
+ * Returns the children of this logger as a map of the child name to the logger.
+ * @return {!Object} The map where the keys are the child leaf names and the
+ *     values are the Logger objects.
+ */
+goog.debug.Logger.prototype.getChildren = function() {
+  if (!this.children_) {
+    this.children_ = {};
+  }
+  return this.children_;
+};
+
+
+/**
+ * Set the log level specifying which message levels will be logged by this
+ * logger. Message levels lower than this value will be discarded.
+ * The level value Level.OFF can be used to turn off logging. If the new level
+ * is null, it means that this node should inherit its level from its nearest
+ * ancestor with a specific (non-null) level value.
+ *
+ * @param {goog.debug.Logger.Level} level The new level.
+ */
+goog.debug.Logger.prototype.setLevel = function(level) {
+  if (goog.debug.LOGGING_ENABLED) {
+    if (goog.debug.Logger.ENABLE_HIERARCHY) {
+      this.level_ = level;
+    } else {
+      goog.asserts.assert(!this.name_,
+          'Cannot call setLevel() on a non-root logger when ' +
+          'goog.debug.Logger.ENABLE_HIERARCHY is false.');
+      goog.debug.Logger.rootLevel_ = level;
+    }
+  }
+};
+
+
+/**
+ * Gets the log level specifying which message levels will be logged by this
+ * logger. Message levels lower than this value will be discarded.
+ * The level value Level.OFF can be used to turn off logging. If the level
+ * is null, it means that this node should inherit its level from its nearest
+ * ancestor with a specific (non-null) level value.
+ *
+ * @return {goog.debug.Logger.Level} The level.
+ */
+goog.debug.Logger.prototype.getLevel = function() {
+  return goog.debug.LOGGING_ENABLED ?
+      this.level_ : goog.debug.Logger.Level.OFF;
+};
+
+
+/**
+ * Returns the effective level of the logger based on its ancestors' levels.
+ * @return {goog.debug.Logger.Level} The level.
+ */
+goog.debug.Logger.prototype.getEffectiveLevel = function() {
+  if (!goog.debug.LOGGING_ENABLED) {
+    return goog.debug.Logger.Level.OFF;
+  }
+
+  if (!goog.debug.Logger.ENABLE_HIERARCHY) {
+    return goog.debug.Logger.rootLevel_;
+  }
+  if (this.level_) {
+    return this.level_;
+  }
+  if (this.parent_) {
+    return this.parent_.getEffectiveLevel();
+  }
+  goog.asserts.fail('Root logger has no level set.');
+  return null;
+};
+
+
+/**
+ * Checks if a message of the given level would actually be logged by this
+ * logger. This check is based on the Loggers effective level, which may be
+ * inherited from its parent.
+ * @param {goog.debug.Logger.Level} level The level to check.
+ * @return {boolean} Whether the message would be logged.
+ */
+goog.debug.Logger.prototype.isLoggable = function(level) {
+  return goog.debug.LOGGING_ENABLED &&
+      level.value >= this.getEffectiveLevel().value;
+};
+
+
+/**
+ * Logs a message. If the logger is currently enabled for the
+ * given message level then the given message is forwarded to all the
+ * registered output Handler objects.
+ * @param {goog.debug.Logger.Level} level One of the level identifiers.
+ * @param {goog.debug.Loggable} msg The message to log.
+ * @param {Error|Object=} opt_exception An exception associated with the
+ *     message.
+ */
+goog.debug.Logger.prototype.log = function(level, msg, opt_exception) {
+  // java caches the effective level, not sure it's necessary here
+  if (goog.debug.LOGGING_ENABLED && this.isLoggable(level)) {
+    // Message callbacks can be useful when a log message is expensive to build.
+    if (goog.isFunction(msg)) {
+      msg = msg();
+    }
+
+    this.doLogRecord_(this.getLogRecord(level, msg, opt_exception));
+  }
+};
+
+
+/**
+ * Creates a new log record and adds the exception (if present) to it.
+ * @param {goog.debug.Logger.Level} level One of the level identifiers.
+ * @param {string} msg The string message.
+ * @param {Error|Object=} opt_exception An exception associated with the
+ *     message.
+ * @return {!goog.debug.LogRecord} A log record.
+ * @suppress {es5Strict}
+ */
+goog.debug.Logger.prototype.getLogRecord = function(
+    level, msg, opt_exception) {
+  if (goog.debug.LogBuffer.isBufferingEnabled()) {
+    var logRecord =
+        goog.debug.LogBuffer.getInstance().addRecord(level, msg, this.name_);
+  } else {
+    logRecord = new goog.debug.LogRecord(level, String(msg), this.name_);
+  }
+  if (opt_exception) {
+    logRecord.setException(opt_exception);
+  }
+  return logRecord;
+};
+
+
+/**
+ * Logs a message at the Logger.Level.SHOUT level.
+ * If the logger is currently enabled for the given message level then the
+ * given message is forwarded to all the registered output Handler objects.
+ * @param {goog.debug.Loggable} msg The message to log.
+ * @param {Error=} opt_exception An exception associated with the message.
+ */
+goog.debug.Logger.prototype.shout = function(msg, opt_exception) {
+  if (goog.debug.LOGGING_ENABLED) {
+    this.log(goog.debug.Logger.Level.SHOUT, msg, opt_exception);
+  }
+};
+
+
+/**
+ * Logs a message at the Logger.Level.SEVERE level.
+ * If the logger is currently enabled for the given message level then the
+ * given message is forwarded to all the registered output Handler objects.
+ * @param {goog.debug.Loggable} msg The message to log.
+ * @param {Error=} opt_exception An exception associated with the message.
+ */
+goog.debug.Logger.prototype.severe = function(msg, opt_exception) {
+  if (goog.debug.LOGGING_ENABLED) {
+    this.log(goog.debug.Logger.Level.SEVERE, msg, opt_exception);
+  }
+};
+
+
+/**
+ * Logs a message at the Logger.Level.WARNING level.
+ * If the logger is currently enabled for the given message level then the
+ * given message is forwarded to all the registered output Handler objects.
+ * @param {goog.debug.Loggable} msg The message to log.
+ * @param {Error=} opt_exception An exception associated with the message.
+ */
+goog.debug.Logger.prototype.warning = function(msg, opt_exception) {
+  if (goog.debug.LOGGING_ENABLED) {
+    this.log(goog.debug.Logger.Level.WARNING, msg, opt_exception);
+  }
+};
+
+
+/**
+ * Logs a message at the Logger.Level.INFO level.
+ * If the logger is currently enabled for the given message level then the
+ * given message is forwarded to all the registered output Handler objects.
+ * @param {goog.debug.Loggable} msg The message to log.
+ * @param {Error=} opt_exception An exception associated with the message.
+ */
+goog.debug.Logger.prototype.info = function(msg, opt_exception) {
+  if (goog.debug.LOGGING_ENABLED) {
+    this.log(goog.debug.Logger.Level.INFO, msg, opt_exception);
+  }
+};
+
+
+/**
+ * Logs a message at the Logger.Level.CONFIG level.
+ * If the logger is currently enabled for the given message level then the
+ * given message is forwarded to all the registered output Handler objects.
+ * @param {goog.debug.Loggable} msg The message to log.
+ * @param {Error=} opt_exception An exception associated with the message.
+ */
+goog.debug.Logger.prototype.config = function(msg, opt_exception) {
+  if (goog.debug.LOGGING_ENABLED) {
+    this.log(goog.debug.Logger.Level.CONFIG, msg, opt_exception);
+  }
+};
+
+
+/**
+ * Logs a message at the Logger.Level.FINE level.
+ * If the logger is currently enabled for the given message level then the
+ * given message is forwarded to all the registered output Handler objects.
+ * @param {goog.debug.Loggable} msg The message to log.
+ * @param {Error=} opt_exception An exception associated with the message.
+ */
+goog.debug.Logger.prototype.fine = function(msg, opt_exception) {
+  if (goog.debug.LOGGING_ENABLED) {
+    this.log(goog.debug.Logger.Level.FINE, msg, opt_exception);
+  }
+};
+
+
+/**
+ * Logs a message at the Logger.Level.FINER level.
+ * If the logger is currently enabled for the given message level then the
+ * given message is forwarded to all the registered output Handler objects.
+ * @param {goog.debug.Loggable} msg The message to log.
+ * @param {Error=} opt_exception An exception associated with the message.
+ */
+goog.debug.Logger.prototype.finer = function(msg, opt_exception) {
+  if (goog.debug.LOGGING_ENABLED) {
+    this.log(goog.debug.Logger.Level.FINER, msg, opt_exception);
+  }
+};
+
+
+/**
+ * Logs a message at the Logger.Level.FINEST level.
+ * If the logger is currently enabled for the given message level then the
+ * given message is forwarded to all the registered output Handler objects.
+ * @param {goog.debug.Loggable} msg The message to log.
+ * @param {Error=} opt_exception An exception associated with the message.
+ */
+goog.debug.Logger.prototype.finest = function(msg, opt_exception) {
+  if (goog.debug.LOGGING_ENABLED) {
+    this.log(goog.debug.Logger.Level.FINEST, msg, opt_exception);
+  }
+};
+
+
+/**
+ * Logs a LogRecord. If the logger is currently enabled for the
+ * given message level then the given message is forwarded to all the
+ * registered output Handler objects.
+ * @param {goog.debug.LogRecord} logRecord A log record to log.
+ */
+goog.debug.Logger.prototype.logRecord = function(logRecord) {
+  if (goog.debug.LOGGING_ENABLED && this.isLoggable(logRecord.getLevel())) {
+    this.doLogRecord_(logRecord);
+  }
+};
+
+
+/**
+ * Logs a LogRecord.
+ * @param {goog.debug.LogRecord} logRecord A log record to log.
+ * @private
+ */
+goog.debug.Logger.prototype.doLogRecord_ = function(logRecord) {
+  goog.debug.Logger.logToProfilers('log:' + logRecord.getMessage());
+  if (goog.debug.Logger.ENABLE_HIERARCHY) {
+    var target = this;
+    while (target) {
+      target.callPublish_(logRecord);
+      target = target.getParent();
+    }
+  } else {
+    for (var i = 0, handler; handler = goog.debug.Logger.rootHandlers_[i++]; ) {
+      handler(logRecord);
+    }
+  }
+};
+
+
+/**
+ * Calls the handlers for publish.
+ * @param {goog.debug.LogRecord} logRecord The log record to publish.
+ * @private
+ */
+goog.debug.Logger.prototype.callPublish_ = function(logRecord) {
+  if (this.handlers_) {
+    for (var i = 0, handler; handler = this.handlers_[i]; i++) {
+      handler(logRecord);
+    }
+  }
+};
+
+
+/**
+ * Sets the parent of this logger. This is used for setting up the logger tree.
+ * @param {goog.debug.Logger} parent The parent logger.
+ * @private
+ */
+goog.debug.Logger.prototype.setParent_ = function(parent) {
+  this.parent_ = parent;
+};
+
+
+/**
+ * Adds a child to this logger. This is used for setting up the logger tree.
+ * @param {string} name The leaf name of the child.
+ * @param {goog.debug.Logger} logger The child logger.
+ * @private
+ */
+goog.debug.Logger.prototype.addChild_ = function(name, logger) {
+  this.getChildren()[name] = logger;
+};
+
+
+/**
+ * There is a single global LogManager object that is used to maintain a set of
+ * shared state about Loggers and log services. This is loosely based on the
+ * java class java.util.logging.LogManager.
+ * @const
+ */
+goog.debug.LogManager = {};
+
+
+/**
+ * Map of logger names to logger objects.
+ *
+ * @type {!Object<string, !goog.debug.Logger>}
+ * @private
+ */
+goog.debug.LogManager.loggers_ = {};
+
+
+/**
+ * The root logger which is the root of the logger tree.
+ * @type {goog.debug.Logger}
+ * @private
+ */
+goog.debug.LogManager.rootLogger_ = null;
+
+
+/**
+ * Initializes the LogManager if not already initialized.
+ */
+goog.debug.LogManager.initialize = function() {
+  if (!goog.debug.LogManager.rootLogger_) {
+    goog.debug.LogManager.rootLogger_ = new goog.debug.Logger(
+        goog.debug.Logger.ROOT_LOGGER_NAME);
+    goog.debug.LogManager.loggers_[goog.debug.Logger.ROOT_LOGGER_NAME] =
+        goog.debug.LogManager.rootLogger_;
+    goog.debug.LogManager.rootLogger_.setLevel(goog.debug.Logger.Level.CONFIG);
+  }
+};
+
+
+/**
+ * Returns all the loggers.
+ * @return {!Object<string, !goog.debug.Logger>} Map of logger names to logger
+ *     objects.
+ */
+goog.debug.LogManager.getLoggers = function() {
+  return goog.debug.LogManager.loggers_;
+};
+
+
+/**
+ * Returns the root of the logger tree namespace, the logger with the empty
+ * string as its name.
+ *
+ * @return {!goog.debug.Logger} The root logger.
+ */
+goog.debug.LogManager.getRoot = function() {
+  goog.debug.LogManager.initialize();
+  return /** @type {!goog.debug.Logger} */ (goog.debug.LogManager.rootLogger_);
+};
+
+
+/**
+ * Finds a named logger.
+ *
+ * @param {string} name A name for the logger. This should be a dot-separated
+ * name and should normally be based on the package name or class name of the
+ * subsystem, such as goog.net.BrowserChannel.
+ * @return {!goog.debug.Logger} The named logger.
+ */
+goog.debug.LogManager.getLogger = function(name) {
+  goog.debug.LogManager.initialize();
+  var ret = goog.debug.LogManager.loggers_[name];
+  return ret || goog.debug.LogManager.createLogger_(name);
+};
+
+
+/**
+ * Creates a function that can be passed to goog.debug.catchErrors. The function
+ * will log all reported errors using the given logger.
+ * @param {goog.debug.Logger=} opt_logger The logger to log the errors to.
+ *     Defaults to the root logger.
+ * @return {function(Object)} The created function.
+ */
+goog.debug.LogManager.createFunctionForCatchErrors = function(opt_logger) {
+  return function(info) {
+    var logger = opt_logger || goog.debug.LogManager.getRoot();
+    logger.severe('Error: ' + info.message + ' (' + info.fileName +
+                  ' @ Line: ' + info.line + ')');
+  };
+};
+
+
+/**
+ * Creates the named logger. Will also create the parents of the named logger
+ * if they don't yet exist.
+ * @param {string} name The name of the logger.
+ * @return {!goog.debug.Logger} The named logger.
+ * @private
+ */
+goog.debug.LogManager.createLogger_ = function(name) {
+  // find parent logger
+  var logger = new goog.debug.Logger(name);
+  if (goog.debug.Logger.ENABLE_HIERARCHY) {
+    var lastDotIndex = name.lastIndexOf('.');
+    var parentName = name.substr(0, lastDotIndex);
+    var leafName = name.substr(lastDotIndex + 1);
+    var parentLogger = goog.debug.LogManager.getLogger(parentName);
+
+    // tell the parent about the child and the child about the parent
+    parentLogger.addChild_(leafName, logger);
+    logger.setParent_(parentLogger);
+  }
+
+  goog.debug.LogManager.loggers_[name] = logger;
+  return logger;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/logrecord.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/logrecord.js b/externs/GCL/externs/goog/debug/logrecord.js
new file mode 100644
index 0000000..df5f982
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/logrecord.js
@@ -0,0 +1,242 @@
+// 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 Definition of the LogRecord class. Please minimize
+ * dependencies this file has on other closure classes as any dependency it
+ * takes won't be able to use the logging infrastructure.
+ *
+ */
+
+goog.provide('goog.debug.LogRecord');
+
+
+
+/**
+ * LogRecord objects are used to pass logging requests between
+ * the logging framework and individual log Handlers.
+ * @constructor
+ * @param {goog.debug.Logger.Level} level One of the level identifiers.
+ * @param {string} msg The string message.
+ * @param {string} loggerName The name of the source logger.
+ * @param {number=} opt_time Time this log record was created if other than now.
+ *     If 0, we use #goog.now.
+ * @param {number=} opt_sequenceNumber Sequence number of this log record. This
+ *     should only be passed in when restoring a log record from persistence.
+ */
+goog.debug.LogRecord = function(level, msg, loggerName,
+    opt_time, opt_sequenceNumber) {
+  this.reset(level, msg, loggerName, opt_time, opt_sequenceNumber);
+};
+
+
+/**
+ * Time the LogRecord was created.
+ * @type {number}
+ * @private
+ */
+goog.debug.LogRecord.prototype.time_;
+
+
+/**
+ * Level of the LogRecord
+ * @type {goog.debug.Logger.Level}
+ * @private
+ */
+goog.debug.LogRecord.prototype.level_;
+
+
+/**
+ * Message associated with the record
+ * @type {string}
+ * @private
+ */
+goog.debug.LogRecord.prototype.msg_;
+
+
+/**
+ * Name of the logger that created the record.
+ * @type {string}
+ * @private
+ */
+goog.debug.LogRecord.prototype.loggerName_;
+
+
+/**
+ * Sequence number for the LogRecord. Each record has a unique sequence number
+ * that is greater than all log records created before it.
+ * @type {number}
+ * @private
+ */
+goog.debug.LogRecord.prototype.sequenceNumber_ = 0;
+
+
+/**
+ * Exception associated with the record
+ * @type {Object}
+ * @private
+ */
+goog.debug.LogRecord.prototype.exception_ = null;
+
+
+/**
+ * @define {boolean} Whether to enable log sequence numbers.
+ */
+goog.define('goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS', true);
+
+
+/**
+ * A sequence counter for assigning increasing sequence numbers to LogRecord
+ * objects.
+ * @type {number}
+ * @private
+ */
+goog.debug.LogRecord.nextSequenceNumber_ = 0;
+
+
+/**
+ * Sets all fields of the log record.
+ * @param {goog.debug.Logger.Level} level One of the level identifiers.
+ * @param {string} msg The string message.
+ * @param {string} loggerName The name of the source logger.
+ * @param {number=} opt_time Time this log record was created if other than now.
+ *     If 0, we use #goog.now.
+ * @param {number=} opt_sequenceNumber Sequence number of this log record. This
+ *     should only be passed in when restoring a log record from persistence.
+ */
+goog.debug.LogRecord.prototype.reset = function(level, msg, loggerName,
+    opt_time, opt_sequenceNumber) {
+  if (goog.debug.LogRecord.ENABLE_SEQUENCE_NUMBERS) {
+    this.sequenceNumber_ = typeof opt_sequenceNumber == 'number' ?
+        opt_sequenceNumber : goog.debug.LogRecord.nextSequenceNumber_++;
+  }
+
+  this.time_ = opt_time || goog.now();
+  this.level_ = level;
+  this.msg_ = msg;
+  this.loggerName_ = loggerName;
+  delete this.exception_;
+};
+
+
+/**
+ * Get the source Logger's name.
+ *
+ * @return {string} source logger name (may be null).
+ */
+goog.debug.LogRecord.prototype.getLoggerName = function() {
+  return this.loggerName_;
+};
+
+
+/**
+ * Get the exception that is part of the log record.
+ *
+ * @return {Object} the exception.
+ */
+goog.debug.LogRecord.prototype.getException = function() {
+  return this.exception_;
+};
+
+
+/**
+ * Set the exception that is part of the log record.
+ *
+ * @param {Object} exception the exception.
+ */
+goog.debug.LogRecord.prototype.setException = function(exception) {
+  this.exception_ = exception;
+};
+
+
+/**
+ * Get the source Logger's name.
+ *
+ * @param {string} loggerName source logger name (may be null).
+ */
+goog.debug.LogRecord.prototype.setLoggerName = function(loggerName) {
+  this.loggerName_ = loggerName;
+};
+
+
+/**
+ * Get the logging message level, for example Level.SEVERE.
+ * @return {goog.debug.Logger.Level} the logging message level.
+ */
+goog.debug.LogRecord.prototype.getLevel = function() {
+  return this.level_;
+};
+
+
+/**
+ * Set the logging message level, for example Level.SEVERE.
+ * @param {goog.debug.Logger.Level} level the logging message level.
+ */
+goog.debug.LogRecord.prototype.setLevel = function(level) {
+  this.level_ = level;
+};
+
+
+/**
+ * Get the "raw" log message, before localization or formatting.
+ *
+ * @return {string} the raw message string.
+ */
+goog.debug.LogRecord.prototype.getMessage = function() {
+  return this.msg_;
+};
+
+
+/**
+ * Set the "raw" log message, before localization or formatting.
+ *
+ * @param {string} msg the raw message string.
+ */
+goog.debug.LogRecord.prototype.setMessage = function(msg) {
+  this.msg_ = msg;
+};
+
+
+/**
+ * Get event time in milliseconds since 1970.
+ *
+ * @return {number} event time in millis since 1970.
+ */
+goog.debug.LogRecord.prototype.getMillis = function() {
+  return this.time_;
+};
+
+
+/**
+ * Set event time in milliseconds since 1970.
+ *
+ * @param {number} time event time in millis since 1970.
+ */
+goog.debug.LogRecord.prototype.setMillis = function(time) {
+  this.time_ = time;
+};
+
+
+/**
+ * Get the sequence number.
+ * <p>
+ * Sequence numbers are normally assigned in the LogRecord
+ * constructor, which assigns unique sequence numbers to
+ * each new LogRecord in increasing order.
+ * @return {number} the sequence number.
+ */
+goog.debug.LogRecord.prototype.getSequenceNumber = function() {
+  return this.sequenceNumber_;
+};
+


[41/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/datasource/fastdatanode.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/datasource/fastdatanode.js b/externs/GCL/externs/goog/datasource/fastdatanode.js
new file mode 100644
index 0000000..c14750f
--- /dev/null
+++ b/externs/GCL/externs/goog/datasource/fastdatanode.js
@@ -0,0 +1,814 @@
+// 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
+ * Efficient implementation of DataNode API.
+ *
+ * The implementation consists of three concrete classes for modelling
+ * DataNodes with different characteristics: FastDataNode,
+ * FastPrimitiveDataNode and FastListNode.
+ *
+ * FastDataNode is for bean-like or map-like objects that consists of
+ * key/value mappings and where the primary access pattern is by key.
+ *
+ * FastPrimitiveDataNode wraps primitives like strings, boolean, and numbers.
+ *
+ * FastListNode is for array-like data nodes. It also supports key-based
+ * lookups if the data nodes have an "id" property or if child nodes are
+ * explicitly added by name. It is most efficient if these features are not
+ * used.
+ *
+ * FastDataNodes can be constructed from JSON-like objects via the function
+ * goog.ds.FastDataNode.fromJs.
+
+ */
+
+goog.provide('goog.ds.AbstractFastDataNode');
+goog.provide('goog.ds.FastDataNode');
+goog.provide('goog.ds.FastListNode');
+goog.provide('goog.ds.PrimitiveFastDataNode');
+
+goog.require('goog.ds.DataManager');
+goog.require('goog.ds.DataNodeList');
+goog.require('goog.ds.EmptyNodeList');
+goog.require('goog.string');
+
+/*
+ * Implementation note: In order to reduce the number of objects,
+ * FastDataNode stores its key/value mappings directly in the FastDataNode
+ * object iself (instead of a separate map). To make this work we have to
+ * sure that there are no name clashes with other attribute names used by
+ * FastDataNode (like dataName and parent). This is especially difficult in
+ * the light of automatic renaming by the JavaScript compiler. For this reason,
+ * all internal attributes start with "__" so that they are not renamed
+ * by the compiler.
+ */
+
+/**
+ * Creates a new abstract data node.
+ * @param {string} dataName Name of the datanode.
+ * @param {goog.ds.DataNode=} opt_parent Parent of this data node.
+ * @constructor
+ * @extends {goog.ds.DataNodeList}
+ */
+// TODO(arv): Use interfaces when available.
+goog.ds.AbstractFastDataNode = function(dataName, opt_parent) {
+  if (!dataName) {
+    throw Error('Cannot create a fast data node without a data name');
+  }
+  this['__dataName'] = dataName;
+  this['__parent'] = opt_parent;
+};
+
+
+/**
+ * Return the name of this data node.
+ * @return {string} Name of this data noden.
+ * @override
+ */
+goog.ds.AbstractFastDataNode.prototype.getDataName = function() {
+  return this['__dataName'];
+};
+
+
+/**
+ * Set the name of this data node.
+ * @param {string} value Name.
+ * @override
+ */
+goog.ds.AbstractFastDataNode.prototype.setDataName = function(value) {
+  this['__dataName'] = value;
+};
+
+
+/**
+ * Get the path leading to this data node.
+ * @return {string} Data path.
+ * @override
+ */
+goog.ds.AbstractFastDataNode.prototype.getDataPath = function() {
+  var parentPath;
+  if (this['__parent']) {
+    parentPath = this['__parent'].getDataPath() + goog.ds.STR_PATH_SEPARATOR;
+  } else {
+    parentPath = '';
+  }
+  return parentPath + this.getDataName();
+};
+
+
+
+/**
+ * Creates a new fast data node, using the properties of root.
+ * @param {Object} root JSON-like object to initialize data node from.
+ * @param {string} dataName Name of this data node.
+ * @param {goog.ds.DataNode=} opt_parent Parent of this data node.
+ * @extends {goog.ds.AbstractFastDataNode}
+ * @constructor
+ */
+goog.ds.FastDataNode = function(root, dataName, opt_parent) {
+  goog.ds.AbstractFastDataNode.call(this, dataName, opt_parent);
+  this.extendWith(root);
+};
+goog.inherits(goog.ds.FastDataNode, goog.ds.AbstractFastDataNode);
+
+
+/**
+ * Add all attributes of object to this data node.
+ * @param {Object} object Object to add attributes from.
+ * @protected
+ */
+goog.ds.FastDataNode.prototype.extendWith = function(object) {
+  for (var key in object) {
+    this[key] = object[key];
+  }
+};
+
+
+/**
+ * Creates a new FastDataNode structure initialized from object. This will
+ * return an instance of the most suitable sub-class of FastDataNode.
+ *
+ * You should not modify object after creating a fast data node from it
+ * or assume that changing object changes the data node. Doing so results
+ * in undefined behaviour.
+ *
+ * @param {Object|number|boolean|string} object Object to initialize data
+ *     node from.
+ * @param {string} dataName Name of data node.
+ * @param {goog.ds.DataNode=} opt_parent Parent of data node.
+ * @return {!goog.ds.AbstractFastDataNode} Data node representing object.
+ */
+goog.ds.FastDataNode.fromJs = function(object, dataName, opt_parent) {
+  if (goog.isArray(object)) {
+    return new goog.ds.FastListNode(object, dataName, opt_parent);
+  } else if (goog.isObject(object)) {
+    return new goog.ds.FastDataNode(object, dataName, opt_parent);
+  } else {
+    return new goog.ds.PrimitiveFastDataNode(object || !!object,
+                                             dataName,
+                                             opt_parent);
+  }
+};
+
+
+/**
+ * Static instance of an empty list.
+ * @type {!goog.ds.EmptyNodeList}
+ * @private
+ */
+goog.ds.FastDataNode.emptyList_ = new goog.ds.EmptyNodeList();
+
+
+/**
+ * Not supported for normal FastDataNodes.
+ * @param {*} value Value to set data node to.
+ * @override
+ */
+goog.ds.FastDataNode.prototype.set = function(value) {
+  throw new Error('Not implemented yet');
+};
+
+
+/** @override */
+goog.ds.FastDataNode.prototype.getChildNodes = function(opt_selector) {
+  if (!opt_selector || opt_selector == goog.ds.STR_ALL_CHILDREN_SELECTOR) {
+    return this;
+  } else if (opt_selector.indexOf(goog.ds.STR_WILDCARD) == -1) {
+    var child = this.getChildNode(opt_selector);
+    return child ? new goog.ds.FastListNode([child], '') :
+        new goog.ds.EmptyNodeList();
+  } else {
+    throw Error('Unsupported selector: ' + opt_selector);
+  }
+};
+
+
+/**
+ * Makes sure that a named child is wrapped in a data node structure.
+ * @param {string} name Name of child to wrap.
+ * @private
+ */
+goog.ds.FastDataNode.prototype.wrapChild_ = function(name) {
+  var child = this[name];
+  if (child != null && !child.getDataName) {
+    this[name] = goog.ds.FastDataNode.fromJs(this[name], name, this);
+  }
+};
+
+
+/**
+ * Get a child node by name.
+ * @param {string} name Name of child node.
+ * @param {boolean=} opt_create Whether to create the child if it does not
+ * exist.
+ * @return {goog.ds.DataNode} Child node.
+ * @override
+ */
+goog.ds.FastDataNode.prototype.getChildNode = function(name, opt_create) {
+  this.wrapChild_(name);
+  // this[name] always is a data node object, so using "||" is fine.
+  var child = this[name] || null;
+  if (child == null && opt_create) {
+    child = new goog.ds.FastDataNode({}, name, this);
+    this[name] = child;
+  }
+  return child;
+};
+
+
+/**
+ * Sets a child node. Creates the child if it does not exist.
+ *
+ * Calling  this function makes any child nodes previously obtained for name
+ * invalid. You should not use these child nodes but instead obtain a new
+ * instance by calling getChildNode.
+ *
+ * @override
+ */
+goog.ds.FastDataNode.prototype.setChildNode = function(name, value) {
+  if (value != null) {
+    this[name] = value;
+  } else {
+    delete this[name];
+  }
+  goog.ds.DataManager.getInstance().fireDataChange(this.getDataPath() +
+      goog.ds.STR_PATH_SEPARATOR + name);
+  return null;
+};
+
+
+/**
+ * Returns the value of a child node. By using this method you can avoid
+ * the need to create PrimitiveFastData nodes.
+ * @param {string} name Name of child node.
+ * @return {Object} Value of child node.
+ * @override
+ */
+goog.ds.FastDataNode.prototype.getChildNodeValue = function(name) {
+  var child = this[name];
+  if (child != null) {
+    return (child.getDataName ? child.get() : child);
+  } else {
+    return null;
+  }
+};
+
+
+/**
+ * Returns whether this data node is a list. Always returns false for
+ * instances of FastDataNode but may return true for subclasses.
+ * @return {boolean} Whether this data node is array-like.
+ * @override
+ */
+goog.ds.FastDataNode.prototype.isList = function() {
+  return false;
+};
+
+
+/**
+ * Returns a javascript object representation of this data node. You should
+ * not modify the object returned by this function.
+ * @return {!Object} Javascript object representation of this data node.
+ */
+goog.ds.FastDataNode.prototype.getJsObject = function() {
+  var result = {};
+  for (var key in this) {
+    if (!goog.string.startsWith(key, '__') && !goog.isFunction(this[key])) {
+      result[key] = (this[key]['__dataName'] ? this[key].getJsObject() :
+          this[key]);
+    }
+  }
+  return result;
+};
+
+
+/**
+ * Creates a deep copy of this data node.
+ * @return {goog.ds.FastDataNode} Clone of this data node.
+ */
+goog.ds.FastDataNode.prototype.clone = function() {
+  return /** @type {!goog.ds.FastDataNode} */(goog.ds.FastDataNode.fromJs(
+      this.getJsObject(), this.getDataName()));
+};
+
+
+/*
+ * Implementation of goog.ds.DataNodeList for FastDataNode.
+ */
+
+
+/**
+ * Adds a child to this data node.
+ * @param {goog.ds.DataNode} value Child node to add.
+ * @override
+ */
+goog.ds.FastDataNode.prototype.add = function(value) {
+  this.setChildNode(value.getDataName(), value);
+};
+
+
+/**
+ * Gets the value of this data node (if called without opt_key) or
+ * gets a child node (if called with opt_key).
+ * @param {string=} opt_key Name of child node.
+ * @return {*} This data node or a child node.
+ * @override
+ */
+goog.ds.FastDataNode.prototype.get = function(opt_key) {
+  if (!goog.isDef(opt_key)) {
+    // if there is no key, DataNode#get was called
+    return this;
+  } else {
+    return this.getChildNode(opt_key);
+  }
+};
+
+
+/**
+ * Gets a child node by index. This method has a complexity of O(n) where
+ * n is the number of children. If you need a faster implementation of this
+ * method, you should use goog.ds.FastListNode.
+ * @param {number} index Index of child node (starting from 0).
+ * @return {goog.ds.DataNode} Child node at specified index.
+ * @override
+ */
+goog.ds.FastDataNode.prototype.getByIndex = function(index) {
+  var i = 0;
+  for (var key in this) {
+    if (!goog.string.startsWith(key, '__') && !goog.isFunction(this[key])) {
+      if (i == index) {
+        this.wrapChild_(key);
+        return this[key];
+      }
+      ++i;
+    }
+  }
+  return null;
+};
+
+
+/**
+ * Gets the number of child nodes. This method has a complexity of O(n) where
+ * n is the number of children. If you need a faster implementation of this
+ * method, you should use goog.ds.FastListNode.
+ * @return {number} Number of child nodes.
+ * @override
+ */
+goog.ds.FastDataNode.prototype.getCount = function() {
+  var count = 0;
+  for (var key in this) {
+    if (!goog.string.startsWith(key, '__') && !goog.isFunction(this[key])) {
+      ++count;
+    }
+  }
+  // maybe cache this?
+  return count;
+};
+
+
+/**
+ * Sets a child node.
+ * @param {string} name Name of child node.
+ * @param {Object} value Value of child node.
+ * @override
+ */
+goog.ds.FastDataNode.prototype.setNode = function(name, value) {
+  this.setChildNode(name, value);
+};
+
+
+/**
+ * Removes a child node.
+ * @override
+ */
+goog.ds.FastDataNode.prototype.removeNode = function(name) {
+  delete this[name];
+  return false;
+};
+
+
+
+/**
+ * Creates a new data node wrapping a primitive value.
+ * @param {number|boolean|string} value Value the value to wrap.
+ * @param {string} dataName name Name of this data node.
+ * @param {goog.ds.DataNode=} opt_parent Parent of this data node.
+ * @extends {goog.ds.AbstractFastDataNode}
+ * @constructor
+ * @final
+ */
+goog.ds.PrimitiveFastDataNode = function(value, dataName, opt_parent) {
+  this.value_ = value;
+  goog.ds.AbstractFastDataNode.call(this, dataName, opt_parent);
+};
+goog.inherits(goog.ds.PrimitiveFastDataNode, goog.ds.AbstractFastDataNode);
+
+
+/**
+ * Returns the value of this data node.
+ * @return {(boolean|number|string)} Value of this data node.
+ * @override
+ */
+goog.ds.PrimitiveFastDataNode.prototype.get = function() {
+  return this.value_;
+};
+
+
+/**
+ * Sets this data node to a new value.
+ * @param {*} value Value to set data node to.
+ * @override
+ */
+goog.ds.PrimitiveFastDataNode.prototype.set = function(value) {
+  if (goog.isArray(value) || goog.isObject(value)) {
+    throw Error('can only set PrimitiveFastDataNode to primitive values');
+  }
+  this.value_ = value;
+  goog.ds.DataManager.getInstance().fireDataChange(this.getDataPath());
+};
+
+
+/**
+ * Returns child nodes of this data node. Always returns an unmodifiable,
+ * empty list.
+ * @return {!goog.ds.DataNodeList} (Empty) list of child nodes.
+ * @override
+ */
+goog.ds.PrimitiveFastDataNode.prototype.getChildNodes = function() {
+  return goog.ds.FastDataNode.emptyList_;
+};
+
+
+/**
+ * Get a child node by name. Always returns null.
+ * @param {string} name Name of child node.
+ * @return {goog.ds.DataNode} Child node.
+ * @override
+ */
+goog.ds.PrimitiveFastDataNode.prototype.getChildNode = function(name) {
+  return null;
+};
+
+
+/**
+ * Returns the value of a child node. Always returns null.
+ * @param {string} name Name of child node.
+ * @return {Object} Value of child node.
+ * @override
+ */
+goog.ds.PrimitiveFastDataNode.prototype.getChildNodeValue = function(name) {
+  return null;
+};
+
+
+/**
+ * Not supported by primitive data nodes.
+ * @param {string} name Name of child node.
+ * @param {Object} value Value of child node.
+ * @override
+ */
+goog.ds.PrimitiveFastDataNode.prototype.setChildNode =
+    function(name, value) {
+  throw Error('Cannot set a child node for a PrimitiveFastDataNode');
+};
+
+
+/**
+ * Returns whether this data node is a list. Always returns false for
+ * instances of PrimitiveFastDataNode.
+ * @return {boolean} Whether this data node is array-like.
+ * @override
+ */
+goog.ds.PrimitiveFastDataNode.prototype.isList = function() {
+  return false;
+};
+
+
+/**
+ * Returns a javascript object representation of this data node. You should
+ * not modify the object returned by this function.
+ * @return {*} Javascript object representation of this data node.
+ */
+goog.ds.PrimitiveFastDataNode.prototype.getJsObject = function() {
+  return this.value_;
+};
+
+
+/**
+ * Creates a new list node from an array.
+ * @param {Array<?>} values values hold by this list node.
+ * @param {string} dataName name of this node.
+ * @param {goog.ds.DataNode=} opt_parent parent of this node.
+ * @extends {goog.ds.AbstractFastDataNode}
+ * @constructor
+ * @final
+ */
+// TODO(arv): Use interfaces when available.  This implements DataNodeList
+// as well.
+goog.ds.FastListNode = function(values, dataName, opt_parent) {
+  this.values_ = [];
+  for (var i = 0; i < values.length; ++i) {
+    var name = values[i].id || ('[' + i + ']');
+    this.values_.push(goog.ds.FastDataNode.fromJs(values[i], name, this));
+    if (values[i].id) {
+      if (!this.map_) {
+        this.map_ = {};
+      }
+      this.map_[values[i].id] = i;
+    }
+  }
+  goog.ds.AbstractFastDataNode.call(this, dataName, opt_parent);
+};
+goog.inherits(goog.ds.FastListNode, goog.ds.AbstractFastDataNode);
+
+
+/**
+ * Not supported for FastListNodes.
+ * @param {*} value Value to set data node to.
+ * @override
+ */
+goog.ds.FastListNode.prototype.set = function(value) {
+  throw Error('Cannot set a FastListNode to a new value');
+};
+
+
+/**
+ * Returns child nodes of this data node. Currently, only supports
+ * returning all children.
+ * @return {!goog.ds.DataNodeList} List of child nodes.
+ * @override
+ */
+goog.ds.FastListNode.prototype.getChildNodes = function() {
+  return this;
+};
+
+
+/**
+ * Get a child node by name.
+ * @param {string} key Name of child node.
+ * @param {boolean=} opt_create Whether to create the child if it does not
+ * exist.
+ * @return {goog.ds.DataNode} Child node.
+ * @override
+ */
+goog.ds.FastListNode.prototype.getChildNode = function(key, opt_create) {
+  var index = this.getKeyAsNumber_(key);
+  if (index == null && this.map_) {
+    index = this.map_[key];
+  }
+  if (index != null && this.values_[index]) {
+    return this.values_[index];
+  } else if (opt_create) {
+    this.setChildNode(key, {});
+    return this.getChildNode(key);
+  } else {
+    return null;
+  }
+};
+
+
+/**
+ * Returns the value of a child node.
+ * @param {string} key Name of child node.
+ * @return {*} Value of child node.
+ * @override
+ */
+goog.ds.FastListNode.prototype.getChildNodeValue = function(key) {
+  var child = this.getChildNode(key);
+  return (child ? child.get() : null);
+};
+
+
+/**
+ * Tries to interpret key as a numeric index enclosed by square brakcets.
+ * @param {string} key Key that should be interpreted as a number.
+ * @return {?number} Numeric index or null if key is not of the form
+ *  described above.
+ * @private
+ */
+goog.ds.FastListNode.prototype.getKeyAsNumber_ = function(key) {
+  if (key.charAt(0) == '[' && key.charAt(key.length - 1) == ']') {
+    return Number(key.substring(1, key.length - 1));
+  } else {
+    return null;
+  }
+};
+
+
+/**
+ * Sets a child node. Creates the child if it does not exist. To set
+ * children at a certain index, use a key of the form '[index]'. Note, that
+ * you can only set values at existing numeric indices. To add a new node
+ * to this list, you have to use the add method.
+ *
+ * Calling  this function makes any child nodes previously obtained for name
+ * invalid. You should not use these child nodes but instead obtain a new
+ * instance by calling getChildNode.
+ *
+ * @override
+ */
+goog.ds.FastListNode.prototype.setChildNode = function(key, value) {
+  var count = this.values_.length;
+  if (value != null) {
+    if (!value.getDataName) {
+      value = goog.ds.FastDataNode.fromJs(value, key, this);
+    }
+    var index = this.getKeyAsNumber_(key);
+    if (index != null) {
+      if (index < 0 || index >= this.values_.length) {
+        throw Error('List index out of bounds: ' + index);
+      }
+      this.values_[key] = value;
+    } else {
+      if (!this.map_) {
+        this.map_ = {};
+      }
+      this.values_.push(value);
+      this.map_[key] = this.values_.length - 1;
+    }
+  } else {
+    this.removeNode(key);
+  }
+  var dm = goog.ds.DataManager.getInstance();
+  dm.fireDataChange(this.getDataPath() + goog.ds.STR_PATH_SEPARATOR + key);
+  if (this.values_.length != count) {
+    this.listSizeChanged_();
+  }
+  return null;
+};
+
+
+/**
+ * Fire data changes that are appropriate when the size of this list changes.
+ * Should be called whenever the list size has changed.
+ * @private
+ */
+goog.ds.FastListNode.prototype.listSizeChanged_ = function() {
+  var dm = goog.ds.DataManager.getInstance();
+  dm.fireDataChange(this.getDataPath());
+  dm.fireDataChange(this.getDataPath() + goog.ds.STR_PATH_SEPARATOR +
+      'count()');
+};
+
+
+/**
+ * Returns whether this data node is a list. Always returns true.
+ * @return {boolean} Whether this data node is array-like.
+ * @override
+ */
+goog.ds.FastListNode.prototype.isList = function() {
+  return true;
+};
+
+
+/**
+ * Returns a javascript object representation of this data node. You should
+ * not modify the object returned by this function.
+ * @return {!Object} Javascript object representation of this data node.
+ */
+goog.ds.FastListNode.prototype.getJsObject = function() {
+  var result = [];
+  for (var i = 0; i < this.values_.length; ++i) {
+    result.push(this.values_[i].getJsObject());
+  }
+  return result;
+};
+
+
+/*
+ * Implementation of goog.ds.DataNodeList for FastListNode.
+ */
+
+
+/**
+ * Adds a child to this data node
+ * @param {goog.ds.DataNode} value Child node to add.
+ * @override
+ */
+goog.ds.FastListNode.prototype.add = function(value) {
+  if (!value.getDataName) {
+    value = goog.ds.FastDataNode.fromJs(value,
+        String('[' + (this.values_.length) + ']'), this);
+  }
+  this.values_.push(value);
+  var dm = goog.ds.DataManager.getInstance();
+  dm.fireDataChange(this.getDataPath() + goog.ds.STR_PATH_SEPARATOR +
+      '[' + (this.values_.length - 1) + ']');
+  this.listSizeChanged_();
+};
+
+
+/**
+ * Gets the value of this data node (if called without opt_key) or
+ * gets a child node (if called with opt_key).
+ * @param {string=} opt_key Name of child node.
+ * @return {Array|goog.ds.DataNode} Array of child nodes (if called without
+ *     opt_key), or a named child node otherwise.
+ * @override
+ */
+goog.ds.FastListNode.prototype.get = function(opt_key) {
+  // if there are no arguments, DataNode.get was called
+  if (!goog.isDef(opt_key)) {
+    return this.values_;
+  } else {
+    return this.getChildNode(opt_key);
+  }
+};
+
+
+/**
+ * Gets a child node by (numeric) index.
+ * @param {number} index Index of child node (starting from 0).
+ * @return {goog.ds.DataNode} Child node at specified index.
+ * @override
+ */
+goog.ds.FastListNode.prototype.getByIndex = function(index) {
+  var child = this.values_[index];
+  return (child != null ? child : null); // never return undefined
+};
+
+
+/**
+ * Gets the number of child nodes.
+ * @return {number} Number of child nodes.
+ * @override
+ */
+goog.ds.FastListNode.prototype.getCount = function() {
+  return this.values_.length;
+};
+
+
+/**
+ * Sets a child node.
+ * @param {string} name Name of child node.
+ * @param {Object} value Value of child node.
+ * @override
+ */
+goog.ds.FastListNode.prototype.setNode = function(name, value) {
+  throw Error('Setting child nodes of a FastListNode is not implemented, yet');
+};
+
+
+/**
+ * Removes a child node.
+ * @override
+ */
+goog.ds.FastListNode.prototype.removeNode = function(name) {
+  var index = this.getKeyAsNumber_(name);
+  if (index == null && this.map_) {
+    index = this.map_[name];
+  }
+  if (index != null) {
+    this.values_.splice(index, 1);
+    if (this.map_) {
+      var keyToDelete = null;
+      for (var key in this.map_) {
+        if (this.map_[key] == index) {
+          keyToDelete = key;
+        } else if (this.map_[key] > index) {
+          --this.map_[key];
+        }
+      }
+      if (keyToDelete) {
+        delete this.map_[keyToDelete];
+      }
+    }
+    var dm = goog.ds.DataManager.getInstance();
+    dm.fireDataChange(this.getDataPath() + goog.ds.STR_PATH_SEPARATOR +
+        '[' + index + ']');
+    this.listSizeChanged_();
+  }
+  return false;
+};
+
+
+/**
+ * Returns the index of a named child nodes. This method only works if
+ * this list uses mixed name/indexed lookup, i.e. if its child node have
+ * an 'id' attribute.
+ * @param {string} name Name of child node to determine index of.
+ * @return {number} Index of child node named name.
+ */
+goog.ds.FastListNode.prototype.indexOf = function(name) {
+  var index = this.getKeyAsNumber_(name);
+  if (index == null && this.map_) {
+    index = this.map_[name];
+  }
+  if (index == null) {
+    throw Error('Cannot determine index for: ' + name);
+  }
+  return /** @type {number} */(index);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/datasource/jsdatasource.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/datasource/jsdatasource.js b/externs/GCL/externs/goog/datasource/jsdatasource.js
new file mode 100644
index 0000000..ccd469e
--- /dev/null
+++ b/externs/GCL/externs/goog/datasource/jsdatasource.js
@@ -0,0 +1,462 @@
+// 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 An implementation of DataNode for wrapping JS data.
+ *
+ */
+
+
+goog.provide('goog.ds.JsDataSource');
+goog.provide('goog.ds.JsPropertyDataSource');
+
+goog.require('goog.ds.BaseDataNode');
+goog.require('goog.ds.BasicNodeList');
+goog.require('goog.ds.DataManager');
+goog.require('goog.ds.DataNode');
+goog.require('goog.ds.EmptyNodeList');
+goog.require('goog.ds.LoadState');
+
+
+/**
+ * Data source whose backing is JavaScript data
+ *
+ * Names that are reserved for system use and shouldn't be used for data node
+ * names: eval, toSource, toString, unwatch, valueOf, watch. Behavior is
+ * undefined if these names are used.
+ *
+ * @param {Object} root The root JS node.
+ * @param {string} dataName The name of this node relative to the parent node.
+ * @param {Object=} opt_parent Optional parent of this JsDataSource.
+ *
+ * implements goog.ds.DataNode.
+ * @constructor
+ * @extends {goog.ds.DataNode}
+ */
+// TODO(arv): Use interfaces when available.
+goog.ds.JsDataSource = function(root, dataName, opt_parent) {
+  this.parent_ = opt_parent;
+  this.dataName_ = dataName;
+  this.setRoot(root);
+};
+
+
+/**
+ * The root JS object. Can be null.
+ * @type {*}
+ * @protected
+ * @suppress {underscore|visibility}
+ */
+goog.ds.JsDataSource.prototype.root_;
+
+
+/**
+ * Sets the root JS object
+ * @param {Object} root The root JS object. Can be null.
+ *
+ * @protected
+ */
+goog.ds.JsDataSource.prototype.setRoot = function(root) {
+  this.root_ = root;
+  this.childNodeList_ = null;
+};
+
+
+/**
+ * Set this data source to use list semantics. List data sources:
+ * - Are assumed to have child nodes of all of the same type of data
+ * - Fire data changes on the root node of the list whenever children
+ *     are added or removed
+ * @param {?boolean} isList True to use list semantics.
+ * @private
+ */
+goog.ds.JsDataSource.prototype.setIsList_ = function(isList) {
+  this.isList_ = isList;
+};
+
+
+/** @override */
+goog.ds.JsDataSource.prototype.get = function() {
+  return !goog.isObject(this.root_) ? this.root_ : this.getChildNodes();
+};
+
+
+/**
+ * Set the value of the node
+ * @param {*} value The new value of the node.
+ * @override
+ */
+goog.ds.JsDataSource.prototype.set = function(value) {
+  if (value && goog.isObject(this.root_)) {
+    throw Error('Can\'t set group nodes to new values yet');
+  }
+
+  if (this.parent_) {
+    this.parent_.root_[this.dataName_] = value;
+  }
+  this.root_ = value;
+  this.childNodeList_ = null;
+
+  goog.ds.DataManager.getInstance().fireDataChange(this.getDataPath());
+};
+
+
+/**
+ * TODO(user) revisit lazy creation.
+ * @override
+ */
+goog.ds.JsDataSource.prototype.getChildNodes = function(opt_selector) {
+  if (!this.root_) {
+    return new goog.ds.EmptyNodeList();
+  }
+
+  if (!opt_selector || opt_selector == goog.ds.STR_ALL_CHILDREN_SELECTOR) {
+    this.createChildNodes_(false);
+    return this.childNodeList_;
+  } else if (opt_selector.indexOf(goog.ds.STR_WILDCARD) == -1) {
+    if (this.root_[opt_selector] != null) {
+      return new goog.ds.BasicNodeList([this.getChildNode(opt_selector)]);
+    } else {
+      return new goog.ds.EmptyNodeList();
+    }
+  } else {
+    throw Error('Selector not supported yet (' + opt_selector + ')');
+  }
+
+};
+
+
+/**
+ * Creates the DataNodeList with the child nodes for this element.
+ * Allows for only building list as needed.
+ *
+ * @param {boolean=} opt_force Whether to force recreating child nodes,
+ *     defaults to false.
+ * @private
+ */
+goog.ds.JsDataSource.prototype.createChildNodes_ = function(opt_force) {
+  if (this.childNodeList_ && !opt_force) {
+    return;
+  }
+
+  if (!goog.isObject(this.root_)) {
+    this.childNodeList_ = new goog.ds.EmptyNodeList();
+    return;
+  }
+
+  var childNodeList = new goog.ds.BasicNodeList();
+  var newNode;
+  if (goog.isArray(this.root_)) {
+    var len = this.root_.length;
+    for (var i = 0; i < len; i++) {
+      // "id" is reserved node name that will map to a named child node
+      // TODO(user) Configurable logic for choosing id node
+      var node = this.root_[i];
+      var id = node.id;
+      var name = id != null ? String(id) : '[' + i + ']';
+      newNode = new goog.ds.JsDataSource(node, name, this);
+      childNodeList.add(newNode);
+    }
+  } else {
+    for (var name in this.root_) {
+      var obj = this.root_[name];
+      // If the node is already a datasource, then add it.
+      if (obj.getDataName) {
+        childNodeList.add(obj);
+      } else if (!goog.isFunction(obj)) {
+        newNode = new goog.ds.JsDataSource(obj, name, this);
+        childNodeList.add(newNode);
+      }
+    }
+  }
+  this.childNodeList_ = childNodeList;
+};
+
+
+/**
+ * Gets a named child node of the current node
+ * @param {string} name The node name.
+ * @param {boolean=} opt_canCreate If true, can create child node.
+ * @return {goog.ds.DataNode} The child node, or null if no node of
+ *     this name exists.
+ * @override
+ */
+goog.ds.JsDataSource.prototype.getChildNode = function(name, opt_canCreate) {
+  if (!this.root_) {
+    return null;
+  }
+  var node = /** @type {goog.ds.DataNode} */ (this.getChildNodes().get(name));
+  if (!node && opt_canCreate) {
+    var newObj = {};
+    if (goog.isArray(this.root_)) {
+      newObj['id'] = name;
+      this.root_.push(newObj);
+    } else {
+      this.root_[name] = newObj;
+    }
+    node = new goog.ds.JsDataSource(newObj, name, this);
+    if (this.childNodeList_) {
+      this.childNodeList_.add(node);
+    }
+  }
+  return node;
+};
+
+
+/**
+ * Gets the value of a child node
+ * @param {string} name The node name.
+ * @return {Object} The value of the node, or null if no value or the child
+ *    node doesn't exist.
+ * @override
+ */
+goog.ds.JsDataSource.prototype.getChildNodeValue = function(name) {
+  if (this.childNodeList_) {
+    var node = this.getChildNodes().get(name);
+    return node ? node.get() : null;
+  } else if (this.root_) {
+    return this.root_[name];
+  } else {
+    return null;
+  }
+};
+
+
+/**
+ * Sets a named child node of the current node.
+ * If value is null, removes the child node.
+ * @param {string} name The node name.
+ * @param {Object} value The value to set, can be DataNode, object,
+ *     property, or null.
+ * @return {Object} The child node, if set.
+ * @override
+ */
+goog.ds.JsDataSource.prototype.setChildNode = function(name, value) {
+  var removedPath = null;
+  var node = null;
+  var addedNode = false;
+
+  // Set node to the DataNode to add - if the value isn't already a DataNode,
+  // creates a JsDataSource or JsPropertyDataSource wrapper
+  if (value != null) {
+    if (value.getDataName) {
+      // The value is a DataNode. We must update its parent.
+      node = value;
+      node.parent_ = this;
+    } else {
+      if (goog.isArray(value) || goog.isObject(value)) {
+        node = new goog.ds.JsDataSource(value, name, this);
+      } else {
+        node = new goog.ds.JsPropertyDataSource(
+            /** @type {goog.ds.DataNode} */ (this.root_), name, this);
+      }
+    }
+  }
+
+  // This logic will get cleaner once we can remove the backing array / object
+  // and just rely on the childNodeList_. This is needed until dependent code
+  // is cleaned up.
+  // TODO(user) Remove backing array / object and just use childNodeList_
+
+  if (goog.isArray(this.root_)) {
+    // To remove by name, need to create a map of the child nodes by ID
+    this.createChildNodes_();
+    var index = this.childNodeList_.indexOf(name);
+    if (value == null) {
+      // Remove the node
+      var nodeToRemove = this.childNodeList_.get(name);
+      if (nodeToRemove) {
+        removedPath = nodeToRemove.getDataPath();
+      }
+      this.root_.splice(index, 1);
+    } else {
+      // Add the node
+      if (index) {
+        this.root_[index] = value;
+      } else {
+        this.root_.push(value);
+      }
+    }
+    if (index == null) {
+      addedNode = true;
+    }
+    this.childNodeList_.setNode(name, /** @type {goog.ds.DataNode} */ (node));
+  } else if (goog.isObject(this.root_)) {
+    if (value == null) {
+      // Remove the node
+      this.createChildNodes_();
+      var nodeToRemove = this.childNodeList_.get(name);
+      if (nodeToRemove) {
+        removedPath = nodeToRemove.getDataPath();
+      }
+      delete this.root_[name];
+    } else {
+      // Add the node
+      if (!this.root_[name]) {
+        addedNode = true;
+      }
+      this.root_[name] = value;
+    }
+    // Only need to update childNodeList_ if has been created already
+    if (this.childNodeList_) {
+      this.childNodeList_.setNode(name, /** @type {goog.ds.DataNode} */ (node));
+    }
+  }
+
+  // Fire the event that the node changed
+  var dm = goog.ds.DataManager.getInstance();
+  if (node) {
+    dm.fireDataChange(node.getDataPath());
+    if (addedNode && this.isList()) {
+      dm.fireDataChange(this.getDataPath());
+      dm.fireDataChange(this.getDataPath() + '/count()');
+    }
+  } else if (removedPath) {
+    dm.fireDataChange(removedPath);
+    if (this.isList()) {
+      dm.fireDataChange(this.getDataPath());
+      dm.fireDataChange(this.getDataPath() + '/count()');
+    }
+  }
+  return node;
+};
+
+
+/**
+ * Get the name of the node relative to the parent node
+ * @return {string} The name of the node.
+ * @override
+ */
+goog.ds.JsDataSource.prototype.getDataName = function() {
+  return this.dataName_;
+};
+
+
+/**
+ * Setthe name of the node relative to the parent node
+ * @param {string} dataName The name of the node.
+ * @override
+ */
+goog.ds.JsDataSource.prototype.setDataName = function(dataName) {
+  this.dataName_ = dataName;
+};
+
+
+/**
+ * Gets the a qualified data path to this node
+ * @return {string} The data path.
+ * @override
+ */
+goog.ds.JsDataSource.prototype.getDataPath = function() {
+  var parentPath = '';
+  if (this.parent_) {
+    parentPath = this.parent_.getDataPath() + goog.ds.STR_PATH_SEPARATOR;
+  }
+
+  return parentPath + this.dataName_;
+};
+
+
+/**
+ * Load or reload the backing data for this node
+ * @override
+ */
+goog.ds.JsDataSource.prototype.load = function() {
+  // Nothing to do
+};
+
+
+/**
+ * Gets the state of the backing data for this node
+ * TODO(user) Discuss null value handling
+ * @return {goog.ds.LoadState} The state.
+ * @override
+ */
+goog.ds.JsDataSource.prototype.getLoadState = function() {
+  return (this.root_ == null) ? goog.ds.LoadState.NOT_LOADED :
+      goog.ds.LoadState.LOADED;
+};
+
+
+/**
+ * Whether the value of this node is a homogeneous list of data
+ * @return {boolean} True if a list.
+ * @override
+ */
+goog.ds.JsDataSource.prototype.isList = function() {
+  return this.isList_ != null ? this.isList_ : goog.isArray(this.root_);
+};
+
+
+
+/**
+ * Data source for JavaScript properties that arent objects. Contains reference
+ * to parent object so that you can set the vaule
+ *
+ * @param {goog.ds.DataNode} parent Parent object.
+ * @param {string} dataName Name of this property.
+ * @param {goog.ds.DataNode=} opt_parentDataNode The parent data node. If
+ *     omitted, assumes that the parent object is the parent data node.
+ *
+ * @constructor
+ * @extends {goog.ds.BaseDataNode}
+ * @final
+ */
+goog.ds.JsPropertyDataSource = function(parent, dataName, opt_parentDataNode) {
+  goog.ds.BaseDataNode.call(this);
+  this.dataName_ = dataName;
+  this.parent_ = parent;
+  this.parentDataNode_ = opt_parentDataNode || this.parent_;
+};
+goog.inherits(goog.ds.JsPropertyDataSource, goog.ds.BaseDataNode);
+
+
+/**
+ * Get the value of the node
+ * @return {Object} The value of the node, or null if no value.
+ */
+goog.ds.JsPropertyDataSource.prototype.get = function() {
+  return this.parent_[this.dataName_];
+};
+
+
+/**
+ * Set the value of the node
+ * @param {Object} value The new value of the node.
+ * @override
+ */
+goog.ds.JsPropertyDataSource.prototype.set = function(value) {
+  var oldValue = this.parent_[this.dataName_];
+  this.parent_[this.dataName_] = value;
+
+  if (oldValue != value) {
+    goog.ds.DataManager.getInstance().fireDataChange(this.getDataPath());
+  }
+};
+
+
+/**
+ * Get the name of the node relative to the parent node
+ * @return {string} The name of the node.
+ * @override
+ */
+goog.ds.JsPropertyDataSource.prototype.getDataName = function() {
+  return this.dataName_;
+};
+
+
+/** @override */
+goog.ds.JsPropertyDataSource.prototype.getParent = function() {
+  return this.parentDataNode_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/datasource/jsondatasource.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/datasource/jsondatasource.js b/externs/GCL/externs/goog/datasource/jsondatasource.js
new file mode 100644
index 0000000..1621002
--- /dev/null
+++ b/externs/GCL/externs/goog/datasource/jsondatasource.js
@@ -0,0 +1,153 @@
+// 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 Implementation of DataNode for wrapping JSON data.
+ *
+ */
+
+
+goog.provide('goog.ds.JsonDataSource');
+
+goog.require('goog.Uri');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.ds.DataManager');
+goog.require('goog.ds.JsDataSource');
+goog.require('goog.ds.LoadState');
+goog.require('goog.ds.logger');
+goog.require('goog.log');
+
+
+
+/**
+ * Data source whose backing is a JSON-like service, in which
+ * retreiving the resource specified by URL with the additional parameter
+ * callback. The resource retreived is executable JavaScript that
+ * makes a call to the named function with a JavaScript object literal
+ * as the only parameter.
+ *
+ * Example URI could be:
+ * http://www.google.com/data/search?q=monkey&callback=mycb
+ * which might return the JS:
+ * mycb({searchresults:
+ *   [{uri: 'http://www.monkey.com', title: 'Site About Monkeys'}]});
+ *
+ * TODO(user): Evaluate using goog.net.Jsonp here.
+ *
+ * A URI of an empty string will mean that no request is made
+ * and the data source will be a data source with no child nodes
+ *
+ * @param {string|goog.Uri} uri URI for the request.
+ * @param {string} name Name of the datasource.
+ * @param {string=} opt_callbackParamName The parameter name that is used to
+ *     specify the callback. Defaults to 'callback'.
+ *
+ * @extends {goog.ds.JsDataSource}
+ * @constructor
+ * @final
+ */
+goog.ds.JsonDataSource = function(uri, name, opt_callbackParamName) {
+  goog.ds.JsDataSource.call(this, null, name, null);
+  if (uri) {
+    this.uri_ = new goog.Uri(uri);
+  } else {
+    this.uri_ = null;
+  }
+
+  /**
+   * This is the callback parameter name that is added to the uri.
+   * @type {string}
+   * @private
+   */
+  this.callbackParamName_ = opt_callbackParamName || 'callback';
+
+};
+goog.inherits(goog.ds.JsonDataSource, goog.ds.JsDataSource);
+
+
+/**
+ * Default load state is NOT_LOADED
+ * @private
+ */
+goog.ds.JsonDataSource.prototype.loadState_ = goog.ds.LoadState.NOT_LOADED;
+
+
+/**
+ * Map of all data sources, needed for callbacks
+ * Doesn't work unless dataSources is exported (not renamed)
+ */
+goog.ds.JsonDataSource['dataSources'] = {};
+
+
+/**
+ * Load or reload the backing data for this node.
+ * Fires the JsonDataSource
+ * @override
+ */
+goog.ds.JsonDataSource.prototype.load = function() {
+  if (this.uri_) {
+    // NOTE: "dataSources" is expose above by name so that it will not be
+    // renamed.  It should therefore be accessed via array notation here so
+    // that it also doesn't get renamed and stops the compiler from complaining
+    goog.ds.JsonDataSource['dataSources'][this.dataName_] = this;
+    goog.log.info(goog.ds.logger, 'Sending JS request for DataSource ' +
+        this.getDataName() + ' to ' + this.uri_);
+
+    this.loadState_ = goog.ds.LoadState.LOADING;
+
+    var uriToCall = new goog.Uri(this.uri_);
+    uriToCall.setParameterValue(this.callbackParamName_,
+        'JsonReceive.' + this.dataName_);
+
+    goog.global['JsonReceive'][this.dataName_] =
+        goog.bind(this.receiveData, this);
+
+    var scriptEl = goog.dom.createDom(goog.dom.TagName.SCRIPT,
+                                      {'src': uriToCall});
+    goog.dom.getElementsByTagNameAndClass(
+        goog.dom.TagName.HEAD)[0].appendChild(scriptEl);
+  } else {
+    this.root_ = {};
+    this.loadState_ = goog.ds.LoadState.NOT_LOADED;
+  }
+};
+
+
+/**
+ * Gets the state of the backing data for this node
+ * @return {goog.ds.LoadState} The state.
+ * @override
+ */
+goog.ds.JsonDataSource.prototype.getLoadState = function() {
+  return this.loadState_;
+};
+
+
+/**
+ * Receives data from a Json request
+ * @param {Object} obj The JSON data.
+ */
+goog.ds.JsonDataSource.prototype.receiveData = function(obj) {
+  this.setRoot(obj);
+  this.loadState_ = goog.ds.LoadState.LOADED;
+  goog.ds.DataManager.getInstance().fireDataChange(this.getDataName());
+};
+
+
+/**
+* Temp variable to hold callbacks
+* until BUILD supports multiple externs.js files
+*/
+goog.global['JsonReceive'] = {};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/datasource/jsxmlhttpdatasource.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/datasource/jsxmlhttpdatasource.js b/externs/GCL/externs/goog/datasource/jsxmlhttpdatasource.js
new file mode 100644
index 0000000..bd2a024
--- /dev/null
+++ b/externs/GCL/externs/goog/datasource/jsxmlhttpdatasource.js
@@ -0,0 +1,196 @@
+// 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
+ * DataSource implementation that uses XMLHttpRequest as transport, with
+ * response as serialized JS object (not required to be JSON) that can
+ * be evaluated and set to a variable.
+ *
+ * Response can have unexecutable starting/ending text to prevent inclusion
+ * using <script src="...">
+ *
+ */
+
+
+goog.provide('goog.ds.JsXmlHttpDataSource');
+
+goog.require('goog.Uri');
+goog.require('goog.ds.DataManager');
+goog.require('goog.ds.FastDataNode');
+goog.require('goog.ds.LoadState');
+goog.require('goog.ds.logger');
+goog.require('goog.events');
+goog.require('goog.log');
+goog.require('goog.net.EventType');
+goog.require('goog.net.XhrIo');
+
+
+
+/**
+ * Similar to JsonDataSource, with using XMLHttpRequest for transport
+ * Currently requires the result be a JS object that can be evaluated and
+ * set to a variable and doesn't require strict JSON notation.
+ *
+ * @param {(string|goog.Uri)} uri URI for the request.
+ * @param {string} name Name of the datasource.
+ * @param {string=} opt_startText Text to expect/strip before JS response.
+ * @param {string=} opt_endText Text to expect/strip after JS response.
+ * @param {boolean=} opt_usePost If true, use POST. Defaults to false (GET).
+ *
+ * @extends {goog.ds.FastDataNode}
+ * @constructor
+ * @final
+ */
+goog.ds.JsXmlHttpDataSource = function(uri, name, opt_startText, opt_endText,
+                                       opt_usePost) {
+  goog.ds.FastDataNode.call(this, {}, name, null);
+  if (uri) {
+    this.uri_ = new goog.Uri(uri);
+    this.xhr_ = new goog.net.XhrIo();
+    this.usePost_ = !!opt_usePost;
+
+    goog.events.listen(this.xhr_, goog.net.EventType.COMPLETE,
+        this.completed_, false, this);
+  } else {
+    this.uri_ = null;
+  }
+  this.startText_ = opt_startText;
+  this.endText_ = opt_endText;
+};
+goog.inherits(goog.ds.JsXmlHttpDataSource, goog.ds.FastDataNode);
+
+
+/**
+ * Delimiter for start of JSON data in response.
+ * null = starts at first character of response
+ * @type {string|undefined}
+ * @private
+ */
+goog.ds.JsXmlHttpDataSource.prototype.startText_;
+
+
+/**
+ * Delimiter for end of JSON data in response.
+ * null = ends at last character of response
+ * @type {string|undefined}
+ * @private
+ */
+goog.ds.JsXmlHttpDataSource.prototype.endText_;
+
+
+/**
+ * Gets the state of the backing data for this node
+ * @return {goog.ds.LoadState} The state.
+ * @override
+ */
+goog.ds.JsXmlHttpDataSource.prototype.getLoadState = function() {
+  return this.loadState_;
+};
+
+
+/**
+ * Sets the request data. This can be used if it is required to
+ * send a specific body rather than build the body from the query
+ * parameters. Only used in POST requests.
+ * @param {string} data The data to send in the request body.
+ */
+goog.ds.JsXmlHttpDataSource.prototype.setQueryData = function(data) {
+  this.queryData_ = data;
+};
+
+
+/**
+ * Load or reload the backing data for this node.
+ * Fires the JsonDataSource
+ * @override
+ */
+goog.ds.JsXmlHttpDataSource.prototype.load = function() {
+  goog.log.info(goog.ds.logger, 'Sending JS request for DataSource ' +
+      this.getDataName() + ' to ' + this.uri_);
+
+  if (this.uri_) {
+    if (this.usePost_) {
+
+      var queryData;
+      if (!this.queryData_) {
+        queryData = this.uri_.getQueryData().toString();
+      } else {
+        queryData = this.queryData_;
+      }
+
+      var uriNoQuery = this.uri_.clone();
+      uriNoQuery.setQueryData(null);
+      this.xhr_.send(String(uriNoQuery), 'POST', queryData);
+    } else {
+      this.xhr_.send(String(this.uri_));
+    }
+  } else {
+    this.loadState_ = goog.ds.LoadState.NOT_LOADED;
+  }
+};
+
+
+/**
+ * Called on successful request.
+ * @private
+ */
+goog.ds.JsXmlHttpDataSource.prototype.success_ = function()  {
+  goog.ds.DataManager.getInstance().fireDataChange(this.getDataName());
+};
+
+
+/**
+ * Completed callback. Loads data if successful, otherwise sets
+ * state to FAILED
+ * @param {goog.events.Event} e Event object, Xhr is target.
+ * @private
+ */
+goog.ds.JsXmlHttpDataSource.prototype.completed_ = function(e) {
+  if (this.xhr_.isSuccess()) {
+    goog.log.info(goog.ds.logger,
+        'Got data for DataSource ' + this.getDataName());
+    var text = this.xhr_.getResponseText();
+
+    // Look for start and end token and trim text
+    if (this.startText_) {
+      var startpos = text.indexOf(this.startText_);
+      text = text.substring(startpos + this.startText_.length);
+    }
+    if (this.endText_) {
+      var endpos = text.lastIndexOf(this.endText_);
+      text = text.substring(0, endpos);
+    }
+
+    // Eval result
+    /** @preserveTry */
+    try {
+      var jsonObj = /** @type {Object} */ (eval('[' + text + '][0]'));
+      this.extendWith(jsonObj);
+      this.loadState_ = goog.ds.LoadState.LOADED;
+    }
+    catch (ex) {
+      // Invalid JS
+      this.loadState_ = goog.ds.LoadState.FAILED;
+      goog.log.error(goog.ds.logger, 'Failed to parse data: ' + ex.message);
+    }
+
+    // Call on a timer to avoid threading issues on IE.
+    goog.global.setTimeout(goog.bind(this.success_, this), 0);
+  } else {
+    goog.log.info(goog.ds.logger, 'Data retrieve failed for DataSource ' +
+        this.getDataName());
+    this.loadState_ = goog.ds.LoadState.FAILED;
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/datasource/xmldatasource.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/datasource/xmldatasource.js b/externs/GCL/externs/goog/datasource/xmldatasource.js
new file mode 100644
index 0000000..5327269
--- /dev/null
+++ b/externs/GCL/externs/goog/datasource/xmldatasource.js
@@ -0,0 +1,417 @@
+// 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
+ * Implementations of DataNode for wrapping XML data.
+ *
+ */
+
+goog.provide('goog.ds.XmlDataSource');
+goog.provide('goog.ds.XmlHttpDataSource');
+
+goog.require('goog.Uri');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.xml');
+goog.require('goog.ds.BasicNodeList');
+goog.require('goog.ds.DataManager');
+goog.require('goog.ds.DataNode');
+goog.require('goog.ds.LoadState');
+goog.require('goog.ds.logger');
+goog.require('goog.net.XhrIo');
+goog.require('goog.string');
+
+
+
+/**
+ * Data source whose backing is an xml node
+ *
+ * @param {Node} node The XML node. Can be null.
+ * @param {goog.ds.XmlDataSource} parent Parent of XML element. Can be null.
+ * @param {string=} opt_name The name of this node relative to the parent node.
+ *
+ * @extends {goog.ds.DataNode}
+ * @constructor
+ */
+// TODO(arv): Use interfaces when available.
+goog.ds.XmlDataSource = function(node, parent, opt_name) {
+  this.parent_ = parent;
+  this.dataName_ = opt_name || (node ? node.nodeName : '');
+  this.setNode_(node);
+};
+
+
+/**
+ * Constant to select XML attributes for getChildNodes
+ * @type {string}
+ * @private
+ */
+goog.ds.XmlDataSource.ATTRIBUTE_SELECTOR_ = '@*';
+
+
+/**
+ * Set the current root nodeof the data source.
+ * Can be an attribute node, text node, or element node
+ * @param {Node} node The node. Can be null.
+ *
+ * @private
+ */
+goog.ds.XmlDataSource.prototype.setNode_ = function(node) {
+  this.node_ = node;
+  if (node != null) {
+    switch (node.nodeType) {
+      case goog.dom.NodeType.ATTRIBUTE:
+      case goog.dom.NodeType.TEXT:
+        this.value_ = node.nodeValue;
+        break;
+      case goog.dom.NodeType.ELEMENT:
+        if (node.childNodes.length == 1 &&
+            node.firstChild.nodeType == goog.dom.NodeType.TEXT) {
+          this.value_ = node.firstChild.nodeValue;
+        }
+    }
+  }
+};
+
+
+/**
+ * Creates the DataNodeList with the child nodes for this element.
+ * Allows for only building list as needed.
+ *
+ * @private
+ */
+goog.ds.XmlDataSource.prototype.createChildNodes_ = function() {
+  if (this.childNodeList_) {
+    return;
+  }
+  var childNodeList = new goog.ds.BasicNodeList();
+  if (this.node_ != null) {
+    var childNodes = this.node_.childNodes;
+    for (var i = 0, childNode; childNode = childNodes[i]; i++) {
+      if (childNode.nodeType != goog.dom.NodeType.TEXT ||
+          !goog.ds.XmlDataSource.isEmptyTextNodeValue_(childNode.nodeValue)) {
+        var newNode = new goog.ds.XmlDataSource(childNode,
+            this, childNode.nodeName);
+        childNodeList.add(newNode);
+      }
+    }
+  }
+  this.childNodeList_ = childNodeList;
+};
+
+
+/**
+ * Creates the DataNodeList with the attributes for the element
+ * Allows for only building list as needed.
+ *
+ * @private
+ */
+goog.ds.XmlDataSource.prototype.createAttributes_ = function() {
+  if (this.attributes_) {
+    return;
+  }
+  var attributes = new goog.ds.BasicNodeList();
+  if (this.node_ != null && this.node_.attributes != null) {
+    var atts = this.node_.attributes;
+    for (var i = 0, att; att = atts[i]; i++) {
+      var newNode = new goog.ds.XmlDataSource(att, this, att.nodeName);
+      attributes.add(newNode);
+    }
+  }
+  this.attributes_ = attributes;
+};
+
+
+/**
+ * Get the value of the node
+ * @return {Object} The value of the node, or null if no value.
+ * @override
+ */
+goog.ds.XmlDataSource.prototype.get = function() {
+  this.createChildNodes_();
+  return this.value_;
+};
+
+
+/**
+ * Set the value of the node
+ * @param {*} value The new value of the node.
+ * @override
+ */
+goog.ds.XmlDataSource.prototype.set = function(value) {
+  throw Error('Can\'t set on XmlDataSource yet');
+};
+
+
+/** @override */
+goog.ds.XmlDataSource.prototype.getChildNodes = function(opt_selector) {
+  if (opt_selector && opt_selector ==
+      goog.ds.XmlDataSource.ATTRIBUTE_SELECTOR_) {
+    this.createAttributes_();
+    return this.attributes_;
+  } else if (opt_selector == null ||
+      opt_selector == goog.ds.STR_ALL_CHILDREN_SELECTOR) {
+    this.createChildNodes_();
+    return this.childNodeList_;
+  } else {
+    throw Error('Unsupported selector');
+  }
+
+};
+
+
+/**
+ * Gets a named child node of the current node
+ * @param {string} name The node name.
+ * @return {goog.ds.DataNode} The child node, or null if
+ *   no node of this name exists.
+ * @override
+ */
+goog.ds.XmlDataSource.prototype.getChildNode = function(name) {
+  if (goog.string.startsWith(name, goog.ds.STR_ATTRIBUTE_START)) {
+    var att = this.node_.getAttributeNode(name.substring(1));
+    return att ? new goog.ds.XmlDataSource(att, this) : null;
+  } else {
+    return /** @type {goog.ds.DataNode} */ (this.getChildNodes().get(name));
+  }
+};
+
+
+/**
+ * Gets the value of a child node
+ * @param {string} name The node name.
+ * @return {*} The value of the node, or null if no value or the child node
+ *    doesn't exist.
+ * @override
+ */
+goog.ds.XmlDataSource.prototype.getChildNodeValue = function(name) {
+  if (goog.string.startsWith(name, goog.ds.STR_ATTRIBUTE_START)) {
+    var node = this.node_.getAttributeNode(name.substring(1));
+    return node ? node.nodeValue : null;
+  } else {
+    var node = this.getChildNode(name);
+    return node ? node.get() : null;
+  }
+};
+
+
+/**
+ * Get the name of the node relative to the parent node
+ * @return {string} The name of the node.
+ * @override
+ */
+goog.ds.XmlDataSource.prototype.getDataName = function() {
+  return this.dataName_;
+};
+
+
+/**
+ * Setthe name of the node relative to the parent node
+ * @param {string} name The name of the node.
+ * @override
+ */
+goog.ds.XmlDataSource.prototype.setDataName = function(name) {
+  this.dataName_ = name;
+};
+
+
+/**
+ * Gets the a qualified data path to this node
+ * @return {string} The data path.
+ * @override
+ */
+goog.ds.XmlDataSource.prototype.getDataPath = function() {
+  var parentPath = '';
+  if (this.parent_) {
+    parentPath = this.parent_.getDataPath() +
+        (this.dataName_.indexOf(goog.ds.STR_ARRAY_START) != -1 ? '' :
+        goog.ds.STR_PATH_SEPARATOR);
+  }
+
+  return parentPath + this.dataName_;
+};
+
+
+/**
+ * Load or reload the backing data for this node
+ * @override
+ */
+goog.ds.XmlDataSource.prototype.load = function() {
+  // Nothing to do
+};
+
+
+/**
+ * Gets the state of the backing data for this node
+ * @return {goog.ds.LoadState} The state.
+ * @override
+ */
+goog.ds.XmlDataSource.prototype.getLoadState = function() {
+  return this.node_ ? goog.ds.LoadState.LOADED : goog.ds.LoadState.NOT_LOADED;
+};
+
+
+/**
+ * Check whether a node is an empty text node. Nodes consisting of only white
+ * space (#x20, #xD, #xA, #x9) can generally be collapsed to a zero length
+ * text string.
+ * @param {string} str String to match.
+ * @return {boolean} True if string equates to empty text node.
+ * @private
+ */
+goog.ds.XmlDataSource.isEmptyTextNodeValue_ = function(str) {
+  return /^[\r\n\t ]*$/.test(str);
+};
+
+
+/**
+ * Creates an XML document with one empty node.
+ * Useful for places where you need a node that
+ * can be queried against.
+ *
+ * @return {Document} Document with one empty node.
+ * @private
+ */
+goog.ds.XmlDataSource.createChildlessDocument_ = function() {
+  return goog.dom.xml.createDocument('nothing');
+};
+
+
+
+/**
+ * Data source whose backing is an XMLHttpRequest,
+ *
+ * A URI of an empty string will mean that no request is made
+ * and the data source will be a single, empty node.
+ *
+ * @param {(string|goog.Uri)} uri URL of the XMLHttpRequest.
+ * @param {string} name Name of the datasource.
+ *
+ * implements goog.ds.XmlHttpDataSource.
+ * @constructor
+ * @extends {goog.ds.XmlDataSource}
+ * @final
+ */
+goog.ds.XmlHttpDataSource = function(uri, name) {
+  goog.ds.XmlDataSource.call(this, null, null, name);
+  if (uri) {
+    this.uri_ = new goog.Uri(uri);
+  } else {
+    this.uri_ = null;
+  }
+};
+goog.inherits(goog.ds.XmlHttpDataSource, goog.ds.XmlDataSource);
+
+
+/**
+ * Default load state is NOT_LOADED
+ * @private
+ */
+goog.ds.XmlHttpDataSource.prototype.loadState_ = goog.ds.LoadState.NOT_LOADED;
+
+
+/**
+ * Load or reload the backing data for this node.
+ * Fires the XMLHttpRequest
+ * @override
+ */
+goog.ds.XmlHttpDataSource.prototype.load = function() {
+  if (this.uri_) {
+    goog.log.info(goog.ds.logger, 'Sending XML request for DataSource ' +
+        this.getDataName() + ' to ' + this.uri_);
+    this.loadState_ = goog.ds.LoadState.LOADING;
+
+    goog.net.XhrIo.send(this.uri_, goog.bind(this.complete_, this));
+  } else {
+    this.node_ = goog.ds.XmlDataSource.createChildlessDocument_();
+    this.loadState_ = goog.ds.LoadState.NOT_LOADED;
+  }
+};
+
+
+/**
+ * Gets the state of the backing data for this node
+ * @return {goog.ds.LoadState} The state.
+ * @override
+ */
+goog.ds.XmlHttpDataSource.prototype.getLoadState = function() {
+  return this.loadState_;
+};
+
+
+/**
+ * Handles the completion of an XhrIo request. Dispatches to success or load
+ * based on the result.
+ * @param {!goog.events.Event} e The XhrIo event object.
+ * @private
+ */
+goog.ds.XmlHttpDataSource.prototype.complete_ = function(e) {
+  var xhr = /** @type {goog.net.XhrIo} */ (e.target);
+  if (xhr && xhr.isSuccess()) {
+    this.success_(xhr);
+  } else {
+    this.failure_();
+  }
+};
+
+
+/**
+ * Success result. Checks whether valid XML was returned
+ * and sets the XML and loadstate.
+ *
+ * @param {!goog.net.XhrIo} xhr The successful XhrIo object.
+ * @private
+ */
+goog.ds.XmlHttpDataSource.prototype.success_ = function(xhr) {
+  goog.log.info(goog.ds.logger,
+      'Got data for DataSource ' + this.getDataName());
+  var xml = xhr.getResponseXml();
+
+  // Fix for case where IE returns valid XML as text but
+  // doesn't parse by default
+  if (xml && !xml.hasChildNodes() &&
+      goog.isObject(xhr.getResponseText())) {
+    xml = goog.dom.xml.loadXml(xhr.getResponseText());
+  }
+  // Failure result
+  if (!xml || !xml.hasChildNodes()) {
+    this.loadState_ = goog.ds.LoadState.FAILED;
+    this.node_ = goog.ds.XmlDataSource.createChildlessDocument_();
+  } else {
+    this.loadState_ = goog.ds.LoadState.LOADED;
+    this.node_ = xml.documentElement;
+  }
+
+  if (this.getDataName()) {
+    goog.ds.DataManager.getInstance().fireDataChange(this.getDataName());
+  }
+};
+
+
+/**
+ * Failure result
+ *
+ * @private
+ */
+goog.ds.XmlHttpDataSource.prototype.failure_ = function() {
+  goog.log.info(goog.ds.logger, 'Data retrieve failed for DataSource ' +
+      this.getDataName());
+
+  this.loadState_ = goog.ds.LoadState.FAILED;
+  this.node_ = goog.ds.XmlDataSource.createChildlessDocument_();
+
+  if (this.getDataName()) {
+    goog.ds.DataManager.getInstance().fireDataChange(this.getDataName());
+  }
+};


[45/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/base64.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/base64.js b/externs/GCL/externs/goog/crypt/base64.js
new file mode 100644
index 0000000..9103fa1
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/base64.js
@@ -0,0 +1,286 @@
+// 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 Base64 en/decoding. Not much to say here except that we
+ * work with decoded values in arrays of bytes. By "byte" I mean a number
+ * in [0, 255].
+ *
+ * @author doughtie@google.com (Gavin Doughtie)
+ */
+
+goog.provide('goog.crypt.base64');
+goog.require('goog.crypt');
+goog.require('goog.userAgent');
+
+// Static lookup maps, lazily populated by init_()
+
+
+/**
+ * Maps bytes to characters.
+ * @type {Object}
+ * @private
+ */
+goog.crypt.base64.byteToCharMap_ = null;
+
+
+/**
+ * Maps characters to bytes.
+ * @type {Object}
+ * @private
+ */
+goog.crypt.base64.charToByteMap_ = null;
+
+
+/**
+ * Maps bytes to websafe characters.
+ * @type {Object}
+ * @private
+ */
+goog.crypt.base64.byteToCharMapWebSafe_ = null;
+
+
+/**
+ * Maps websafe characters to bytes.
+ * @type {Object}
+ * @private
+ */
+goog.crypt.base64.charToByteMapWebSafe_ = null;
+
+
+/**
+ * Our default alphabet, shared between
+ * ENCODED_VALS and ENCODED_VALS_WEBSAFE
+ * @type {string}
+ */
+goog.crypt.base64.ENCODED_VALS_BASE =
+    'ABCDEFGHIJKLMNOPQRSTUVWXYZ' +
+    'abcdefghijklmnopqrstuvwxyz' +
+    '0123456789';
+
+
+/**
+ * Our default alphabet. Value 64 (=) is special; it means "nothing."
+ * @type {string}
+ */
+goog.crypt.base64.ENCODED_VALS =
+    goog.crypt.base64.ENCODED_VALS_BASE + '+/=';
+
+
+/**
+ * Our websafe alphabet.
+ * @type {string}
+ */
+goog.crypt.base64.ENCODED_VALS_WEBSAFE =
+    goog.crypt.base64.ENCODED_VALS_BASE + '-_.';
+
+
+/**
+ * Whether this browser supports the atob and btoa functions. This extension
+ * started at Mozilla but is now implemented by many browsers. We use the
+ * ASSUME_* variables to avoid pulling in the full useragent detection library
+ * but still allowing the standard per-browser compilations.
+ *
+ * @type {boolean}
+ */
+goog.crypt.base64.HAS_NATIVE_SUPPORT = goog.userAgent.GECKO ||
+                                       goog.userAgent.WEBKIT ||
+                                       goog.userAgent.OPERA ||
+                                       typeof(goog.global.atob) == 'function';
+
+
+/**
+ * Base64-encode an array of bytes.
+ *
+ * @param {Array<number>|Uint8Array} input An array of bytes (numbers with
+ *     value in [0, 255]) to encode.
+ * @param {boolean=} opt_webSafe Boolean indicating we should use the
+ *     alternative alphabet.
+ * @return {string} The base64 encoded string.
+ */
+goog.crypt.base64.encodeByteArray = function(input, opt_webSafe) {
+  if (!goog.isArrayLike(input)) {
+    throw Error('encodeByteArray takes an array as a parameter');
+  }
+
+  goog.crypt.base64.init_();
+
+  var byteToCharMap = opt_webSafe ?
+                      goog.crypt.base64.byteToCharMapWebSafe_ :
+                      goog.crypt.base64.byteToCharMap_;
+
+  var output = [];
+
+  for (var i = 0; i < input.length; i += 3) {
+    var byte1 = input[i];
+    var haveByte2 = i + 1 < input.length;
+    var byte2 = haveByte2 ? input[i + 1] : 0;
+    var haveByte3 = i + 2 < input.length;
+    var byte3 = haveByte3 ? input[i + 2] : 0;
+
+    var outByte1 = byte1 >> 2;
+    var outByte2 = ((byte1 & 0x03) << 4) | (byte2 >> 4);
+    var outByte3 = ((byte2 & 0x0F) << 2) | (byte3 >> 6);
+    var outByte4 = byte3 & 0x3F;
+
+    if (!haveByte3) {
+      outByte4 = 64;
+
+      if (!haveByte2) {
+        outByte3 = 64;
+      }
+    }
+
+    output.push(byteToCharMap[outByte1],
+                byteToCharMap[outByte2],
+                byteToCharMap[outByte3],
+                byteToCharMap[outByte4]);
+  }
+
+  return output.join('');
+};
+
+
+/**
+ * Base64-encode a string.
+ *
+ * @param {string} input A string to encode.
+ * @param {boolean=} opt_webSafe If true, we should use the
+ *     alternative alphabet.
+ * @return {string} The base64 encoded string.
+ */
+goog.crypt.base64.encodeString = function(input, opt_webSafe) {
+  // Shortcut for Mozilla browsers that implement
+  // a native base64 encoder in the form of "btoa/atob"
+  if (goog.crypt.base64.HAS_NATIVE_SUPPORT && !opt_webSafe) {
+    return goog.global.btoa(input);
+  }
+  return goog.crypt.base64.encodeByteArray(
+      goog.crypt.stringToByteArray(input), opt_webSafe);
+};
+
+
+/**
+ * Base64-decode a string.
+ *
+ * @param {string} input to decode.
+ * @param {boolean=} opt_webSafe True if we should use the
+ *     alternative alphabet.
+ * @return {string} string representing the decoded value.
+ */
+goog.crypt.base64.decodeString = function(input, opt_webSafe) {
+  // Shortcut for Mozilla browsers that implement
+  // a native base64 encoder in the form of "btoa/atob"
+  if (goog.crypt.base64.HAS_NATIVE_SUPPORT && !opt_webSafe) {
+    return goog.global.atob(input);
+  }
+  return goog.crypt.byteArrayToString(
+      goog.crypt.base64.decodeStringToByteArray(input, opt_webSafe));
+};
+
+
+/**
+ * Base64-decode a string.
+ *
+ * In base-64 decoding, groups of four characters are converted into three
+ * bytes.  If the encoder did not apply padding, the input length may not
+ * be a multiple of 4.
+ *
+ * In this case, the last group will have fewer than 4 characters, and
+ * padding will be inferred.  If the group has one or two characters, it decodes
+ * to one byte.  If the group has three characters, it decodes to two bytes.
+ *
+ * @param {string} input Input to decode.
+ * @param {boolean=} opt_webSafe True if we should use the web-safe alphabet.
+ * @return {!Array<number>} bytes representing the decoded value.
+ */
+goog.crypt.base64.decodeStringToByteArray = function(input, opt_webSafe) {
+  goog.crypt.base64.init_();
+
+  var charToByteMap = opt_webSafe ?
+                      goog.crypt.base64.charToByteMapWebSafe_ :
+                      goog.crypt.base64.charToByteMap_;
+
+  var output = [];
+
+  for (var i = 0; i < input.length; ) {
+    var byte1 = charToByteMap[input.charAt(i++)];
+
+    var haveByte2 = i < input.length;
+    var byte2 = haveByte2 ? charToByteMap[input.charAt(i)] : 0;
+    ++i;
+
+    var haveByte3 = i < input.length;
+    var byte3 = haveByte3 ? charToByteMap[input.charAt(i)] : 64;
+    ++i;
+
+    var haveByte4 = i < input.length;
+    var byte4 = haveByte4 ? charToByteMap[input.charAt(i)] : 64;
+    ++i;
+
+    if (byte1 == null || byte2 == null ||
+        byte3 == null || byte4 == null) {
+      throw Error();
+    }
+
+    var outByte1 = (byte1 << 2) | (byte2 >> 4);
+    output.push(outByte1);
+
+    if (byte3 != 64) {
+      var outByte2 = ((byte2 << 4) & 0xF0) | (byte3 >> 2);
+      output.push(outByte2);
+
+      if (byte4 != 64) {
+        var outByte3 = ((byte3 << 6) & 0xC0) | byte4;
+        output.push(outByte3);
+      }
+    }
+  }
+
+  return output;
+};
+
+
+/**
+ * Lazy static initialization function. Called before
+ * accessing any of the static map variables.
+ * @private
+ */
+goog.crypt.base64.init_ = function() {
+  if (!goog.crypt.base64.byteToCharMap_) {
+    goog.crypt.base64.byteToCharMap_ = {};
+    goog.crypt.base64.charToByteMap_ = {};
+    goog.crypt.base64.byteToCharMapWebSafe_ = {};
+    goog.crypt.base64.charToByteMapWebSafe_ = {};
+
+    // We want quick mappings back and forth, so we precompute two maps.
+    for (var i = 0; i < goog.crypt.base64.ENCODED_VALS.length; i++) {
+      goog.crypt.base64.byteToCharMap_[i] =
+          goog.crypt.base64.ENCODED_VALS.charAt(i);
+      goog.crypt.base64.charToByteMap_[goog.crypt.base64.byteToCharMap_[i]] = i;
+      goog.crypt.base64.byteToCharMapWebSafe_[i] =
+          goog.crypt.base64.ENCODED_VALS_WEBSAFE.charAt(i);
+      goog.crypt.base64.charToByteMapWebSafe_[
+          goog.crypt.base64.byteToCharMapWebSafe_[i]] = i;
+
+      // Be forgiving when decoding and correctly decode both encodings.
+      if (i >= goog.crypt.base64.ENCODED_VALS_BASE.length) {
+        goog.crypt.base64.charToByteMap_[
+            goog.crypt.base64.ENCODED_VALS_WEBSAFE.charAt(i)] = i;
+        goog.crypt.base64.charToByteMapWebSafe_[
+            goog.crypt.base64.ENCODED_VALS.charAt(i)] = i;
+      }
+    }
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/basen.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/basen.js b/externs/GCL/externs/goog/crypt/basen.js
new file mode 100644
index 0000000..2bac248
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/basen.js
@@ -0,0 +1,242 @@
+// 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 Numeric base conversion library.  Works for arbitrary bases and
+ * arbitrary length numbers.
+ *
+ * For base-64 conversion use base64.js because it is optimized for the specific
+ * conversion to base-64 while this module is generic.  Base-64 is defined here
+ * mostly for demonstration purpose.
+ *
+ * TODO: Make base64 and baseN classes that have common interface.  (Perhaps...)
+ *
+ */
+
+goog.provide('goog.crypt.baseN');
+
+
+/**
+ * Base-2, i.e. '01'.
+ * @type {string}
+ */
+goog.crypt.baseN.BASE_BINARY = '01';
+
+
+/**
+ * Base-8, i.e. '01234567'.
+ * @type {string}
+ */
+goog.crypt.baseN.BASE_OCTAL = '01234567';
+
+
+/**
+ * Base-10, i.e. '0123456789'.
+ * @type {string}
+ */
+goog.crypt.baseN.BASE_DECIMAL = '0123456789';
+
+
+/**
+ * Base-16 using lower case, i.e. '0123456789abcdef'.
+ * @type {string}
+ */
+goog.crypt.baseN.BASE_LOWERCASE_HEXADECIMAL = '0123456789abcdef';
+
+
+/**
+ * Base-16 using upper case, i.e. '0123456789ABCDEF'.
+ * @type {string}
+ */
+goog.crypt.baseN.BASE_UPPERCASE_HEXADECIMAL = '0123456789ABCDEF';
+
+
+/**
+ * The more-known version of the BASE-64 encoding.  Uses + and / characters.
+ * @type {string}
+ */
+goog.crypt.baseN.BASE_64 =
+    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+
+
+/**
+ * URL-safe version of the BASE-64 encoding.
+ * @type {string}
+ */
+goog.crypt.baseN.BASE_64_URL_SAFE =
+    'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
+
+
+/**
+ * Converts a number from one numeric base to another.
+ *
+ * The bases are represented as strings, which list allowed digits.  Each digit
+ * should be unique.  The bases can either be user defined, or any of
+ * goog.crypt.baseN.BASE_xxx.
+ *
+ * The number is in human-readable format, most significant digit first, and is
+ * a non-negative integer.  Base designators such as $, 0x, d, b or h (at end)
+ * will be interpreted as digits, so avoid them.  Leading zeros will be trimmed.
+ *
+ * Note: for huge bases the result may be inaccurate because of overflowing
+ * 64-bit doubles used by JavaScript for integer calculus.  This may happen
+ * if the product of the number of digits in the input and output bases comes
+ * close to 10^16, which is VERY unlikely (100M digits in each base), but
+ * may be possible in the future unicode world.  (Unicode 3.2 has less than 100K
+ * characters.  However, it reserves some more, close to 1M.)
+ *
+ * @param {string} number The number to convert.
+ * @param {string} inputBase The numeric base the number is in (all digits).
+ * @param {string} outputBase Requested numeric base.
+ * @return {string} The converted number.
+ */
+goog.crypt.baseN.recodeString = function(number, inputBase, outputBase) {
+  if (outputBase == '') {
+    throw Error('Empty output base');
+  }
+
+  // Check if number is 0 (special case when we don't want to return '').
+  var isZero = true;
+  for (var i = 0, n = number.length; i < n; i++) {
+    if (number.charAt(i) != inputBase.charAt(0)) {
+      isZero = false;
+      break;
+    }
+  }
+  if (isZero) {
+    return outputBase.charAt(0);
+  }
+
+  var numberDigits = goog.crypt.baseN.stringToArray_(number, inputBase);
+
+  var inputBaseSize = inputBase.length;
+  var outputBaseSize = outputBase.length;
+
+  // result = 0.
+  var result = [];
+
+  // For all digits of number, starting with the most significant ...
+  for (var i = numberDigits.length - 1; i >= 0; i--) {
+
+    // result *= number.base.
+    var carry = 0;
+    for (var j = 0, n = result.length; j < n; j++) {
+      var digit = result[j];
+      // This may overflow for huge bases.  See function comment.
+      digit = digit * inputBaseSize + carry;
+      if (digit >= outputBaseSize) {
+        var remainder = digit % outputBaseSize;
+        carry = (digit - remainder) / outputBaseSize;
+        digit = remainder;
+      } else {
+        carry = 0;
+      }
+      result[j] = digit;
+    }
+    while (carry) {
+      var remainder = carry % outputBaseSize;
+      result.push(remainder);
+      carry = (carry - remainder) / outputBaseSize;
+    }
+
+    // result += number[i].
+    carry = numberDigits[i];
+    var j = 0;
+    while (carry) {
+      if (j >= result.length) {
+        // Extend result with a leading zero which will be overwritten below.
+        result.push(0);
+      }
+      var digit = result[j];
+      digit += carry;
+      if (digit >= outputBaseSize) {
+        var remainder = digit % outputBaseSize;
+        carry = (digit - remainder) / outputBaseSize;
+        digit = remainder;
+      } else {
+        carry = 0;
+      }
+      result[j] = digit;
+      j++;
+    }
+  }
+
+  return goog.crypt.baseN.arrayToString_(result, outputBase);
+};
+
+
+/**
+ * Converts a string representation of a number to an array of digit values.
+ *
+ * More precisely, the digit values are indices into the number base, which
+ * is represented as a string, which can either be user defined or one of the
+ * BASE_xxx constants.
+ *
+ * Throws an Error if the number contains a digit not found in the base.
+ *
+ * @param {string} number The string to convert, most significant digit first.
+ * @param {string} base Digits in the base.
+ * @return {!Array<number>} Array of digit values, least significant digit
+ *     first.
+ * @private
+ */
+goog.crypt.baseN.stringToArray_ = function(number, base) {
+  var index = {};
+  for (var i = 0, n = base.length; i < n; i++) {
+    index[base.charAt(i)] = i;
+  }
+  var result = [];
+  for (var i = number.length - 1; i >= 0; i--) {
+    var character = number.charAt(i);
+    var digit = index[character];
+    if (typeof digit == 'undefined') {
+      throw Error('Number ' + number +
+                  ' contains a character not found in base ' +
+                  base + ', which is ' + character);
+    }
+    result.push(digit);
+  }
+  return result;
+};
+
+
+/**
+ * Converts an array representation of a number to a string.
+ *
+ * More precisely, the elements of the input array are indices into the base,
+ * which is represented as a string, which can either be user defined or one of
+ * the BASE_xxx constants.
+ *
+ * Throws an Error if the number contains a digit which is outside the range
+ * 0 ... base.length - 1.
+ *
+ * @param {Array<number>} number Array of digit values, least significant
+ *     first.
+ * @param {string} base Digits in the base.
+ * @return {string} Number as a string, most significant digit first.
+ * @private
+ */
+goog.crypt.baseN.arrayToString_ = function(number, base) {
+  var n = number.length;
+  var chars = [];
+  var baseSize = base.length;
+  for (var i = n - 1; i >= 0; i--) {
+    var digit = number[i];
+    if (digit >= baseSize || digit < 0) {
+      throw Error('Number ' + number + ' contains an invalid digit: ' + digit);
+    }
+    chars.push(base.charAt(digit));
+  }
+  return chars.join('');
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/blobhasher.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/blobhasher.js b/externs/GCL/externs/goog/crypt/blobhasher.js
new file mode 100644
index 0000000..cb4af79
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/blobhasher.js
@@ -0,0 +1,285 @@
+// Copyright 2011 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 Asynchronous hash computer for the Blob interface.
+ *
+ * The Blob interface, part of the HTML5 File API, is supported on Chrome 7+,
+ * Firefox 4.0 and Opera 11. No Blob interface implementation is expected on
+ * Internet Explorer 10. Chrome 11, Firefox 5.0 and the subsequent release of
+ * Opera are supposed to use vendor prefixes due to evolving API, see
+ * http://dev.w3.org/2006/webapi/FileAPI/ for details.
+ *
+ * This implementation currently uses upcoming Chrome and Firefox prefixes,
+ * plus the original Blob.slice specification, as implemented on Chrome 10
+ * and Firefox 4.0.
+ *
+ */
+
+goog.provide('goog.crypt.BlobHasher');
+goog.provide('goog.crypt.BlobHasher.EventType');
+
+goog.require('goog.asserts');
+goog.require('goog.events.EventTarget');
+goog.require('goog.fs');
+goog.require('goog.log');
+
+
+
+/**
+ * Construct the hash computer.
+ *
+ * @param {!goog.crypt.Hash} hashFn The hash function to use.
+ * @param {number=} opt_blockSize Processing block size.
+ * @constructor
+ * @struct
+ * @suppress {checkStructDictInheritance}
+ * @extends {goog.events.EventTarget}
+ * @final
+ */
+goog.crypt.BlobHasher = function(hashFn, opt_blockSize) {
+  goog.crypt.BlobHasher.base(this, 'constructor');
+
+  /**
+   * The actual hash function.
+   * @type {!goog.crypt.Hash}
+   * @private
+   */
+  this.hashFn_ = hashFn;
+
+  /**
+   * The blob being processed or null if no blob is being processed.
+   * @type {Blob}
+   * @private
+   */
+  this.blob_ = null;
+
+  /**
+   * Computed hash value.
+   * @type {Array<number>}
+   * @private
+   */
+  this.hashVal_ = null;
+
+  /**
+   * Number of bytes already processed.
+   * @type {number}
+   * @private
+   */
+  this.bytesProcessed_ = 0;
+
+  /**
+   * The number of bytes to hash or Infinity for no limit.
+   * @type {number}
+   * @private
+   */
+  this.hashingLimit_ = Infinity;
+
+  /**
+   * Processing block size.
+   * @type {number}
+   * @private
+   */
+  this.blockSize_ = opt_blockSize || 5000000;
+
+  /**
+   * File reader object. Will be null if no chunk is currently being read.
+   * @type {FileReader}
+   * @private
+   */
+  this.fileReader_ = null;
+
+  /**
+   * The logger used by this object.
+   * @type {goog.log.Logger}
+   * @private
+   */
+  this.logger_ = goog.log.getLogger('goog.crypt.BlobHasher');
+};
+goog.inherits(goog.crypt.BlobHasher, goog.events.EventTarget);
+
+
+/**
+ * Event names for hash computation events
+ * @enum {string}
+ */
+goog.crypt.BlobHasher.EventType = {
+  STARTED: 'started',
+  PROGRESS: 'progress',
+  THROTTLED: 'throttled',
+  COMPLETE: 'complete',
+  ABORT: 'abort',
+  ERROR: 'error'
+};
+
+
+/**
+ * Start the hash computation.
+ * @param {!Blob} blob The blob of data to compute the hash for.
+ */
+goog.crypt.BlobHasher.prototype.hash = function(blob) {
+  this.abort();
+  this.hashFn_.reset();
+  this.blob_ = blob;
+  this.hashVal_ = null;
+  this.bytesProcessed_ = 0;
+  this.dispatchEvent(goog.crypt.BlobHasher.EventType.STARTED);
+
+  this.processNextBlock_();
+};
+
+
+/**
+ * Sets the maximum number of bytes to hash or Infinity for no limit. Can be
+ * called before hash() to throttle the hash computation. The hash computation
+ * can then be continued by repeatedly calling setHashingLimit() with greater
+ * byte offsets. This is useful if you don't need the hash until some time in
+ * the future, for example when uploading a file and you don't need the hash
+ * until the transfer is complete.
+ * @param {number} byteOffset The byte offset to compute the hash up to.
+ *     Should be a non-negative integer or Infinity for no limit. Negative
+ *     values are not allowed.
+ */
+goog.crypt.BlobHasher.prototype.setHashingLimit = function(byteOffset) {
+  goog.asserts.assert(byteOffset >= 0, 'Hashing limit must be non-negative.');
+  this.hashingLimit_ = byteOffset;
+
+  // Resume processing if a blob is currently being hashed, but no block read
+  // is currently in progress.
+  if (this.blob_ && !this.fileReader_) {
+    this.processNextBlock_();
+  }
+};
+
+
+/**
+ * Abort hash computation.
+ */
+goog.crypt.BlobHasher.prototype.abort = function() {
+  if (this.fileReader_) {
+    this.fileReader_.abort();
+    this.fileReader_ = null;
+  }
+
+  if (this.blob_) {
+    this.blob_ = null;
+    this.dispatchEvent(goog.crypt.BlobHasher.EventType.ABORT);
+  }
+};
+
+
+/**
+ * @return {number} Number of bytes processed so far.
+ */
+goog.crypt.BlobHasher.prototype.getBytesProcessed = function() {
+  return this.bytesProcessed_;
+};
+
+
+/**
+ * @return {Array<number>} The computed hash value or null if not ready.
+ */
+goog.crypt.BlobHasher.prototype.getHash = function() {
+  return this.hashVal_;
+};
+
+
+/**
+ * Helper function setting up the processing for the next block, or finalizing
+ * the computation if all blocks were processed.
+ * @private
+ */
+goog.crypt.BlobHasher.prototype.processNextBlock_ = function() {
+  goog.asserts.assert(this.blob_, 'A hash computation must be in progress.');
+
+  if (this.bytesProcessed_ < this.blob_.size) {
+
+    if (this.hashingLimit_ <= this.bytesProcessed_) {
+      // Throttle limit reached. Wait until we are allowed to hash more bytes.
+      this.dispatchEvent(goog.crypt.BlobHasher.EventType.THROTTLED);
+      return;
+    }
+
+    // We have to reset the FileReader every time, otherwise it fails on
+    // Chrome, including the latest Chrome 12 beta.
+    // http://code.google.com/p/chromium/issues/detail?id=82346
+    this.fileReader_ = new FileReader();
+    this.fileReader_.onload = goog.bind(this.onLoad_, this);
+    this.fileReader_.onerror = goog.bind(this.onError_, this);
+
+    var endOffset = Math.min(this.hashingLimit_, this.blob_.size);
+    var size = Math.min(endOffset - this.bytesProcessed_, this.blockSize_);
+    var chunk = goog.fs.sliceBlob(this.blob_, this.bytesProcessed_,
+                                  this.bytesProcessed_ + size);
+    if (!chunk || chunk.size != size) {
+      goog.log.error(this.logger_, 'Failed slicing the blob');
+      this.onError_();
+      return;
+    }
+
+    if (this.fileReader_.readAsArrayBuffer) {
+      this.fileReader_.readAsArrayBuffer(chunk);
+    } else if (this.fileReader_.readAsBinaryString) {
+      this.fileReader_.readAsBinaryString(chunk);
+    } else {
+      goog.log.error(this.logger_, 'Failed calling the chunk reader');
+      this.onError_();
+    }
+  } else {
+    this.hashVal_ = this.hashFn_.digest();
+    this.blob_ = null;
+    this.dispatchEvent(goog.crypt.BlobHasher.EventType.COMPLETE);
+  }
+};
+
+
+/**
+ * Handle processing block loaded.
+ * @private
+ */
+goog.crypt.BlobHasher.prototype.onLoad_ = function() {
+  goog.log.info(this.logger_, 'Successfully loaded a chunk');
+
+  var array = null;
+  if (this.fileReader_.result instanceof Array ||
+      goog.isString(this.fileReader_.result)) {
+    array = this.fileReader_.result;
+  } else if (goog.global['ArrayBuffer'] && goog.global['Uint8Array'] &&
+             this.fileReader_.result instanceof ArrayBuffer) {
+    array = new Uint8Array(this.fileReader_.result);
+  }
+  if (!array) {
+    goog.log.error(this.logger_, 'Failed reading the chunk');
+    this.onError_();
+    return;
+  }
+
+  this.hashFn_.update(array);
+  this.bytesProcessed_ += array.length;
+  this.fileReader_ = null;
+  this.dispatchEvent(goog.crypt.BlobHasher.EventType.PROGRESS);
+
+  this.processNextBlock_();
+};
+
+
+/**
+ * Handles error.
+ * @private
+ */
+goog.crypt.BlobHasher.prototype.onError_ = function() {
+  this.fileReader_ = null;
+  this.blob_ = null;
+  this.dispatchEvent(goog.crypt.BlobHasher.EventType.ERROR);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/blockcipher.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/blockcipher.js b/externs/GCL/externs/goog/crypt/blockcipher.js
new file mode 100644
index 0000000..be766f0
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/blockcipher.js
@@ -0,0 +1,52 @@
+// 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 Interface definition of a block cipher. A block cipher is a
+ * pair of algorithms that implement encryption and decryption of input bytes.
+ *
+ * @see http://en.wikipedia.org/wiki/Block_cipher
+ *
+ * @author nnaze@google.com (Nathan Naze)
+ */
+
+goog.provide('goog.crypt.BlockCipher');
+
+
+
+/**
+ * Interface definition for a block cipher.
+ * @interface
+ */
+goog.crypt.BlockCipher = function() {};
+
+
+/**
+ * Encrypt a plaintext block.  The implementation may expect (and assert)
+ * a particular block length.
+ * @param {!Array<number>} input Plaintext array of input bytes.
+ * @return {!Array<number>} Encrypted ciphertext array of bytes.  Should be the
+ *     same length as input.
+ */
+goog.crypt.BlockCipher.prototype.encrypt;
+
+
+/**
+ * Decrypt a plaintext block.  The implementation may expect (and assert)
+ * a particular block length.
+ * @param {!Array<number>} input Ciphertext. Array of input bytes.
+ * @return {!Array<number>} Decrypted plaintext array of bytes.  Should be the
+ *     same length as input.
+ */
+goog.crypt.BlockCipher.prototype.decrypt;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/cbc.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/cbc.js b/externs/GCL/externs/goog/crypt/cbc.js
new file mode 100644
index 0000000..68a2656
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/cbc.js
@@ -0,0 +1,153 @@
+// 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 Implementation of CBC mode for block ciphers.  See
+ *     http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation
+ *     #Cipher-block_chaining_.28CBC.29. for description.
+ *
+ * @author nnaze@google.com (Nathan Naze)
+ */
+
+goog.provide('goog.crypt.Cbc');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.crypt');
+
+
+
+/**
+ * Implements the CBC mode for block ciphers. See
+ * http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation
+ * #Cipher-block_chaining_.28CBC.29
+ *
+ * @param {!goog.crypt.BlockCipher} cipher The block cipher to use.
+ * @param {number=} opt_blockSize The block size of the cipher in bytes.
+ *     Defaults to 16 bytes.
+ * @constructor
+ * @final
+ * @struct
+ */
+goog.crypt.Cbc = function(cipher, opt_blockSize) {
+
+  /**
+   * Block cipher.
+   * @type {!goog.crypt.BlockCipher}
+   * @private
+   */
+  this.cipher_ = cipher;
+
+  /**
+   * Block size in bytes.
+   * @type {number}
+   * @private
+   */
+  this.blockSize_ = opt_blockSize || 16;
+};
+
+
+/**
+ * Encrypt a message.
+ *
+ * @param {!Array<number>} plainText Message to encrypt. An array of bytes.
+ *     The length should be a multiple of the block size.
+ * @param {!Array<number>} initialVector Initial vector for the CBC mode.
+ *     An array of bytes with the same length as the block size.
+ * @return {!Array<number>} Encrypted message.
+ */
+goog.crypt.Cbc.prototype.encrypt = function(plainText, initialVector) {
+
+  goog.asserts.assert(
+      plainText.length % this.blockSize_ == 0,
+      'Data\'s length must be multiple of block size.');
+
+  goog.asserts.assert(
+      initialVector.length == this.blockSize_,
+      'Initial vector must be size of one block.');
+
+  // Implementation of
+  // http://en.wikipedia.org/wiki/File:Cbc_encryption.png
+
+  var cipherText = [];
+  var vector = initialVector;
+
+  // Generate each block of the encrypted cypher text.
+  for (var blockStartIndex = 0;
+       blockStartIndex < plainText.length;
+       blockStartIndex += this.blockSize_) {
+
+    // Takes one block from the input message.
+    var plainTextBlock = goog.array.slice(
+        plainText,
+        blockStartIndex,
+        blockStartIndex + this.blockSize_);
+
+    var input = goog.crypt.xorByteArray(plainTextBlock, vector);
+    var resultBlock = this.cipher_.encrypt(input);
+
+    goog.array.extend(cipherText, resultBlock);
+    vector = resultBlock;
+  }
+
+  return cipherText;
+};
+
+
+/**
+ * Decrypt a message.
+ *
+ * @param {!Array<number>} cipherText Message to decrypt. An array of bytes.
+ *     The length should be a multiple of the block size.
+ * @param {!Array<number>} initialVector Initial vector for the CBC mode.
+ *     An array of bytes with the same length as the block size.
+ * @return {!Array<number>} Decrypted message.
+ */
+goog.crypt.Cbc.prototype.decrypt = function(cipherText, initialVector) {
+
+  goog.asserts.assert(
+      cipherText.length % this.blockSize_ == 0,
+      'Data\'s length must be multiple of block size.');
+
+  goog.asserts.assert(
+      initialVector.length == this.blockSize_,
+      'Initial vector must be size of one block.');
+
+  // Implementation of
+  // http://en.wikipedia.org/wiki/File:Cbc_decryption.png
+
+  var plainText = [];
+  var blockStartIndex = 0;
+  var vector = initialVector;
+
+  // Generate each block of the decrypted plain text.
+  while (blockStartIndex < cipherText.length) {
+
+    // Takes one block.
+    var cipherTextBlock = goog.array.slice(
+        cipherText,
+        blockStartIndex,
+        blockStartIndex + this.blockSize_);
+
+    var resultBlock = this.cipher_.decrypt(cipherTextBlock);
+    var plainTextBlock = goog.crypt.xorByteArray(vector, resultBlock);
+
+    goog.array.extend(plainText, plainTextBlock);
+    vector = cipherTextBlock;
+
+    blockStartIndex += this.blockSize_;
+  }
+
+  return plainText;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/crypt.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/crypt.js b/externs/GCL/externs/goog/crypt/crypt.js
new file mode 100644
index 0000000..e8f722a
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/crypt.js
@@ -0,0 +1,173 @@
+// Copyright 2008 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 Namespace with crypto related helper functions.
+ */
+
+goog.provide('goog.crypt');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+
+
+/**
+ * Turns a string into an array of bytes; a "byte" being a JS number in the
+ * range 0-255.
+ * @param {string} str String value to arrify.
+ * @return {!Array<number>} Array of numbers corresponding to the
+ *     UCS character codes of each character in str.
+ */
+goog.crypt.stringToByteArray = function(str) {
+  var output = [], p = 0;
+  for (var i = 0; i < str.length; i++) {
+    var c = str.charCodeAt(i);
+    while (c > 0xff) {
+      output[p++] = c & 0xff;
+      c >>= 8;
+    }
+    output[p++] = c;
+  }
+  return output;
+};
+
+
+/**
+ * Turns an array of numbers into the string given by the concatenation of the
+ * characters to which the numbers correspond.
+ * @param {Array<number>} bytes Array of numbers representing characters.
+ * @return {string} Stringification of the array.
+ */
+goog.crypt.byteArrayToString = function(bytes) {
+  var CHUNK_SIZE = 8192;
+
+  // Special-case the simple case for speed's sake.
+  if (bytes.length < CHUNK_SIZE) {
+    return String.fromCharCode.apply(null, bytes);
+  }
+
+  // The remaining logic splits conversion by chunks since
+  // Function#apply() has a maximum parameter count.
+  // See discussion: http://goo.gl/LrWmZ9
+
+  var str = '';
+  for (var i = 0; i < bytes.length; i += CHUNK_SIZE) {
+    var chunk = goog.array.slice(bytes, i, i + CHUNK_SIZE);
+    str += String.fromCharCode.apply(null, chunk);
+  }
+  return str;
+};
+
+
+/**
+ * Turns an array of numbers into the hex string given by the concatenation of
+ * the hex values to which the numbers correspond.
+ * @param {Uint8Array|Array<number>} array Array of numbers representing
+ *     characters.
+ * @return {string} Hex string.
+ */
+goog.crypt.byteArrayToHex = function(array) {
+  return goog.array.map(array, function(numByte) {
+    var hexByte = numByte.toString(16);
+    return hexByte.length > 1 ? hexByte : '0' + hexByte;
+  }).join('');
+};
+
+
+/**
+ * Converts a hex string into an integer array.
+ * @param {string} hexString Hex string of 16-bit integers (two characters
+ *     per integer).
+ * @return {!Array<number>} Array of {0,255} integers for the given string.
+ */
+goog.crypt.hexToByteArray = function(hexString) {
+  goog.asserts.assert(hexString.length % 2 == 0,
+                      'Key string length must be multiple of 2');
+  var arr = [];
+  for (var i = 0; i < hexString.length; i += 2) {
+    arr.push(parseInt(hexString.substring(i, i + 2), 16));
+  }
+  return arr;
+};
+
+
+/**
+ * Converts a JS string to a UTF-8 "byte" array.
+ * @param {string} str 16-bit unicode string.
+ * @return {!Array<number>} UTF-8 byte array.
+ */
+goog.crypt.stringToUtf8ByteArray = function(str) {
+  // TODO(user): Use native implementations if/when available
+  str = str.replace(/\r\n/g, '\n');
+  var out = [], p = 0;
+  for (var i = 0; i < str.length; i++) {
+    var c = str.charCodeAt(i);
+    if (c < 128) {
+      out[p++] = c;
+    } else if (c < 2048) {
+      out[p++] = (c >> 6) | 192;
+      out[p++] = (c & 63) | 128;
+    } else {
+      out[p++] = (c >> 12) | 224;
+      out[p++] = ((c >> 6) & 63) | 128;
+      out[p++] = (c & 63) | 128;
+    }
+  }
+  return out;
+};
+
+
+/**
+ * Converts a UTF-8 byte array to JavaScript's 16-bit Unicode.
+ * @param {Uint8Array|Array<number>} bytes UTF-8 byte array.
+ * @return {string} 16-bit Unicode string.
+ */
+goog.crypt.utf8ByteArrayToString = function(bytes) {
+  // TODO(user): Use native implementations if/when available
+  var out = [], pos = 0, c = 0;
+  while (pos < bytes.length) {
+    var c1 = bytes[pos++];
+    if (c1 < 128) {
+      out[c++] = String.fromCharCode(c1);
+    } else if (c1 > 191 && c1 < 224) {
+      var c2 = bytes[pos++];
+      out[c++] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
+    } else {
+      var c2 = bytes[pos++];
+      var c3 = bytes[pos++];
+      out[c++] = String.fromCharCode(
+          (c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
+    }
+  }
+  return out.join('');
+};
+
+
+/**
+ * XOR two byte arrays.
+ * @param {!ArrayBufferView|!Array<number>} bytes1 Byte array 1.
+ * @param {!ArrayBufferView|!Array<number>} bytes2 Byte array 2.
+ * @return {!Array<number>} Resulting XOR of the two byte arrays.
+ */
+goog.crypt.xorByteArray = function(bytes1, bytes2) {
+  goog.asserts.assert(
+      bytes1.length == bytes2.length,
+      'XOR array lengths must match');
+
+  var result = [];
+  for (var i = 0; i < bytes1.length; i++) {
+    result.push(bytes1[i] ^ bytes2[i]);
+  }
+  return result;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/hash.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/hash.js b/externs/GCL/externs/goog/crypt/hash.js
new file mode 100644
index 0000000..51209be
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/hash.js
@@ -0,0 +1,69 @@
+// Copyright 2011 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 Abstract cryptographic hash interface.
+ *
+ * See goog.crypt.Sha1 and goog.crypt.Md5 for sample implementations.
+ *
+ */
+
+goog.provide('goog.crypt.Hash');
+
+
+
+/**
+ * Create a cryptographic hash instance.
+ *
+ * @constructor
+ * @struct
+ */
+goog.crypt.Hash = function() {
+  /**
+   * The block size for the hasher.
+   * @type {number}
+   */
+  this.blockSize = -1;
+};
+
+
+/**
+ * Resets the internal accumulator.
+ */
+goog.crypt.Hash.prototype.reset = goog.abstractMethod;
+
+
+/**
+ * Adds a byte array (array with values in [0-255] range) or a string (might
+ * only contain 8-bit, i.e., Latin1 characters) to the internal accumulator.
+ *
+ * Many hash functions operate on blocks of data and implement optimizations
+ * when a full chunk of data is readily available. Hence it is often preferable
+ * to provide large chunks of data (a kilobyte or more) than to repeatedly
+ * call the update method with few tens of bytes. If this is not possible, or
+ * not feasible, it might be good to provide data in multiplies of hash block
+ * size (often 64 bytes). Please see the implementation and performance tests
+ * of your favourite hash.
+ *
+ * @param {Array<number>|Uint8Array|string} bytes Data used for the update.
+ * @param {number=} opt_length Number of bytes to use.
+ */
+goog.crypt.Hash.prototype.update = goog.abstractMethod;
+
+
+/**
+ * @return {!Array<number>} The finalized hash computed
+ *     from the internal accumulator.
+ */
+goog.crypt.Hash.prototype.digest = goog.abstractMethod;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/hash32.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/hash32.js b/externs/GCL/externs/goog/crypt/hash32.js
new file mode 100644
index 0000000..fa24ccf
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/hash32.js
@@ -0,0 +1,184 @@
+// Copyright 2008 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 Implementation of 32-bit hashing functions.
+ *
+ * This is a direct port from the Google Java Hash class
+ *
+ */
+
+goog.provide('goog.crypt.hash32');
+
+goog.require('goog.crypt');
+
+
+/**
+ * Default seed used during hashing, digits of pie.
+ * See SEED32 in http://go/base.hash.java
+ * @type {number}
+ */
+goog.crypt.hash32.SEED32 = 314159265;
+
+
+/**
+ * Arbitrary constant used during hashing.
+ * See CONSTANT32 in http://go/base.hash.java
+ * @type {number}
+ */
+goog.crypt.hash32.CONSTANT32 = -1640531527;
+
+
+/**
+ * Hashes a string to a 32-bit value.
+ * @param {string} str String to hash.
+ * @return {number} 32-bit hash.
+ */
+goog.crypt.hash32.encodeString = function(str) {
+  return goog.crypt.hash32.encodeByteArray(goog.crypt.stringToByteArray(str));
+};
+
+
+/**
+ * Hashes a string to a 32-bit value, converting the string to UTF-8 before
+ * doing the encoding.
+ * @param {string} str String to hash.
+ * @return {number} 32-bit hash.
+ */
+goog.crypt.hash32.encodeStringUtf8 = function(str) {
+  return goog.crypt.hash32.encodeByteArray(
+      goog.crypt.stringToUtf8ByteArray(str));
+};
+
+
+/**
+ * Hashes an integer to a 32-bit value.
+ * @param {number} value Number to hash.
+ * @return {number} 32-bit hash.
+ */
+goog.crypt.hash32.encodeInteger = function(value) {
+  // TODO(user): Does this make sense in JavaScript with doubles?  Should we
+  // force the value to be in the correct range?
+  return goog.crypt.hash32.mix32_({
+    a: value,
+    b: goog.crypt.hash32.CONSTANT32,
+    c: goog.crypt.hash32.SEED32
+  });
+};
+
+
+/**
+ * Hashes a "byte" array to a 32-bit value using the supplied seed.
+ * @param {Array<number>} bytes Array of bytes.
+ * @param {number=} opt_offset The starting position to use for hash
+ * computation.
+ * @param {number=} opt_length Number of bytes that are used for hashing.
+ * @param {number=} opt_seed The seed.
+ * @return {number} 32-bit hash.
+ */
+goog.crypt.hash32.encodeByteArray = function(
+    bytes, opt_offset, opt_length, opt_seed) {
+  var offset = opt_offset || 0;
+  var length = opt_length || bytes.length;
+  var seed = opt_seed || goog.crypt.hash32.SEED32;
+
+  var mix = {
+    a: goog.crypt.hash32.CONSTANT32,
+    b: goog.crypt.hash32.CONSTANT32,
+    c: seed
+  };
+
+  var keylen;
+  for (keylen = length; keylen >= 12; keylen -= 12, offset += 12) {
+    mix.a += goog.crypt.hash32.wordAt_(bytes, offset);
+    mix.b += goog.crypt.hash32.wordAt_(bytes, offset + 4);
+    mix.c += goog.crypt.hash32.wordAt_(bytes, offset + 8);
+    goog.crypt.hash32.mix32_(mix);
+  }
+  // Hash any remaining bytes
+  mix.c += length;
+  switch (keylen) {  // deal with rest.  Some cases fall through
+    case 11: mix.c += (bytes[offset + 10]) << 24;
+    case 10: mix.c += (bytes[offset + 9] & 0xff) << 16;
+    case 9 : mix.c += (bytes[offset + 8] & 0xff) << 8;
+    // the first byte of c is reserved for the length
+    case 8 :
+      mix.b += goog.crypt.hash32.wordAt_(bytes, offset + 4);
+      mix.a += goog.crypt.hash32.wordAt_(bytes, offset);
+      break;
+    case 7 : mix.b += (bytes[offset + 6] & 0xff) << 16;
+    case 6 : mix.b += (bytes[offset + 5] & 0xff) << 8;
+    case 5 : mix.b += (bytes[offset + 4] & 0xff);
+    case 4 :
+      mix.a += goog.crypt.hash32.wordAt_(bytes, offset);
+      break;
+    case 3 : mix.a += (bytes[offset + 2] & 0xff) << 16;
+    case 2 : mix.a += (bytes[offset + 1] & 0xff) << 8;
+    case 1 : mix.a += (bytes[offset + 0] & 0xff);
+    // case 0 : nothing left to add
+  }
+  return goog.crypt.hash32.mix32_(mix);
+};
+
+
+/**
+ * Performs an inplace mix of an object with the integer properties (a, b, c)
+ * and returns the final value of c.
+ * @param {Object} mix Object with properties, a, b, and c.
+ * @return {number} The end c-value for the mixing.
+ * @private
+ */
+goog.crypt.hash32.mix32_ = function(mix) {
+  var a = mix.a, b = mix.b, c = mix.c;
+  a -= b; a -= c; a ^= c >>> 13;
+  b -= c; b -= a; b ^= a << 8;
+  c -= a; c -= b; c ^= b >>> 13;
+  a -= b; a -= c; a ^= c >>> 12;
+  b -= c; b -= a; b ^= a << 16;
+  c -= a; c -= b; c ^= b >>> 5;
+  a -= b; a -= c; a ^= c >>> 3;
+  b -= c; b -= a; b ^= a << 10;
+  c -= a; c -= b; c ^= b >>> 15;
+  mix.a = a; mix.b = b; mix.c = c;
+  return c;
+};
+
+
+/**
+ * Returns the word at a given offset.  Treating an array of bytes a word at a
+ * time is far more efficient than byte-by-byte.
+ * @param {Array<number>} bytes Array of bytes.
+ * @param {number} offset Offset in the byte array.
+ * @return {number} Integer value for the word.
+ * @private
+ */
+goog.crypt.hash32.wordAt_ = function(bytes, offset) {
+  var a = goog.crypt.hash32.toSigned_(bytes[offset + 0]);
+  var b = goog.crypt.hash32.toSigned_(bytes[offset + 1]);
+  var c = goog.crypt.hash32.toSigned_(bytes[offset + 2]);
+  var d = goog.crypt.hash32.toSigned_(bytes[offset + 3]);
+  return a + (b << 8) + (c << 16) + (d << 24);
+};
+
+
+/**
+ * Converts an unsigned "byte" to signed, that is, convert a value in the range
+ * (0, 2^8-1) to (-2^7, 2^7-1) in order to be compatible with Java's byte type.
+ * @param {number} n Unsigned "byte" value.
+ * @return {number} Signed "byte" value.
+ * @private
+ */
+goog.crypt.hash32.toSigned_ = function(n) {
+  return n > 127 ? n - 256 : n;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/hmac.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/hmac.js b/externs/GCL/externs/goog/crypt/hmac.js
new file mode 100644
index 0000000..15e0e1d
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/hmac.js
@@ -0,0 +1,160 @@
+// Copyright 2011 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 Implementation of HMAC in JavaScript.
+ *
+ * Usage:
+ *   var hmac = new goog.crypt.Hmac(new goog.crypt.sha1(), key, 64);
+ *   var digest = hmac.getHmac(bytes);
+ *
+ * @author benyu@google.com (Jige Yu) - port to closure
+ */
+
+
+goog.provide('goog.crypt.Hmac');
+
+goog.require('goog.crypt.Hash');
+
+
+
+/**
+ * @constructor
+ * @param {!goog.crypt.Hash} hasher An object to serve as a hash function.
+ * @param {Array<number>} key The secret key to use to calculate the hmac.
+ *     Should be an array of not more than {@code blockSize} integers in
+       {0, 255}.
+ * @param {number=} opt_blockSize Optional. The block size {@code hasher} uses.
+ *     If not specified, uses the block size from the hasher, or 16 if it is
+ *     not specified.
+ * @extends {goog.crypt.Hash}
+ * @final
+ * @struct
+ */
+goog.crypt.Hmac = function(hasher, key, opt_blockSize) {
+  goog.crypt.Hmac.base(this, 'constructor');
+
+  /**
+   * The underlying hasher to calculate hash.
+   *
+   * @type {!goog.crypt.Hash}
+   * @private
+   */
+  this.hasher_ = hasher;
+
+  this.blockSize = opt_blockSize || hasher.blockSize || 16;
+
+  /**
+   * The outer padding array of hmac
+   *
+   * @type {!Array<number>}
+   * @private
+   */
+  this.keyO_ = new Array(this.blockSize);
+
+  /**
+   * The inner padding array of hmac
+   *
+   * @type {!Array<number>}
+   * @private
+   */
+  this.keyI_ = new Array(this.blockSize);
+
+  this.initialize_(key);
+};
+goog.inherits(goog.crypt.Hmac, goog.crypt.Hash);
+
+
+/**
+ * Outer padding byte of HMAC algorith, per http://en.wikipedia.org/wiki/HMAC
+ *
+ * @type {number}
+ * @private
+ */
+goog.crypt.Hmac.OPAD_ = 0x5c;
+
+
+/**
+ * Inner padding byte of HMAC algorith, per http://en.wikipedia.org/wiki/HMAC
+ *
+ * @type {number}
+ * @private
+ */
+goog.crypt.Hmac.IPAD_ = 0x36;
+
+
+/**
+ * Initializes Hmac by precalculating the inner and outer paddings.
+ *
+ * @param {Array<number>} key The secret key to use to calculate the hmac.
+ *     Should be an array of not more than {@code blockSize} integers in
+       {0, 255}.
+ * @private
+ */
+goog.crypt.Hmac.prototype.initialize_ = function(key) {
+  if (key.length > this.blockSize) {
+    this.hasher_.update(key);
+    key = this.hasher_.digest();
+    this.hasher_.reset();
+  }
+  // Precalculate padded and xor'd keys.
+  var keyByte;
+  for (var i = 0; i < this.blockSize; i++) {
+    if (i < key.length) {
+      keyByte = key[i];
+    } else {
+      keyByte = 0;
+    }
+    this.keyO_[i] = keyByte ^ goog.crypt.Hmac.OPAD_;
+    this.keyI_[i] = keyByte ^ goog.crypt.Hmac.IPAD_;
+  }
+  // Be ready for an immediate update.
+  this.hasher_.update(this.keyI_);
+};
+
+
+/** @override */
+goog.crypt.Hmac.prototype.reset = function() {
+  this.hasher_.reset();
+  this.hasher_.update(this.keyI_);
+};
+
+
+/** @override */
+goog.crypt.Hmac.prototype.update = function(bytes, opt_length) {
+  this.hasher_.update(bytes, opt_length);
+};
+
+
+/** @override */
+goog.crypt.Hmac.prototype.digest = function() {
+  var temp = this.hasher_.digest();
+  this.hasher_.reset();
+  this.hasher_.update(this.keyO_);
+  this.hasher_.update(temp);
+  return this.hasher_.digest();
+};
+
+
+/**
+ * Calculates an HMAC for a given message.
+ *
+ * @param {Array<number>|Uint8Array|string} message  Data to Hmac.
+ * @return {!Array<number>} the digest of the given message.
+ */
+goog.crypt.Hmac.prototype.getHmac = function(message) {
+  this.reset();
+  this.update(message);
+  return this.digest();
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/md5.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/md5.js b/externs/GCL/externs/goog/crypt/md5.js
new file mode 100644
index 0000000..56335e1
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/md5.js
@@ -0,0 +1,435 @@
+// Copyright 2011 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 MD5 cryptographic hash.
+ * Implementation of http://tools.ietf.org/html/rfc1321 with common
+ * optimizations and tweaks (see http://en.wikipedia.org/wiki/MD5).
+ *
+ * Usage:
+ *   var md5 = new goog.crypt.Md5();
+ *   md5.update(bytes);
+ *   var hash = md5.digest();
+ *
+ * Performance:
+ *   Chrome 23              ~680 Mbit/s
+ *   Chrome 13 (in a VM)    ~250 Mbit/s
+ *   Firefox 6.0 (in a VM)  ~100 Mbit/s
+ *   IE9 (in a VM)           ~27 Mbit/s
+ *   Firefox 3.6             ~15 Mbit/s
+ *   IE8 (in a VM)           ~13 Mbit/s
+ *
+ */
+
+goog.provide('goog.crypt.Md5');
+
+goog.require('goog.crypt.Hash');
+
+
+
+/**
+ * MD5 cryptographic hash constructor.
+ * @constructor
+ * @extends {goog.crypt.Hash}
+ * @final
+ * @struct
+ */
+goog.crypt.Md5 = function() {
+  goog.crypt.Md5.base(this, 'constructor');
+
+  this.blockSize = 512 / 8;
+
+  /**
+   * Holds the current values of accumulated A-D variables (MD buffer).
+   * @type {!Array<number>}
+   * @private
+   */
+  this.chain_ = new Array(4);
+
+  /**
+   * A buffer holding the data until the whole block can be processed.
+   * @type {!Array<number>}
+   * @private
+   */
+  this.block_ = new Array(this.blockSize);
+
+  /**
+   * The length of yet-unprocessed data as collected in the block.
+   * @type {number}
+   * @private
+   */
+  this.blockLength_ = 0;
+
+  /**
+   * The total length of the message so far.
+   * @type {number}
+   * @private
+   */
+  this.totalLength_ = 0;
+
+  this.reset();
+};
+goog.inherits(goog.crypt.Md5, goog.crypt.Hash);
+
+
+/**
+ * Integer rotation constants used by the abbreviated implementation.
+ * They are hardcoded in the unrolled implementation, so it is left
+ * here commented out.
+ * @type {Array<number>}
+ * @private
+ *
+goog.crypt.Md5.S_ = [
+  7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+  5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
+  4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+  6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
+];
+ */
+
+/**
+ * Sine function constants used by the abbreviated implementation.
+ * They are hardcoded in the unrolled implementation, so it is left
+ * here commented out.
+ * @type {Array<number>}
+ * @private
+ *
+goog.crypt.Md5.T_ = [
+  0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+  0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+  0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+  0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+  0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+  0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+  0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+  0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+  0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+  0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+  0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+  0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+  0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+  0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+  0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+  0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+];
+ */
+
+
+/** @override */
+goog.crypt.Md5.prototype.reset = function() {
+  this.chain_[0] = 0x67452301;
+  this.chain_[1] = 0xefcdab89;
+  this.chain_[2] = 0x98badcfe;
+  this.chain_[3] = 0x10325476;
+
+  this.blockLength_ = 0;
+  this.totalLength_ = 0;
+};
+
+
+/**
+ * Internal compress helper function. It takes a block of data (64 bytes)
+ * and updates the accumulator.
+ * @param {Array<number>|Uint8Array|string} buf The block to compress.
+ * @param {number=} opt_offset Offset of the block in the buffer.
+ * @private
+ */
+goog.crypt.Md5.prototype.compress_ = function(buf, opt_offset) {
+  if (!opt_offset) {
+    opt_offset = 0;
+  }
+
+  // We allocate the array every time, but it's cheap in practice.
+  var X = new Array(16);
+
+  // Get 16 little endian words. It is not worth unrolling this for Chrome 11.
+  if (goog.isString(buf)) {
+    for (var i = 0; i < 16; ++i) {
+      X[i] = (buf.charCodeAt(opt_offset++)) |
+             (buf.charCodeAt(opt_offset++) << 8) |
+             (buf.charCodeAt(opt_offset++) << 16) |
+             (buf.charCodeAt(opt_offset++) << 24);
+    }
+  } else {
+    for (var i = 0; i < 16; ++i) {
+      X[i] = (buf[opt_offset++]) |
+             (buf[opt_offset++] << 8) |
+             (buf[opt_offset++] << 16) |
+             (buf[opt_offset++] << 24);
+    }
+  }
+
+  var A = this.chain_[0];
+  var B = this.chain_[1];
+  var C = this.chain_[2];
+  var D = this.chain_[3];
+  var sum = 0;
+
+  /*
+   * This is an abbreviated implementation, it is left here commented out for
+   * reference purposes. See below for an unrolled version in use.
+   *
+  var f, n, tmp;
+  for (var i = 0; i < 64; ++i) {
+
+    if (i < 16) {
+      f = (D ^ (B & (C ^ D)));
+      n = i;
+    } else if (i < 32) {
+      f = (C ^ (D & (B ^ C)));
+      n = (5 * i + 1) % 16;
+    } else if (i < 48) {
+      f = (B ^ C ^ D);
+      n = (3 * i + 5) % 16;
+    } else {
+      f = (C ^ (B | (~D)));
+      n = (7 * i) % 16;
+    }
+
+    tmp = D;
+    D = C;
+    C = B;
+    sum = (A + f + goog.crypt.Md5.T_[i] + X[n]) & 0xffffffff;
+    B += ((sum << goog.crypt.Md5.S_[i]) & 0xffffffff) |
+         (sum >>> (32 - goog.crypt.Md5.S_[i]));
+    A = tmp;
+  }
+   */
+
+  /*
+   * This is an unrolled MD5 implementation, which gives ~30% speedup compared
+   * to the abbreviated implementation above, as measured on Chrome 11. It is
+   * important to keep 32-bit croppings to minimum and inline the integer
+   * rotation.
+   */
+  sum = (A + (D ^ (B & (C ^ D))) + X[0] + 0xd76aa478) & 0xffffffff;
+  A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));
+  sum = (D + (C ^ (A & (B ^ C))) + X[1] + 0xe8c7b756) & 0xffffffff;
+  D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));
+  sum = (C + (B ^ (D & (A ^ B))) + X[2] + 0x242070db) & 0xffffffff;
+  C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));
+  sum = (B + (A ^ (C & (D ^ A))) + X[3] + 0xc1bdceee) & 0xffffffff;
+  B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));
+  sum = (A + (D ^ (B & (C ^ D))) + X[4] + 0xf57c0faf) & 0xffffffff;
+  A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));
+  sum = (D + (C ^ (A & (B ^ C))) + X[5] + 0x4787c62a) & 0xffffffff;
+  D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));
+  sum = (C + (B ^ (D & (A ^ B))) + X[6] + 0xa8304613) & 0xffffffff;
+  C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));
+  sum = (B + (A ^ (C & (D ^ A))) + X[7] + 0xfd469501) & 0xffffffff;
+  B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));
+  sum = (A + (D ^ (B & (C ^ D))) + X[8] + 0x698098d8) & 0xffffffff;
+  A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));
+  sum = (D + (C ^ (A & (B ^ C))) + X[9] + 0x8b44f7af) & 0xffffffff;
+  D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));
+  sum = (C + (B ^ (D & (A ^ B))) + X[10] + 0xffff5bb1) & 0xffffffff;
+  C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));
+  sum = (B + (A ^ (C & (D ^ A))) + X[11] + 0x895cd7be) & 0xffffffff;
+  B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));
+  sum = (A + (D ^ (B & (C ^ D))) + X[12] + 0x6b901122) & 0xffffffff;
+  A = B + (((sum << 7) & 0xffffffff) | (sum >>> 25));
+  sum = (D + (C ^ (A & (B ^ C))) + X[13] + 0xfd987193) & 0xffffffff;
+  D = A + (((sum << 12) & 0xffffffff) | (sum >>> 20));
+  sum = (C + (B ^ (D & (A ^ B))) + X[14] + 0xa679438e) & 0xffffffff;
+  C = D + (((sum << 17) & 0xffffffff) | (sum >>> 15));
+  sum = (B + (A ^ (C & (D ^ A))) + X[15] + 0x49b40821) & 0xffffffff;
+  B = C + (((sum << 22) & 0xffffffff) | (sum >>> 10));
+  sum = (A + (C ^ (D & (B ^ C))) + X[1] + 0xf61e2562) & 0xffffffff;
+  A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));
+  sum = (D + (B ^ (C & (A ^ B))) + X[6] + 0xc040b340) & 0xffffffff;
+  D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));
+  sum = (C + (A ^ (B & (D ^ A))) + X[11] + 0x265e5a51) & 0xffffffff;
+  C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));
+  sum = (B + (D ^ (A & (C ^ D))) + X[0] + 0xe9b6c7aa) & 0xffffffff;
+  B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));
+  sum = (A + (C ^ (D & (B ^ C))) + X[5] + 0xd62f105d) & 0xffffffff;
+  A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));
+  sum = (D + (B ^ (C & (A ^ B))) + X[10] + 0x02441453) & 0xffffffff;
+  D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));
+  sum = (C + (A ^ (B & (D ^ A))) + X[15] + 0xd8a1e681) & 0xffffffff;
+  C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));
+  sum = (B + (D ^ (A & (C ^ D))) + X[4] + 0xe7d3fbc8) & 0xffffffff;
+  B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));
+  sum = (A + (C ^ (D & (B ^ C))) + X[9] + 0x21e1cde6) & 0xffffffff;
+  A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));
+  sum = (D + (B ^ (C & (A ^ B))) + X[14] + 0xc33707d6) & 0xffffffff;
+  D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));
+  sum = (C + (A ^ (B & (D ^ A))) + X[3] + 0xf4d50d87) & 0xffffffff;
+  C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));
+  sum = (B + (D ^ (A & (C ^ D))) + X[8] + 0x455a14ed) & 0xffffffff;
+  B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));
+  sum = (A + (C ^ (D & (B ^ C))) + X[13] + 0xa9e3e905) & 0xffffffff;
+  A = B + (((sum << 5) & 0xffffffff) | (sum >>> 27));
+  sum = (D + (B ^ (C & (A ^ B))) + X[2] + 0xfcefa3f8) & 0xffffffff;
+  D = A + (((sum << 9) & 0xffffffff) | (sum >>> 23));
+  sum = (C + (A ^ (B & (D ^ A))) + X[7] + 0x676f02d9) & 0xffffffff;
+  C = D + (((sum << 14) & 0xffffffff) | (sum >>> 18));
+  sum = (B + (D ^ (A & (C ^ D))) + X[12] + 0x8d2a4c8a) & 0xffffffff;
+  B = C + (((sum << 20) & 0xffffffff) | (sum >>> 12));
+  sum = (A + (B ^ C ^ D) + X[5] + 0xfffa3942) & 0xffffffff;
+  A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));
+  sum = (D + (A ^ B ^ C) + X[8] + 0x8771f681) & 0xffffffff;
+  D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));
+  sum = (C + (D ^ A ^ B) + X[11] + 0x6d9d6122) & 0xffffffff;
+  C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));
+  sum = (B + (C ^ D ^ A) + X[14] + 0xfde5380c) & 0xffffffff;
+  B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));
+  sum = (A + (B ^ C ^ D) + X[1] + 0xa4beea44) & 0xffffffff;
+  A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));
+  sum = (D + (A ^ B ^ C) + X[4] + 0x4bdecfa9) & 0xffffffff;
+  D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));
+  sum = (C + (D ^ A ^ B) + X[7] + 0xf6bb4b60) & 0xffffffff;
+  C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));
+  sum = (B + (C ^ D ^ A) + X[10] + 0xbebfbc70) & 0xffffffff;
+  B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));
+  sum = (A + (B ^ C ^ D) + X[13] + 0x289b7ec6) & 0xffffffff;
+  A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));
+  sum = (D + (A ^ B ^ C) + X[0] + 0xeaa127fa) & 0xffffffff;
+  D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));
+  sum = (C + (D ^ A ^ B) + X[3] + 0xd4ef3085) & 0xffffffff;
+  C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));
+  sum = (B + (C ^ D ^ A) + X[6] + 0x04881d05) & 0xffffffff;
+  B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));
+  sum = (A + (B ^ C ^ D) + X[9] + 0xd9d4d039) & 0xffffffff;
+  A = B + (((sum << 4) & 0xffffffff) | (sum >>> 28));
+  sum = (D + (A ^ B ^ C) + X[12] + 0xe6db99e5) & 0xffffffff;
+  D = A + (((sum << 11) & 0xffffffff) | (sum >>> 21));
+  sum = (C + (D ^ A ^ B) + X[15] + 0x1fa27cf8) & 0xffffffff;
+  C = D + (((sum << 16) & 0xffffffff) | (sum >>> 16));
+  sum = (B + (C ^ D ^ A) + X[2] + 0xc4ac5665) & 0xffffffff;
+  B = C + (((sum << 23) & 0xffffffff) | (sum >>> 9));
+  sum = (A + (C ^ (B | (~D))) + X[0] + 0xf4292244) & 0xffffffff;
+  A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));
+  sum = (D + (B ^ (A | (~C))) + X[7] + 0x432aff97) & 0xffffffff;
+  D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));
+  sum = (C + (A ^ (D | (~B))) + X[14] + 0xab9423a7) & 0xffffffff;
+  C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));
+  sum = (B + (D ^ (C | (~A))) + X[5] + 0xfc93a039) & 0xffffffff;
+  B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));
+  sum = (A + (C ^ (B | (~D))) + X[12] + 0x655b59c3) & 0xffffffff;
+  A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));
+  sum = (D + (B ^ (A | (~C))) + X[3] + 0x8f0ccc92) & 0xffffffff;
+  D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));
+  sum = (C + (A ^ (D | (~B))) + X[10] + 0xffeff47d) & 0xffffffff;
+  C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));
+  sum = (B + (D ^ (C | (~A))) + X[1] + 0x85845dd1) & 0xffffffff;
+  B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));
+  sum = (A + (C ^ (B | (~D))) + X[8] + 0x6fa87e4f) & 0xffffffff;
+  A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));
+  sum = (D + (B ^ (A | (~C))) + X[15] + 0xfe2ce6e0) & 0xffffffff;
+  D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));
+  sum = (C + (A ^ (D | (~B))) + X[6] + 0xa3014314) & 0xffffffff;
+  C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));
+  sum = (B + (D ^ (C | (~A))) + X[13] + 0x4e0811a1) & 0xffffffff;
+  B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));
+  sum = (A + (C ^ (B | (~D))) + X[4] + 0xf7537e82) & 0xffffffff;
+  A = B + (((sum << 6) & 0xffffffff) | (sum >>> 26));
+  sum = (D + (B ^ (A | (~C))) + X[11] + 0xbd3af235) & 0xffffffff;
+  D = A + (((sum << 10) & 0xffffffff) | (sum >>> 22));
+  sum = (C + (A ^ (D | (~B))) + X[2] + 0x2ad7d2bb) & 0xffffffff;
+  C = D + (((sum << 15) & 0xffffffff) | (sum >>> 17));
+  sum = (B + (D ^ (C | (~A))) + X[9] + 0xeb86d391) & 0xffffffff;
+  B = C + (((sum << 21) & 0xffffffff) | (sum >>> 11));
+
+  this.chain_[0] = (this.chain_[0] + A) & 0xffffffff;
+  this.chain_[1] = (this.chain_[1] + B) & 0xffffffff;
+  this.chain_[2] = (this.chain_[2] + C) & 0xffffffff;
+  this.chain_[3] = (this.chain_[3] + D) & 0xffffffff;
+};
+
+
+/** @override */
+goog.crypt.Md5.prototype.update = function(bytes, opt_length) {
+  if (!goog.isDef(opt_length)) {
+    opt_length = bytes.length;
+  }
+  var lengthMinusBlock = opt_length - this.blockSize;
+
+  // Copy some object properties to local variables in order to save on access
+  // time from inside the loop (~10% speedup was observed on Chrome 11).
+  var block = this.block_;
+  var blockLength = this.blockLength_;
+  var i = 0;
+
+  // The outer while loop should execute at most twice.
+  while (i < opt_length) {
+    // When we have no data in the block to top up, we can directly process the
+    // input buffer (assuming it contains sufficient data). This gives ~30%
+    // speedup on Chrome 14 and ~70% speedup on Firefox 6.0, but requires that
+    // the data is provided in large chunks (or in multiples of 64 bytes).
+    if (blockLength == 0) {
+      while (i <= lengthMinusBlock) {
+        this.compress_(bytes, i);
+        i += this.blockSize;
+      }
+    }
+
+    if (goog.isString(bytes)) {
+      while (i < opt_length) {
+        block[blockLength++] = bytes.charCodeAt(i++);
+        if (blockLength == this.blockSize) {
+          this.compress_(block);
+          blockLength = 0;
+          // Jump to the outer loop so we use the full-block optimization.
+          break;
+        }
+      }
+    } else {
+      while (i < opt_length) {
+        block[blockLength++] = bytes[i++];
+        if (blockLength == this.blockSize) {
+          this.compress_(block);
+          blockLength = 0;
+          // Jump to the outer loop so we use the full-block optimization.
+          break;
+        }
+      }
+    }
+  }
+
+  this.blockLength_ = blockLength;
+  this.totalLength_ += opt_length;
+};
+
+
+/** @override */
+goog.crypt.Md5.prototype.digest = function() {
+  // This must accommodate at least 1 padding byte (0x80), 8 bytes of
+  // total bitlength, and must end at a 64-byte boundary.
+  var pad = new Array((this.blockLength_ < 56 ?
+                       this.blockSize :
+                       this.blockSize * 2) - this.blockLength_);
+
+  // Add padding: 0x80 0x00*
+  pad[0] = 0x80;
+  for (var i = 1; i < pad.length - 8; ++i) {
+    pad[i] = 0;
+  }
+  // Add the total number of bits, little endian 64-bit integer.
+  var totalBits = this.totalLength_ * 8;
+  for (var i = pad.length - 8; i < pad.length; ++i) {
+    pad[i] = totalBits & 0xff;
+    totalBits /= 0x100; // Don't use bit-shifting here!
+  }
+  this.update(pad);
+
+  var digest = new Array(16);
+  var n = 0;
+  for (var i = 0; i < 4; ++i) {
+    for (var j = 0; j < 32; j += 8) {
+      digest[n++] = (this.chain_[i] >>> j) & 0xff;
+    }
+  }
+  return digest;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/pbkdf2.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/pbkdf2.js b/externs/GCL/externs/goog/crypt/pbkdf2.js
new file mode 100644
index 0000000..2fd1807
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/pbkdf2.js
@@ -0,0 +1,128 @@
+// 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 Implementation of PBKDF2 in JavaScript.
+ * @see http://en.wikipedia.org/wiki/PBKDF2
+ *
+ * Currently we only support HMAC-SHA1 as the underlying hash function. To add a
+ * new hash function, add a static method similar to deriveKeyFromPasswordSha1()
+ * and implement the specific computeBlockCallback() using the hash function.
+ *
+ * Usage:
+ *   var key = pbkdf2.deriveKeySha1(
+ *       stringToByteArray('password'), stringToByteArray('salt'), 1000, 128);
+ *
+ */
+
+goog.provide('goog.crypt.pbkdf2');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.crypt');
+goog.require('goog.crypt.Hmac');
+goog.require('goog.crypt.Sha1');
+
+
+/**
+ * Derives key from password using PBKDF2-SHA1
+ * @param {!Array<number>} password Byte array representation of the password
+ *     from which the key is derived.
+ * @param {!Array<number>} initialSalt Byte array representation of the salt.
+ * @param {number} iterations Number of interations when computing the key.
+ * @param {number} keyLength Length of the output key in bits.
+ *     Must be multiple of 8.
+ * @return {!Array<number>} Byte array representation of the output key.
+ */
+goog.crypt.pbkdf2.deriveKeySha1 = function(
+    password, initialSalt, iterations, keyLength) {
+  // Length of the HMAC-SHA1 output in bits.
+  var HASH_LENGTH = 160;
+
+  /**
+   * Compute each block of the key using HMAC-SHA1.
+   * @param {!Array<number>} index Byte array representation of the index of
+   *     the block to be computed.
+   * @return {!Array<number>} Byte array representation of the output block.
+   */
+  var computeBlock = function(index) {
+    // Initialize the result to be array of 0 such that its xor with the first
+    // block would be the first block.
+    var result = goog.array.repeat(0, HASH_LENGTH / 8);
+    // Initialize the salt of the first iteration to initialSalt || i.
+    var salt = initialSalt.concat(index);
+    var hmac = new goog.crypt.Hmac(new goog.crypt.Sha1(), password, 64);
+    // Compute and XOR each iteration.
+    for (var i = 0; i < iterations; i++) {
+      // The salt of the next iteration is the result of the current iteration.
+      salt = hmac.getHmac(salt);
+      result = goog.crypt.xorByteArray(result, salt);
+    }
+    return result;
+  };
+
+  return goog.crypt.pbkdf2.deriveKeyFromPassword_(
+      computeBlock, HASH_LENGTH, keyLength);
+};
+
+
+/**
+ * Compute each block of the key using PBKDF2.
+ * @param {Function} computeBlock Function to compute each block of the output
+ *     key.
+ * @param {number} hashLength Length of each block in bits. This is determined
+ *     by the specific hash function used. Must be multiple of 8.
+ * @param {number} keyLength Length of the output key in bits.
+ *     Must be multiple of 8.
+ * @return {!Array<number>} Byte array representation of the output key.
+ * @private
+ */
+goog.crypt.pbkdf2.deriveKeyFromPassword_ =
+    function(computeBlock, hashLength, keyLength) {
+  goog.asserts.assert(keyLength % 8 == 0, 'invalid output key length');
+
+  // Compute and concactate each block of the output key.
+  var numBlocks = Math.ceil(keyLength / hashLength);
+  goog.asserts.assert(numBlocks >= 1, 'invalid number of blocks');
+  var result = [];
+  for (var i = 1; i <= numBlocks; i++) {
+    var indexBytes = goog.crypt.pbkdf2.integerToByteArray_(i);
+    result = result.concat(computeBlock(indexBytes));
+  }
+
+  // Trim the last block if needed.
+  var lastBlockSize = keyLength % hashLength;
+  if (lastBlockSize != 0) {
+    var desiredBytes = ((numBlocks - 1) * hashLength + lastBlockSize) / 8;
+    result.splice(desiredBytes, (hashLength - lastBlockSize) / 8);
+  }
+  return result;
+};
+
+
+/**
+ * Converts an integer number to a 32-bit big endian byte array.
+ * @param {number} n Integer number to be converted.
+ * @return {!Array<number>} Byte Array representation of the 32-bit big endian
+ *     encoding of n.
+ * @private
+ */
+goog.crypt.pbkdf2.integerToByteArray_ = function(n) {
+  var result = new Array(4);
+  result[0] = n >> 24 & 0xFF;
+  result[1] = n >> 16 & 0xFF;
+  result[2] = n >> 8 & 0xFF;
+  result[3] = n & 0xFF;
+  return result;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/sha1.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/sha1.js b/externs/GCL/externs/goog/crypt/sha1.js
new file mode 100644
index 0000000..b1a5219
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/sha1.js
@@ -0,0 +1,294 @@
+// Copyright 2005 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 SHA-1 cryptographic hash.
+ * Variable names follow the notation in FIPS PUB 180-3:
+ * http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf.
+ *
+ * Usage:
+ *   var sha1 = new goog.crypt.sha1();
+ *   sha1.update(bytes);
+ *   var hash = sha1.digest();
+ *
+ * Performance:
+ *   Chrome 23:   ~400 Mbit/s
+ *   Firefox 16:  ~250 Mbit/s
+ *
+ */
+
+goog.provide('goog.crypt.Sha1');
+
+goog.require('goog.crypt.Hash');
+
+
+
+/**
+ * SHA-1 cryptographic hash constructor.
+ *
+ * The properties declared here are discussed in the above algorithm document.
+ * @constructor
+ * @extends {goog.crypt.Hash}
+ * @final
+ * @struct
+ */
+goog.crypt.Sha1 = function() {
+  goog.crypt.Sha1.base(this, 'constructor');
+
+  this.blockSize = 512 / 8;
+
+  /**
+   * Holds the previous values of accumulated variables a-e in the compress_
+   * function.
+   * @type {!Array<number>}
+   * @private
+   */
+  this.chain_ = [];
+
+  /**
+   * A buffer holding the partially computed hash result.
+   * @type {!Array<number>}
+   * @private
+   */
+  this.buf_ = [];
+
+  /**
+   * An array of 80 bytes, each a part of the message to be hashed.  Referred to
+   * as the message schedule in the docs.
+   * @type {!Array<number>}
+   * @private
+   */
+  this.W_ = [];
+
+  /**
+   * Contains data needed to pad messages less than 64 bytes.
+   * @type {!Array<number>}
+   * @private
+   */
+  this.pad_ = [];
+
+  this.pad_[0] = 128;
+  for (var i = 1; i < this.blockSize; ++i) {
+    this.pad_[i] = 0;
+  }
+
+  /**
+   * @private {number}
+   */
+  this.inbuf_ = 0;
+
+  /**
+   * @private {number}
+   */
+  this.total_ = 0;
+
+  this.reset();
+};
+goog.inherits(goog.crypt.Sha1, goog.crypt.Hash);
+
+
+/** @override */
+goog.crypt.Sha1.prototype.reset = function() {
+  this.chain_[0] = 0x67452301;
+  this.chain_[1] = 0xefcdab89;
+  this.chain_[2] = 0x98badcfe;
+  this.chain_[3] = 0x10325476;
+  this.chain_[4] = 0xc3d2e1f0;
+
+  this.inbuf_ = 0;
+  this.total_ = 0;
+};
+
+
+/**
+ * Internal compress helper function.
+ * @param {!Array<number>|!Uint8Array|string} buf Block to compress.
+ * @param {number=} opt_offset Offset of the block in the buffer.
+ * @private
+ */
+goog.crypt.Sha1.prototype.compress_ = function(buf, opt_offset) {
+  if (!opt_offset) {
+    opt_offset = 0;
+  }
+
+  var W = this.W_;
+
+  // get 16 big endian words
+  if (goog.isString(buf)) {
+    for (var i = 0; i < 16; i++) {
+      // TODO(user): [bug 8140122] Recent versions of Safari for Mac OS and iOS
+      // have a bug that turns the post-increment ++ operator into pre-increment
+      // during JIT compilation.  We have code that depends heavily on SHA-1 for
+      // correctness and which is affected by this bug, so I've removed all uses
+      // of post-increment ++ in which the result value is used.  We can revert
+      // this change once the Safari bug
+      // (https://bugs.webkit.org/show_bug.cgi?id=109036) has been fixed and
+      // most clients have been updated.
+      W[i] = (buf.charCodeAt(opt_offset) << 24) |
+             (buf.charCodeAt(opt_offset + 1) << 16) |
+             (buf.charCodeAt(opt_offset + 2) << 8) |
+             (buf.charCodeAt(opt_offset + 3));
+      opt_offset += 4;
+    }
+  } else {
+    for (var i = 0; i < 16; i++) {
+      W[i] = (buf[opt_offset] << 24) |
+             (buf[opt_offset + 1] << 16) |
+             (buf[opt_offset + 2] << 8) |
+             (buf[opt_offset + 3]);
+      opt_offset += 4;
+    }
+  }
+
+  // expand to 80 words
+  for (var i = 16; i < 80; i++) {
+    var t = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
+    W[i] = ((t << 1) | (t >>> 31)) & 0xffffffff;
+  }
+
+  var a = this.chain_[0];
+  var b = this.chain_[1];
+  var c = this.chain_[2];
+  var d = this.chain_[3];
+  var e = this.chain_[4];
+  var f, k;
+
+  // TODO(user): Try to unroll this loop to speed up the computation.
+  for (var i = 0; i < 80; i++) {
+    if (i < 40) {
+      if (i < 20) {
+        f = d ^ (b & (c ^ d));
+        k = 0x5a827999;
+      } else {
+        f = b ^ c ^ d;
+        k = 0x6ed9eba1;
+      }
+    } else {
+      if (i < 60) {
+        f = (b & c) | (d & (b | c));
+        k = 0x8f1bbcdc;
+      } else {
+        f = b ^ c ^ d;
+        k = 0xca62c1d6;
+      }
+    }
+
+    var t = (((a << 5) | (a >>> 27)) + f + e + k + W[i]) & 0xffffffff;
+    e = d;
+    d = c;
+    c = ((b << 30) | (b >>> 2)) & 0xffffffff;
+    b = a;
+    a = t;
+  }
+
+  this.chain_[0] = (this.chain_[0] + a) & 0xffffffff;
+  this.chain_[1] = (this.chain_[1] + b) & 0xffffffff;
+  this.chain_[2] = (this.chain_[2] + c) & 0xffffffff;
+  this.chain_[3] = (this.chain_[3] + d) & 0xffffffff;
+  this.chain_[4] = (this.chain_[4] + e) & 0xffffffff;
+};
+
+
+/** @override */
+goog.crypt.Sha1.prototype.update = function(bytes, opt_length) {
+  // TODO(johnlenz): tighten the function signature and remove this check
+  if (bytes == null) {
+    return;
+  }
+
+  if (!goog.isDef(opt_length)) {
+    opt_length = bytes.length;
+  }
+
+  var lengthMinusBlock = opt_length - this.blockSize;
+  var n = 0;
+  // Using local instead of member variables gives ~5% speedup on Firefox 16.
+  var buf = this.buf_;
+  var inbuf = this.inbuf_;
+
+  // The outer while loop should execute at most twice.
+  while (n < opt_length) {
+    // When we have no data in the block to top up, we can directly process the
+    // input buffer (assuming it contains sufficient data). This gives ~25%
+    // speedup on Chrome 23 and ~15% speedup on Firefox 16, but requires that
+    // the data is provided in large chunks (or in multiples of 64 bytes).
+    if (inbuf == 0) {
+      while (n <= lengthMinusBlock) {
+        this.compress_(bytes, n);
+        n += this.blockSize;
+      }
+    }
+
+    if (goog.isString(bytes)) {
+      while (n < opt_length) {
+        buf[inbuf] = bytes.charCodeAt(n);
+        ++inbuf;
+        ++n;
+        if (inbuf == this.blockSize) {
+          this.compress_(buf);
+          inbuf = 0;
+          // Jump to the outer loop so we use the full-block optimization.
+          break;
+        }
+      }
+    } else {
+      while (n < opt_length) {
+        buf[inbuf] = bytes[n];
+        ++inbuf;
+        ++n;
+        if (inbuf == this.blockSize) {
+          this.compress_(buf);
+          inbuf = 0;
+          // Jump to the outer loop so we use the full-block optimization.
+          break;
+        }
+      }
+    }
+  }
+
+  this.inbuf_ = inbuf;
+  this.total_ += opt_length;
+};
+
+
+/** @override */
+goog.crypt.Sha1.prototype.digest = function() {
+  var digest = [];
+  var totalBits = this.total_ * 8;
+
+  // Add pad 0x80 0x00*.
+  if (this.inbuf_ < 56) {
+    this.update(this.pad_, 56 - this.inbuf_);
+  } else {
+    this.update(this.pad_, this.blockSize - (this.inbuf_ - 56));
+  }
+
+  // Add # bits.
+  for (var i = this.blockSize - 1; i >= 56; i--) {
+    this.buf_[i] = totalBits & 255;
+    totalBits /= 256; // Don't use bit-shifting here!
+  }
+
+  this.compress_(this.buf_);
+
+  var n = 0;
+  for (var i = 0; i < 5; i++) {
+    for (var j = 24; j >= 0; j -= 8) {
+      digest[n] = (this.chain_[i] >> j) & 255;
+      ++n;
+    }
+  }
+
+  return digest;
+};


[46/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/bootstrap/webworkers.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/bootstrap/webworkers.js b/externs/GCL/externs/goog/bootstrap/webworkers.js
new file mode 100644
index 0000000..7799a0a
--- /dev/null
+++ b/externs/GCL/externs/goog/bootstrap/webworkers.js
@@ -0,0 +1,37 @@
+// Copyright 2010 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 bootstrap for dynamically requiring Closure within an HTML5
+ * Web Worker context. To use this, first set CLOSURE_BASE_PATH to the directory
+ * containing base.js (relative to the main script), then use importScripts to
+ * load this file and base.js (in that order). After this you can use
+ * goog.require for further imports.
+ *
+ * @nocompile
+ */
+
+
+/**
+ * Imports a script using the Web Worker importScript API.
+ *
+ * @param {string} src The script source.
+ * @return {boolean} True if the script was imported, false otherwise.
+ */
+this.CLOSURE_IMPORT_SCRIPT = (function(global) {
+  return function(src) {
+    global['importScripts'](src);
+    return true;
+  };
+})(this);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/color/alpha.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/color/alpha.js b/externs/GCL/externs/goog/color/alpha.js
new file mode 100644
index 0000000..4cd4781
--- /dev/null
+++ b/externs/GCL/externs/goog/color/alpha.js
@@ -0,0 +1,472 @@
+// 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 related to alpha/transparent colors and alpha color
+ * conversion.
+ */
+
+goog.provide('goog.color.alpha');
+
+goog.require('goog.color');
+
+
+/**
+ * Parses an alpha color out of a string.
+ * @param {string} str Color in some format.
+ * @return {{hex: string, type: string}} 'hex' is a string containing
+ *     a hex representation of the color, and 'type' is a string
+ *     containing the type of color format passed in ('hex', 'rgb', 'named').
+ */
+goog.color.alpha.parse = function(str) {
+  var result = {};
+  str = String(str);
+
+  var maybeHex = goog.color.prependHashIfNecessaryHelper(str);
+  if (goog.color.alpha.isValidAlphaHexColor_(maybeHex)) {
+    result.hex = goog.color.alpha.normalizeAlphaHex_(maybeHex);
+    result.type = 'hex';
+    return result;
+  } else {
+    var rgba = goog.color.alpha.isValidRgbaColor_(str);
+    if (rgba.length) {
+      result.hex = goog.color.alpha.rgbaArrayToHex(rgba);
+      result.type = 'rgba';
+      return result;
+    } else {
+      var hsla = goog.color.alpha.isValidHslaColor_(str);
+      if (hsla.length) {
+        result.hex = goog.color.alpha.hslaArrayToHex(hsla);
+        result.type = 'hsla';
+        return result;
+      }
+    }
+  }
+  throw Error(str + ' is not a valid color string');
+};
+
+
+/**
+ * Converts a hex representation of a color to RGBA.
+ * @param {string} hexColor Color to convert.
+ * @return {string} string of the form 'rgba(R,G,B,A)' which can be used in
+ *    styles.
+ */
+goog.color.alpha.hexToRgbaStyle = function(hexColor) {
+  return goog.color.alpha.rgbaStyle_(goog.color.alpha.hexToRgba(hexColor));
+};
+
+
+/**
+ * Gets the hex color part of an alpha hex color. For example, from '#abcdef55'
+ * return '#abcdef'.
+ * @param {string} colorWithAlpha The alpha hex color to get the hex color from.
+ * @return {string} The hex color where the alpha part has been stripped off.
+ */
+goog.color.alpha.extractHexColor = function(colorWithAlpha) {
+  if (goog.color.alpha.isValidAlphaHexColor_(colorWithAlpha)) {
+    var fullColor = goog.color.prependHashIfNecessaryHelper(colorWithAlpha);
+    var normalizedColor = goog.color.alpha.normalizeAlphaHex_(fullColor);
+    return normalizedColor.substring(0, 7);
+  } else {
+    throw Error(colorWithAlpha + ' is not a valid 8-hex color string');
+  }
+};
+
+
+/**
+ * Gets the alpha color part of an alpha hex color. For example, from
+ * '#abcdef55' return '55'. The result is guaranteed to be two characters long.
+ * @param {string} colorWithAlpha The alpha hex color to get the hex color from.
+ * @return {string} The hex color where the alpha part has been stripped off.
+ */
+goog.color.alpha.extractAlpha = function(colorWithAlpha) {
+  if (goog.color.alpha.isValidAlphaHexColor_(colorWithAlpha)) {
+    var fullColor = goog.color.prependHashIfNecessaryHelper(colorWithAlpha);
+    var normalizedColor = goog.color.alpha.normalizeAlphaHex_(fullColor);
+    return normalizedColor.substring(7, 9);
+  } else {
+    throw Error(colorWithAlpha + ' is not a valid 8-hex color string');
+  }
+};
+
+
+/**
+ * Regular expression for extracting the digits in a hex color quadruplet.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.alpha.hexQuadrupletRe_ = /#(.)(.)(.)(.)/;
+
+
+/**
+ * Normalize a hex representation of an alpha color.
+ * @param {string} hexColor an alpha hex color string.
+ * @return {string} hex color in the format '#rrggbbaa' with all lowercase
+ *     literals.
+ * @private
+ */
+goog.color.alpha.normalizeAlphaHex_ = function(hexColor) {
+  if (!goog.color.alpha.isValidAlphaHexColor_(hexColor)) {
+    throw Error("'" + hexColor + "' is not a valid alpha hex color");
+  }
+  if (hexColor.length == 5) { // of the form #RGBA
+    hexColor = hexColor.replace(goog.color.alpha.hexQuadrupletRe_,
+        '#$1$1$2$2$3$3$4$4');
+  }
+  return hexColor.toLowerCase();
+};
+
+
+/**
+ * Converts an 8-hex representation of a color to RGBA.
+ * @param {string} hexColor Color to convert.
+ * @return {!Array<number>} array containing [r, g, b, a].
+ *     r, g, b are ints between 0
+ *     and 255, and a is a value between 0 and 1.
+ */
+goog.color.alpha.hexToRgba = function(hexColor) {
+  // TODO(user): Enhance code sharing with goog.color, for example by
+  //     adding a goog.color.genericHexToRgb method.
+  hexColor = goog.color.alpha.normalizeAlphaHex_(hexColor);
+  var r = parseInt(hexColor.substr(1, 2), 16);
+  var g = parseInt(hexColor.substr(3, 2), 16);
+  var b = parseInt(hexColor.substr(5, 2), 16);
+  var a = parseInt(hexColor.substr(7, 2), 16);
+
+  return [r, g, b, a / 255];
+};
+
+
+/**
+ * Converts a color from RGBA to hex representation.
+ * @param {number} r Amount of red, int between 0 and 255.
+ * @param {number} g Amount of green, int between 0 and 255.
+ * @param {number} b Amount of blue, int between 0 and 255.
+ * @param {number} a Amount of alpha, float between 0 and 1.
+ * @return {string} hex representation of the color.
+ */
+goog.color.alpha.rgbaToHex = function(r, g, b, a) {
+  var intAlpha = Math.floor(a * 255);
+  if (isNaN(intAlpha) || intAlpha < 0 || intAlpha > 255) {
+    // TODO(user): The CSS spec says the value should be clamped.
+    throw Error('"(' + r + ',' + g + ',' + b + ',' + a +
+        '") is not a valid RGBA color');
+  }
+  var hexA = goog.color.prependZeroIfNecessaryHelper(intAlpha.toString(16));
+  return goog.color.rgbToHex(r, g, b) + hexA;
+};
+
+
+/**
+ * Converts a color from HSLA to hex representation.
+ * @param {number} h Amount of hue, int between 0 and 360.
+ * @param {number} s Amount of saturation, int between 0 and 100.
+ * @param {number} l Amount of lightness, int between 0 and 100.
+ * @param {number} a Amount of alpha, float between 0 and 1.
+ * @return {string} hex representation of the color.
+ */
+goog.color.alpha.hslaToHex = function(h, s, l, a) {
+  var intAlpha = Math.floor(a * 255);
+  if (isNaN(intAlpha) || intAlpha < 0 || intAlpha > 255) {
+    // TODO(user): The CSS spec says the value should be clamped.
+    throw Error('"(' + h + ',' + s + ',' + l + ',' + a +
+        '") is not a valid HSLA color');
+  }
+  var hexA = goog.color.prependZeroIfNecessaryHelper(intAlpha.toString(16));
+  return goog.color.hslToHex(h, s / 100, l / 100) + hexA;
+};
+
+
+/**
+ * Converts a color from RGBA to hex representation.
+ * @param {Array<number>} rgba Array of [r, g, b, a], with r, g, b in [0, 255]
+ *     and a in [0, 1].
+ * @return {string} hex representation of the color.
+ */
+goog.color.alpha.rgbaArrayToHex = function(rgba) {
+  return goog.color.alpha.rgbaToHex(rgba[0], rgba[1], rgba[2], rgba[3]);
+};
+
+
+/**
+ * Converts a color from RGBA to an RGBA style string.
+ * @param {number} r Value of red, in [0, 255].
+ * @param {number} g Value of green, in [0, 255].
+ * @param {number} b Value of blue, in [0, 255].
+ * @param {number} a Value of alpha, in [0, 1].
+ * @return {string} An 'rgba(r,g,b,a)' string ready for use in a CSS rule.
+ */
+goog.color.alpha.rgbaToRgbaStyle = function(r, g, b, a) {
+  if (isNaN(r) || r < 0 || r > 255 ||
+      isNaN(g) || g < 0 || g > 255 ||
+      isNaN(b) || b < 0 || b > 255 ||
+      isNaN(a) || a < 0 || a > 1) {
+    throw Error('"(' + r + ',' + g + ',' + b + ',' + a +
+        ')" is not a valid RGBA color');
+  }
+  return goog.color.alpha.rgbaStyle_([r, g, b, a]);
+};
+
+
+/**
+ * Converts a color from RGBA to an RGBA style string.
+ * @param {(Array<number>|Float32Array)} rgba Array of [r, g, b, a],
+ *     with r, g, b in [0, 255] and a in [0, 1].
+ * @return {string} An 'rgba(r,g,b,a)' string ready for use in a CSS rule.
+ */
+goog.color.alpha.rgbaArrayToRgbaStyle = function(rgba) {
+  return goog.color.alpha.rgbaToRgbaStyle(rgba[0], rgba[1], rgba[2], rgba[3]);
+};
+
+
+/**
+ * Converts a color from HSLA to hex representation.
+ * @param {Array<number>} hsla Array of [h, s, l, a], where h is an integer in
+ *     [0, 360], s and l are integers in [0, 100], and a is in [0, 1].
+ * @return {string} hex representation of the color, such as '#af457eff'.
+ */
+goog.color.alpha.hslaArrayToHex = function(hsla) {
+  return goog.color.alpha.hslaToHex(hsla[0], hsla[1], hsla[2], hsla[3]);
+};
+
+
+/**
+ * Converts a color from HSLA to an RGBA style string.
+ * @param {Array<number>} hsla Array of [h, s, l, a], where h is and integer in
+ *     [0, 360], s and l are integers in [0, 100], and a is in [0, 1].
+ * @return {string} An 'rgba(r,g,b,a)' string ready for use in a CSS rule.
+ */
+goog.color.alpha.hslaArrayToRgbaStyle = function(hsla) {
+  return goog.color.alpha.hslaToRgbaStyle(hsla[0], hsla[1], hsla[2], hsla[3]);
+};
+
+
+/**
+ * Converts a color from HSLA to an RGBA style string.
+ * @param {number} h Amount of hue, int between 0 and 360.
+ * @param {number} s Amount of saturation, int between 0 and 100.
+ * @param {number} l Amount of lightness, int between 0 and 100.
+ * @param {number} a Amount of alpha, float between 0 and 1.
+ * @return {string} An 'rgba(r,g,b,a)' string ready for use in a CSS rule.
+ *     styles.
+ */
+goog.color.alpha.hslaToRgbaStyle = function(h, s, l, a) {
+  return goog.color.alpha.rgbaStyle_(goog.color.alpha.hslaToRgba(h, s, l, a));
+};
+
+
+/**
+ * Converts a color from HSLA color space to RGBA color space.
+ * @param {number} h Amount of hue, int between 0 and 360.
+ * @param {number} s Amount of saturation, int between 0 and 100.
+ * @param {number} l Amount of lightness, int between 0 and 100.
+ * @param {number} a Amount of alpha, float between 0 and 1.
+ * @return {!Array<number>} [r, g, b, a] values for the color, where r, g, b
+ *     are integers in [0, 255] and a is a float in [0, 1].
+ */
+goog.color.alpha.hslaToRgba = function(h, s, l, a) {
+  return goog.color.hslToRgb(h, s / 100, l / 100).concat(a);
+};
+
+
+/**
+ * Converts a color from RGBA color space to HSLA color space.
+ * Modified from {@link http://en.wikipedia.org/wiki/HLS_color_space}.
+ * @param {number} r Value of red, in [0, 255].
+ * @param {number} g Value of green, in [0, 255].
+ * @param {number} b Value of blue, in [0, 255].
+ * @param {number} a Value of alpha, in [0, 255].
+ * @return {!Array<number>} [h, s, l, a] values for the color, with h an int in
+ *     [0, 360] and s, l and a in [0, 1].
+ */
+goog.color.alpha.rgbaToHsla = function(r, g, b, a) {
+  return goog.color.rgbToHsl(r, g, b).concat(a);
+};
+
+
+/**
+ * Converts a color from RGBA color space to HSLA color space.
+ * @param {Array<number>} rgba [r, g, b, a] values for the color, each in
+ *     [0, 255].
+ * @return {!Array<number>} [h, s, l, a] values for the color, with h in
+ *     [0, 360] and s, l and a in [0, 1].
+ */
+goog.color.alpha.rgbaArrayToHsla = function(rgba) {
+  return goog.color.alpha.rgbaToHsla(rgba[0], rgba[1], rgba[2], rgba[3]);
+};
+
+
+/**
+ * Helper for isValidAlphaHexColor_.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.alpha.validAlphaHexColorRe_ = /^#(?:[0-9a-f]{4}){1,2}$/i;
+
+
+/**
+ * Checks if a string is a valid alpha hex color.  We expect strings of the
+ * format #RRGGBBAA (ex: #1b3d5f5b) or #RGBA (ex: #3CAF == #33CCAAFF).
+ * @param {string} str String to check.
+ * @return {boolean} Whether the string is a valid alpha hex color.
+ * @private
+ */
+// TODO(user): Support percentages when goog.color also supports them.
+goog.color.alpha.isValidAlphaHexColor_ = function(str) {
+  return goog.color.alpha.validAlphaHexColorRe_.test(str);
+};
+
+
+/**
+ * Helper for isNormalizedAlphaHexColor_.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.alpha.normalizedAlphaHexColorRe_ = /^#[0-9a-f]{8}$/;
+
+
+/**
+ * Checks if a string is a normalized alpha hex color.
+ * We expect strings of the format #RRGGBBAA (ex: #1b3d5f5b)
+ * using only lowercase letters.
+ * @param {string} str String to check.
+ * @return {boolean} Whether the string is a normalized hex color.
+ * @private
+ */
+goog.color.alpha.isNormalizedAlphaHexColor_ = function(str) {
+  return goog.color.alpha.normalizedAlphaHexColorRe_.test(str);
+};
+
+
+/**
+ * Regular expression for matching and capturing RGBA style strings. Helper for
+ * isValidRgbaColor_.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.alpha.rgbaColorRe_ =
+    /^(?:rgba)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|1|0\.\d{0,10})\)$/i;
+
+
+/**
+ * Regular expression for matching and capturing HSLA style strings. Helper for
+ * isValidHslaColor_.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.alpha.hslaColorRe_ =
+    /^(?:hsla)\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\%,\s?(0|[1-9]\d{0,2})\%,\s?(0|1|0\.\d{0,10})\)$/i;
+
+
+/**
+ * Checks if a string is a valid rgba color.  We expect strings of the format
+ * '(r, g, b, a)', or 'rgba(r, g, b, a)', where r, g, b are ints in [0, 255]
+ *     and a is a float in [0, 1].
+ * @param {string} str String to check.
+ * @return {!Array<number>} the integers [r, g, b, a] for valid colors or the
+ *     empty array for invalid colors.
+ * @private
+ */
+goog.color.alpha.isValidRgbaColor_ = function(str) {
+  // Each component is separate (rather than using a repeater) so we can
+  // capture the match. Also, we explicitly set each component to be either 0,
+  // or start with a non-zero, to prevent octal numbers from slipping through.
+  var regExpResultArray = str.match(goog.color.alpha.rgbaColorRe_);
+  if (regExpResultArray) {
+    var r = Number(regExpResultArray[1]);
+    var g = Number(regExpResultArray[2]);
+    var b = Number(regExpResultArray[3]);
+    var a = Number(regExpResultArray[4]);
+    if (r >= 0 && r <= 255 &&
+        g >= 0 && g <= 255 &&
+        b >= 0 && b <= 255 &&
+        a >= 0 && a <= 1) {
+      return [r, g, b, a];
+    }
+  }
+  return [];
+};
+
+
+/**
+ * Checks if a string is a valid hsla color.  We expect strings of the format
+ * 'hsla(h, s, l, a)', where s in an int in [0, 360], s and l are percentages
+ *     between 0 and 100 such as '50%' or '70%', and a is a float in [0, 1].
+ * @param {string} str String to check.
+ * @return {!Array<number>} the integers [h, s, l, a] for valid colors or the
+ *     empty array for invalid colors.
+ * @private
+ */
+goog.color.alpha.isValidHslaColor_ = function(str) {
+  // Each component is separate (rather than using a repeater) so we can
+  // capture the match. Also, we explicitly set each component to be either 0,
+  // or start with a non-zero, to prevent octal numbers from slipping through.
+  var regExpResultArray = str.match(goog.color.alpha.hslaColorRe_);
+  if (regExpResultArray) {
+    var h = Number(regExpResultArray[1]);
+    var s = Number(regExpResultArray[2]);
+    var l = Number(regExpResultArray[3]);
+    var a = Number(regExpResultArray[4]);
+    if (h >= 0 && h <= 360 &&
+        s >= 0 && s <= 100 &&
+        l >= 0 && l <= 100 &&
+        a >= 0 && a <= 1) {
+      return [h, s, l, a];
+    }
+  }
+  return [];
+};
+
+
+/**
+ * Takes an array of [r, g, b, a] and converts it into a string appropriate for
+ * CSS styles. The alpha channel value is rounded to 3 decimal places to make
+ * sure the produced string is not too long.
+ * @param {Array<number>} rgba [r, g, b, a] with r, g, b in [0, 255] and a
+ *     in [0, 1].
+ * @return {string} string of the form 'rgba(r,g,b,a)'.
+ * @private
+ */
+goog.color.alpha.rgbaStyle_ = function(rgba) {
+  var roundedRgba = rgba.slice(0);
+  roundedRgba[3] = Math.round(rgba[3] * 1000) / 1000;
+  return 'rgba(' + roundedRgba.join(',') + ')';
+};
+
+
+/**
+ * Converts from h,s,v,a values to a hex string
+ * @param {number} h Hue, in [0, 1].
+ * @param {number} s Saturation, in [0, 1].
+ * @param {number} v Value, in [0, 255].
+ * @param {number} a Alpha, in [0, 1].
+ * @return {string} hex representation of the color.
+ */
+goog.color.alpha.hsvaToHex = function(h, s, v, a) {
+  var alpha = Math.floor(a * 255);
+  return goog.color.hsvArrayToHex([h, s, v]) +
+         goog.color.prependZeroIfNecessaryHelper(alpha.toString(16));
+};
+
+
+/**
+ * Converts from an HSVA array to a hex string
+ * @param {Array<number>} hsva Array of [h, s, v, a] in
+ *     [[0, 1], [0, 1], [0, 255], [0, 1]].
+ * @return {string} hex representation of the color.
+ */
+goog.color.alpha.hsvaArrayToHex = function(hsva) {
+  return goog.color.alpha.hsvaToHex(hsva[0], hsva[1], hsva[2], hsva[3]);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/color/color.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/color/color.js b/externs/GCL/externs/goog/color/color.js
new file mode 100644
index 0000000..8220532
--- /dev/null
+++ b/externs/GCL/externs/goog/color/color.js
@@ -0,0 +1,776 @@
+// 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 related to color and color conversion.
+ */
+
+goog.provide('goog.color');
+goog.provide('goog.color.Hsl');
+goog.provide('goog.color.Hsv');
+goog.provide('goog.color.Rgb');
+
+goog.require('goog.color.names');
+goog.require('goog.math');
+
+
+/**
+ * RGB color representation. An array containing three elements [r, g, b],
+ * each an integer in [0, 255], representing the red, green, and blue components
+ * of the color respectively.
+ * @typedef {Array<number>}
+ */
+goog.color.Rgb;
+
+
+/**
+ * HSV color representation. An array containing three elements [h, s, v]:
+ * h (hue) must be an integer in [0, 360], cyclic.
+ * s (saturation) must be a number in [0, 1].
+ * v (value/brightness) must be an integer in [0, 255].
+ * @typedef {Array<number>}
+ */
+goog.color.Hsv;
+
+
+/**
+ * HSL color representation. An array containing three elements [h, s, l]:
+ * h (hue) must be an integer in [0, 360], cyclic.
+ * s (saturation) must be a number in [0, 1].
+ * l (lightness) must be a number in [0, 1].
+ * @typedef {Array<number>}
+ */
+goog.color.Hsl;
+
+
+/**
+ * Parses a color out of a string.
+ * @param {string} str Color in some format.
+ * @return {{hex: string, type: string}} 'hex' is a string containing a hex
+ *     representation of the color, 'type' is a string containing the type
+ *     of color format passed in ('hex', 'rgb', 'named').
+ */
+goog.color.parse = function(str) {
+  var result = {};
+  str = String(str);
+
+  var maybeHex = goog.color.prependHashIfNecessaryHelper(str);
+  if (goog.color.isValidHexColor_(maybeHex)) {
+    result.hex = goog.color.normalizeHex(maybeHex);
+    result.type = 'hex';
+    return result;
+  } else {
+    var rgb = goog.color.isValidRgbColor_(str);
+    if (rgb.length) {
+      result.hex = goog.color.rgbArrayToHex(rgb);
+      result.type = 'rgb';
+      return result;
+    } else if (goog.color.names) {
+      var hex = goog.color.names[str.toLowerCase()];
+      if (hex) {
+        result.hex = hex;
+        result.type = 'named';
+        return result;
+      }
+    }
+  }
+  throw Error(str + ' is not a valid color string');
+};
+
+
+/**
+ * Determines if the given string can be parsed as a color.
+ *     {@see goog.color.parse}.
+ * @param {string} str Potential color string.
+ * @return {boolean} True if str is in a format that can be parsed to a color.
+ */
+goog.color.isValidColor = function(str) {
+  var maybeHex = goog.color.prependHashIfNecessaryHelper(str);
+  return !!(goog.color.isValidHexColor_(maybeHex) ||
+            goog.color.isValidRgbColor_(str).length ||
+            goog.color.names && goog.color.names[str.toLowerCase()]);
+};
+
+
+/**
+ * Parses red, green, blue components out of a valid rgb color string.
+ * Throws Error if the color string is invalid.
+ * @param {string} str RGB representation of a color.
+ *    {@see goog.color.isValidRgbColor_}.
+ * @return {!goog.color.Rgb} rgb representation of the color.
+ */
+goog.color.parseRgb = function(str) {
+  var rgb = goog.color.isValidRgbColor_(str);
+  if (!rgb.length) {
+    throw Error(str + ' is not a valid RGB color');
+  }
+  return rgb;
+};
+
+
+/**
+ * Converts a hex representation of a color to RGB.
+ * @param {string} hexColor Color to convert.
+ * @return {string} string of the form 'rgb(R,G,B)' which can be used in
+ *    styles.
+ */
+goog.color.hexToRgbStyle = function(hexColor) {
+  return goog.color.rgbStyle_(goog.color.hexToRgb(hexColor));
+};
+
+
+/**
+ * Regular expression for extracting the digits in a hex color triplet.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.hexTripletRe_ = /#(.)(.)(.)/;
+
+
+/**
+ * Normalize an hex representation of a color
+ * @param {string} hexColor an hex color string.
+ * @return {string} hex color in the format '#rrggbb' with all lowercase
+ *     literals.
+ */
+goog.color.normalizeHex = function(hexColor) {
+  if (!goog.color.isValidHexColor_(hexColor)) {
+    throw Error("'" + hexColor + "' is not a valid hex color");
+  }
+  if (hexColor.length == 4) { // of the form #RGB
+    hexColor = hexColor.replace(goog.color.hexTripletRe_, '#$1$1$2$2$3$3');
+  }
+  return hexColor.toLowerCase();
+};
+
+
+/**
+ * Converts a hex representation of a color to RGB.
+ * @param {string} hexColor Color to convert.
+ * @return {!goog.color.Rgb} rgb representation of the color.
+ */
+goog.color.hexToRgb = function(hexColor) {
+  hexColor = goog.color.normalizeHex(hexColor);
+  var r = parseInt(hexColor.substr(1, 2), 16);
+  var g = parseInt(hexColor.substr(3, 2), 16);
+  var b = parseInt(hexColor.substr(5, 2), 16);
+
+  return [r, g, b];
+};
+
+
+/**
+ * Converts a color from RGB to hex representation.
+ * @param {number} r Amount of red, int between 0 and 255.
+ * @param {number} g Amount of green, int between 0 and 255.
+ * @param {number} b Amount of blue, int between 0 and 255.
+ * @return {string} hex representation of the color.
+ */
+goog.color.rgbToHex = function(r, g, b) {
+  r = Number(r);
+  g = Number(g);
+  b = Number(b);
+  if (isNaN(r) || r < 0 || r > 255 ||
+      isNaN(g) || g < 0 || g > 255 ||
+      isNaN(b) || b < 0 || b > 255) {
+    throw Error('"(' + r + ',' + g + ',' + b + '") is not a valid RGB color');
+  }
+  var hexR = goog.color.prependZeroIfNecessaryHelper(r.toString(16));
+  var hexG = goog.color.prependZeroIfNecessaryHelper(g.toString(16));
+  var hexB = goog.color.prependZeroIfNecessaryHelper(b.toString(16));
+  return '#' + hexR + hexG + hexB;
+};
+
+
+/**
+ * Converts a color from RGB to hex representation.
+ * @param {goog.color.Rgb} rgb rgb representation of the color.
+ * @return {string} hex representation of the color.
+ */
+goog.color.rgbArrayToHex = function(rgb) {
+  return goog.color.rgbToHex(rgb[0], rgb[1], rgb[2]);
+};
+
+
+/**
+ * Converts a color from RGB color space to HSL color space.
+ * Modified from {@link http://en.wikipedia.org/wiki/HLS_color_space}.
+ * @param {number} r Value of red, in [0, 255].
+ * @param {number} g Value of green, in [0, 255].
+ * @param {number} b Value of blue, in [0, 255].
+ * @return {!goog.color.Hsl} hsl representation of the color.
+ */
+goog.color.rgbToHsl = function(r, g, b) {
+  // First must normalize r, g, b to be between 0 and 1.
+  var normR = r / 255;
+  var normG = g / 255;
+  var normB = b / 255;
+  var max = Math.max(normR, normG, normB);
+  var min = Math.min(normR, normG, normB);
+  var h = 0;
+  var s = 0;
+
+  // Luminosity is the average of the max and min rgb color intensities.
+  var l = 0.5 * (max + min);
+
+  // The hue and saturation are dependent on which color intensity is the max.
+  // If max and min are equal, the color is gray and h and s should be 0.
+  if (max != min) {
+    if (max == normR) {
+      h = 60 * (normG - normB) / (max - min);
+    } else if (max == normG) {
+      h = 60 * (normB - normR) / (max - min) + 120;
+    } else if (max == normB) {
+      h = 60 * (normR - normG) / (max - min) + 240;
+    }
+
+    if (0 < l && l <= 0.5) {
+      s = (max - min) / (2 * l);
+    } else {
+      s = (max - min) / (2 - 2 * l);
+    }
+  }
+
+  // Make sure the hue falls between 0 and 360.
+  return [Math.round(h + 360) % 360, s, l];
+};
+
+
+/**
+ * Converts a color from RGB color space to HSL color space.
+ * @param {goog.color.Rgb} rgb rgb representation of the color.
+ * @return {!goog.color.Hsl} hsl representation of the color.
+ */
+goog.color.rgbArrayToHsl = function(rgb) {
+  return goog.color.rgbToHsl(rgb[0], rgb[1], rgb[2]);
+};
+
+
+/**
+ * Helper for hslToRgb.
+ * @param {number} v1 Helper variable 1.
+ * @param {number} v2 Helper variable 2.
+ * @param {number} vH Helper variable 3.
+ * @return {number} Appropriate RGB value, given the above.
+ * @private
+ */
+goog.color.hueToRgb_ = function(v1, v2, vH) {
+  if (vH < 0) {
+    vH += 1;
+  } else if (vH > 1) {
+    vH -= 1;
+  }
+  if ((6 * vH) < 1) {
+    return (v1 + (v2 - v1) * 6 * vH);
+  } else if (2 * vH < 1) {
+    return v2;
+  } else if (3 * vH < 2) {
+    return (v1 + (v2 - v1) * ((2 / 3) - vH) * 6);
+  }
+  return v1;
+};
+
+
+/**
+ * Converts a color from HSL color space to RGB color space.
+ * Modified from {@link http://www.easyrgb.com/math.html}
+ * @param {number} h Hue, in [0, 360].
+ * @param {number} s Saturation, in [0, 1].
+ * @param {number} l Luminosity, in [0, 1].
+ * @return {!goog.color.Rgb} rgb representation of the color.
+ */
+goog.color.hslToRgb = function(h, s, l) {
+  var r = 0;
+  var g = 0;
+  var b = 0;
+  var normH = h / 360; // normalize h to fall in [0, 1]
+
+  if (s == 0) {
+    r = g = b = l * 255;
+  } else {
+    var temp1 = 0;
+    var temp2 = 0;
+    if (l < 0.5) {
+      temp2 = l * (1 + s);
+    } else {
+      temp2 = l + s - (s * l);
+    }
+    temp1 = 2 * l - temp2;
+    r = 255 * goog.color.hueToRgb_(temp1, temp2, normH + (1 / 3));
+    g = 255 * goog.color.hueToRgb_(temp1, temp2, normH);
+    b = 255 * goog.color.hueToRgb_(temp1, temp2, normH - (1 / 3));
+  }
+
+  return [Math.round(r), Math.round(g), Math.round(b)];
+};
+
+
+/**
+ * Converts a color from HSL color space to RGB color space.
+ * @param {goog.color.Hsl} hsl hsl representation of the color.
+ * @return {!goog.color.Rgb} rgb representation of the color.
+ */
+goog.color.hslArrayToRgb = function(hsl) {
+  return goog.color.hslToRgb(hsl[0], hsl[1], hsl[2]);
+};
+
+
+/**
+ * Helper for isValidHexColor_.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.validHexColorRe_ = /^#(?:[0-9a-f]{3}){1,2}$/i;
+
+
+/**
+ * Checks if a string is a valid hex color.  We expect strings of the format
+ * #RRGGBB (ex: #1b3d5f) or #RGB (ex: #3CA == #33CCAA).
+ * @param {string} str String to check.
+ * @return {boolean} Whether the string is a valid hex color.
+ * @private
+ */
+goog.color.isValidHexColor_ = function(str) {
+  return goog.color.validHexColorRe_.test(str);
+};
+
+
+/**
+ * Helper for isNormalizedHexColor_.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.normalizedHexColorRe_ = /^#[0-9a-f]{6}$/;
+
+
+/**
+ * Checks if a string is a normalized hex color.
+ * We expect strings of the format #RRGGBB (ex: #1b3d5f)
+ * using only lowercase letters.
+ * @param {string} str String to check.
+ * @return {boolean} Whether the string is a normalized hex color.
+ * @private
+ */
+goog.color.isNormalizedHexColor_ = function(str) {
+  return goog.color.normalizedHexColorRe_.test(str);
+};
+
+
+/**
+ * Regular expression for matching and capturing RGB style strings. Helper for
+ * isValidRgbColor_.
+ * @type {RegExp}
+ * @private
+ */
+goog.color.rgbColorRe_ =
+    /^(?:rgb)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\)$/i;
+
+
+/**
+ * Checks if a string is a valid rgb color.  We expect strings of the format
+ * '(r, g, b)', or 'rgb(r, g, b)', where each color component is an int in
+ * [0, 255].
+ * @param {string} str String to check.
+ * @return {!goog.color.Rgb} the rgb representation of the color if it is
+ *     a valid color, or the empty array otherwise.
+ * @private
+ */
+goog.color.isValidRgbColor_ = function(str) {
+  // Each component is separate (rather than using a repeater) so we can
+  // capture the match. Also, we explicitly set each component to be either 0,
+  // or start with a non-zero, to prevent octal numbers from slipping through.
+  var regExpResultArray = str.match(goog.color.rgbColorRe_);
+  if (regExpResultArray) {
+    var r = Number(regExpResultArray[1]);
+    var g = Number(regExpResultArray[2]);
+    var b = Number(regExpResultArray[3]);
+    if (r >= 0 && r <= 255 &&
+        g >= 0 && g <= 255 &&
+        b >= 0 && b <= 255) {
+      return [r, g, b];
+    }
+  }
+  return [];
+};
+
+
+/**
+ * Takes a hex value and prepends a zero if it's a single digit.
+ * Small helper method for use by goog.color and friends.
+ * @param {string} hex Hex value to prepend if single digit.
+ * @return {string} hex value prepended with zero if it was single digit,
+ *     otherwise the same value that was passed in.
+ */
+goog.color.prependZeroIfNecessaryHelper = function(hex) {
+  return hex.length == 1 ? '0' + hex : hex;
+};
+
+
+/**
+ * Takes a string a prepends a '#' sign if one doesn't exist.
+ * Small helper method for use by goog.color and friends.
+ * @param {string} str String to check.
+ * @return {string} The value passed in, prepended with a '#' if it didn't
+ *     already have one.
+ */
+goog.color.prependHashIfNecessaryHelper = function(str) {
+  return str.charAt(0) == '#' ? str : '#' + str;
+};
+
+
+/**
+ * Takes an array of [r, g, b] and converts it into a string appropriate for
+ * CSS styles.
+ * @param {goog.color.Rgb} rgb rgb representation of the color.
+ * @return {string} string of the form 'rgb(r,g,b)'.
+ * @private
+ */
+goog.color.rgbStyle_ = function(rgb) {
+  return 'rgb(' + rgb.join(',') + ')';
+};
+
+
+/**
+ * Converts an HSV triplet to an RGB array.  V is brightness because b is
+ *   reserved for blue in RGB.
+ * @param {number} h Hue value in [0, 360].
+ * @param {number} s Saturation value in [0, 1].
+ * @param {number} brightness brightness in [0, 255].
+ * @return {!goog.color.Rgb} rgb representation of the color.
+ */
+goog.color.hsvToRgb = function(h, s, brightness) {
+  var red = 0;
+  var green = 0;
+  var blue = 0;
+  if (s == 0) {
+    red = brightness;
+    green = brightness;
+    blue = brightness;
+  } else {
+    var sextant = Math.floor(h / 60);
+    var remainder = (h / 60) - sextant;
+    var val1 = brightness * (1 - s);
+    var val2 = brightness * (1 - (s * remainder));
+    var val3 = brightness * (1 - (s * (1 - remainder)));
+    switch (sextant) {
+      case 1:
+        red = val2;
+        green = brightness;
+        blue = val1;
+        break;
+      case 2:
+        red = val1;
+        green = brightness;
+        blue = val3;
+        break;
+      case 3:
+        red = val1;
+        green = val2;
+        blue = brightness;
+        break;
+      case 4:
+        red = val3;
+        green = val1;
+        blue = brightness;
+        break;
+      case 5:
+        red = brightness;
+        green = val1;
+        blue = val2;
+        break;
+      case 6:
+      case 0:
+        red = brightness;
+        green = val3;
+        blue = val1;
+        break;
+    }
+  }
+
+  return [Math.floor(red), Math.floor(green), Math.floor(blue)];
+};
+
+
+/**
+ * Converts from RGB values to an array of HSV values.
+ * @param {number} red Red value in [0, 255].
+ * @param {number} green Green value in [0, 255].
+ * @param {number} blue Blue value in [0, 255].
+ * @return {!goog.color.Hsv} hsv representation of the color.
+ */
+goog.color.rgbToHsv = function(red, green, blue) {
+
+  var max = Math.max(Math.max(red, green), blue);
+  var min = Math.min(Math.min(red, green), blue);
+  var hue;
+  var saturation;
+  var value = max;
+  if (min == max) {
+    hue = 0;
+    saturation = 0;
+  } else {
+    var delta = (max - min);
+    saturation = delta / max;
+
+    if (red == max) {
+      hue = (green - blue) / delta;
+    } else if (green == max) {
+      hue = 2 + ((blue - red) / delta);
+    } else {
+      hue = 4 + ((red - green) / delta);
+    }
+    hue *= 60;
+    if (hue < 0) {
+      hue += 360;
+    }
+    if (hue > 360) {
+      hue -= 360;
+    }
+  }
+
+  return [hue, saturation, value];
+};
+
+
+/**
+ * Converts from an array of RGB values to an array of HSV values.
+ * @param {goog.color.Rgb} rgb rgb representation of the color.
+ * @return {!goog.color.Hsv} hsv representation of the color.
+ */
+goog.color.rgbArrayToHsv = function(rgb) {
+  return goog.color.rgbToHsv(rgb[0], rgb[1], rgb[2]);
+};
+
+
+/**
+ * Converts an HSV triplet to an RGB array.
+ * @param {goog.color.Hsv} hsv hsv representation of the color.
+ * @return {!goog.color.Rgb} rgb representation of the color.
+ */
+goog.color.hsvArrayToRgb = function(hsv) {
+  return goog.color.hsvToRgb(hsv[0], hsv[1], hsv[2]);
+};
+
+
+/**
+ * Converts a hex representation of a color to HSL.
+ * @param {string} hex Color to convert.
+ * @return {!goog.color.Hsv} hsv representation of the color.
+ */
+goog.color.hexToHsl = function(hex) {
+  var rgb = goog.color.hexToRgb(hex);
+  return goog.color.rgbToHsl(rgb[0], rgb[1], rgb[2]);
+};
+
+
+/**
+ * Converts from h,s,l values to a hex string
+ * @param {number} h Hue, in [0, 360].
+ * @param {number} s Saturation, in [0, 1].
+ * @param {number} l Luminosity, in [0, 1].
+ * @return {string} hex representation of the color.
+ */
+goog.color.hslToHex = function(h, s, l) {
+  return goog.color.rgbArrayToHex(goog.color.hslToRgb(h, s, l));
+};
+
+
+/**
+ * Converts from an hsl array to a hex string
+ * @param {goog.color.Hsl} hsl hsl representation of the color.
+ * @return {string} hex representation of the color.
+ */
+goog.color.hslArrayToHex = function(hsl) {
+  return goog.color.rgbArrayToHex(goog.color.hslToRgb(hsl[0], hsl[1], hsl[2]));
+};
+
+
+/**
+ * Converts a hex representation of a color to HSV
+ * @param {string} hex Color to convert.
+ * @return {!goog.color.Hsv} hsv representation of the color.
+ */
+goog.color.hexToHsv = function(hex) {
+  return goog.color.rgbArrayToHsv(goog.color.hexToRgb(hex));
+};
+
+
+/**
+ * Converts from h,s,v values to a hex string
+ * @param {number} h Hue, in [0, 360].
+ * @param {number} s Saturation, in [0, 1].
+ * @param {number} v Value, in [0, 255].
+ * @return {string} hex representation of the color.
+ */
+goog.color.hsvToHex = function(h, s, v) {
+  return goog.color.rgbArrayToHex(goog.color.hsvToRgb(h, s, v));
+};
+
+
+/**
+ * Converts from an HSV array to a hex string
+ * @param {goog.color.Hsv} hsv hsv representation of the color.
+ * @return {string} hex representation of the color.
+ */
+goog.color.hsvArrayToHex = function(hsv) {
+  return goog.color.hsvToHex(hsv[0], hsv[1], hsv[2]);
+};
+
+
+/**
+ * Calculates the Euclidean distance between two color vectors on an HSL sphere.
+ * A demo of the sphere can be found at:
+ * http://en.wikipedia.org/wiki/HSL_color_space
+ * In short, a vector for color (H, S, L) in this system can be expressed as
+ * (S*L'*cos(2*PI*H), S*L'*sin(2*PI*H), L), where L' = abs(L - 0.5), and we
+ * simply calculate the 1-2 distance using these coordinates
+ * @param {goog.color.Hsl} hsl1 First color in hsl representation.
+ * @param {goog.color.Hsl} hsl2 Second color in hsl representation.
+ * @return {number} Distance between the two colors, in the range [0, 1].
+ */
+goog.color.hslDistance = function(hsl1, hsl2) {
+  var sl1, sl2;
+  if (hsl1[2] <= 0.5) {
+    sl1 = hsl1[1] * hsl1[2];
+  } else {
+    sl1 = hsl1[1] * (1.0 - hsl1[2]);
+  }
+
+  if (hsl2[2] <= 0.5) {
+    sl2 = hsl2[1] * hsl2[2];
+  } else {
+    sl2 = hsl2[1] * (1.0 - hsl2[2]);
+  }
+
+  var h1 = hsl1[0] / 360.0;
+  var h2 = hsl2[0] / 360.0;
+  var dh = (h1 - h2) * 2.0 * Math.PI;
+  return (hsl1[2] - hsl2[2]) * (hsl1[2] - hsl2[2]) +
+      sl1 * sl1 + sl2 * sl2 - 2 * sl1 * sl2 * Math.cos(dh);
+};
+
+
+/**
+ * Blend two colors together, using the specified factor to indicate the weight
+ * given to the first color
+ * @param {goog.color.Rgb} rgb1 First color represented in rgb.
+ * @param {goog.color.Rgb} rgb2 Second color represented in rgb.
+ * @param {number} factor The weight to be given to rgb1 over rgb2. Values
+ *     should be in the range [0, 1]. If less than 0, factor will be set to 0.
+ *     If greater than 1, factor will be set to 1.
+ * @return {!goog.color.Rgb} Combined color represented in rgb.
+ */
+goog.color.blend = function(rgb1, rgb2, factor) {
+  factor = goog.math.clamp(factor, 0, 1);
+
+  return [
+    Math.round(factor * rgb1[0] + (1.0 - factor) * rgb2[0]),
+    Math.round(factor * rgb1[1] + (1.0 - factor) * rgb2[1]),
+    Math.round(factor * rgb1[2] + (1.0 - factor) * rgb2[2])
+  ];
+};
+
+
+/**
+ * Adds black to the specified color, darkening it
+ * @param {goog.color.Rgb} rgb rgb representation of the color.
+ * @param {number} factor Number in the range [0, 1]. 0 will do nothing, while
+ *     1 will return black. If less than 0, factor will be set to 0. If greater
+ *     than 1, factor will be set to 1.
+ * @return {!goog.color.Rgb} Combined rgb color.
+ */
+goog.color.darken = function(rgb, factor) {
+  var black = [0, 0, 0];
+  return goog.color.blend(black, rgb, factor);
+};
+
+
+/**
+ * Adds white to the specified color, lightening it
+ * @param {goog.color.Rgb} rgb rgb representation of the color.
+ * @param {number} factor Number in the range [0, 1].  0 will do nothing, while
+ *     1 will return white. If less than 0, factor will be set to 0. If greater
+ *     than 1, factor will be set to 1.
+ * @return {!goog.color.Rgb} Combined rgb color.
+ */
+goog.color.lighten = function(rgb, factor) {
+  var white = [255, 255, 255];
+  return goog.color.blend(white, rgb, factor);
+};
+
+
+/**
+ * Find the "best" (highest-contrast) of the suggested colors for the prime
+ * color. Uses W3C formula for judging readability and visual accessibility:
+ * http://www.w3.org/TR/AERT#color-contrast
+ * @param {goog.color.Rgb} prime Color represented as a rgb array.
+ * @param {Array<goog.color.Rgb>} suggestions Array of colors,
+ *     each representing a rgb array.
+ * @return {!goog.color.Rgb} Highest-contrast color represented by an array..
+ */
+goog.color.highContrast = function(prime, suggestions) {
+  var suggestionsWithDiff = [];
+  for (var i = 0; i < suggestions.length; i++) {
+    suggestionsWithDiff.push({
+      color: suggestions[i],
+      diff: goog.color.yiqBrightnessDiff_(suggestions[i], prime) +
+          goog.color.colorDiff_(suggestions[i], prime)
+    });
+  }
+  suggestionsWithDiff.sort(function(a, b) {
+    return b.diff - a.diff;
+  });
+  return suggestionsWithDiff[0].color;
+};
+
+
+/**
+ * Calculate brightness of a color according to YIQ formula (brightness is Y).
+ * More info on YIQ here: http://en.wikipedia.org/wiki/YIQ. Helper method for
+ * goog.color.highContrast()
+ * @param {goog.color.Rgb} rgb Color represented by a rgb array.
+ * @return {number} brightness (Y).
+ * @private
+ */
+goog.color.yiqBrightness_ = function(rgb) {
+  return Math.round((rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000);
+};
+
+
+/**
+ * Calculate difference in brightness of two colors. Helper method for
+ * goog.color.highContrast()
+ * @param {goog.color.Rgb} rgb1 Color represented by a rgb array.
+ * @param {goog.color.Rgb} rgb2 Color represented by a rgb array.
+ * @return {number} Brightness difference.
+ * @private
+ */
+goog.color.yiqBrightnessDiff_ = function(rgb1, rgb2) {
+  return Math.abs(goog.color.yiqBrightness_(rgb1) -
+                  goog.color.yiqBrightness_(rgb2));
+};
+
+
+/**
+ * Calculate color difference between two colors. Helper method for
+ * goog.color.highContrast()
+ * @param {goog.color.Rgb} rgb1 Color represented by a rgb array.
+ * @param {goog.color.Rgb} rgb2 Color represented by a rgb array.
+ * @return {number} Color difference.
+ * @private
+ */
+goog.color.colorDiff_ = function(rgb1, rgb2) {
+  return Math.abs(rgb1[0] - rgb2[0]) + Math.abs(rgb1[1] - rgb2[1]) +
+      Math.abs(rgb1[2] - rgb2[2]);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/color/names.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/color/names.js b/externs/GCL/externs/goog/color/names.js
new file mode 100644
index 0000000..c4b3ac8
--- /dev/null
+++ b/externs/GCL/externs/goog/color/names.js
@@ -0,0 +1,176 @@
+// 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 Names of standard colors with their associated hex values.
+ */
+
+goog.provide('goog.color.names');
+
+
+/**
+ * A map that contains a lot of colors that are recognised by various browsers.
+ * This list is way larger than the minimal one dictated by W3C.
+ * The keys of this map are the lowercase "readable" names of the colors, while
+ * the values are the "hex" values.
+ */
+goog.color.names = {
+  'aliceblue': '#f0f8ff',
+  'antiquewhite': '#faebd7',
+  'aqua': '#00ffff',
+  'aquamarine': '#7fffd4',
+  'azure': '#f0ffff',
+  'beige': '#f5f5dc',
+  'bisque': '#ffe4c4',
+  'black': '#000000',
+  'blanchedalmond': '#ffebcd',
+  'blue': '#0000ff',
+  'blueviolet': '#8a2be2',
+  'brown': '#a52a2a',
+  'burlywood': '#deb887',
+  'cadetblue': '#5f9ea0',
+  'chartreuse': '#7fff00',
+  'chocolate': '#d2691e',
+  'coral': '#ff7f50',
+  'cornflowerblue': '#6495ed',
+  'cornsilk': '#fff8dc',
+  'crimson': '#dc143c',
+  'cyan': '#00ffff',
+  'darkblue': '#00008b',
+  'darkcyan': '#008b8b',
+  'darkgoldenrod': '#b8860b',
+  'darkgray': '#a9a9a9',
+  'darkgreen': '#006400',
+  'darkgrey': '#a9a9a9',
+  'darkkhaki': '#bdb76b',
+  'darkmagenta': '#8b008b',
+  'darkolivegreen': '#556b2f',
+  'darkorange': '#ff8c00',
+  'darkorchid': '#9932cc',
+  'darkred': '#8b0000',
+  'darksalmon': '#e9967a',
+  'darkseagreen': '#8fbc8f',
+  'darkslateblue': '#483d8b',
+  'darkslategray': '#2f4f4f',
+  'darkslategrey': '#2f4f4f',
+  'darkturquoise': '#00ced1',
+  'darkviolet': '#9400d3',
+  'deeppink': '#ff1493',
+  'deepskyblue': '#00bfff',
+  'dimgray': '#696969',
+  'dimgrey': '#696969',
+  'dodgerblue': '#1e90ff',
+  'firebrick': '#b22222',
+  'floralwhite': '#fffaf0',
+  'forestgreen': '#228b22',
+  'fuchsia': '#ff00ff',
+  'gainsboro': '#dcdcdc',
+  'ghostwhite': '#f8f8ff',
+  'gold': '#ffd700',
+  'goldenrod': '#daa520',
+  'gray': '#808080',
+  'green': '#008000',
+  'greenyellow': '#adff2f',
+  'grey': '#808080',
+  'honeydew': '#f0fff0',
+  'hotpink': '#ff69b4',
+  'indianred': '#cd5c5c',
+  'indigo': '#4b0082',
+  'ivory': '#fffff0',
+  'khaki': '#f0e68c',
+  'lavender': '#e6e6fa',
+  'lavenderblush': '#fff0f5',
+  'lawngreen': '#7cfc00',
+  'lemonchiffon': '#fffacd',
+  'lightblue': '#add8e6',
+  'lightcoral': '#f08080',
+  'lightcyan': '#e0ffff',
+  'lightgoldenrodyellow': '#fafad2',
+  'lightgray': '#d3d3d3',
+  'lightgreen': '#90ee90',
+  'lightgrey': '#d3d3d3',
+  'lightpink': '#ffb6c1',
+  'lightsalmon': '#ffa07a',
+  'lightseagreen': '#20b2aa',
+  'lightskyblue': '#87cefa',
+  'lightslategray': '#778899',
+  'lightslategrey': '#778899',
+  'lightsteelblue': '#b0c4de',
+  'lightyellow': '#ffffe0',
+  'lime': '#00ff00',
+  'limegreen': '#32cd32',
+  'linen': '#faf0e6',
+  'magenta': '#ff00ff',
+  'maroon': '#800000',
+  'mediumaquamarine': '#66cdaa',
+  'mediumblue': '#0000cd',
+  'mediumorchid': '#ba55d3',
+  'mediumpurple': '#9370db',
+  'mediumseagreen': '#3cb371',
+  'mediumslateblue': '#7b68ee',
+  'mediumspringgreen': '#00fa9a',
+  'mediumturquoise': '#48d1cc',
+  'mediumvioletred': '#c71585',
+  'midnightblue': '#191970',
+  'mintcream': '#f5fffa',
+  'mistyrose': '#ffe4e1',
+  'moccasin': '#ffe4b5',
+  'navajowhite': '#ffdead',
+  'navy': '#000080',
+  'oldlace': '#fdf5e6',
+  'olive': '#808000',
+  'olivedrab': '#6b8e23',
+  'orange': '#ffa500',
+  'orangered': '#ff4500',
+  'orchid': '#da70d6',
+  'palegoldenrod': '#eee8aa',
+  'palegreen': '#98fb98',
+  'paleturquoise': '#afeeee',
+  'palevioletred': '#db7093',
+  'papayawhip': '#ffefd5',
+  'peachpuff': '#ffdab9',
+  'peru': '#cd853f',
+  'pink': '#ffc0cb',
+  'plum': '#dda0dd',
+  'powderblue': '#b0e0e6',
+  'purple': '#800080',
+  'red': '#ff0000',
+  'rosybrown': '#bc8f8f',
+  'royalblue': '#4169e1',
+  'saddlebrown': '#8b4513',
+  'salmon': '#fa8072',
+  'sandybrown': '#f4a460',
+  'seagreen': '#2e8b57',
+  'seashell': '#fff5ee',
+  'sienna': '#a0522d',
+  'silver': '#c0c0c0',
+  'skyblue': '#87ceeb',
+  'slateblue': '#6a5acd',
+  'slategray': '#708090',
+  'slategrey': '#708090',
+  'snow': '#fffafa',
+  'springgreen': '#00ff7f',
+  'steelblue': '#4682b4',
+  'tan': '#d2b48c',
+  'teal': '#008080',
+  'thistle': '#d8bfd8',
+  'tomato': '#ff6347',
+  'turquoise': '#40e0d0',
+  'violet': '#ee82ee',
+  'wheat': '#f5deb3',
+  'white': '#ffffff',
+  'whitesmoke': '#f5f5f5',
+  'yellow': '#ffff00',
+  'yellowgreen': '#9acd32'
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/aes.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/aes.js b/externs/GCL/externs/goog/crypt/aes.js
new file mode 100644
index 0000000..d5a1674
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/aes.js
@@ -0,0 +1,1029 @@
+// 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 Implementation of AES in JavaScript.
+ * @see http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
+ *
+ * @author nnaze@google.com (Nathan Naze) - port to Closure
+ */
+
+goog.provide('goog.crypt.Aes');
+
+goog.require('goog.asserts');
+goog.require('goog.crypt.BlockCipher');
+
+
+
+/**
+ * Implementation of AES in JavaScript.
+ * See http://en.wikipedia.org/wiki/Advanced_Encryption_Standard
+ *
+ * WARNING: This is ECB mode only. If you are encrypting something
+ * longer than 16 bytes, or encrypting more than one value with the same key
+ * (so basically, always) you need to use this with a block cipher mode of
+ * operation.  See goog.crypt.Cbc.
+ *
+ * See http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation for more
+ * information.
+ *
+ * @constructor
+ * @implements {goog.crypt.BlockCipher}
+ * @param {!Array<number>} key The key as an array of integers in {0, 255}.
+ *     The key must have lengths of 16, 24, or 32 integers for 128-,
+ *     192-, or 256-bit encryption, respectively.
+ * @final
+ * @struct
+ */
+goog.crypt.Aes = function(key) {
+  goog.crypt.Aes.assertKeyArray_(key);
+
+  /**
+   * The AES key.
+   * @type {!Array<number>}
+   * @private
+   */
+  this.key_ = key;
+
+  /**
+   * Key length, in words.
+   * @type {number}
+   * @private
+   */
+  this.keyLength_ = this.key_.length / 4;
+
+  /**
+   * Number of rounds.  Based on key length per AES spec.
+   * @type {number}
+   * @private
+   */
+  this.numberOfRounds_ = this.keyLength_ + 6;
+
+  /**
+   * 4x4 byte array containing the current state.
+   * @type {!Array<!Array<number>>}
+   * @private
+   */
+  this.state_ = [[], [], [], []];
+
+  /**
+   * Scratch temporary array for calculation.
+   * @type {!Array<!Array<number>>}
+   * @private
+   */
+  this.temp_ = [[], [], [], []];
+
+  /**
+   * The key schedule.
+   * @type {!Array<!Array<number>>}
+   * @private
+   */
+  this.keySchedule_;
+
+  this.keyExpansion_();
+};
+
+
+/**
+ * @define {boolean} Whether to call test method stubs.  This can be enabled
+ *     for unit testing.
+ */
+goog.define('goog.crypt.Aes.ENABLE_TEST_MODE', false);
+
+
+/**
+ * @override
+ */
+goog.crypt.Aes.prototype.encrypt = function(input) {
+
+  if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+    this.testKeySchedule_(0, this.keySchedule_, 0);
+  }
+
+  this.copyInput_(input);
+  this.addRoundKey_(0);
+
+  for (var round = 1; round < this.numberOfRounds_; ++round) {
+    if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+      this.testKeySchedule_(round, this.keySchedule_, round);
+      this.testStartRound_(round, this.state_);
+    }
+
+    this.subBytes_(goog.crypt.Aes.SBOX_);
+    if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+      this.testAfterSubBytes_(round, this.state_);
+    }
+
+    this.shiftRows_();
+    if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+      this.testAfterShiftRows_(round, this.state_);
+    }
+
+    this.mixColumns_();
+    if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+      this.testAfterMixColumns_(round, this.state_);
+    }
+
+    this.addRoundKey_(round);
+  }
+
+  this.subBytes_(goog.crypt.Aes.SBOX_);
+  if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+    this.testAfterSubBytes_(round, this.state_);
+  }
+
+  this.shiftRows_();
+  if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+    this.testAfterShiftRows_(round, this.state_);
+  }
+
+  this.addRoundKey_(this.numberOfRounds_);
+
+  return this.generateOutput_();
+};
+
+
+/**
+ * @override
+ */
+goog.crypt.Aes.prototype.decrypt = function(input) {
+
+  if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+    this.testKeySchedule_(0, this.keySchedule_, this.numberOfRounds_);
+  }
+
+  this.copyInput_(input);
+  this.addRoundKey_(this.numberOfRounds_);
+
+  for (var round = 1; round < this.numberOfRounds_; ++round) {
+    if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+      this.testKeySchedule_(round, this.keySchedule_,
+                            this.numberOfRounds_ - round);
+      this.testStartRound_(round, this.state_);
+    }
+
+    this.invShiftRows_();
+    if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+      this.testAfterShiftRows_(round, this.state_);
+    }
+
+    this.subBytes_(goog.crypt.Aes.INV_SBOX_);
+    if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+      this.testAfterSubBytes_(round, this.state_);
+    }
+
+    this.addRoundKey_(this.numberOfRounds_ - round);
+    if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+      this.testAfterAddRoundKey_(round, this.state_);
+    }
+
+    this.invMixColumns_();
+  }
+
+  this.invShiftRows_();
+  if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+    this.testAfterShiftRows_(round, this.state_);
+  }
+
+  this.subBytes_(goog.crypt.Aes.INV_SBOX_);
+  if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+    this.testAfterSubBytes_(this.numberOfRounds_, this.state_);
+  }
+
+  if (goog.crypt.Aes.ENABLE_TEST_MODE) {
+    this.testKeySchedule_(this.numberOfRounds_, this.keySchedule_, 0);
+  }
+
+  this.addRoundKey_(0);
+
+  return this.generateOutput_();
+};
+
+
+/**
+ * Block size, in words.  Fixed at 4 per AES spec.
+ * @type {number}
+ * @private
+ */
+goog.crypt.Aes.BLOCK_SIZE_ = 4;
+
+
+/**
+ * Asserts that the key's array of integers is in the correct format.
+ * @param {!Array<number>} arr AES key as array of integers.
+ * @private
+ */
+goog.crypt.Aes.assertKeyArray_ = function(arr) {
+  if (goog.asserts.ENABLE_ASSERTS) {
+    goog.asserts.assert(arr.length == 16 || arr.length == 24 ||
+                        arr.length == 32,
+                        'Key must have length 16, 24, or 32.');
+    for (var i = 0; i < arr.length; i++) {
+      goog.asserts.assertNumber(arr[i]);
+      goog.asserts.assert(arr[i] >= 0 && arr[i] <= 255);
+    }
+  }
+};
+
+
+/**
+ * Tests can populate this with a callback, and that callback will get called
+ * at the start of each round *in both functions encrypt() and decrypt()*.
+ * @param {number} roundNum Round number.
+ * @param {!Array<Array<number>>} Current state.
+ * @private
+ */
+goog.crypt.Aes.prototype.testStartRound_ = goog.nullFunction;
+
+
+/**
+ * Tests can populate this with a callback, and that callback will get called
+ * each round right after the SubBytes step gets executed *in both functions
+ * encrypt() and decrypt()*.
+ * @param {number} roundNum Round number.
+ * @param {!Array<Array<number>>} Current state.
+ * @private
+ */
+goog.crypt.Aes.prototype.testAfterSubBytes_ = goog.nullFunction;
+
+
+/**
+ * Tests can populate this with a callback, and that callback will get called
+ * each round right after the ShiftRows step gets executed *in both functions
+ * encrypt() and decrypt()*.
+ * @param {number} roundNum Round number.
+ * @param {!Array<Array<number>>} Current state.
+ * @private
+ */
+goog.crypt.Aes.prototype.testAfterShiftRows_ = goog.nullFunction;
+
+
+/**
+ * Tests can populate this with a callback, and that callback will get called
+ * each round right after the MixColumns step gets executed *but only in the
+ * decrypt() function*.
+ * @param {number} roundNum Round number.
+ * @param {!Array<Array<number>>} Current state.
+ * @private
+ */
+goog.crypt.Aes.prototype.testAfterMixColumns_ = goog.nullFunction;
+
+
+/**
+ * Tests can populate this with a callback, and that callback will get called
+ * each round right after the AddRoundKey step gets executed  encrypt().
+ * @param {number} roundNum Round number.
+ * @param {!Array<Array<number>>} Current state.
+ * @private
+ */
+goog.crypt.Aes.prototype.testAfterAddRoundKey_ = goog.nullFunction;
+
+
+/**
+ * Tests can populate this with a callback, and that callback will get called
+ * before each round on the round key.  *Gets called in both the encrypt() and
+ * decrypt() functions.*
+ * @param {number} roundNum Round number.
+ * @param {Array<!Array<number>>} Computed key schedule.
+ * @param {number} index The index into the key schedule to test. This is not
+ *     necessarily roundNum because the key schedule is used in reverse
+ *     in the case of decryption.
+ * @private
+ */
+goog.crypt.Aes.prototype.testKeySchedule_ = goog.nullFunction;
+
+
+/**
+ * Helper to copy input into the AES state matrix.
+ * @param {!Array<number>} input Byte array to copy into the state matrix.
+ * @private
+ */
+goog.crypt.Aes.prototype.copyInput_ = function(input) {
+  var v, p;
+
+  goog.asserts.assert(input.length == goog.crypt.Aes.BLOCK_SIZE_ * 4,
+                      'Expecting input of 4 times block size.');
+
+  for (var r = 0; r < goog.crypt.Aes.BLOCK_SIZE_; r++) {
+    for (var c = 0; c < 4; c++) {
+      p = c * 4 + r;
+      v = input[p];
+
+      goog.asserts.assert(
+          v <= 255 && v >= 0,
+          'Invalid input. Value %s at position %s is not a byte.', v, p);
+
+      this.state_[r][c] = v;
+    }
+  }
+};
+
+
+/**
+ * Helper to copy the state matrix into an output array.
+ * @return {!Array<number>} Output byte array.
+ * @private
+ */
+goog.crypt.Aes.prototype.generateOutput_ = function() {
+  var output = [];
+  for (var r = 0; r < goog.crypt.Aes.BLOCK_SIZE_; r++) {
+    for (var c = 0; c < 4; c++) {
+      output[c * 4 + r] = this.state_[r][c];
+    }
+  }
+  return output;
+};
+
+
+/**
+ * AES's AddRoundKey procedure. Add the current round key to the state.
+ * @param {number} round The current round.
+ * @private
+ */
+goog.crypt.Aes.prototype.addRoundKey_ = function(round) {
+  for (var r = 0; r < 4; r++) {
+    for (var c = 0; c < 4; c++) {
+      this.state_[r][c] ^= this.keySchedule_[round * 4 + c][r];
+    }
+  }
+};
+
+
+/**
+ * AES's SubBytes procedure. Substitute bytes from the precomputed SBox lookup
+ * into the state.
+ * @param {!Array<number>} box The SBox or invSBox.
+ * @private
+ */
+goog.crypt.Aes.prototype.subBytes_ = function(box) {
+  for (var r = 0; r < 4; r++) {
+    for (var c = 0; c < 4; c++) {
+      this.state_[r][c] = box[this.state_[r][c]];
+    }
+  }
+};
+
+
+/**
+ * AES's ShiftRows procedure. Shift the values in each row to the right. Each
+ * row is shifted one more slot than the one above it.
+ * @private
+ */
+goog.crypt.Aes.prototype.shiftRows_ = function() {
+  for (var r = 1; r < 4; r++) {
+    for (var c = 0; c < 4; c++) {
+      this.temp_[r][c] = this.state_[r][c];
+    }
+  }
+
+  for (var r = 1; r < 4; r++) {
+    for (var c = 0; c < 4; c++) {
+      this.state_[r][c] = this.temp_[r][(c + r) %
+          goog.crypt.Aes.BLOCK_SIZE_];
+    }
+  }
+};
+
+
+/**
+ * AES's InvShiftRows procedure. Shift the values in each row to the right.
+ * @private
+ */
+goog.crypt.Aes.prototype.invShiftRows_ = function() {
+  for (var r = 1; r < 4; r++) {
+    for (var c = 0; c < 4; c++) {
+      this.temp_[r][(c + r) % goog.crypt.Aes.BLOCK_SIZE_] =
+          this.state_[r][c];
+    }
+  }
+
+  for (var r = 1; r < 4; r++) {
+    for (var c = 0; c < 4; c++) {
+      this.state_[r][c] = this.temp_[r][c];
+    }
+  }
+};
+
+
+/**
+ * AES's MixColumns procedure. Mix the columns of the state using magic.
+ * @private
+ */
+goog.crypt.Aes.prototype.mixColumns_ = function() {
+  var s = this.state_;
+  var t = this.temp_[0];
+
+  for (var c = 0; c < 4; c++) {
+    t[0] = s[0][c];
+    t[1] = s[1][c];
+    t[2] = s[2][c];
+    t[3] = s[3][c];
+
+    s[0][c] = (goog.crypt.Aes.MULT_2_[t[0]] ^
+               goog.crypt.Aes.MULT_3_[t[1]] ^ t[2] ^ t[3]);
+    s[1][c] = (t[0] ^ goog.crypt.Aes.MULT_2_[t[1]] ^
+               goog.crypt.Aes.MULT_3_[t[2]] ^ t[3]);
+    s[2][c] = (t[0] ^ t[1] ^ goog.crypt.Aes.MULT_2_[t[2]] ^
+               goog.crypt.Aes.MULT_3_[t[3]]);
+    s[3][c] = (goog.crypt.Aes.MULT_3_[t[0]] ^ t[1] ^ t[2] ^
+               goog.crypt.Aes.MULT_2_[t[3]]);
+  }
+};
+
+
+/**
+ * AES's InvMixColumns procedure.
+ * @private
+ */
+goog.crypt.Aes.prototype.invMixColumns_ = function() {
+  var s = this.state_;
+  var t = this.temp_[0];
+
+  for (var c = 0; c < 4; c++) {
+    t[0] = s[0][c];
+    t[1] = s[1][c];
+    t[2] = s[2][c];
+    t[3] = s[3][c];
+
+    s[0][c] = (
+        goog.crypt.Aes.MULT_E_[t[0]] ^ goog.crypt.Aes.MULT_B_[t[1]] ^
+        goog.crypt.Aes.MULT_D_[t[2]] ^ goog.crypt.Aes.MULT_9_[t[3]]);
+
+    s[1][c] = (
+        goog.crypt.Aes.MULT_9_[t[0]] ^ goog.crypt.Aes.MULT_E_[t[1]] ^
+        goog.crypt.Aes.MULT_B_[t[2]] ^ goog.crypt.Aes.MULT_D_[t[3]]);
+
+    s[2][c] = (
+        goog.crypt.Aes.MULT_D_[t[0]] ^ goog.crypt.Aes.MULT_9_[t[1]] ^
+        goog.crypt.Aes.MULT_E_[t[2]] ^ goog.crypt.Aes.MULT_B_[t[3]]);
+
+    s[3][c] = (
+        goog.crypt.Aes.MULT_B_[t[0]] ^ goog.crypt.Aes.MULT_D_[t[1]] ^
+        goog.crypt.Aes.MULT_9_[t[2]] ^ goog.crypt.Aes.MULT_E_[t[3]]);
+  }
+};
+
+
+/**
+ * AES's KeyExpansion procedure. Create the key schedule from the initial key.
+ * @private
+ */
+goog.crypt.Aes.prototype.keyExpansion_ = function() {
+  this.keySchedule_ = new Array(goog.crypt.Aes.BLOCK_SIZE_ * (
+      this.numberOfRounds_ + 1));
+
+  for (var rowNum = 0; rowNum < this.keyLength_; rowNum++) {
+    this.keySchedule_[rowNum] = [
+      this.key_[4 * rowNum],
+      this.key_[4 * rowNum + 1],
+      this.key_[4 * rowNum + 2],
+      this.key_[4 * rowNum + 3]
+    ];
+  }
+
+  var temp = new Array(4);
+
+  for (var rowNum = this.keyLength_;
+       rowNum < (goog.crypt.Aes.BLOCK_SIZE_ * (this.numberOfRounds_ + 1));
+       rowNum++) {
+    temp[0] = this.keySchedule_[rowNum - 1][0];
+    temp[1] = this.keySchedule_[rowNum - 1][1];
+    temp[2] = this.keySchedule_[rowNum - 1][2];
+    temp[3] = this.keySchedule_[rowNum - 1][3];
+
+    if (rowNum % this.keyLength_ == 0) {
+      this.rotWord_(temp);
+      this.subWord_(temp);
+
+      temp[0] ^= goog.crypt.Aes.RCON_[rowNum / this.keyLength_][0];
+      temp[1] ^= goog.crypt.Aes.RCON_[rowNum / this.keyLength_][1];
+      temp[2] ^= goog.crypt.Aes.RCON_[rowNum / this.keyLength_][2];
+      temp[3] ^= goog.crypt.Aes.RCON_[rowNum / this.keyLength_][3];
+    } else if (this.keyLength_ > 6 && rowNum % this.keyLength_ == 4) {
+      this.subWord_(temp);
+    }
+
+    this.keySchedule_[rowNum] = new Array(4);
+    this.keySchedule_[rowNum][0] =
+        this.keySchedule_[rowNum - this.keyLength_][0] ^ temp[0];
+    this.keySchedule_[rowNum][1] =
+        this.keySchedule_[rowNum - this.keyLength_][1] ^ temp[1];
+    this.keySchedule_[rowNum][2] =
+        this.keySchedule_[rowNum - this.keyLength_][2] ^ temp[2];
+    this.keySchedule_[rowNum][3] =
+        this.keySchedule_[rowNum - this.keyLength_][3] ^ temp[3];
+  }
+};
+
+
+/**
+ * AES's SubWord procedure.
+ * @param {!Array<number>} w Bytes to find the SBox substitution for.
+ * @return {!Array<number>} The substituted bytes.
+ * @private
+ */
+goog.crypt.Aes.prototype.subWord_ = function(w) {
+  w[0] = goog.crypt.Aes.SBOX_[w[0]];
+  w[1] = goog.crypt.Aes.SBOX_[w[1]];
+  w[2] = goog.crypt.Aes.SBOX_[w[2]];
+  w[3] = goog.crypt.Aes.SBOX_[w[3]];
+
+  return w;
+};
+
+
+/**
+ * AES's RotWord procedure.
+ * @param {!Array<number>} w Array of bytes to rotate.
+ * @return {!Array<number>} The rotated bytes.
+ * @private
+ */
+goog.crypt.Aes.prototype.rotWord_ = function(w) {
+  var temp = w[0];
+
+  w[0] = w[1];
+  w[1] = w[2];
+  w[2] = w[3];
+  w[3] = temp;
+
+  return w;
+};
+
+
+/**
+ * Precomputed SBox lookup.
+ * @type {!Array<number>}
+ * @private
+ */
+goog.crypt.Aes.SBOX_ = [
+  0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe,
+  0xd7, 0xab, 0x76,
+
+  0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c,
+  0xa4, 0x72, 0xc0,
+
+  0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71,
+  0xd8, 0x31, 0x15,
+
+  0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb,
+  0x27, 0xb2, 0x75,
+
+  0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29,
+  0xe3, 0x2f, 0x84,
+
+  0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a,
+  0x4c, 0x58, 0xcf,
+
+  0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50,
+  0x3c, 0x9f, 0xa8,
+
+  0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10,
+  0xff, 0xf3, 0xd2,
+
+  0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64,
+  0x5d, 0x19, 0x73,
+
+  0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde,
+  0x5e, 0x0b, 0xdb,
+
+  0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91,
+  0x95, 0xe4, 0x79,
+
+  0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65,
+  0x7a, 0xae, 0x08,
+
+  0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b,
+  0xbd, 0x8b, 0x8a,
+
+  0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86,
+  0xc1, 0x1d, 0x9e,
+
+  0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce,
+  0x55, 0x28, 0xdf,
+
+  0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0,
+  0x54, 0xbb, 0x16
+];
+
+
+/**
+ * Precomputed InvSBox lookup.
+ * @type {!Array<number>}
+ * @private
+ */
+goog.crypt.Aes.INV_SBOX_ = [
+  0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81,
+  0xf3, 0xd7, 0xfb,
+
+  0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4,
+  0xde, 0xe9, 0xcb,
+
+  0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42,
+  0xfa, 0xc3, 0x4e,
+
+  0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d,
+  0x8b, 0xd1, 0x25,
+
+  0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d,
+  0x65, 0xb6, 0x92,
+
+  0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7,
+  0x8d, 0x9d, 0x84,
+
+  0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8,
+  0xb3, 0x45, 0x06,
+
+  0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01,
+  0x13, 0x8a, 0x6b,
+
+  0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0,
+  0xb4, 0xe6, 0x73,
+
+  0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c,
+  0x75, 0xdf, 0x6e,
+
+  0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa,
+  0x18, 0xbe, 0x1b,
+
+  0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78,
+  0xcd, 0x5a, 0xf4,
+
+  0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27,
+  0x80, 0xec, 0x5f,
+
+  0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93,
+  0xc9, 0x9c, 0xef,
+
+  0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83,
+  0x53, 0x99, 0x61,
+
+  0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55,
+  0x21, 0x0c, 0x7d
+];
+
+
+/**
+ * Precomputed RCon lookup.
+ * @type {!Array<number>}
+ * @private
+ */
+goog.crypt.Aes.RCON_ = [
+  [0x00, 0x00, 0x00, 0x00],
+  [0x01, 0x00, 0x00, 0x00],
+  [0x02, 0x00, 0x00, 0x00],
+  [0x04, 0x00, 0x00, 0x00],
+  [0x08, 0x00, 0x00, 0x00],
+  [0x10, 0x00, 0x00, 0x00],
+  [0x20, 0x00, 0x00, 0x00],
+  [0x40, 0x00, 0x00, 0x00],
+  [0x80, 0x00, 0x00, 0x00],
+  [0x1b, 0x00, 0x00, 0x00],
+  [0x36, 0x00, 0x00, 0x00]
+];
+
+
+/**
+ * Precomputed lookup of multiplication by 2 in GF(2^8)
+ * @type {!Array<number>}
+ * @private
+ */
+goog.crypt.Aes.MULT_2_ = [
+  0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16,
+  0x18, 0x1A, 0x1C, 0x1E,
+
+  0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E, 0x30, 0x32, 0x34, 0x36,
+  0x38, 0x3A, 0x3C, 0x3E,
+
+  0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E, 0x50, 0x52, 0x54, 0x56,
+  0x58, 0x5A, 0x5C, 0x5E,
+
+  0x60, 0x62, 0x64, 0x66, 0x68, 0x6A, 0x6C, 0x6E, 0x70, 0x72, 0x74, 0x76,
+  0x78, 0x7A, 0x7C, 0x7E,
+
+  0x80, 0x82, 0x84, 0x86, 0x88, 0x8A, 0x8C, 0x8E, 0x90, 0x92, 0x94, 0x96,
+  0x98, 0x9A, 0x9C, 0x9E,
+
+  0xA0, 0xA2, 0xA4, 0xA6, 0xA8, 0xAA, 0xAC, 0xAE, 0xB0, 0xB2, 0xB4, 0xB6,
+  0xB8, 0xBA, 0xBC, 0xBE,
+
+  0xC0, 0xC2, 0xC4, 0xC6, 0xC8, 0xCA, 0xCC, 0xCE, 0xD0, 0xD2, 0xD4, 0xD6,
+  0xD8, 0xDA, 0xDC, 0xDE,
+
+  0xE0, 0xE2, 0xE4, 0xE6, 0xE8, 0xEA, 0xEC, 0xEE, 0xF0, 0xF2, 0xF4, 0xF6,
+  0xF8, 0xFA, 0xFC, 0xFE,
+
+  0x1B, 0x19, 0x1F, 0x1D, 0x13, 0x11, 0x17, 0x15, 0x0B, 0x09, 0x0F, 0x0D,
+  0x03, 0x01, 0x07, 0x05,
+
+  0x3B, 0x39, 0x3F, 0x3D, 0x33, 0x31, 0x37, 0x35, 0x2B, 0x29, 0x2F, 0x2D,
+  0x23, 0x21, 0x27, 0x25,
+
+  0x5B, 0x59, 0x5F, 0x5D, 0x53, 0x51, 0x57, 0x55, 0x4B, 0x49, 0x4F, 0x4D,
+  0x43, 0x41, 0x47, 0x45,
+
+  0x7B, 0x79, 0x7F, 0x7D, 0x73, 0x71, 0x77, 0x75, 0x6B, 0x69, 0x6F, 0x6D,
+  0x63, 0x61, 0x67, 0x65,
+
+  0x9B, 0x99, 0x9F, 0x9D, 0x93, 0x91, 0x97, 0x95, 0x8B, 0x89, 0x8F, 0x8D,
+  0x83, 0x81, 0x87, 0x85,
+
+  0xBB, 0xB9, 0xBF, 0xBD, 0xB3, 0xB1, 0xB7, 0xB5, 0xAB, 0xA9, 0xAF, 0xAD,
+  0xA3, 0xA1, 0xA7, 0xA5,
+
+  0xDB, 0xD9, 0xDF, 0xDD, 0xD3, 0xD1, 0xD7, 0xD5, 0xCB, 0xC9, 0xCF, 0xCD,
+  0xC3, 0xC1, 0xC7, 0xC5,
+
+  0xFB, 0xF9, 0xFF, 0xFD, 0xF3, 0xF1, 0xF7, 0xF5, 0xEB, 0xE9, 0xEF, 0xED,
+  0xE3, 0xE1, 0xE7, 0xE5
+];
+
+
+/**
+ * Precomputed lookup of multiplication by 3 in GF(2^8)
+ * @type {!Array<number>}
+ * @private
+ */
+goog.crypt.Aes.MULT_3_ = [
+  0x00, 0x03, 0x06, 0x05, 0x0C, 0x0F, 0x0A, 0x09, 0x18, 0x1B, 0x1E, 0x1D,
+  0x14, 0x17, 0x12, 0x11,
+
+  0x30, 0x33, 0x36, 0x35, 0x3C, 0x3F, 0x3A, 0x39, 0x28, 0x2B, 0x2E, 0x2D,
+  0x24, 0x27, 0x22, 0x21,
+
+  0x60, 0x63, 0x66, 0x65, 0x6C, 0x6F, 0x6A, 0x69, 0x78, 0x7B, 0x7E, 0x7D,
+  0x74, 0x77, 0x72, 0x71,
+
+  0x50, 0x53, 0x56, 0x55, 0x5C, 0x5F, 0x5A, 0x59, 0x48, 0x4B, 0x4E, 0x4D,
+  0x44, 0x47, 0x42, 0x41,
+
+  0xC0, 0xC3, 0xC6, 0xC5, 0xCC, 0xCF, 0xCA, 0xC9, 0xD8, 0xDB, 0xDE, 0xDD,
+  0xD4, 0xD7, 0xD2, 0xD1,
+
+  0xF0, 0xF3, 0xF6, 0xF5, 0xFC, 0xFF, 0xFA, 0xF9, 0xE8, 0xEB, 0xEE, 0xED,
+  0xE4, 0xE7, 0xE2, 0xE1,
+
+  0xA0, 0xA3, 0xA6, 0xA5, 0xAC, 0xAF, 0xAA, 0xA9, 0xB8, 0xBB, 0xBE, 0xBD,
+  0xB4, 0xB7, 0xB2, 0xB1,
+
+  0x90, 0x93, 0x96, 0x95, 0x9C, 0x9F, 0x9A, 0x99, 0x88, 0x8B, 0x8E, 0x8D,
+  0x84, 0x87, 0x82, 0x81,
+
+  0x9B, 0x98, 0x9D, 0x9E, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86,
+  0x8F, 0x8C, 0x89, 0x8A,
+
+  0xAB, 0xA8, 0xAD, 0xAE, 0xA7, 0xA4, 0xA1, 0xA2, 0xB3, 0xB0, 0xB5, 0xB6,
+  0xBF, 0xBC, 0xB9, 0xBA,
+
+  0xFB, 0xF8, 0xFD, 0xFE, 0xF7, 0xF4, 0xF1, 0xF2, 0xE3, 0xE0, 0xE5, 0xE6,
+  0xEF, 0xEC, 0xE9, 0xEA,
+
+  0xCB, 0xC8, 0xCD, 0xCE, 0xC7, 0xC4, 0xC1, 0xC2, 0xD3, 0xD0, 0xD5, 0xD6,
+  0xDF, 0xDC, 0xD9, 0xDA,
+
+  0x5B, 0x58, 0x5D, 0x5E, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46,
+  0x4F, 0x4C, 0x49, 0x4A,
+
+  0x6B, 0x68, 0x6D, 0x6E, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76,
+  0x7F, 0x7C, 0x79, 0x7A,
+
+  0x3B, 0x38, 0x3D, 0x3E, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26,
+  0x2F, 0x2C, 0x29, 0x2A,
+
+  0x0B, 0x08, 0x0D, 0x0E, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16,
+  0x1F, 0x1C, 0x19, 0x1A
+];
+
+
+/**
+ * Precomputed lookup of multiplication by 9 in GF(2^8)
+ * @type {!Array<number>}
+ * @private
+ */
+goog.crypt.Aes.MULT_9_ = [
+  0x00, 0x09, 0x12, 0x1B, 0x24, 0x2D, 0x36, 0x3F, 0x48, 0x41, 0x5A, 0x53,
+  0x6C, 0x65, 0x7E, 0x77,
+
+  0x90, 0x99, 0x82, 0x8B, 0xB4, 0xBD, 0xA6, 0xAF, 0xD8, 0xD1, 0xCA, 0xC3,
+  0xFC, 0xF5, 0xEE, 0xE7,
+
+  0x3B, 0x32, 0x29, 0x20, 0x1F, 0x16, 0x0D, 0x04, 0x73, 0x7A, 0x61, 0x68,
+  0x57, 0x5E, 0x45, 0x4C,
+
+  0xAB, 0xA2, 0xB9, 0xB0, 0x8F, 0x86, 0x9D, 0x94, 0xE3, 0xEA, 0xF1, 0xF8,
+  0xC7, 0xCE, 0xD5, 0xDC,
+
+  0x76, 0x7F, 0x64, 0x6D, 0x52, 0x5B, 0x40, 0x49, 0x3E, 0x37, 0x2C, 0x25,
+  0x1A, 0x13, 0x08, 0x01,
+
+  0xE6, 0xEF, 0xF4, 0xFD, 0xC2, 0xCB, 0xD0, 0xD9, 0xAE, 0xA7, 0xBC, 0xB5,
+  0x8A, 0x83, 0x98, 0x91,
+
+  0x4D, 0x44, 0x5F, 0x56, 0x69, 0x60, 0x7B, 0x72, 0x05, 0x0C, 0x17, 0x1E,
+  0x21, 0x28, 0x33, 0x3A,
+
+  0xDD, 0xD4, 0xCF, 0xC6, 0xF9, 0xF0, 0xEB, 0xE2, 0x95, 0x9C, 0x87, 0x8E,
+  0xB1, 0xB8, 0xA3, 0xAA,
+
+  0xEC, 0xE5, 0xFE, 0xF7, 0xC8, 0xC1, 0xDA, 0xD3, 0xA4, 0xAD, 0xB6, 0xBF,
+  0x80, 0x89, 0x92, 0x9B,
+
+  0x7C, 0x75, 0x6E, 0x67, 0x58, 0x51, 0x4A, 0x43, 0x34, 0x3D, 0x26, 0x2F,
+  0x10, 0x19, 0x02, 0x0B,
+
+  0xD7, 0xDE, 0xC5, 0xCC, 0xF3, 0xFA, 0xE1, 0xE8, 0x9F, 0x96, 0x8D, 0x84,
+  0xBB, 0xB2, 0xA9, 0xA0,
+
+  0x47, 0x4E, 0x55, 0x5C, 0x63, 0x6A, 0x71, 0x78, 0x0F, 0x06, 0x1D, 0x14,
+  0x2B, 0x22, 0x39, 0x30,
+
+  0x9A, 0x93, 0x88, 0x81, 0xBE, 0xB7, 0xAC, 0xA5, 0xD2, 0xDB, 0xC0, 0xC9,
+  0xF6, 0xFF, 0xE4, 0xED,
+
+  0x0A, 0x03, 0x18, 0x11, 0x2E, 0x27, 0x3C, 0x35, 0x42, 0x4B, 0x50, 0x59,
+  0x66, 0x6F, 0x74, 0x7D,
+
+  0xA1, 0xA8, 0xB3, 0xBA, 0x85, 0x8C, 0x97, 0x9E, 0xE9, 0xE0, 0xFB, 0xF2,
+  0xCD, 0xC4, 0xDF, 0xD6,
+
+  0x31, 0x38, 0x23, 0x2A, 0x15, 0x1C, 0x07, 0x0E, 0x79, 0x70, 0x6B, 0x62,
+  0x5D, 0x54, 0x4F, 0x46
+];
+
+
+/**
+ * Precomputed lookup of multiplication by 11 in GF(2^8)
+ * @type {!Array<number>}
+ * @private
+ */
+goog.crypt.Aes.MULT_B_ = [
+  0x00, 0x0B, 0x16, 0x1D, 0x2C, 0x27, 0x3A, 0x31, 0x58, 0x53, 0x4E, 0x45,
+  0x74, 0x7F, 0x62, 0x69,
+
+  0xB0, 0xBB, 0xA6, 0xAD, 0x9C, 0x97, 0x8A, 0x81, 0xE8, 0xE3, 0xFE, 0xF5,
+  0xC4, 0xCF, 0xD2, 0xD9,
+
+  0x7B, 0x70, 0x6D, 0x66, 0x57, 0x5C, 0x41, 0x4A, 0x23, 0x28, 0x35, 0x3E,
+  0x0F, 0x04, 0x19, 0x12,
+
+  0xCB, 0xC0, 0xDD, 0xD6, 0xE7, 0xEC, 0xF1, 0xFA, 0x93, 0x98, 0x85, 0x8E,
+  0xBF, 0xB4, 0xA9, 0xA2,
+
+  0xF6, 0xFD, 0xE0, 0xEB, 0xDA, 0xD1, 0xCC, 0xC7, 0xAE, 0xA5, 0xB8, 0xB3,
+  0x82, 0x89, 0x94, 0x9F,
+
+  0x46, 0x4D, 0x50, 0x5B, 0x6A, 0x61, 0x7C, 0x77, 0x1E, 0x15, 0x08, 0x03,
+  0x32, 0x39, 0x24, 0x2F,
+
+  0x8D, 0x86, 0x9B, 0x90, 0xA1, 0xAA, 0xB7, 0xBC, 0xD5, 0xDE, 0xC3, 0xC8,
+  0xF9, 0xF2, 0xEF, 0xE4,
+
+  0x3D, 0x36, 0x2B, 0x20, 0x11, 0x1A, 0x07, 0x0C, 0x65, 0x6E, 0x73, 0x78,
+  0x49, 0x42, 0x5F, 0x54,
+
+  0xF7, 0xFC, 0xE1, 0xEA, 0xDB, 0xD0, 0xCD, 0xC6, 0xAF, 0xA4, 0xB9, 0xB2,
+  0x83, 0x88, 0x95, 0x9E,
+
+  0x47, 0x4C, 0x51, 0x5A, 0x6B, 0x60, 0x7D, 0x76, 0x1F, 0x14, 0x09, 0x02,
+  0x33, 0x38, 0x25, 0x2E,
+
+  0x8C, 0x87, 0x9A, 0x91, 0xA0, 0xAB, 0xB6, 0xBD, 0xD4, 0xDF, 0xC2, 0xC9,
+  0xF8, 0xF3, 0xEE, 0xE5,
+
+  0x3C, 0x37, 0x2A, 0x21, 0x10, 0x1B, 0x06, 0x0D, 0x64, 0x6F, 0x72, 0x79,
+  0x48, 0x43, 0x5E, 0x55,
+
+  0x01, 0x0A, 0x17, 0x1C, 0x2D, 0x26, 0x3B, 0x30, 0x59, 0x52, 0x4F, 0x44,
+  0x75, 0x7E, 0x63, 0x68,
+
+  0xB1, 0xBA, 0xA7, 0xAC, 0x9D, 0x96, 0x8B, 0x80, 0xE9, 0xE2, 0xFF, 0xF4,
+  0xC5, 0xCE, 0xD3, 0xD8,
+
+  0x7A, 0x71, 0x6C, 0x67, 0x56, 0x5D, 0x40, 0x4B, 0x22, 0x29, 0x34, 0x3F,
+  0x0E, 0x05, 0x18, 0x13,
+
+  0xCA, 0xC1, 0xDC, 0xD7, 0xE6, 0xED, 0xF0, 0xFB, 0x92, 0x99, 0x84, 0x8F,
+  0xBE, 0xB5, 0xA8, 0xA3
+];
+
+
+/**
+ * Precomputed lookup of multiplication by 13 in GF(2^8)
+ * @type {!Array<number>}
+ * @private
+ */
+goog.crypt.Aes.MULT_D_ = [
+  0x00, 0x0D, 0x1A, 0x17, 0x34, 0x39, 0x2E, 0x23, 0x68, 0x65, 0x72, 0x7F,
+  0x5C, 0x51, 0x46, 0x4B,
+
+  0xD0, 0xDD, 0xCA, 0xC7, 0xE4, 0xE9, 0xFE, 0xF3, 0xB8, 0xB5, 0xA2, 0xAF,
+  0x8C, 0x81, 0x96, 0x9B,
+
+  0xBB, 0xB6, 0xA1, 0xAC, 0x8F, 0x82, 0x95, 0x98, 0xD3, 0xDE, 0xC9, 0xC4,
+  0xE7, 0xEA, 0xFD, 0xF0,
+
+  0x6B, 0x66, 0x71, 0x7C, 0x5F, 0x52, 0x45, 0x48, 0x03, 0x0E, 0x19, 0x14,
+  0x37, 0x3A, 0x2D, 0x20,
+
+  0x6D, 0x60, 0x77, 0x7A, 0x59, 0x54, 0x43, 0x4E, 0x05, 0x08, 0x1F, 0x12,
+  0x31, 0x3C, 0x2B, 0x26,
+
+  0xBD, 0xB0, 0xA7, 0xAA, 0x89, 0x84, 0x93, 0x9E, 0xD5, 0xD8, 0xCF, 0xC2,
+  0xE1, 0xEC, 0xFB, 0xF6,
+
+  0xD6, 0xDB, 0xCC, 0xC1, 0xE2, 0xEF, 0xF8, 0xF5, 0xBE, 0xB3, 0xA4, 0xA9,
+  0x8A, 0x87, 0x90, 0x9D,
+
+  0x06, 0x0B, 0x1C, 0x11, 0x32, 0x3F, 0x28, 0x25, 0x6E, 0x63, 0x74, 0x79,
+  0x5A, 0x57, 0x40, 0x4D,
+
+  0xDA, 0xD7, 0xC0, 0xCD, 0xEE, 0xE3, 0xF4, 0xF9, 0xB2, 0xBF, 0xA8, 0xA5,
+  0x86, 0x8B, 0x9C, 0x91,
+
+  0x0A, 0x07, 0x10, 0x1D, 0x3E, 0x33, 0x24, 0x29, 0x62, 0x6F, 0x78, 0x75,
+  0x56, 0x5B, 0x4C, 0x41,
+
+  0x61, 0x6C, 0x7B, 0x76, 0x55, 0x58, 0x4F, 0x42, 0x09, 0x04, 0x13, 0x1E,
+  0x3D, 0x30, 0x27, 0x2A,
+
+  0xB1, 0xBC, 0xAB, 0xA6, 0x85, 0x88, 0x9F, 0x92, 0xD9, 0xD4, 0xC3, 0xCE,
+  0xED, 0xE0, 0xF7, 0xFA,
+
+  0xB7, 0xBA, 0xAD, 0xA0, 0x83, 0x8E, 0x99, 0x94, 0xDF, 0xD2, 0xC5, 0xC8,
+  0xEB, 0xE6, 0xF1, 0xFC,
+
+  0x67, 0x6A, 0x7D, 0x70, 0x53, 0x5E, 0x49, 0x44, 0x0F, 0x02, 0x15, 0x18,
+  0x3B, 0x36, 0x21, 0x2C,
+
+  0x0C, 0x01, 0x16, 0x1B, 0x38, 0x35, 0x22, 0x2F, 0x64, 0x69, 0x7E, 0x73,
+  0x50, 0x5D, 0x4A, 0x47,
+
+  0xDC, 0xD1, 0xC6, 0xCB, 0xE8, 0xE5, 0xF2, 0xFF, 0xB4, 0xB9, 0xAE, 0xA3,
+  0x80, 0x8D, 0x9A, 0x97
+];
+
+
+/**
+ * Precomputed lookup of multiplication by 14 in GF(2^8)
+ * @type {!Array<number>}
+ * @private
+ */
+goog.crypt.Aes.MULT_E_ = [
+  0x00, 0x0E, 0x1C, 0x12, 0x38, 0x36, 0x24, 0x2A, 0x70, 0x7E, 0x6C, 0x62,
+  0x48, 0x46, 0x54, 0x5A,
+
+  0xE0, 0xEE, 0xFC, 0xF2, 0xD8, 0xD6, 0xC4, 0xCA, 0x90, 0x9E, 0x8C, 0x82,
+  0xA8, 0xA6, 0xB4, 0xBA,
+
+  0xDB, 0xD5, 0xC7, 0xC9, 0xE3, 0xED, 0xFF, 0xF1, 0xAB, 0xA5, 0xB7, 0xB9,
+  0x93, 0x9D, 0x8F, 0x81,
+
+  0x3B, 0x35, 0x27, 0x29, 0x03, 0x0D, 0x1F, 0x11, 0x4B, 0x45, 0x57, 0x59,
+  0x73, 0x7D, 0x6F, 0x61,
+
+  0xAD, 0xA3, 0xB1, 0xBF, 0x95, 0x9B, 0x89, 0x87, 0xDD, 0xD3, 0xC1, 0xCF,
+  0xE5, 0xEB, 0xF9, 0xF7,
+
+  0x4D, 0x43, 0x51, 0x5F, 0x75, 0x7B, 0x69, 0x67, 0x3D, 0x33, 0x21, 0x2F,
+  0x05, 0x0B, 0x19, 0x17,
+
+  0x76, 0x78, 0x6A, 0x64, 0x4E, 0x40, 0x52, 0x5C, 0x06, 0x08, 0x1A, 0x14,
+  0x3E, 0x30, 0x22, 0x2C,
+
+  0x96, 0x98, 0x8A, 0x84, 0xAE, 0xA0, 0xB2, 0xBC, 0xE6, 0xE8, 0xFA, 0xF4,
+  0xDE, 0xD0, 0xC2, 0xCC,
+
+  0x41, 0x4F, 0x5D, 0x53, 0x79, 0x77, 0x65, 0x6B, 0x31, 0x3F, 0x2D, 0x23,
+  0x09, 0x07, 0x15, 0x1B,
+
+  0xA1, 0xAF, 0xBD, 0xB3, 0x99, 0x97, 0x85, 0x8B, 0xD1, 0xDF, 0xCD, 0xC3,
+  0xE9, 0xE7, 0xF5, 0xFB,
+
+  0x9A, 0x94, 0x86, 0x88, 0xA2, 0xAC, 0xBE, 0xB0, 0xEA, 0xE4, 0xF6, 0xF8,
+  0xD2, 0xDC, 0xCE, 0xC0,
+
+  0x7A, 0x74, 0x66, 0x68, 0x42, 0x4C, 0x5E, 0x50, 0x0A, 0x04, 0x16, 0x18,
+  0x32, 0x3C, 0x2E, 0x20,
+
+  0xEC, 0xE2, 0xF0, 0xFE, 0xD4, 0xDA, 0xC8, 0xC6, 0x9C, 0x92, 0x80, 0x8E,
+  0xA4, 0xAA, 0xB8, 0xB6,
+
+  0x0C, 0x02, 0x10, 0x1E, 0x34, 0x3A, 0x28, 0x26, 0x7C, 0x72, 0x60, 0x6E,
+  0x44, 0x4A, 0x58, 0x56,
+
+  0x37, 0x39, 0x2B, 0x25, 0x0F, 0x01, 0x13, 0x1D, 0x47, 0x49, 0x5B, 0x55,
+  0x7F, 0x71, 0x63, 0x6D,
+
+  0xD7, 0xD9, 0xCB, 0xC5, 0xEF, 0xE1, 0xF3, 0xFD, 0xA7, 0xA9, 0xBB, 0xB5,
+  0x9F, 0x91, 0x83, 0x8D
+];

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/arc4.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/arc4.js b/externs/GCL/externs/goog/crypt/arc4.js
new file mode 100644
index 0000000..73c6758
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/arc4.js
@@ -0,0 +1,164 @@
+// Copyright 2005 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 ARC4 streamcipher implementation.  A description of the
+ * algorithm can be found at:
+ * http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt.
+ *
+ * Usage:
+ * <code>
+ *   var arc4 = new goog.crypt.Arc4();
+ *   arc4.setKey(key);
+ *   arc4.discard(1536);
+ *   arc4.crypt(bytes);
+ * </code>
+ *
+ * Note: For converting between strings and byte arrays, goog.crypt.base64 may
+ * be useful.
+ *
+ */
+
+goog.provide('goog.crypt.Arc4');
+
+goog.require('goog.asserts');
+
+
+
+/**
+ * ARC4 streamcipher implementation.
+ * @constructor
+ * @final
+ * @struct
+ */
+goog.crypt.Arc4 = function() {
+  /**
+   * A permutation of all 256 possible bytes.
+   * @type {Array<number>}
+   * @private
+   */
+  this.state_ = [];
+
+  /**
+   * 8 bit index pointer into this.state_.
+   * @type {number}
+   * @private
+   */
+  this.index1_ = 0;
+
+  /**
+   * 8 bit index pointer into this.state_.
+   * @type {number}
+   * @private
+   */
+  this.index2_ = 0;
+};
+
+
+/**
+ * Initialize the cipher for use with new key.
+ * @param {Array<number>} key A byte array containing the key.
+ * @param {number=} opt_length Indicates # of bytes to take from the key.
+ */
+goog.crypt.Arc4.prototype.setKey = function(key, opt_length) {
+  goog.asserts.assertArray(key, 'Key parameter must be a byte array');
+
+  if (!opt_length) {
+    opt_length = key.length;
+  }
+
+  var state = this.state_;
+
+  for (var i = 0; i < 256; ++i) {
+    state[i] = i;
+  }
+
+  var j = 0;
+  for (var i = 0; i < 256; ++i) {
+    j = (j + state[i] + key[i % opt_length]) & 255;
+
+    var tmp = state[i];
+    state[i] = state[j];
+    state[j] = tmp;
+  }
+
+  this.index1_ = 0;
+  this.index2_ = 0;
+};
+
+
+/**
+ * Discards n bytes of the keystream.
+ * These days 1536 is considered a decent amount to drop to get the key state
+ * warmed-up enough for secure usage. This is not done in the constructor to
+ * preserve efficiency for use cases that do not need this.
+ * NOTE: Discard is identical to crypt without actually xoring any data. It's
+ * unfortunate to have this code duplicated, but this was done for performance
+ * reasons. Alternatives which were attempted:
+ * 1. Create a temp array of the correct length and pass it to crypt. This
+ *    works but needlessly allocates an array. But more importantly this
+ *    requires choosing an array type (Array or Uint8Array) in discard, and
+ *    choosing a different type than will be passed to crypt by the client
+ *    code hurts the javascript engines ability to optimize crypt (7x hit in
+ *    v8).
+ * 2. Make data option in crypt so discard can pass null, this has a huge
+ *    perf hit for crypt.
+ * @param {number} length Number of bytes to disregard from the stream.
+ */
+goog.crypt.Arc4.prototype.discard = function(length) {
+  var i = this.index1_;
+  var j = this.index2_;
+  var state = this.state_;
+
+  for (var n = 0; n < length; ++n) {
+    i = (i + 1) & 255;
+    j = (j + state[i]) & 255;
+
+    var tmp = state[i];
+    state[i] = state[j];
+    state[j] = tmp;
+  }
+
+  this.index1_ = i;
+  this.index2_ = j;
+};
+
+
+/**
+ * En- or decrypt (same operation for streamciphers like ARC4)
+ * @param {Array<number>|Uint8Array} data The data to be xor-ed in place.
+ * @param {number=} opt_length The number of bytes to crypt.
+ */
+goog.crypt.Arc4.prototype.crypt = function(data, opt_length) {
+  if (!opt_length) {
+    opt_length = data.length;
+  }
+  var i = this.index1_;
+  var j = this.index2_;
+  var state = this.state_;
+
+  for (var n = 0; n < opt_length; ++n) {
+    i = (i + 1) & 255;
+    j = (j + state[i]) & 255;
+
+    var tmp = state[i];
+    state[i] = state[j];
+    state[j] = tmp;
+
+    data[n] ^= state[(state[i] + state[j]) & 255];
+  }
+
+  this.index1_ = i;
+  this.index2_ = j;
+};


[44/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/sha2.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/sha2.js b/externs/GCL/externs/goog/crypt/sha2.js
new file mode 100644
index 0000000..eae5b14
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/sha2.js
@@ -0,0 +1,338 @@
+// 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 Base class for SHA-2 cryptographic hash.
+ *
+ * Variable names follow the notation in FIPS PUB 180-3:
+ * http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf.
+ *
+ * Some code similar to SHA1 are borrowed from sha1.js written by mschilder@.
+ *
+ */
+
+goog.provide('goog.crypt.Sha2');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.crypt.Hash');
+
+
+
+/**
+ * SHA-2 cryptographic hash constructor.
+ * This constructor should not be used directly to create the object. Rather,
+ * one should use the constructor of the sub-classes.
+ * @param {number} numHashBlocks The size of output in 16-byte blocks.
+ * @param {!Array<number>} initHashBlocks The hash-specific initialization
+ * @constructor
+ * @extends {goog.crypt.Hash}
+ * @struct
+ */
+goog.crypt.Sha2 = function(numHashBlocks, initHashBlocks) {
+  goog.crypt.Sha2.base(this, 'constructor');
+
+  this.blockSize = goog.crypt.Sha2.BLOCKSIZE_;
+
+  /**
+   * A chunk holding the currently processed message bytes. Once the chunk has
+   * 64 bytes, we feed it into computeChunk_ function and reset this.chunk_.
+   * @private {!Array<number>|!Uint8Array}
+   */
+  this.chunk_ = goog.global['Uint8Array'] ?
+      new Uint8Array(this.blockSize) : new Array(this.blockSize);
+
+  /**
+   * Current number of bytes in this.chunk_.
+   * @private {number}
+   */
+  this.inChunk_ = 0;
+
+  /**
+   * Total number of bytes in currently processed message.
+   * @private {number}
+   */
+  this.total_ = 0;
+
+
+  /**
+   * Holds the previous values of accumulated hash a-h in the computeChunk_
+   * function.
+   * @private {!Array<number>|!Int32Array}
+   */
+  this.hash_ = [];
+
+  /**
+   * The number of output hash blocks (each block is 4 bytes long).
+   * @private {number}
+   */
+  this.numHashBlocks_ = numHashBlocks;
+
+  /**
+   * @private {!Array<number>} initHashBlocks
+   */
+  this.initHashBlocks_ = initHashBlocks;
+
+  /**
+   * Temporary array used in chunk computation.  Allocate here as a
+   * member rather than as a local within computeChunk_() as a
+   * performance optimization to reduce the number of allocations and
+   * reduce garbage collection.
+   * @private {!Int32Array|!Array<number>}
+   */
+  this.w_ = goog.global['Int32Array'] ? new Int32Array(64) : new Array(64);
+
+  if (!goog.isDef(goog.crypt.Sha2.Kx_)) {
+    // This is the first time this constructor has been called.
+    if (goog.global['Int32Array']) {
+      // Typed arrays exist
+      goog.crypt.Sha2.Kx_ = new Int32Array(goog.crypt.Sha2.K_);
+    } else {
+      // Typed arrays do not exist
+      goog.crypt.Sha2.Kx_ = goog.crypt.Sha2.K_;
+    }
+  }
+
+  this.reset();
+};
+goog.inherits(goog.crypt.Sha2, goog.crypt.Hash);
+
+
+/**
+ * The block size
+ * @private {number}
+ */
+goog.crypt.Sha2.BLOCKSIZE_ = 512 / 8;
+
+
+/**
+ * Contains data needed to pad messages less than BLOCK_SIZE_ bytes.
+ * @private {!Array<number>}
+ */
+goog.crypt.Sha2.PADDING_ = goog.array.concat(128,
+    goog.array.repeat(0, goog.crypt.Sha2.BLOCKSIZE_ - 1));
+
+
+/** @override */
+goog.crypt.Sha2.prototype.reset = function() {
+  this.inChunk_ = 0;
+  this.total_ = 0;
+  this.hash_ = goog.global['Int32Array'] ?
+      new Int32Array(this.initHashBlocks_) :
+      goog.array.clone(this.initHashBlocks_);
+};
+
+
+/**
+ * Helper function to compute the hashes for a given 512-bit message chunk.
+ * @private
+ */
+goog.crypt.Sha2.prototype.computeChunk_ = function() {
+  var chunk = this.chunk_;
+  goog.asserts.assert(chunk.length == this.blockSize);
+  var rounds = 64;
+
+  // Divide the chunk into 16 32-bit-words.
+  var w = this.w_;
+  var index = 0;
+  var offset = 0;
+  while (offset < chunk.length) {
+    w[index++] = (chunk[offset] << 24) |
+                 (chunk[offset + 1] << 16) |
+                 (chunk[offset + 2] << 8) |
+                 (chunk[offset + 3]);
+    offset = index * 4;
+  }
+
+  // Extend the w[] array to be the number of rounds.
+  for (var i = 16; i < rounds; i++) {
+    var w_15 = w[i - 15] | 0;
+    var s0 = ((w_15 >>> 7) | (w_15 << 25)) ^
+             ((w_15 >>> 18) | (w_15 << 14)) ^
+             (w_15 >>> 3);
+    var w_2 = w[i - 2] | 0;
+    var s1 = ((w_2 >>> 17) | (w_2 << 15)) ^
+             ((w_2 >>> 19) | (w_2 << 13)) ^
+             (w_2 >>> 10);
+
+    // As a performance optimization, construct the sum a pair at a time
+    // with casting to integer (bitwise OR) to eliminate unnecessary
+    // double<->integer conversions.
+    var partialSum1 = ((w[i - 16] | 0) + s0) | 0;
+    var partialSum2 = ((w[i - 7] | 0) + s1) | 0;
+    w[i] = (partialSum1 + partialSum2) | 0;
+  }
+
+  var a = this.hash_[0] | 0;
+  var b = this.hash_[1] | 0;
+  var c = this.hash_[2] | 0;
+  var d = this.hash_[3] | 0;
+  var e = this.hash_[4] | 0;
+  var f = this.hash_[5] | 0;
+  var g = this.hash_[6] | 0;
+  var h = this.hash_[7] | 0;
+  for (var i = 0; i < rounds; i++) {
+    var S0 = ((a >>> 2) | (a << 30)) ^
+             ((a >>> 13) | (a << 19)) ^
+             ((a >>> 22) | (a << 10));
+    var maj = ((a & b) ^ (a & c) ^ (b & c));
+    var t2 = (S0 + maj) | 0;
+    var S1 = ((e >>> 6) | (e << 26)) ^
+             ((e >>> 11) | (e << 21)) ^
+             ((e >>> 25) | (e << 7));
+    var ch = ((e & f) ^ ((~ e) & g));
+
+    // As a performance optimization, construct the sum a pair at a time
+    // with casting to integer (bitwise OR) to eliminate unnecessary
+    // double<->integer conversions.
+    var partialSum1 = (h + S1) | 0;
+    var partialSum2 = (ch + (goog.crypt.Sha2.Kx_[i] | 0)) | 0;
+    var partialSum3 = (partialSum2 + (w[i] | 0)) | 0;
+    var t1 = (partialSum1 + partialSum3) | 0;
+
+    h = g;
+    g = f;
+    f = e;
+    e = (d + t1) | 0;
+    d = c;
+    c = b;
+    b = a;
+    a = (t1 + t2) | 0;
+  }
+
+  this.hash_[0] = (this.hash_[0] + a) | 0;
+  this.hash_[1] = (this.hash_[1] + b) | 0;
+  this.hash_[2] = (this.hash_[2] + c) | 0;
+  this.hash_[3] = (this.hash_[3] + d) | 0;
+  this.hash_[4] = (this.hash_[4] + e) | 0;
+  this.hash_[5] = (this.hash_[5] + f) | 0;
+  this.hash_[6] = (this.hash_[6] + g) | 0;
+  this.hash_[7] = (this.hash_[7] + h) | 0;
+};
+
+
+/** @override */
+goog.crypt.Sha2.prototype.update = function(message, opt_length) {
+  if (!goog.isDef(opt_length)) {
+    opt_length = message.length;
+  }
+  // Process the message from left to right up to |opt_length| bytes.
+  // When we get a 512-bit chunk, compute the hash of it and reset
+  // this.chunk_. The message might not be multiple of 512 bits so we
+  // might end up with a chunk that is less than 512 bits. We store
+  // such partial chunk in this.chunk_ and it will be filled up later
+  // in digest().
+  var n = 0;
+  var inChunk = this.inChunk_;
+
+  // The input message could be either byte array of string.
+  if (goog.isString(message)) {
+    while (n < opt_length) {
+      this.chunk_[inChunk++] = message.charCodeAt(n++);
+      if (inChunk == this.blockSize) {
+        this.computeChunk_();
+        inChunk = 0;
+      }
+    }
+  } else if (goog.isArray(message)) {
+    while (n < opt_length) {
+      var b = message[n++];
+      if (!('number' == typeof b && 0 <= b && 255 >= b && b == (b | 0))) {
+        throw Error('message must be a byte array');
+      }
+      this.chunk_[inChunk++] = b;
+      if (inChunk == this.blockSize) {
+        this.computeChunk_();
+        inChunk = 0;
+      }
+    }
+  } else {
+    throw Error('message must be string or array');
+  }
+
+  // Record the current bytes in chunk to support partial update.
+  this.inChunk_ = inChunk;
+
+  // Record total message bytes we have processed so far.
+  this.total_ += opt_length;
+};
+
+
+/** @override */
+goog.crypt.Sha2.prototype.digest = function() {
+  var digest = [];
+  var totalBits = this.total_ * 8;
+
+  // Append pad 0x80 0x00*.
+  if (this.inChunk_ < 56) {
+    this.update(goog.crypt.Sha2.PADDING_, 56 - this.inChunk_);
+  } else {
+    this.update(goog.crypt.Sha2.PADDING_,
+        this.blockSize - (this.inChunk_ - 56));
+  }
+
+  // Append # bits in the 64-bit big-endian format.
+  for (var i = 63; i >= 56; i--) {
+    this.chunk_[i] = totalBits & 255;
+    totalBits /= 256; // Don't use bit-shifting here!
+  }
+  this.computeChunk_();
+
+  // Finally, output the result digest.
+  var n = 0;
+  for (var i = 0; i < this.numHashBlocks_; i++) {
+    for (var j = 24; j >= 0; j -= 8) {
+      digest[n++] = ((this.hash_[i] >> j) & 255);
+    }
+  }
+  return digest;
+};
+
+
+/**
+ * Constants used in SHA-2.
+ * @const
+ * @private {!Array<number>}
+ */
+goog.crypt.Sha2.K_ = [
+  0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+  0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+  0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+  0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+  0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+  0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+  0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+  0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+  0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+  0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+  0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+  0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+  0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+  0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+  0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+  0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+];
+
+
+/**
+ * Sha2.K as an Int32Array if this JS supports typed arrays; otherwise,
+ * the same array as Sha2.K.
+ *
+ * The compiler cannot remove an Int32Array, even if it is not needed
+ * (There are certain cases where creating an Int32Array is not
+ * side-effect free).  Instead, the first time we construct a Sha2
+ * instance, we convert or assign Sha2.K as appropriate.
+ * @private {undefined|!Array<number>|!Int32Array}
+ */
+goog.crypt.Sha2.Kx_;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/sha224.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/sha224.js b/externs/GCL/externs/goog/crypt/sha224.js
new file mode 100644
index 0000000..40c59e9
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/sha224.js
@@ -0,0 +1,50 @@
+// 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 SHA-224 cryptographic hash.
+ *
+ * Usage:
+ *   var sha224 = new goog.crypt.Sha224();
+ *   sha224.update(bytes);
+ *   var hash = sha224.digest();
+ *
+ */
+
+goog.provide('goog.crypt.Sha224');
+
+goog.require('goog.crypt.Sha2');
+
+
+
+/**
+ * SHA-224 cryptographic hash constructor.
+ *
+ * @constructor
+ * @extends {goog.crypt.Sha2}
+ * @final
+ * @struct
+ */
+goog.crypt.Sha224 = function() {
+  goog.crypt.Sha224.base(this, 'constructor',
+      7, goog.crypt.Sha224.INIT_HASH_BLOCK_);
+};
+goog.inherits(goog.crypt.Sha224, goog.crypt.Sha2);
+
+
+/** @private {!Array<number>} */
+goog.crypt.Sha224.INIT_HASH_BLOCK_ = [
+  0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+  0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4];
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/sha256.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/sha256.js b/externs/GCL/externs/goog/crypt/sha256.js
new file mode 100644
index 0000000..38dafb0
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/sha256.js
@@ -0,0 +1,49 @@
+// 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 SHA-256 cryptographic hash.
+ *
+ * Usage:
+ *   var sha256 = new goog.crypt.Sha256();
+ *   sha256.update(bytes);
+ *   var hash = sha256.digest();
+ *
+ */
+
+goog.provide('goog.crypt.Sha256');
+
+goog.require('goog.crypt.Sha2');
+
+
+
+/**
+ * SHA-256 cryptographic hash constructor.
+ *
+ * @constructor
+ * @extends {goog.crypt.Sha2}
+ * @final
+ * @struct
+ */
+goog.crypt.Sha256 = function() {
+  goog.crypt.Sha256.base(this, 'constructor',
+      8, goog.crypt.Sha256.INIT_HASH_BLOCK_);
+};
+goog.inherits(goog.crypt.Sha256, goog.crypt.Sha2);
+
+
+/** @private {!Array<number>} */
+goog.crypt.Sha256.INIT_HASH_BLOCK_ = [
+  0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+  0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19];

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/sha2_64bit.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/sha2_64bit.js b/externs/GCL/externs/goog/crypt/sha2_64bit.js
new file mode 100644
index 0000000..077b9c4
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/sha2_64bit.js
@@ -0,0 +1,550 @@
+// Copyright 2014 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 Base class for the 64-bit SHA-2 cryptographic hashes.
+ *
+ * Variable names follow the notation in FIPS PUB 180-3:
+ * http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf.
+ *
+ * This code borrows heavily from the 32-bit SHA2 implementation written by
+ * Yue Zhang (zysxqn@).
+ *
+ * @author fy@google.com (Frank Yellin)
+ */
+
+goog.provide('goog.crypt.Sha2_64bit');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.crypt.Hash');
+goog.require('goog.math.Long');
+
+
+
+/**
+ * Constructs a SHA-2 64-bit cryptographic hash.
+ * This class should not be used. Rather, one should use one of its
+ * subclasses.
+ * @constructor
+ * @param {number} numHashBlocks The size of the output in 16-byte blocks
+ * @param {!Array<number>} initHashBlocks The hash-specific initialization
+ *     vector, as a sequence of sixteen 32-bit numbers.
+ * @extends {goog.crypt.Hash}
+ * @struct
+ */
+goog.crypt.Sha2_64bit = function(numHashBlocks, initHashBlocks) {
+  goog.crypt.Sha2_64bit.base(this, 'constructor');
+
+  /**
+   * The number of bytes that are digested in each pass of this hasher.
+   * @const {number}
+   */
+  this.blockSize = goog.crypt.Sha2_64bit.BLOCK_SIZE_;
+
+  /**
+   * A chunk holding the currently processed message bytes. Once the chunk has
+   * {@code this.blocksize} bytes, we feed it into [@code computeChunk_}.
+   * @private {!Uint8Array|!Array<number>}
+   */
+  this.chunk_ = goog.isDef(goog.global.Uint8Array) ?
+      new Uint8Array(goog.crypt.Sha2_64bit.BLOCK_SIZE_) :
+      new Array(goog.crypt.Sha2_64bit.BLOCK_SIZE_);
+
+  /**
+   * Current number of bytes in {@code this.chunk_}.
+   * @private {number}
+   */
+  this.chunkBytes_ = 0;
+
+  /**
+   * Total number of bytes in currently processed message.
+   * @private {number}
+   */
+  this.total_ = 0;
+
+  /**
+   * Holds the previous values of accumulated hash a-h in the
+   * {@code computeChunk_} function.
+   * @private {!Array<!goog.math.Long>}
+   */
+  this.hash_ = [];
+
+  /**
+   * The number of blocks of output produced by this hash function, where each
+   * block is eight bytes long.
+   * @private {number}
+   */
+  this.numHashBlocks_ = numHashBlocks;
+
+  /**
+   * Temporary array used in chunk computation.  Allocate here as a
+   * member rather than as a local within computeChunk_() as a
+   * performance optimization to reduce the number of allocations and
+   * reduce garbage collection.
+   * @type {!Array<!goog.math.Long>}
+   * @private
+   */
+  this.w_ = [];
+
+  /**
+   * The value to which {@code this.hash_} should be reset when this
+   * Hasher is reset.
+   * @private @const {!Array<!goog.math.Long>}
+   */
+  this.initHashBlocks_ = goog.crypt.Sha2_64bit.toLongArray_(initHashBlocks);
+
+  /**
+   * If true, we have taken the digest from this hasher, but we have not
+   * yet reset it.
+   *
+   * @private {boolean}
+   */
+  this.needsReset_ = false;
+
+  this.reset();
+};
+goog.inherits(goog.crypt.Sha2_64bit, goog.crypt.Hash);
+
+
+/**
+ * The number of bytes that are digested in each pass of this hasher.
+ * @private @const {number}
+ */
+goog.crypt.Sha2_64bit.BLOCK_SIZE_ = 1024 / 8;
+
+
+/**
+ * Contains data needed to pad messages less than {@code blocksize} bytes.
+ * @private {!Array<number>}
+ */
+goog.crypt.Sha2_64bit.PADDING_ = goog.array.concat(
+    [0x80], goog.array.repeat(0, goog.crypt.Sha2_64bit.BLOCK_SIZE_ - 1));
+
+
+/**
+ * Resets this hash function.
+ * @override
+ */
+goog.crypt.Sha2_64bit.prototype.reset = function() {
+  this.chunkBytes_ = 0;
+  this.total_ = 0;
+  this.hash_ = goog.array.clone(this.initHashBlocks_);
+  this.needsReset_ = false;
+};
+
+
+/** @override */
+goog.crypt.Sha2_64bit.prototype.update = function(message, opt_length) {
+  var length = goog.isDef(opt_length) ? opt_length : message.length;
+
+  // Make sure this hasher is usable.
+  if (this.needsReset_) {
+    throw Error('this hasher needs to be reset');
+  }
+  // Process the message from left to right up to |length| bytes.
+  // When we get a 512-bit chunk, compute the hash of it and reset
+  // this.chunk_. The message might not be multiple of 512 bits so we
+  // might end up with a chunk that is less than 512 bits. We store
+  // such partial chunk in chunk_ and it will be filled up later
+  // in digest().
+  var chunkBytes = this.chunkBytes_;
+
+  // The input message could be either byte array or string.
+  if (goog.isString(message)) {
+    for (var i = 0; i < length; i++) {
+      var b = message.charCodeAt(i);
+      if (b > 255) {
+        throw Error('Characters must be in range [0,255]');
+      }
+      this.chunk_[chunkBytes++] = b;
+      if (chunkBytes == this.blockSize) {
+        this.computeChunk_();
+        chunkBytes = 0;
+      }
+    }
+  } else if (goog.isArray(message)) {
+    for (var i = 0; i < length; i++) {
+      var b = message[i];
+      // Hack:  b|0 coerces b to an integer, so the last part confirms that
+      // b has no fractional part.
+      if (!goog.isNumber(b) || b < 0 || b > 255 || b != (b | 0)) {
+        throw Error('message must be a byte array');
+      }
+      this.chunk_[chunkBytes++] = b;
+      if (chunkBytes == this.blockSize) {
+        this.computeChunk_();
+        chunkBytes = 0;
+      }
+    }
+  } else {
+    throw Error('message must be string or array');
+  }
+
+  // Record the current bytes in chunk to support partial update.
+  this.chunkBytes_ = chunkBytes;
+
+  // Record total message bytes we have processed so far.
+  this.total_ += length;
+};
+
+
+/** @override */
+goog.crypt.Sha2_64bit.prototype.digest = function() {
+  if (this.needsReset_) {
+    throw Error('this hasher needs to be reset');
+  }
+  var totalBits = this.total_ * 8;
+
+  // Append pad 0x80 0x00* until this.chunkBytes_ == 112
+  if (this.chunkBytes_ < 112) {
+    this.update(goog.crypt.Sha2_64bit.PADDING_, 112 - this.chunkBytes_);
+  } else {
+    // the rest of this block, plus 112 bytes of next block
+    this.update(goog.crypt.Sha2_64bit.PADDING_,
+        this.blockSize - this.chunkBytes_ + 112);
+  }
+
+  // Append # bits in the 64-bit big-endian format.
+  for (var i = 127; i >= 112; i--) {
+    this.chunk_[i] = totalBits & 255;
+    totalBits /= 256; // Don't use bit-shifting here!
+  }
+  this.computeChunk_();
+
+  // Finally, output the result digest.
+  var n = 0;
+  var digest = new Array(8 * this.numHashBlocks_);
+  for (var i = 0; i < this.numHashBlocks_; i++) {
+    var block = this.hash_[i];
+    var high = block.getHighBits();
+    var low = block.getLowBits();
+    for (var j = 24; j >= 0; j -= 8) {
+      digest[n++] = ((high >> j) & 255);
+    }
+    for (var j = 24; j >= 0; j -= 8) {
+      digest[n++] = ((low >> j) & 255);
+    }
+  }
+
+  // The next call to this hasher must be a reset
+  this.needsReset_ = true;
+  return digest;
+};
+
+
+/**
+ * Updates this hash by processing the 1024-bit message chunk in this.chunk_.
+ * @private
+ */
+goog.crypt.Sha2_64bit.prototype.computeChunk_ = function() {
+  var chunk = this.chunk_;
+  var K_ = goog.crypt.Sha2_64bit.K_;
+
+  // Divide the chunk into 16 64-bit-words.
+  var w = this.w_;
+  for (var i = 0; i < 16; i++) {
+    var offset = i * 8;
+    w[i] = new goog.math.Long(
+        (chunk[offset + 4] << 24) | (chunk[offset + 5] << 16) |
+            (chunk[offset + 6] << 8) | (chunk[offset + 7]),
+        (chunk[offset] << 24) | (chunk[offset + 1] << 16) |
+            (chunk[offset + 2] << 8) | (chunk[offset + 3]));
+
+  }
+
+  // Extend the w[] array to be the number of rounds.
+  for (var i = 16; i < 80; i++) {
+    var s0 = this.sigma0_(w[i - 15]);
+    var s1 = this.sigma1_(w[i - 2]);
+    w[i] = this.sum_(w[i - 16], w[i - 7], s0, s1);
+  }
+
+  var a = this.hash_[0];
+  var b = this.hash_[1];
+  var c = this.hash_[2];
+  var d = this.hash_[3];
+  var e = this.hash_[4];
+  var f = this.hash_[5];
+  var g = this.hash_[6];
+  var h = this.hash_[7];
+  for (var i = 0; i < 80; i++) {
+    var S0 = this.Sigma0_(a);
+    var maj = this.majority_(a, b, c);
+    var t2 = S0.add(maj);
+    var S1 = this.Sigma1_(e);
+    var ch = this.choose_(e, f, g);
+    var t1 = this.sum_(h, S1, ch, K_[i], w[i]);
+    h = g;
+    g = f;
+    f = e;
+    e = d.add(t1);
+    d = c;
+    c = b;
+    b = a;
+    a = t1.add(t2);
+  }
+
+  this.hash_[0] = this.hash_[0].add(a);
+  this.hash_[1] = this.hash_[1].add(b);
+  this.hash_[2] = this.hash_[2].add(c);
+  this.hash_[3] = this.hash_[3].add(d);
+  this.hash_[4] = this.hash_[4].add(e);
+  this.hash_[5] = this.hash_[5].add(f);
+  this.hash_[6] = this.hash_[6].add(g);
+  this.hash_[7] = this.hash_[7].add(h);
+};
+
+
+/**
+ * Calculates the SHA2 64-bit sigma0 function.
+ * rotateRight(value, 1) ^ rotateRight(value, 8) ^ (value >>> 7)
+ *
+ * @private
+ * @param {!goog.math.Long} value
+ * @return {!goog.math.Long}
+ */
+goog.crypt.Sha2_64bit.prototype.sigma0_ = function(value) {
+  var valueLow = value.getLowBits();
+  var valueHigh = value.getHighBits();
+  // Implementation note: We purposely do not use the shift operations defined
+  // in goog.math.Long.  Inlining the code for specific values of shifting and
+  // not generating the intermediate results doubles the speed of this code.
+  var low = (valueLow >>> 1) ^ (valueHigh << 31) ^
+            (valueLow >>> 8) ^ (valueHigh << 24) ^
+            (valueLow >>> 7) ^ (valueHigh << 25);
+  var high = (valueHigh >>> 1) ^ (valueLow << 31) ^
+             (valueHigh >>> 8) ^ (valueLow << 24) ^
+             (valueHigh >>> 7);
+  return new goog.math.Long(low, high);
+};
+
+
+/**
+ * Calculates the SHA2 64-bit sigma1 function.
+ * rotateRight(value, 19) ^ rotateRight(value, 61) ^ (value >>> 6)
+ *
+ * @private
+ * @param {!goog.math.Long} value
+ * @return {!goog.math.Long}
+ */
+goog.crypt.Sha2_64bit.prototype.sigma1_ = function(value) {
+  var valueLow = value.getLowBits();
+  var valueHigh = value.getHighBits();
+  // Implementation note:  See _sigma0() above
+  var low = (valueLow >>> 19) ^ (valueHigh << 13) ^
+            (valueHigh >>> 29) ^ (valueLow << 3) ^
+            (valueLow >>> 6) ^ (valueHigh << 26);
+  var high = (valueHigh >>> 19) ^ (valueLow << 13) ^
+             (valueLow >>> 29) ^ (valueHigh << 3) ^
+             (valueHigh >>> 6);
+  return new goog.math.Long(low, high);
+};
+
+
+/**
+ * Calculates the SHA2 64-bit Sigma0 function.
+ * rotateRight(value, 28) ^ rotateRight(value, 34) ^ rotateRight(value, 39)
+ *
+ * @private
+ * @param {!goog.math.Long} value
+ * @return {!goog.math.Long}
+ */
+goog.crypt.Sha2_64bit.prototype.Sigma0_ = function(value) {
+  var valueLow = value.getLowBits();
+  var valueHigh = value.getHighBits();
+  // Implementation note:  See _sigma0() above
+  var low = (valueLow >>> 28) ^ (valueHigh << 4) ^
+            (valueHigh >>> 2) ^ (valueLow << 30) ^
+            (valueHigh >>> 7) ^ (valueLow << 25);
+  var high = (valueHigh >>> 28) ^ (valueLow << 4) ^
+             (valueLow >>> 2) ^ (valueHigh << 30) ^
+             (valueLow >>> 7) ^ (valueHigh << 25);
+  return new goog.math.Long(low, high);
+};
+
+
+/**
+ * Calculates the SHA2 64-bit Sigma1 function.
+ * rotateRight(value, 14) ^ rotateRight(value, 18) ^ rotateRight(value, 41)
+ *
+ * @private
+ * @param {!goog.math.Long} value
+ * @return {!goog.math.Long}
+ */
+goog.crypt.Sha2_64bit.prototype.Sigma1_ = function(value) {
+  var valueLow = value.getLowBits();
+  var valueHigh = value.getHighBits();
+  // Implementation note:  See _sigma0() above
+  var low = (valueLow >>> 14) ^ (valueHigh << 18) ^
+            (valueLow >>> 18) ^ (valueHigh << 14) ^
+            (valueHigh >>> 9) ^ (valueLow << 23);
+  var high = (valueHigh >>> 14) ^ (valueLow << 18) ^
+             (valueHigh >>> 18) ^ (valueLow << 14) ^
+             (valueLow >>> 9) ^ (valueHigh << 23);
+  return new goog.math.Long(low, high);
+};
+
+
+/**
+ * Calculates the SHA-2 64-bit choose function.
+ *
+ * This function uses {@code value} as a mask to choose bits from either
+ * {@code one} if the bit is set or {@code two} if the bit is not set.
+ *
+ * @private
+ * @param {!goog.math.Long} value
+ * @param {!goog.math.Long} one
+ * @param {!goog.math.Long} two
+ * @return {!goog.math.Long}
+ */
+goog.crypt.Sha2_64bit.prototype.choose_ = function(value, one, two) {
+  var valueLow = value.getLowBits();
+  var valueHigh = value.getHighBits();
+  return new goog.math.Long(
+      (valueLow & one.getLowBits()) | (~valueLow & two.getLowBits()),
+      (valueHigh & one.getHighBits()) | (~valueHigh & two.getHighBits()));
+};
+
+
+/**
+ * Calculates the SHA-2 64-bit majority function.
+ * This function returns, for each bit position, the bit held by the majority
+ * of its three arguments.
+ *
+ * @private
+ * @param {!goog.math.Long} one
+ * @param {!goog.math.Long} two
+ * @param {!goog.math.Long} three
+ * @return {!goog.math.Long}
+ */
+goog.crypt.Sha2_64bit.prototype.majority_ = function(one, two, three) {
+  return new goog.math.Long(
+      (one.getLowBits() & two.getLowBits()) |
+          (two.getLowBits() & three.getLowBits()) |
+          (one.getLowBits() & three.getLowBits()),
+      (one.getHighBits() & two.getHighBits()) |
+          (two.getHighBits() & three.getHighBits()) |
+          (one.getHighBits() & three.getHighBits()));
+};
+
+
+/**
+ * Adds two or more goog.math.Long values.
+ *
+ * @private
+ * @param {!goog.math.Long} one first summand
+ * @param {!goog.math.Long} two second summand
+ * @param {...goog.math.Long} var_args more arguments to sum
+ * @return {!goog.math.Long} The resulting sum.
+ */
+goog.crypt.Sha2_64bit.prototype.sum_ = function(one, two, var_args) {
+  // The low bits may be signed, but they represent a 32-bit unsigned quantity.
+  // We must be careful to normalize them.
+  // This doesn't matter for the high bits.
+  // Implementation note:  Performance testing shows that this method runs
+  // fastest when the first two arguments are pulled out of the loop.
+  var low = (one.getLowBits() ^ 0x80000000) + (two.getLowBits() ^ 0x80000000);
+  var high = one.getHighBits() + two.getHighBits();
+  for (var i = arguments.length - 1; i >= 2; --i) {
+    low += arguments[i].getLowBits() ^ 0x80000000;
+    high += arguments[i].getHighBits();
+  }
+  // Because of the ^0x80000000, each value we added is 0x80000000 too small.
+  // Add arguments.length * 0x80000000 to the current sum.  We can do this
+  // quickly by adding 0x80000000 to low when the number of arguments is
+  // odd, and adding (number of arguments) >> 1 to high.
+  if (arguments.length & 1) {
+    low += 0x80000000;
+  }
+  high += arguments.length >> 1;
+
+  // If low is outside the range [0, 0xFFFFFFFF], its overflow or underflow
+  // should be added to high.  We don't actually need to modify low or
+  // normalize high because the goog.math.Long constructor already does that.
+  high += Math.floor(low / 0x100000000);
+  return new goog.math.Long(low, high);
+};
+
+
+/**
+ * Converts an array of 32-bit integers into an array of goog.math.Long
+ * elements.
+ *
+ * @private
+ * @param {!Array<number>} values An array of 32-bit numbers.  Its length
+ *     must be even.  Each pair of numbers represents a 64-bit integer
+ *     in big-endian order
+ * @return {!Array<!goog.math.Long>}
+ */
+goog.crypt.Sha2_64bit.toLongArray_ = function(values) {
+  goog.asserts.assert(values.length % 2 == 0);
+  var result = [];
+  for (var i = 0; i < values.length; i += 2) {
+    result.push(new goog.math.Long(values[i + 1], values[i]));
+  }
+  return result;
+};
+
+
+/**
+ * Fixed constants used in SHA-512 variants.
+ *
+ * These values are from Section 4.2.3 of
+ * http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+ * @const
+ * @private {!Array<!goog.math.Long>}
+ */
+goog.crypt.Sha2_64bit.K_ = goog.crypt.Sha2_64bit.toLongArray_([
+  0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd,
+  0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
+  0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019,
+  0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
+  0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe,
+  0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
+  0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1,
+  0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
+  0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3,
+  0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
+  0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483,
+  0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
+  0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210,
+  0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
+  0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725,
+  0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
+  0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926,
+  0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
+  0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8,
+  0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
+  0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001,
+  0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
+  0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910,
+  0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
+  0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53,
+  0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
+  0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb,
+  0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
+  0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60,
+  0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
+  0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9,
+  0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
+  0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207,
+  0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
+  0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6,
+  0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
+  0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493,
+  0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
+  0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a,
+  0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817
+]);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/sha384.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/sha384.js b/externs/GCL/externs/goog/crypt/sha384.js
new file mode 100644
index 0000000..08ad946
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/sha384.js
@@ -0,0 +1,59 @@
+// Copyright 2014 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 SHA-384  cryptographic hash.
+ *
+ * Usage:
+ *   var sha384 = new goog.crypt.Sha384();
+ *   sha384.update(bytes);
+ *   var hash = sha384.digest();
+ *
+ * @author fy@google.com (Frank Yellin)
+ */
+
+goog.provide('goog.crypt.Sha384');
+
+goog.require('goog.crypt.Sha2_64bit');
+
+
+
+/**
+ * Constructs a SHA-384 cryptographic hash.
+ *
+ * @constructor
+ * @extends {goog.crypt.Sha2_64bit}
+ * @final
+ * @struct
+ */
+goog.crypt.Sha384 = function() {
+  goog.crypt.Sha384.base(this, 'constructor', 6  /* numHashBlocks */,
+      goog.crypt.Sha384.INIT_HASH_BLOCK_);
+};
+goog.inherits(goog.crypt.Sha384, goog.crypt.Sha2_64bit);
+
+
+/** @private {!Array<number>} */
+goog.crypt.Sha384.INIT_HASH_BLOCK_ = [
+  // Section 5.3.4 of
+  // csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+  0xcbbb9d5d, 0xc1059ed8,  // H0
+  0x629a292a, 0x367cd507,  // H1
+  0x9159015a, 0x3070dd17,  // H2
+  0x152fecd8, 0xf70e5939,  // H3
+  0x67332667, 0xffc00b31,  // H4
+  0x8eb44a87, 0x68581511,  // H5
+  0xdb0c2e0d, 0x64f98fa7,  // H6
+  0x47b5481d, 0xbefa4fa4   // H7
+];

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/sha512.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/sha512.js b/externs/GCL/externs/goog/crypt/sha512.js
new file mode 100644
index 0000000..9ac2280
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/sha512.js
@@ -0,0 +1,59 @@
+// Copyright 2014 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 SHA-512 cryptographic hash.
+ *
+ * Usage:
+ *   var sha512 = new goog.crypt.Sha512();
+ *   sha512.update(bytes);
+ *   var hash = sha512.digest();
+ *
+ * @author fy@google.com (Frank Yellin)
+ */
+
+goog.provide('goog.crypt.Sha512');
+
+goog.require('goog.crypt.Sha2_64bit');
+
+
+
+/**
+ * Constructs a SHA-512 cryptographic hash.
+ *
+ * @constructor
+ * @extends {goog.crypt.Sha2_64bit}
+ * @final
+ * @struct
+ */
+goog.crypt.Sha512 = function() {
+  goog.crypt.Sha512.base(this, 'constructor', 8  /* numHashBlocks */,
+      goog.crypt.Sha512.INIT_HASH_BLOCK_);
+};
+goog.inherits(goog.crypt.Sha512, goog.crypt.Sha2_64bit);
+
+
+/** @private {!Array<number>} */
+goog.crypt.Sha512.INIT_HASH_BLOCK_ = [
+  // Section 5.3.5 of
+  // csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+  0x6a09e667, 0xf3bcc908,  // H0
+  0xbb67ae85, 0x84caa73b,  // H1
+  0x3c6ef372, 0xfe94f82b,  // H2
+  0xa54ff53a, 0x5f1d36f1,  // H3
+  0x510e527f, 0xade682d1,  // H4
+  0x9b05688c, 0x2b3e6c1f,  // H5
+  0x1f83d9ab, 0xfb41bd6b,  // H6
+  0x5be0cd19, 0x137e2179   // H7
+];

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/crypt/sha512_256.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/crypt/sha512_256.js b/externs/GCL/externs/goog/crypt/sha512_256.js
new file mode 100644
index 0000000..75a4256
--- /dev/null
+++ b/externs/GCL/externs/goog/crypt/sha512_256.js
@@ -0,0 +1,65 @@
+// Copyright 2014 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 SHA-512/256 cryptographic hash.
+ *
+ * WARNING:  SHA-256 and SHA-512/256 are different members of the SHA-2
+ * family of hashes.  Although both give 32-byte results, the two results
+ * should bear no relationship to each other.
+ *
+ * Please be careful before using this hash function.
+ * <p>
+ * Usage:
+ *   var sha512_256 = new goog.crypt.Sha512_256();
+ *   sha512_256.update(bytes);
+ *   var hash = sha512_256.digest();
+ *
+ * @author fy@google.com (Frank Yellin)
+ */
+
+goog.provide('goog.crypt.Sha512_256');
+
+goog.require('goog.crypt.Sha2_64bit');
+
+
+
+/**
+ * Constructs a SHA-512/256 cryptographic hash.
+ *
+ * @constructor
+ * @extends {goog.crypt.Sha2_64bit}
+ * @final
+ * @struct
+ */
+goog.crypt.Sha512_256 = function() {
+  goog.crypt.Sha512_256.base(this, 'constructor', 4  /* numHashBlocks */,
+      goog.crypt.Sha512_256.INIT_HASH_BLOCK_);
+};
+goog.inherits(goog.crypt.Sha512_256, goog.crypt.Sha2_64bit);
+
+
+/** @private {!Array<number>} */
+goog.crypt.Sha512_256.INIT_HASH_BLOCK_ = [
+  // Section 5.3.6.2 of
+  // csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+  0x22312194, 0xFC2BF72C,  // H0
+  0x9F555FA3, 0xC84C64C2,  // H1
+  0x2393B86B, 0x6F53B151,  // H2
+  0x96387719, 0x5940EABD,  // H3
+  0x96283EE2, 0xA88EFFE3,  // H4
+  0xBE5E1E25, 0x53863992,  // H5
+  0x2B0199FC, 0x2C85B8AA,  // H6
+  0x0EB72DDC, 0x81C52CA2   // H7
+];

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/autocomplete.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/autocomplete.css b/externs/GCL/externs/goog/css/autocomplete.css
new file mode 100644
index 0000000..033ceba
--- /dev/null
+++ b/externs/GCL/externs/goog/css/autocomplete.css
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Styles for goog.ui.ac.AutoComplete and its derivatives.
+ * Note: these styles need some work to get them working properly at various
+ * font sizes other than the default.
+ *
+ * @author pupius@google.com (Daniel Pupius)
+ * @author annams@google.com (Srinivas Annam)
+ */
+
+
+/*
+ * TODO(annams): Rename (here and in renderer.js) to specify class name as
+ * goog-autocomplete-renderer
+ */
+.ac-renderer {
+  font: normal 13px Arial, sans-serif;
+  position: absolute;
+  background: #fff;
+  border: 1px solid #666;
+  -moz-box-shadow: 2px 2px 2px rgba(102, 102, 102, .4);
+  -webkit-box-shadow: 2px 2px 2px rgba(102, 102, 102, .4);
+  width: 300px;
+}
+
+.ac-row {
+  cursor: pointer;
+  padding: .4em;
+}
+
+.ac-highlighted {
+  font-weight: bold;
+}
+
+.ac-active {
+  background-color: #b2b4bf;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/bubble.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/bubble.css b/externs/GCL/externs/goog/css/bubble.css
new file mode 100644
index 0000000..4e8d612
--- /dev/null
+++ b/externs/GCL/externs/goog/css/bubble.css
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2010 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+.goog-bubble-font {
+  font-size: 80%;
+  color: #888888;
+}
+
+.goog-bubble-close-button {
+  background-image:url(//ssl.gstatic.com/closure/bubble_close.jpg);
+  background-color: white;
+  background-position: top right;
+  background-repeat: no-repeat;
+  width: 16px;
+  height: 16px;
+}
+
+.goog-bubble-left {
+  background-image:url(//ssl.gstatic.com/closure/bubble_left.gif);
+  background-position:left;
+  background-repeat:repeat-y;
+  width: 4px;
+}
+
+.goog-bubble-right {
+  background-image:url(//ssl.gstatic.com/closure/bubble_right.gif);
+  background-position: right;
+  background-repeat: repeat-y;
+  width: 4px;
+}
+
+.goog-bubble-top-right-anchor {
+  background-image:url(//ssl.gstatic.com/closure/right_anchor_bubble_top.gif);
+  background-position: center;
+  background-repeat: no-repeat;
+  width: 147px;
+  height: 16px;
+}
+
+.goog-bubble-top-left-anchor {
+  background-image:url(//ssl.gstatic.com/closure/left_anchor_bubble_top.gif);
+  background-position: center;
+  background-repeat: no-repeat;
+  width: 147px;
+  height: 16px;
+}
+
+.goog-bubble-top-no-anchor {
+  background-image:url(//ssl.gstatic.com/closure/no_anchor_bubble_top.gif);
+  background-position: center;
+  background-repeat: no-repeat;
+  width: 147px;
+  height: 6px;
+}
+
+.goog-bubble-bottom-right-anchor {
+  background-image:url(//ssl.gstatic.com/closure/right_anchor_bubble_bot.gif);
+  background-position: center;
+  background-repeat: no-repeat;
+  width: 147px;
+  height: 16px;
+}
+
+.goog-bubble-bottom-left-anchor {
+  background-image:url(//ssl.gstatic.com/closure/left_anchor_bubble_bot.gif);
+  background-position: center;
+  background-repeat: no-repeat;
+  width: 147px;
+  height: 16px;
+}
+
+.goog-bubble-bottom-no-anchor {
+  background-image:url(//ssl.gstatic.com/closure/no_anchor_bubble_bot.gif);
+  background-position: center;
+  background-repeat: no-repeat;
+  width: 147px;
+  height: 8px;
+}
+
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/button.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/button.css b/externs/GCL/externs/goog/css/button.css
new file mode 100644
index 0000000..b80a92f
--- /dev/null
+++ b/externs/GCL/externs/goog/css/button.css
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Styling for buttons rendered by goog.ui.ButtonRenderer.
+ *
+ * @author attila@google.com (Attila Bodis)
+ */
+
+.goog-button {
+  color: #036;
+  border-color: #036;
+  background-color: #69c;
+}
+
+/* State: disabled. */
+.goog-button-disabled {
+  border-color: #333;
+  color: #333;
+  background-color: #999;
+}
+
+/* State: hover. */
+.goog-button-hover {
+  color: #369;
+  border-color: #369;
+  background-color: #9cf;
+}
+
+/* State: active. */
+.goog-button-active {
+  color: #69c;
+  border-color: #69c;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/charpicker.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/charpicker.css b/externs/GCL/externs/goog/css/charpicker.css
new file mode 100644
index 0000000..fb33447
--- /dev/null
+++ b/externs/GCL/externs/goog/css/charpicker.css
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: pupius@google.com (Daniel Pupius) */
+/* Author: cibu@google.com (Cibu Johny) */
+
+.goog-char-picker {
+  background-color: #ddd;
+  padding: 16px;
+  border: 1px solid #777;
+}
+
+/* goog.ui.HoverCard */
+.goog-char-picker-hovercard {
+  border: solid 5px #ffcc33;
+  min-width: 64px;
+  max-width: 160px;
+  padding: 16px;
+  background-color: white;
+  text-align: center;
+  position: absolute;
+  visibility: hidden;
+}
+
+.goog-char-picker-name {
+  font-size: x-small;
+}
+
+.goog-char-picker-unicode {
+  font-size: x-small;
+  color: GrayText;
+}
+
+.goog-char-picker-char-zoom {
+  font-size: xx-large;
+}
+
+/*
+ * grid
+ */
+.goog-char-picker-grid-container {
+  border: 1px solid #777;
+  background-color: #fff;
+  width: 272px;
+}
+
+.goog-char-picker-grid {
+  overflow: hidden;
+  height: 250px;
+  width: 250px;
+  position: relative;
+}
+
+.goog-stick {
+  width: 1px;
+  overflow: hidden;
+}
+.goog-stickwrap {
+  width: 17px;
+  height: 250px;
+  float: right;
+  overflow: auto;
+}
+
+.goog-char-picker-recents {
+  border: 1px solid #777;
+  background-color: #fff;
+  height: 25px;
+  width: 275px;
+  margin: 0 0 16px 0;
+  position: relative;
+}
+
+.goog-char-picker-notice {
+  font-size: x-small;
+  height: 16px;
+  color: GrayText;
+  margin: 0 0 16px 0;
+}
+
+/*
+ * Hex entry
+ */
+
+.goog-char-picker-uplus {
+}
+
+.goog-char-picker-input-box {
+  width: 96px;
+}
+
+.label-input-label {
+  color: GrayText;
+}
+
+.goog-char-picker-okbutton {
+}
+
+/*
+ * Grid buttons
+ */
+.goog-char-picker-grid .goog-flat-button {
+  position: relative;
+  width: 24px;
+  height: 24px;
+  line-height: 24px;
+  border-bottom: 1px solid #ddd;
+  border-right: 1px solid #ddd;
+  text-align: center;
+  cursor: pointer;
+  outline: none;
+}
+
+.goog-char-picker-grid .goog-flat-button-hover,
+.goog-char-picker-grid .goog-flat-button-focus {
+  background-color: #ffcc33;
+}
+
+/*
+ * goog.ui.Menu
+ */
+
+/* State: resting. */
+.goog-char-picker-button {
+  border-width: 0px;
+  margin: 0;
+  padding: 0;
+  position: absolute;
+  background-position: center left;
+}
+
+/* State: resting. */
+.goog-char-picker-menu {
+  background-color: #fff;
+  border-color: #ccc #666 #666 #ccc;
+  border-style: solid;
+  border-width: 1px;
+  cursor: default;
+  margin: 0;
+  outline: none;
+  padding: 0;
+  position: absolute;
+  max-height: 400px;
+  overflow-y: auto;
+  overflow-x: hide;
+}
+
+/*
+ * goog.ui.MenuItem
+ */
+
+/* State: resting. */
+.goog-char-picker-menu .goog-menuitem {
+  color: #000;
+  list-style: none;
+  margin: 0;
+  /* 28px on the left for icon or checkbox; 10ex on the right for shortcut. */
+  padding: 1px 32px 1px 8px;
+  white-space: nowrap;
+}
+
+.goog-char-picker-menu2 .goog-menuitem {
+  color: #000;
+  list-style: none;
+  margin: 0;
+  /* 28px on the left for icon or checkbox; 10ex on the right for shortcut. */
+  padding: 1px 32px 1px 8px;
+  white-space: nowrap;
+}
+
+.goog-char-picker-menu .goog-subtitle {
+  color: #fff !important;
+  background-color: #666;
+  font-weight: bold;
+  list-style: none;
+  margin: 0;
+  /* 28px on the left for icon or checkbox; 10ex on the right for shortcut. */
+  padding: 3px 32px 3px 8px;
+  white-space: nowrap;
+}
+
+/* BiDi override for the resting state. */
+.goog-char-picker-menu .goog-menuitem-rtl {
+  /* Flip left/right padding for BiDi. */
+  padding: 2px 16px 2px 32px !important;
+}
+
+/* State: hover. */
+.goog-char-picker-menu .goog-menuitem-highlight {
+  background-color: #d6e9f8;
+}
+/*
+ * goog.ui.MenuSeparator
+ */
+
+/* State: resting. */
+.goog-char-picker-menu .goog-menuseparator {
+  border-top: 1px solid #ccc;
+  margin: 2px 0;
+  padding: 0;
+}
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/checkbox.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/checkbox.css b/externs/GCL/externs/goog/css/checkbox.css
new file mode 100644
index 0000000..2aed8b5
--- /dev/null
+++ b/externs/GCL/externs/goog/css/checkbox.css
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: pallosp@google.com (Peter Pallos) */
+
+/* Sample 3-state checkbox styles. */
+
+.goog-checkbox {
+  border: 1px solid #1C5180;
+  display: -moz-inline-box;
+  display: inline-block;
+  font-size: 1px;  /* Fixes the height in IE6 */
+  height: 11px;
+  margin: 0 4px 0 1px;
+  vertical-align: text-bottom;
+  width: 11px;
+}
+
+.goog-checkbox-checked {
+  background: #fff url(//ssl.gstatic.com/closure/check-sprite.gif) no-repeat 2px center;
+}
+
+.goog-checkbox-undetermined {
+  background: #bbb url(//ssl.gstatic.com/closure/check-sprite.gif) no-repeat 2px center;
+}
+
+.goog-checkbox-unchecked {
+  background: #fff;
+}
+
+.goog-checkbox-disabled {
+  border: 1px solid lightgray;
+  background-position: -7px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/colormenubutton.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/colormenubutton.css b/externs/GCL/externs/goog/css/colormenubutton.css
new file mode 100644
index 0000000..83655dd
--- /dev/null
+++ b/externs/GCL/externs/goog/css/colormenubutton.css
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for buttons created by goog.ui.ColorMenuButtonRenderer.
+ *
+ * @author attila@google.com (Attila Bodis)
+ */
+
+
+/* Color indicator. */
+.goog-color-menu-button-indicator {
+  border-bottom: 4px solid #f0f0f0;
+}
+
+/* Thinner padding for color picker buttons, to leave room for the indicator. */
+.goog-color-menu-button .goog-menu-button-inner-box,
+.goog-toolbar-color-menu-button .goog-toolbar-menu-button-inner-box {
+  padding-top: 2px !important;
+  padding-bottom: 2px !important;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/colorpalette.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/colorpalette.css b/externs/GCL/externs/goog/css/colorpalette.css
new file mode 100644
index 0000000..17bed42
--- /dev/null
+++ b/externs/GCL/externs/goog/css/colorpalette.css
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for color palettes.
+ *
+ * @author pupius@google.com (Daniel Pupius)
+ * @author attila@google.com (Attila Bodis)
+ */
+
+
+.goog-palette-cell .goog-palette-colorswatch {
+  border: none;
+  font-size: x-small;
+  height: 18px;
+  position: relative;
+  width: 18px;
+}
+
+.goog-palette-cell-hover .goog-palette-colorswatch {
+  border: 1px solid #fff;
+  height: 16px;
+  width: 16px;
+}
+
+.goog-palette-cell-selected .goog-palette-colorswatch {
+  /* Client apps may override the URL at which they serve the sprite. */
+  background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -368px 0;
+  border: 1px solid #333;
+  color: #fff;
+  font-weight: bold;
+  height: 16px;
+  width: 16px;
+}
+
+.goog-palette-customcolor {
+  background-color: #fafafa;
+  border: 1px solid #eee;
+  color: #666;
+  font-size: x-small;
+  height: 15px;
+  position: relative;
+  width: 15px;
+}
+
+.goog-palette-cell-hover .goog-palette-customcolor {
+  background-color: #fee;
+  border: 1px solid #f66;
+  color: #f66;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/colorpicker-simplegrid.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/colorpicker-simplegrid.css b/externs/GCL/externs/goog/css/colorpicker-simplegrid.css
new file mode 100644
index 0000000..b98f5dc
--- /dev/null
+++ b/externs/GCL/externs/goog/css/colorpicker-simplegrid.css
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2007 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: pupius@google.com (Daniel Pupius) */
+
+/*
+  Styles to make the colorpicker look like the old gmail color picker
+  NOTE: without CSS scoping this will override styles defined in palette.css
+*/
+.goog-palette {
+  outline: none;
+  cursor: default;
+}
+
+.goog-palette-table {
+  border: 1px solid #666;
+  border-collapse: collapse;
+}
+
+.goog-palette-cell {
+  height: 13px;
+  width: 15px;
+  margin: 0;
+  border: 0;
+  text-align: center;
+  vertical-align: middle;
+  border-right: 1px solid #666;
+  font-size: 1px;
+}
+
+.goog-palette-colorswatch {
+  position: relative;
+  height: 13px;
+  width: 15px;
+  border: 1px solid #666;
+}
+
+.goog-palette-cell-hover .goog-palette-colorswatch {
+  border: 1px solid #FFF;
+}
+
+.goog-palette-cell-selected .goog-palette-colorswatch {
+  border: 1px solid #000;
+  color: #fff;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/combobox.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/combobox.css b/externs/GCL/externs/goog/css/combobox.css
new file mode 100644
index 0000000..dd1571a
--- /dev/null
+++ b/externs/GCL/externs/goog/css/combobox.css
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2007 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: pupius@google.com (Daniel Pupius) */
+/* Author: pallosp@google.com (Peter Pallos) */
+
+/* Styles for goog.ui.ComboBox and its derivatives. */
+
+
+.goog-combobox {
+  background: #ddd url(//ssl.gstatic.com/closure/button-bg.gif) repeat-x scroll left top;
+  border: 1px solid #b5b6b5;
+  font: normal small arial, sans-serif;
+}
+
+.goog-combobox input {
+  background-color: #fff;
+  border: 0;
+  border-right: 1px solid #b5b6b5;
+  color: #000;
+  font: normal small arial, sans-serif;
+  margin: 0;
+  padding: 0 0 0 2px;
+  vertical-align: bottom; /* override demo.css */
+  width: 200px;
+}
+
+.goog-combobox input.label-input-label {
+  background-color: #fff;
+  color: #aaa;
+}
+
+.goog-combobox .goog-menu {
+  margin-top: -1px;
+  width: 219px;  /* input width + button width + 3 * 1px border */
+  z-index: 1000;
+}
+
+.goog-combobox-button {
+  cursor: pointer;
+  display: inline-block;
+  font-size: 10px;
+  text-align: center;
+  width: 16px;
+}
+
+/* IE6 only hack */
+* html .goog-combobox-button {
+  padding: 0 3px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/common.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/common.css b/externs/GCL/externs/goog/css/common.css
new file mode 100644
index 0000000..de140b8
--- /dev/null
+++ b/externs/GCL/externs/goog/css/common.css
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Cross-browser implementation of the "display: inline-block" CSS property.
+ * See http://www.w3.org/TR/CSS21/visuren.html#propdef-display for details.
+ * Tested on IE 6 & 7, FF 1.5 & 2.0, Safari 2 & 3, Webkit, and Opera 9.
+ *
+ * @author attila@google.com (Attila Bodis)
+ */
+
+/*
+ * Default rule; only Safari, Webkit, and Opera handle it without hacks.
+ */
+.goog-inline-block {
+  position: relative;
+  display: -moz-inline-box; /* Ignored by FF3 and later. */
+  display: inline-block;
+}
+
+/*
+ * Pre-IE7 IE hack.  On IE, "display: inline-block" only gives the element
+ * layout, but doesn't give it inline behavior.  Subsequently setting display
+ * to inline does the trick.
+ */
+* html .goog-inline-block {
+  display: inline;
+}
+
+/*
+ * IE7-only hack.  On IE, "display: inline-block" only gives the element
+ * layout, but doesn't give it inline behavior.  Subsequently setting display
+ * to inline does the trick.
+ */
+*:first-child+html .goog-inline-block {
+  display: inline;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/css3button.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/css3button.css b/externs/GCL/externs/goog/css/css3button.css
new file mode 100644
index 0000000..a26306f
--- /dev/null
+++ b/externs/GCL/externs/goog/css/css3button.css
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2010 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: slightlyoff@google.com (Alex Russell) */
+/* Author: eae@google.com (Emil A Eklund) */
+
+/* Imageless button styles. */
+.goog-css3-button {
+  margin: 0 2px;
+  padding: 3px 6px;
+  text-align: center;
+  vertical-align: middle;
+  white-space: nowrap;
+  cursor: default;
+  outline: none;
+  font-family: Arial, sans-serif;
+  color: #000;
+  border: 1px solid #bbb;
+  -webkit-border-radius: 3px;
+  -moz-border-radius: 3px;
+  /* TODO(eae): Change this to -webkit-linear-gradient once
+                https://bugs.webkit.org/show_bug.cgi?id=28152 is resolved. */
+  background: -webkit-gradient(linear, 0% 40%, 0% 70%, from(#f9f9f9),
+      to(#e3e3e3));
+  /* @alternate */ background: -moz-linear-gradient(top, #f9f9f9, #e3e3e3);
+}
+
+
+/* Styles for different states (hover, active, focused, open, checked). */
+.goog-css3-button-hover {
+  border-color: #939393 !important;
+}
+
+.goog-css3-button-focused {
+  border-color: #444;
+}
+
+.goog-css3-button-active, .goog-css3-button-open, .goog-css3-button-checked {
+  border-color: #444 !important;
+  background: -webkit-gradient(linear, 0% 40%, 0% 70%, from(#e3e3e3),
+      to(#f9f9f9));
+  /* @alternate */ background: -moz-linear-gradient(top, #e3e3e3, #f9f9f9);
+}
+
+.goog-css3-button-disabled {
+  color: #888;
+}
+
+.goog-css3-button-primary {
+  font-weight: bold;
+}
+
+
+/*
+ * Pill (collapsed border) styles.
+ */
+.goog-css3-button-collapse-right {
+  margin-right: 0 !important;
+  border-right: 1px solid #bbb;
+  -webkit-border-top-right-radius: 0px;
+  -webkit-border-bottom-right-radius: 0px;
+  -moz-border-radius-topright: 0px;
+  -moz-border-radius-bottomright: 0px;
+}
+
+.goog-css3-button-collapse-left {
+  border-left: 1px solid #f9f9f9;
+  margin-left: 0 !important;
+  -webkit-border-top-left-radius: 0px;
+  -webkit-border-bottom-left-radius: 0px;
+  -moz-border-radius-topleft: 0px;
+  -moz-border-radius-bottomleft: 0px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/css3menubutton.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/css3menubutton.css b/externs/GCL/externs/goog/css/css3menubutton.css
new file mode 100644
index 0000000..a020700
--- /dev/null
+++ b/externs/GCL/externs/goog/css/css3menubutton.css
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2010 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for buttons created by goog.ui.Css3MenuButtonRenderer.
+ *
+ * @author attila@google.com (Attila Bodis)
+ * @author dalewis@google.com (Darren Lewis)
+ */
+
+/* Dropdown arrow style. */
+.goog-css3-button-dropdown {
+  height: 16px;
+  width: 7px;
+  /* Client apps may override the URL at which they serve the sprite. */
+  background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -388px 0;
+  vertical-align: top;
+  margin-left: 3px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/custombutton.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/custombutton.css b/externs/GCL/externs/goog/css/custombutton.css
new file mode 100644
index 0000000..1f17052
--- /dev/null
+++ b/externs/GCL/externs/goog/css/custombutton.css
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Styling for custom buttons rendered by goog.ui.CustomButtonRenderer.
+ *
+ * @author attila@google.com (Attila Bodis)
+ */
+
+.goog-custom-button {
+  margin: 2px;
+  border: 0;
+  padding: 0;
+  font-family: Arial, sans-serif;
+  color: #000;
+  /* Client apps may override the URL at which they serve the image. */
+  background: #ddd url(//ssl.gstatic.com/editor/button-bg.png) repeat-x top left;
+  text-decoration: none;
+  list-style: none;
+  vertical-align: middle;
+  cursor: default;
+  outline: none;
+}
+
+/* Pseudo-rounded corners. */
+.goog-custom-button-outer-box,
+.goog-custom-button-inner-box {
+  border-style: solid;
+  border-color: #aaa;
+  vertical-align: top;
+}
+
+.goog-custom-button-outer-box {
+  margin: 0;
+  border-width: 1px 0;
+  padding: 0;
+}
+
+.goog-custom-button-inner-box {
+  margin: 0 -1px;
+  border-width: 0 1px;
+  padding: 3px 4px;
+  white-space: nowrap; /* Prevents buttons from line breaking on android. */
+}
+
+/* Pre-IE7 IE hack; ignored by IE7 and all non-IE browsers. */
+* html .goog-custom-button-inner-box {
+  /* IE6 needs to have the box shifted to make the borders line up. */
+  left: -1px;
+}
+/* Pre-IE7 BiDi fixes. */
+* html .goog-custom-button-rtl .goog-custom-button-outer-box {
+  /* @noflip */ left: -1px;
+}
+* html .goog-custom-button-rtl .goog-custom-button-inner-box {
+  /* @noflip */ right: auto;
+}
+
+/* IE7-only hack; ignored by all other browsers. */
+*:first-child+html .goog-custom-button-inner-box {
+  /* IE7 needs to have the box shifted to make the borders line up. */
+  left: -1px;
+}
+/* IE7 BiDi fix. */
+*:first-child+html .goog-custom-button-rtl .goog-custom-button-inner-box {
+  /* @noflip */ left: 1px;
+}
+
+/* Safari-only hacks. */
+::root .goog-custom-button,
+::root .goog-custom-button-outer-box {
+  /* Required to make pseudo-rounded corners work on Safari. */
+  line-height: 0;
+}
+
+::root .goog-custom-button-inner-box {
+  /* Required to make pseudo-rounded corners work on Safari. */
+  line-height: normal;
+}
+
+/* State: disabled. */
+.goog-custom-button-disabled {
+  background-image: none !important;
+  opacity: 0.3;
+  -moz-opacity: 0.3;
+  filter: alpha(opacity=30);
+}
+
+.goog-custom-button-disabled .goog-custom-button-outer-box,
+.goog-custom-button-disabled .goog-custom-button-inner-box {
+  color: #333 !important;
+  border-color: #999 !important;
+}
+
+/* Pre-IE7 IE hack; ignored by IE7 and all non-IE browsers. */
+* html .goog-custom-button-disabled {
+  margin: 2px 1px !important;
+  padding: 0 1px !important;
+}
+
+/* IE7-only hack; ignored by all other browsers. */
+*:first-child+html .goog-custom-button-disabled {
+  margin: 2px 1px !important;
+  padding: 0 1px !important;
+}
+
+/* State: hover. */
+.goog-custom-button-hover .goog-custom-button-outer-box,
+.goog-custom-button-hover .goog-custom-button-inner-box {
+  border-color: #9cf #69e #69e #7af !important; /* Hover border wins. */
+}
+
+/* State: active, checked. */
+.goog-custom-button-active,
+.goog-custom-button-checked {
+  background-color: #bbb;
+  background-position: bottom left;
+}
+
+/* State: focused. */
+.goog-custom-button-focused .goog-custom-button-outer-box,
+.goog-custom-button-focused .goog-custom-button-inner-box {
+  border-color: orange;
+}
+
+/* Pill (collapsed border) styles. */
+.goog-custom-button-collapse-right,
+.goog-custom-button-collapse-right .goog-custom-button-outer-box,
+.goog-custom-button-collapse-right .goog-custom-button-inner-box {
+  margin-right: 0;
+}
+
+.goog-custom-button-collapse-left,
+.goog-custom-button-collapse-left .goog-custom-button-outer-box,
+.goog-custom-button-collapse-left .goog-custom-button-inner-box {
+  margin-left: 0;
+}
+
+.goog-custom-button-collapse-left .goog-custom-button-inner-box  {
+  border-left: 1px solid #fff;
+}
+
+.goog-custom-button-collapse-left.goog-custom-button-checked
+.goog-custom-button-inner-box {
+  border-left: 1px solid #ddd;
+}
+
+/* Pre-IE7 IE hack; ignored by IE7 and all non-IE browsers. */
+* html .goog-custom-button-collapse-left .goog-custom-button-inner-box {
+  left: 0;
+}
+
+/* IE7-only hack; ignored by all other browsers. */
+*:first-child+html .goog-custom-button-collapse-left
+.goog-custom-button-inner-box {
+  left: 0;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/datepicker.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/datepicker.css b/externs/GCL/externs/goog/css/datepicker.css
new file mode 100644
index 0000000..6d5b914
--- /dev/null
+++ b/externs/GCL/externs/goog/css/datepicker.css
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for a goog.ui.DatePicker.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+.goog-date-picker,
+.goog-date-picker th,
+.goog-date-picker td {
+  font: 13px Arial, sans-serif;
+}
+
+.goog-date-picker {
+  -moz-user-focus: normal;
+  -moz-user-select: none;
+  position: relative;
+  border: 1px solid #000;
+  float: left;
+  padding: 2px;
+  color: #000;
+  background: #c3d9ff;
+  cursor: default;
+}
+
+.goog-date-picker th {
+  text-align: center;
+}
+
+.goog-date-picker td {
+  text-align: center;
+  vertical-align: middle;
+  padding: 1px 3px;
+}
+
+
+.goog-date-picker-menu {
+  position: absolute;
+  background: threedface;
+  border: 1px solid gray;
+  -moz-user-focus: normal;
+  z-index: 1;
+  outline: none;
+}
+
+.goog-date-picker-menu ul {
+  list-style: none;
+  margin: 0px;
+  padding: 0px;
+}
+
+.goog-date-picker-menu ul li {
+  cursor: default;
+}
+
+.goog-date-picker-menu-selected {
+  background: #ccf;
+}
+
+.goog-date-picker th {
+  font-size: .9em;
+}
+
+.goog-date-picker td div {
+  float: left;
+}
+
+.goog-date-picker button {
+  padding: 0px;
+  margin: 1px 0;
+  border: 0;
+  color: #20c;
+  font-weight: bold;
+  background: transparent;
+}
+
+.goog-date-picker-date {
+  background: #fff;
+}
+
+.goog-date-picker-week,
+.goog-date-picker-wday {
+  padding: 1px 3px;
+  border: 0;
+  border-color: #a2bbdd;
+  border-style: solid;
+}
+
+.goog-date-picker-week {
+  border-right-width: 1px;
+}
+
+.goog-date-picker-wday {
+  border-bottom-width: 1px;
+}
+
+.goog-date-picker-head td {
+  text-align: center;
+}
+
+/** Use td.className instead of !important */
+td.goog-date-picker-today-cont {
+  text-align: center;
+}
+
+/** Use td.className instead of !important */
+td.goog-date-picker-none-cont {
+  text-align: center;
+}
+
+.goog-date-picker-month {
+  min-width: 11ex;
+  white-space: nowrap;
+}
+
+.goog-date-picker-year {
+  min-width: 6ex;
+  white-space: nowrap;
+}
+
+.goog-date-picker-monthyear {
+  white-space: nowrap;
+}
+
+.goog-date-picker table {
+  border-collapse: collapse;
+}
+
+.goog-date-picker-other-month {
+  color: #888;
+}
+
+.goog-date-picker-wkend-start,
+.goog-date-picker-wkend-end {
+  background: #eee;
+}
+
+/** Use td.className instead of !important */
+td.goog-date-picker-selected {
+  background: #c3d9ff;
+}
+
+.goog-date-picker-today {
+  background: #9ab;
+  font-weight: bold !important;
+  border-color: #246 #9bd #9bd #246;
+  color: #fff;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/dialog.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/dialog.css b/externs/GCL/externs/goog/css/dialog.css
new file mode 100644
index 0000000..6bf9020
--- /dev/null
+++ b/externs/GCL/externs/goog/css/dialog.css
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for goog.ui.Dialog.
+ *
+ * @author ssaviano@google.com (Steven Saviano)
+ * @author attila@google.com (Attila Bodis)
+ */
+
+
+.modal-dialog {
+  background: #c1d9ff;
+  border: 1px solid #3a5774;
+  color: #000;
+  padding: 4px;
+  position: absolute;
+}
+
+.modal-dialog a,
+.modal-dialog a:link,
+.modal-dialog a:visited  {
+  color: #06c;
+  cursor: pointer;
+}
+
+.modal-dialog-bg {
+  background: #666;
+  left: 0;
+  position: absolute;
+  top: 0;
+}
+
+.modal-dialog-title {
+  background: #e0edfe;
+  color: #000;
+  cursor: pointer;
+  font-size: 120%;
+  font-weight: bold;
+
+  /* Add padding on the right to ensure the close button has room. */
+  padding: 8px 31px 8px 8px;
+
+  position: relative;
+  _zoom: 1; /* Ensures proper width in IE6 RTL. */
+}
+
+.modal-dialog-title-close {
+  /* Client apps may override the URL at which they serve the sprite. */
+  background: #e0edfe url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -528px 0;
+  cursor: default;
+  height: 15px;
+  position: absolute;
+  right: 10px;
+  top: 8px;
+  width: 15px;
+  vertical-align: middle;
+}
+
+.modal-dialog-buttons,
+.modal-dialog-content {
+  background-color: #fff;
+  padding: 8px;
+}
+
+.goog-buttonset-default {
+  font-weight: bold;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/dimensionpicker.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/dimensionpicker.css b/externs/GCL/externs/goog/css/dimensionpicker.css
new file mode 100644
index 0000000..5c51ab8
--- /dev/null
+++ b/externs/GCL/externs/goog/css/dimensionpicker.css
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2008 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Styling for dimension pickers rendered by goog.ui.DimensionPickerRenderer.
+ *
+ * Author: robbyw@google.com (Robby Walker)
+ * Author: abefettig@google.com (Abe Fettig)
+ */
+
+.goog-dimension-picker {
+  font-size: 18px;
+  padding: 4px;
+}
+
+.goog-dimension-picker div {
+  position: relative;
+}
+
+.goog-dimension-picker div.goog-dimension-picker-highlighted {
+/* Client apps must provide the URL at which they serve the image. */
+  /* background: url(dimension-highlighted.png); */
+  left: 0;
+  overflow: hidden;
+  position: absolute;
+  top: 0;
+}
+
+.goog-dimension-picker-unhighlighted {
+  /* Client apps must provide the URL at which they serve the image. */
+  /* background: url(dimension-unhighlighted.png); */
+}
+
+.goog-dimension-picker-status {
+  font-size: 10pt;
+  text-align: center;
+}
+
+.goog-dimension-picker div.goog-dimension-picker-mousecatcher {
+  left: 0;
+  position: absolute !important;
+  top: 0;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/dragdropdetector.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/dragdropdetector.css b/externs/GCL/externs/goog/css/dragdropdetector.css
new file mode 100644
index 0000000..88266d6
--- /dev/null
+++ b/externs/GCL/externs/goog/css/dragdropdetector.css
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2007 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Styling for the drag drop detector.
+ *
+ * Author: robbyw@google.com (Robby Walker)
+ * Author: wcrosby@google.com (Wayne Crosby)
+ */
+
+.goog-dragdrop-w3c-editable-iframe {
+  position: absolute;
+  width: 100%;
+  height: 10px;
+  top: -150px;
+  left: 0;
+  z-index: 10000;
+  padding: 0;
+  overflow: hidden;
+  opacity: 0;
+  -moz-opacity: 0;
+}
+
+.goog-dragdrop-ie-editable-iframe {
+  width: 100%;
+  height: 5000px;
+}
+
+.goog-dragdrop-ie-input {
+  width: 100%;
+  height: 5000px;
+}
+
+.goog-dragdrop-ie-div {
+  position: absolute;
+  top: -5000px;
+  left: 0;
+  width: 100%;
+  height: 5000px;
+  z-index: 10000;
+  background-color: white;
+  filter: alpha(opacity=0);
+  overflow: hidden;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/editor/bubble.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/editor/bubble.css b/externs/GCL/externs/goog/css/editor/bubble.css
new file mode 100644
index 0000000..c76f98f
--- /dev/null
+++ b/externs/GCL/externs/goog/css/editor/bubble.css
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2005 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Bubble styles.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ * @author nicksantos@google.com (Nick Santos)
+ * @author jparent@google.com (Julie Parent)
+ */
+
+div.tr_bubble {
+  position: absolute;
+
+  background-color: #e0ecff;
+  border: 1px solid #99c0ff;
+  border-radius: 2px;
+  -moz-border-radius: 2px;
+  -webkit-border-radius: 2px;
+  font-size: 83%;
+  font-family: Arial, Helvetica, sans-serif;
+  padding: 2px 19px 6px 6px;
+  white-space: nowrap;
+}
+
+.tr_bubble_link {
+  color: #00c;
+  text-decoration: underline;
+  cursor: pointer;
+  font-size: 100%;
+}
+
+.tr_bubble .tr_option-link,
+.tr_bubble #tr_delete-image,
+.tr_bubble #tr_module-options-link {
+  font-size: 83%;
+}
+
+.tr_bubble_closebox {
+  position: absolute;
+  cursor: default;
+  background: url(//ssl.gstatic.com/editor/bubble_closebox.gif) top left no-repeat;
+  padding: 0;
+  margin: 0;
+  width: 10px;
+  height: 10px;
+  top: 3px;
+  right: 5px;
+}
+
+div.tr_bubble_panel {
+  padding: 2px 0 1px;
+}
+
+div.tr_bubble_panel_title {
+  display: none;
+}
+
+div.tr_multi_bubble div.tr_bubble_panel_title {
+  margin-right: 1px;
+  display: block;
+  float: left;
+  width: 50px;
+}
+
+div.tr_multi_bubble div.tr_bubble_panel {
+  padding: 2px 0 1px;
+  margin-right: 50px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/editor/dialog.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/editor/dialog.css b/externs/GCL/externs/goog/css/editor/dialog.css
new file mode 100644
index 0000000..8868a10
--- /dev/null
+++ b/externs/GCL/externs/goog/css/editor/dialog.css
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2007 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Styles for Editor dialogs and their sub-components.
+ *
+ * @author marcosalmeida@google.com (Marcos Almeida)
+ */
+
+
+.tr-dialog {
+  width: 475px;
+}
+
+.tr-dialog .goog-tab-content {
+  margin: 0;
+  border: 1px solid #6b90da;
+  padding: 4px 8px;
+  background: #fff;
+  overflow: auto;
+}
+
+.tr-tabpane {
+  font-size: 10pt;
+  padding: 1.3ex 0;
+}
+
+.tr-tabpane-caption {
+  font-size: 10pt;
+  margin-bottom: 0.7ex;
+  background-color: #fffaf5;
+  line-height: 1.3em;
+}
+
+.tr-tabpane .goog-tab-content {
+  border: none;
+  padding: 5px 7px 1px;
+}
+
+.tr-tabpane .goog-tab {
+  background-color: #fff;
+  border: none;
+  width: 136px;
+  line-height: 1.3em;
+  margin-bottom: 0.7ex;
+}
+
+.tr-tabpane .goog-tab {
+  text-decoration: underline;
+  color: blue;
+  cursor: pointer;
+}
+
+.tr-tabpane .goog-tab-selected {
+  font-weight: bold;
+  text-decoration: none;
+  color: black;
+}
+
+.tr-tabpane .goog-tab input {
+  margin: -2px 5px 0 0;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/editor/equationeditor.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/editor/equationeditor.css b/externs/GCL/externs/goog/css/editor/equationeditor.css
new file mode 100644
index 0000000..b6aff34
--- /dev/null
+++ b/externs/GCL/externs/goog/css/editor/equationeditor.css
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * The CSS definition for everything inside equation editor dialog.
+ *
+ * Author: yoah@google.com (Yoah Bar-David)
+ * Author: kfk@google.com (Ming Zhang)
+ */
+
+.ee-modal-dialog {
+  width: 475px;
+}
+
+.ee-content {
+  background: #FFF;
+  border: 1px solid #369;
+  overflow: auto;
+  padding: 4px 8px;
+}
+
+.ee-tex {
+  border: 1px solid #000;
+  display: block;
+  height: 7.5em;
+  margin: 4px 0 10px 0;
+  width: 100%;
+}
+
+.ee-section-title {
+  font-weight: bold;
+}
+
+.ee-section-title-floating {
+  float: left;
+}
+
+#ee-section-learn-more {
+  float: right;
+}
+
+.ee-preview-container {
+  border: 1px dashed #ccc;
+  height: 80px;
+  margin: 4px 0 10px 0;
+  width: 100%;
+  overflow: auto;
+}
+
+.ee-warning {
+  color: #F00;
+}
+
+.ee-palette {
+  border: 1px solid #aaa;
+  left: 0;
+  outline: none;
+  position: absolute;
+}
+
+.ee-palette-table {
+  border: 0;
+  border-collapse: separate;
+}
+
+.ee-palette-cell {
+  background: #F0F0F0;
+  border: 1px solid #FFF;
+  margin: 0;
+  padding: 1px;
+}
+
+.ee-palette-cell-hover {
+  background: #E2ECF9 !important;
+  border: 1px solid #000;
+  padding: 1px;
+}
+
+.ee-palette-cell-selected {
+  background: #F0F0F0;
+  border: 1px solid #CCC !important;
+  padding: 1px;
+}
+
+.ee-menu-palette-table {
+  margin-right: 10px;
+}
+
+.ee-menu-palette {
+  outline: none;
+  padding-top: 2px;
+}
+
+.ee-menu-palette-cell {
+  background: #F0F0F0 none repeat scroll 0 0;
+  border-color: #888 #AAA #AAA #888;
+  border-style: solid;
+  border-width: 1px;
+}
+.ee-menu-palette-cell-hover,
+.ee-menu-palette-cell-selected {
+  background: #F0F0F0;
+}
+
+.ee-palette-item,
+.ee-menu-palette-item {
+  background-image: url(//ssl.gstatic.com/editor/ee-palettes.gif);
+}
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/editor/linkdialog.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/editor/linkdialog.css b/externs/GCL/externs/goog/css/editor/linkdialog.css
new file mode 100644
index 0000000..a58a4b2
--- /dev/null
+++ b/externs/GCL/externs/goog/css/editor/linkdialog.css
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2007 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/**
+ * Styles for the Editor's Edit Link dialog.
+ *
+ * @author marcosalmeida@google.com (Marcos Almeida)
+ */
+
+
+.tr-link-dialog-explanation-text {
+  font-size: 83%;
+  margin-top: 15px;
+}
+
+.tr-link-dialog-target-input {
+  width: 98%; /* 98% prevents scroll bars in standards mode. */
+  /* Input boxes for URLs and email address should always be LTR. */
+  direction: ltr;
+}
+
+.tr-link-dialog-email-warning {
+  text-align: center;
+  color: #c00;
+  font-weight: bold;
+}
+
+.tr_pseudo-link {
+ color: #00c;
+ text-decoration: underline;
+ cursor: pointer;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/editortoolbar.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/editortoolbar.css b/externs/GCL/externs/goog/css/editortoolbar.css
new file mode 100644
index 0000000..1e26f4f
--- /dev/null
+++ b/externs/GCL/externs/goog/css/editortoolbar.css
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2008 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+
+/*
+ * Editor toolbar styles.
+ *
+ * @author attila@google.com (Attila Bodis)
+ */
+
+/* Common base style for all icons. */
+.tr-icon {
+  width: 16px;
+  height: 16px;
+  background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat;
+  vertical-align: middle;
+}
+
+.goog-color-menu-button-indicator .tr-icon {
+  height: 14px;
+}
+
+/* Undo (redo when the chrome is right-to-left). */
+.tr-undo,
+.goog-toolbar-button-rtl .tr-redo {
+  background-position: 0;
+}
+
+/* Redo (undo when the chrome is right-to-left). */
+.tr-redo,
+.goog-toolbar-button-rtl .tr-undo {
+  background-position: -16px;
+}
+
+/* Font name. */
+.tr-fontName .goog-toolbar-menu-button-caption {
+  color: #246;
+  width: 16ex;
+  height: 16px;
+  overflow: hidden;
+}
+
+/* Font size. */
+.tr-fontSize .goog-toolbar-menu-button-caption {
+  color: #246;
+  width: 8ex;
+  height: 16px;
+  overflow: hidden;
+}
+
+/* Bold. */
+.tr-bold {
+  background-position: -32px;
+}
+
+/* Italic. */
+.tr-italic {
+  background-position: -48px;
+}
+
+/* Underline. */
+.tr-underline {
+  background-position: -64px;
+}
+
+/* Foreground color. */
+.tr-foreColor {
+  height: 14px;
+  background-position: -80px;
+}
+
+/* Background color. */
+.tr-backColor {
+  height: 14px;
+  background-position: -96px;
+}
+
+/* Link. */
+.tr-link {
+  font-weight: bold;
+  color: #009;
+  text-decoration: underline;
+}
+
+/* Insert image. */
+.tr-image {
+  background-position: -112px;
+}
+
+/* Insert drawing. */
+.tr-newDrawing {
+  background-position: -592px;
+}
+
+/* Insert special character. */
+.tr-spChar {
+  font-weight: bold;
+  color: #900;
+}
+
+/* Increase indent. */
+.tr-indent {
+  background-position: -128px;
+}
+
+/* Increase ident in right-to-left text mode, regardless of chrome direction. */
+.tr-rtl-mode .tr-indent {
+  background-position: -400px;
+}
+
+/* Decrease indent. */
+.tr-outdent {
+  background-position: -144px;
+}
+
+/* Decrease indent in right-to-left text mode, regardless of chrome direction. */
+.tr-rtl-mode .tr-outdent {
+  background-position: -416px;
+}
+
+/* Bullet (unordered) list. */
+.tr-insertUnorderedList {
+  background-position: -160px;
+}
+
+/* Bullet list in right-to-left text mode, regardless of chrome direction. */
+.tr-rtl-mode .tr-insertUnorderedList {
+  background-position: -432px;
+}
+
+/* Number (ordered) list. */
+.tr-insertOrderedList {
+  background-position: -176px;
+}
+
+/* Number list in right-to-left text mode, regardless of chrome direction. */
+.tr-rtl-mode .tr-insertOrderedList {
+  background-position: -448px;
+}
+
+/* Text alignment buttons. */
+.tr-justifyLeft {
+  background-position: -192px;
+}
+.tr-justifyCenter {
+  background-position: -208px;
+}
+.tr-justifyRight {
+  background-position: -224px;
+}
+.tr-justifyFull {
+  background-position: -480px;
+}
+
+/* Blockquote. */
+.tr-BLOCKQUOTE {
+  background-position: -240px;
+}
+
+/* Blockquote in right-to-left text mode, regardless of chrome direction. */
+.tr-rtl-mode .tr-BLOCKQUOTE {
+  background-position: -464px;
+}
+
+/* Remove formatting. */
+.tr-removeFormat {
+  background-position: -256px;
+}
+
+/* Spellcheck. */
+.tr-spell {
+  background-position: -272px;
+}
+
+/* Left-to-right text direction. */
+.tr-ltr {
+  background-position: -288px;
+}
+
+/* Right-to-left text direction. */
+.tr-rtl {
+  background-position: -304px;
+}
+
+/* Insert iGoogle module. */
+.tr-insertModule {
+  background-position: -496px;
+}
+
+/* Strike through text */
+.tr-strikeThrough {
+  background-position: -544px;
+}
+
+/* Subscript */
+.tr-subscript {
+  background-position: -560px;
+}
+
+/* Superscript */
+.tr-superscript {
+  background-position: -576px;
+}
+
+/* Insert drawing. */
+.tr-equation {
+  background-position: -608px;
+}
+
+/* Edit HTML. */
+.tr-editHtml {
+  color: #009;
+}
+
+/* "Format block" menu. */
+.tr-formatBlock .goog-toolbar-menu-button-caption {
+  color: #246;
+  width: 12ex;
+  height: 16px;
+  overflow: hidden;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/filteredmenu.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/filteredmenu.css b/externs/GCL/externs/goog/css/filteredmenu.css
new file mode 100644
index 0000000..b43a113
--- /dev/null
+++ b/externs/GCL/externs/goog/css/filteredmenu.css
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2007 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: pupius@google.com (Daniel Pupius) */
+
+/* goog.ui.FilteredMenu */
+
+.goog-menu-filter {
+  margin: 2px;
+  border: 1px solid silver;
+  background: white;
+  overflow: hidden;
+}
+
+.goog-menu-filter div {
+  color: gray;
+  position: absolute;
+  padding: 1px;
+}
+
+.goog-menu-filter input {
+  margin: 0;
+  border: 0;
+  background: transparent;
+  width: 100%;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/filterobservingmenuitem.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/filterobservingmenuitem.css b/externs/GCL/externs/goog/css/filterobservingmenuitem.css
new file mode 100644
index 0000000..d48a609
--- /dev/null
+++ b/externs/GCL/externs/goog/css/filterobservingmenuitem.css
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2007 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: pupius@google.com (Daniel Pupius) */
+
+/* goog.ui.FilterObservingMenuItem */
+
+.goog-filterobsmenuitem {
+  padding: 2px 5px;
+  margin: 0;
+  list-style: none;
+}
+
+.goog-filterobsmenuitem-highlight {
+  background-color: #4279A5;
+  color: #FFF;
+}
+
+.goog-filterobsmenuitem-disabled {
+  color: #999;
+}


[03/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/i18n/compactnumberformatsymbols.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/i18n/compactnumberformatsymbols.js b/externs/GCL/externs/goog/i18n/compactnumberformatsymbols.js
new file mode 100644
index 0000000..29b4abb
--- /dev/null
+++ b/externs/GCL/externs/goog/i18n/compactnumberformatsymbols.js
@@ -0,0 +1,9763 @@
+// Copyright 2013 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 Compact number formatting symbols.
+ *
+ * This file is autogenerated by script:
+ * http://go/generate_number_constants.py
+ * using the --for_closure flag.
+ * File generated from CLDR ver. 27.0.1
+ *
+ * To reduce the file size (which may cause issues in some JS
+ * developing environments), this file will only contain locales
+ * that are frequently used by web applications. This is defined as
+ * closure_tier1_locales and will change (most likely addition)
+ * over time.  Rest of the data can be found in another file named
+ * "compactnumberformatsymbols_ext.js", which will be generated at
+ * the same time together with this file.
+ *
+ * Before checkin, this file could have been manually edited. This is
+ * to incorporate changes before we could fix CLDR. All manual
+ * modification must be documented in this section, and should be
+ * removed after those changes land to CLDR.
+ */
+
+goog.provide('goog.i18n.CompactNumberFormatSymbols');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_af');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_af_ZA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_am');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_am_ET');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_001');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ar_EG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_az');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_az_Latn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_az_Latn_AZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bg');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bg_BG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_bn_BD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_br');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_br_FR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ca');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ca_AD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ca_ES');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ca_ES_VALENCIA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ca_FR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ca_IT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_chr');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_chr_US');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_cs');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_cs_CZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_cy');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_cy_GB');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_da');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_da_DK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_da_GL');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_de');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_de_AT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_de_BE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_de_CH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_de_DE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_de_LU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_el');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_el_CY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_el_GR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_001');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_AS');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_AU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_DG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_FM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_GB');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_GU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_IE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_IO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_MH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_MP');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_PR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_PW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_SG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_TC');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_UM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_US');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_VG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_VI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_ZA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_en_ZW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_419');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_EA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_ES');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_es_IC');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_et');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_et_EE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_eu');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_eu_ES');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fa');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fa_IR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fi');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fi_FI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fil');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fil_PH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_BL');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_CA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_FR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_GF');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_GP');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_MC');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_MF');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_MQ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_PM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_RE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_fr_YT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ga');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ga_IE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_gl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_gl_ES');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_gsw');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_gsw_CH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_gsw_LI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_gu');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_gu_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_haw');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_haw_US');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_he');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_he_IL');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_hi');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_hi_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_hr');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_hr_HR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_hu');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_hu_HU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_hy');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_hy_AM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_id');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_id_ID');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_in');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_is');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_is_IS');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_it');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_it_IT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_it_SM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_iw');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ja');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ja_JP');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ka');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ka_GE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kk');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kk_Cyrl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kk_Cyrl_KZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_km');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_km_KH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_kn_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ko');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ko_KR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ky');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ky_Cyrl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ky_Cyrl_KG');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ln');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ln_CD');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lo');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lo_LA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lt');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lt_LT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lv');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_lv_LV');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mk');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mk_MK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ml');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ml_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mn_Cyrl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mn_Cyrl_MN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mr');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mr_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ms');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ms_Latn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ms_Latn_MY');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mt');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_mt_MT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_my');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_my_MM');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nb');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nb_NO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nb_SJ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ne');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ne_NP');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_nl_NL');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_no');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_no_NO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_or');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_or_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pa');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pa_Guru');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pa_Guru_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pl_PL');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pt');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pt_BR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_pt_PT');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ro');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ro_RO');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ru');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ru_RU');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_si');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_si_LK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sk');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sk_SK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sl_SI');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sq');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sq_AL');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sr');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sr_Cyrl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sr_Cyrl_RS');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sv');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sv_SE');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sw');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_sw_TZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ta');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ta_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_te');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_te_IN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_th');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_th_TH');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_tl');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_tr');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_tr_TR');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_uk');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_uk_UA');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ur');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_ur_PK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_uz');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_uz_Latn');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_uz_Latn_UZ');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_vi');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_vi_VN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh_CN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh_HK');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh_Hans');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh_Hans_CN');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zh_TW');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zu');
+goog.provide('goog.i18n.CompactNumberFormatSymbols_zu_ZA');
+
+
+/**
+ * Compact number formatting symbols for locale af.
+ */
+goog.i18n.CompactNumberFormatSymbols_af = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0'
+    },
+    '10000': {
+      'other': '0'
+    },
+    '100000': {
+      'other': '0'
+    },
+    '1000000': {
+      'other': '0\u00A0m'
+    },
+    '10000000': {
+      'other': '00\u00A0m'
+    },
+    '100000000': {
+      'other': '000\u00A0m'
+    },
+    '1000000000': {
+      'other': '0\u00A0mjd'
+    },
+    '10000000000': {
+      'other': '00\u00A0mjd'
+    },
+    '100000000000': {
+      'other': '000\u00A0mjd'
+    },
+    '1000000000000': {
+      'other': '0\u00A0bn'
+    },
+    '10000000000000': {
+      'other': '00\u00A0bn'
+    },
+    '100000000000000': {
+      'other': '000\u00A0bn'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 duisend'
+    },
+    '10000': {
+      'other': '00 duisend'
+    },
+    '100000': {
+      'other': '000 duisend'
+    },
+    '1000000': {
+      'other': '0 miljoen'
+    },
+    '10000000': {
+      'other': '00 miljoen'
+    },
+    '100000000': {
+      'other': '000 miljoen'
+    },
+    '1000000000': {
+      'other': '0 miljard'
+    },
+    '10000000000': {
+      'other': '00 miljard'
+    },
+    '100000000000': {
+      'other': '000 miljard'
+    },
+    '1000000000000': {
+      'other': '0 biljoen'
+    },
+    '10000000000000': {
+      'other': '00 biljoen'
+    },
+    '100000000000000': {
+      'other': '000 biljoen'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale af_ZA.
+ */
+goog.i18n.CompactNumberFormatSymbols_af_ZA =
+    goog.i18n.CompactNumberFormatSymbols_af;
+
+
+/**
+ * Compact number formatting symbols for locale am.
+ */
+goog.i18n.CompactNumberFormatSymbols_am = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u123A'
+    },
+    '10000': {
+      'other': '00\u00A0\u123A'
+    },
+    '100000': {
+      'other': '000\u00A0\u123A'
+    },
+    '1000000': {
+      'other': '0\u00A0\u121C\u1275\u122D'
+    },
+    '10000000': {
+      'other': '00\u00A0\u121C\u1275\u122D'
+    },
+    '100000000': {
+      'other': '000\u00A0\u121C\u1275\u122D'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u1262'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u1262'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u1262'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u1275'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u1275'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u1275'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u123A'
+    },
+    '10000': {
+      'other': '00 \u123A'
+    },
+    '100000': {
+      'other': '000 \u123A'
+    },
+    '1000000': {
+      'other': '0 \u121A\u120A\u12EE\u1295'
+    },
+    '10000000': {
+      'other': '00 \u121A\u120A\u12EE\u1295'
+    },
+    '100000000': {
+      'other': '000 \u121A\u120A\u12EE\u1295'
+    },
+    '1000000000': {
+      'other': '0 \u1262\u120A\u12EE\u1295'
+    },
+    '10000000000': {
+      'other': '00 \u1262\u120A\u12EE\u1295'
+    },
+    '100000000000': {
+      'other': '000 \u1262\u120A\u12EE\u1295'
+    },
+    '1000000000000': {
+      'other': '0 \u1275\u122A\u120A\u12EE\u1295'
+    },
+    '10000000000000': {
+      'other': '00 \u1275\u122A\u120A\u12EE\u1295'
+    },
+    '100000000000000': {
+      'other': '000 \u1275\u122A\u120A\u12EE\u1295'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale am_ET.
+ */
+goog.i18n.CompactNumberFormatSymbols_am_ET =
+    goog.i18n.CompactNumberFormatSymbols_am;
+
+
+/**
+ * Compact number formatting symbols for locale ar.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00\u00A0\u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000\u00A0\u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '10000000': {
+      'other': '00\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '100000000': {
+      'other': '000\u00A0\u0645\u0644\u064A\u0648'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u0628\u0644\u064A\u0648'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u062A\u0631\u0644\u064A\u0648'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u062A\u0631\u0644\u064A\u0648'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0623\u0644\u0641'
+    },
+    '10000': {
+      'other': '00 \u0623\u0644\u0641'
+    },
+    '100000': {
+      'other': '000 \u0623\u0644\u0641'
+    },
+    '1000000': {
+      'other': '0 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u0644\u064A\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '10000000000': {
+      'other': '00 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '100000000000': {
+      'other': '000 \u0628\u0644\u064A\u0648\u0646'
+    },
+    '1000000000000': {
+      'other': '0 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '10000000000000': {
+      'other': '00 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    },
+    '100000000000000': {
+      'other': '000 \u062A\u0631\u064A\u0644\u064A\u0648\u0646'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ar_001.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_001 =
+    goog.i18n.CompactNumberFormatSymbols_ar;
+
+
+/**
+ * Compact number formatting symbols for locale ar_EG.
+ */
+goog.i18n.CompactNumberFormatSymbols_ar_EG =
+    goog.i18n.CompactNumberFormatSymbols_ar;
+
+
+/**
+ * Compact number formatting symbols for locale az.
+ */
+goog.i18n.CompactNumberFormatSymbols_az = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0G'
+    },
+    '10000000000': {
+      'other': '00G'
+    },
+    '100000000000': {
+      'other': '000G'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0G'
+    },
+    '10000000000': {
+      'other': '00G'
+    },
+    '100000000000': {
+      'other': '000G'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale az_Latn.
+ */
+goog.i18n.CompactNumberFormatSymbols_az_Latn =
+    goog.i18n.CompactNumberFormatSymbols_az;
+
+
+/**
+ * Compact number formatting symbols for locale az_Latn_AZ.
+ */
+goog.i18n.CompactNumberFormatSymbols_az_Latn_AZ =
+    goog.i18n.CompactNumberFormatSymbols_az;
+
+
+/**
+ * Compact number formatting symbols for locale bg.
+ */
+goog.i18n.CompactNumberFormatSymbols_bg = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0445\u0438\u043B.'
+    },
+    '10000': {
+      'other': '00\u00A0\u0445\u0438\u043B.'
+    },
+    '100000': {
+      'other': '000\u00A0\u0445\u0438\u043B.'
+    },
+    '1000000': {
+      'other': '0\u00A0\u043C\u043B\u043D.'
+    },
+    '10000000': {
+      'other': '00\u00A0\u043C\u043B\u043D.'
+    },
+    '100000000': {
+      'other': '000\u00A0\u043C\u043B\u043D.'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u043C\u043B\u0440\u0434.'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u043C\u043B\u0440\u0434.'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u043C\u043B\u0440\u0434.'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u0442\u0440\u043B\u043D.'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u0442\u0440\u043B\u043D.'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u0442\u0440\u043B\u043D.'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0445\u0438\u043B\u044F\u0434\u0438'
+    },
+    '10000': {
+      'other': '00 \u0445\u0438\u043B\u044F\u0434\u0438'
+    },
+    '100000': {
+      'other': '000 \u0445\u0438\u043B\u044F\u0434\u0438'
+    },
+    '1000000': {
+      'other': '0 \u043C\u0438\u043B\u0438\u043E\u043D\u0430'
+    },
+    '10000000': {
+      'other': '00 \u043C\u0438\u043B\u0438\u043E\u043D\u0430'
+    },
+    '100000000': {
+      'other': '000 \u043C\u0438\u043B\u0438\u043E\u043D\u0430'
+    },
+    '1000000000': {
+      'other': '0 \u043C\u0438\u043B\u0438\u0430\u0440\u0434\u0430'
+    },
+    '10000000000': {
+      'other': '00 \u043C\u0438\u043B\u0438\u0430\u0440\u0434\u0430'
+    },
+    '100000000000': {
+      'other': '000 \u043C\u0438\u043B\u0438\u0430\u0440\u0434\u0430'
+    },
+    '1000000000000': {
+      'other': '0 \u0442\u0440\u0438\u043B\u0438\u043E\u043D\u0430'
+    },
+    '10000000000000': {
+      'other': '00 \u0442\u0440\u0438\u043B\u0438\u043E\u043D\u0430'
+    },
+    '100000000000000': {
+      'other': '000 \u0442\u0440\u0438\u043B\u0438\u043E\u043D\u0430'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale bg_BG.
+ */
+goog.i18n.CompactNumberFormatSymbols_bg_BG =
+    goog.i18n.CompactNumberFormatSymbols_bg;
+
+
+/**
+ * Compact number formatting symbols for locale bn.
+ */
+goog.i18n.CompactNumberFormatSymbols_bn = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u09B9\u09BE\u099C\u09BE\u09B0'
+    },
+    '10000': {
+      'other': '00\u00A0\u09B9\u09BE\u099C\u09BE\u09B0'
+    },
+    '100000': {
+      'other': '0\u00A0\u09B2\u09BE\u0996'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0B'
+    },
+    '10000000000': {
+      'other': '00B'
+    },
+    '100000000000': {
+      'other': '000B'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u09B9\u09BE\u099C\u09BE\u09B0'
+    },
+    '10000': {
+      'other': '00 \u09B9\u09BE\u099C\u09BE\u09B0'
+    },
+    '100000': {
+      'other': '0 \u09B2\u09BE\u0996'
+    },
+    '1000000': {
+      'other': '0 \u09AE\u09BF\u09B2\u09BF\u09AF\u09BC\u09A8'
+    },
+    '10000000': {
+      'other': '00 \u09AE\u09BF\u09B2\u09BF\u09AF\u09BC\u09A8'
+    },
+    '100000000': {
+      'other': '000 \u09AE\u09BF\u09B2\u09BF\u09AF\u09BC\u09A8'
+    },
+    '1000000000': {
+      'other': '0 \u09AC\u09BF\u09B2\u09BF\u09AF\u09BC\u09A8'
+    },
+    '10000000000': {
+      'other': '00 \u09AC\u09BF\u09B2\u09BF\u09AF\u09BC\u09A8'
+    },
+    '100000000000': {
+      'other': '000 \u09AC\u09BF\u09B2\u09BF\u09AF\u09BC\u09A8'
+    },
+    '1000000000000': {
+      'other': '0 \u099F\u09CD\u09B0\u09BF\u09B2\u09BF\u09AF\u09BC\u09A8'
+    },
+    '10000000000000': {
+      'other': '00 \u099F\u09CD\u09B0\u09BF\u09B2\u09BF\u09AF\u09BC\u09A8'
+    },
+    '100000000000000': {
+      'other': '000 \u099F\u09CD\u09B0\u09BF\u09B2\u09BF\u09AF\u09BC\u09A8'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale bn_BD.
+ */
+goog.i18n.CompactNumberFormatSymbols_bn_BD =
+    goog.i18n.CompactNumberFormatSymbols_bn;
+
+
+/**
+ * Compact number formatting symbols for locale br.
+ */
+goog.i18n.CompactNumberFormatSymbols_br = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0G'
+    },
+    '10000000000': {
+      'other': '00G'
+    },
+    '100000000000': {
+      'other': '000G'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale br_FR.
+ */
+goog.i18n.CompactNumberFormatSymbols_br_FR =
+    goog.i18n.CompactNumberFormatSymbols_br;
+
+
+/**
+ * Compact number formatting symbols for locale ca.
+ */
+goog.i18n.CompactNumberFormatSymbols_ca = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0m'
+    },
+    '10000': {
+      'other': '00m'
+    },
+    '100000': {
+      'other': '000m'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00\u00A0M'
+    },
+    '100000000': {
+      'other': '000\u00A0M'
+    },
+    '1000000000': {
+      'other': '0000\u00A0M'
+    },
+    '10000000000': {
+      'other': '00mM'
+    },
+    '100000000000': {
+      'other': '000mM'
+    },
+    '1000000000000': {
+      'other': '0B'
+    },
+    '10000000000000': {
+      'other': '00\u00A0B'
+    },
+    '100000000000000': {
+      'other': '000\u00A0B'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 milers'
+    },
+    '10000': {
+      'other': '00 milers'
+    },
+    '100000': {
+      'other': '000 milers'
+    },
+    '1000000': {
+      'other': '0 milions'
+    },
+    '10000000': {
+      'other': '00 milions'
+    },
+    '100000000': {
+      'other': '000 milions'
+    },
+    '1000000000': {
+      'other': '0 milers de milions'
+    },
+    '10000000000': {
+      'other': '00 milers de milions'
+    },
+    '100000000000': {
+      'other': '000 milers de milions'
+    },
+    '1000000000000': {
+      'other': '0 bilions'
+    },
+    '10000000000000': {
+      'other': '00 bilions'
+    },
+    '100000000000000': {
+      'other': '000 bilions'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ca_AD.
+ */
+goog.i18n.CompactNumberFormatSymbols_ca_AD =
+    goog.i18n.CompactNumberFormatSymbols_ca;
+
+
+/**
+ * Compact number formatting symbols for locale ca_ES.
+ */
+goog.i18n.CompactNumberFormatSymbols_ca_ES =
+    goog.i18n.CompactNumberFormatSymbols_ca;
+
+
+/**
+ * Compact number formatting symbols for locale ca_ES_VALENCIA.
+ */
+goog.i18n.CompactNumberFormatSymbols_ca_ES_VALENCIA =
+    goog.i18n.CompactNumberFormatSymbols_ca;
+
+
+/**
+ * Compact number formatting symbols for locale ca_FR.
+ */
+goog.i18n.CompactNumberFormatSymbols_ca_FR =
+    goog.i18n.CompactNumberFormatSymbols_ca;
+
+
+/**
+ * Compact number formatting symbols for locale ca_IT.
+ */
+goog.i18n.CompactNumberFormatSymbols_ca_IT =
+    goog.i18n.CompactNumberFormatSymbols_ca;
+
+
+/**
+ * Compact number formatting symbols for locale chr.
+ */
+goog.i18n.CompactNumberFormatSymbols_chr = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0G'
+    },
+    '10000000000': {
+      'other': '00G'
+    },
+    '100000000000': {
+      'other': '000G'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale chr_US.
+ */
+goog.i18n.CompactNumberFormatSymbols_chr_US =
+    goog.i18n.CompactNumberFormatSymbols_chr;
+
+
+/**
+ * Compact number formatting symbols for locale cs.
+ */
+goog.i18n.CompactNumberFormatSymbols_cs = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0tis.'
+    },
+    '10000': {
+      'other': '00\u00A0tis.'
+    },
+    '100000': {
+      'other': '000\u00A0tis.'
+    },
+    '1000000': {
+      'other': '0\u00A0mil.'
+    },
+    '10000000': {
+      'other': '00\u00A0mil.'
+    },
+    '100000000': {
+      'other': '000\u00A0mil.'
+    },
+    '1000000000': {
+      'other': '0\u00A0mld.'
+    },
+    '10000000000': {
+      'other': '00\u00A0mld.'
+    },
+    '100000000000': {
+      'other': '000\u00A0mld.'
+    },
+    '1000000000000': {
+      'other': '0\u00A0bil.'
+    },
+    '10000000000000': {
+      'other': '00\u00A0bil.'
+    },
+    '100000000000000': {
+      'other': '000\u00A0bil.'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 tis\u00EDc'
+    },
+    '10000': {
+      'other': '00 tis\u00EDc'
+    },
+    '100000': {
+      'other': '000 tis\u00EDc'
+    },
+    '1000000': {
+      'other': '0 milion\u016F'
+    },
+    '10000000': {
+      'other': '00 milion\u016F'
+    },
+    '100000000': {
+      'other': '000 milion\u016F'
+    },
+    '1000000000': {
+      'other': '0 miliard'
+    },
+    '10000000000': {
+      'other': '00 miliard'
+    },
+    '100000000000': {
+      'other': '000 miliard'
+    },
+    '1000000000000': {
+      'other': '0 bilion\u016F'
+    },
+    '10000000000000': {
+      'other': '00 bilion\u016F'
+    },
+    '100000000000000': {
+      'other': '000 bilion\u016F'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale cs_CZ.
+ */
+goog.i18n.CompactNumberFormatSymbols_cs_CZ =
+    goog.i18n.CompactNumberFormatSymbols_cs;
+
+
+/**
+ * Compact number formatting symbols for locale cy.
+ */
+goog.i18n.CompactNumberFormatSymbols_cy = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0B'
+    },
+    '10000000000': {
+      'other': '00B'
+    },
+    '100000000000': {
+      'other': '000B'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 mil'
+    },
+    '10000': {
+      'other': '00 mil'
+    },
+    '100000': {
+      'other': '000 mil'
+    },
+    '1000000': {
+      'other': '0 miliwn'
+    },
+    '10000000': {
+      'other': '00 miliwn'
+    },
+    '100000000': {
+      'other': '000 miliwn'
+    },
+    '1000000000': {
+      'other': '0 biliwn'
+    },
+    '10000000000': {
+      'other': '00 biliwn'
+    },
+    '100000000000': {
+      'other': '000 biliwn'
+    },
+    '1000000000000': {
+      'other': '0 triliwn'
+    },
+    '10000000000000': {
+      'other': '00 triliwn'
+    },
+    '100000000000000': {
+      'other': '000 triliwn'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale cy_GB.
+ */
+goog.i18n.CompactNumberFormatSymbols_cy_GB =
+    goog.i18n.CompactNumberFormatSymbols_cy;
+
+
+/**
+ * Compact number formatting symbols for locale da.
+ */
+goog.i18n.CompactNumberFormatSymbols_da = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0td'
+    },
+    '10000': {
+      'other': '00\u00A0td'
+    },
+    '100000': {
+      'other': '000\u00A0td'
+    },
+    '1000000': {
+      'other': '0\u00A0mio'
+    },
+    '10000000': {
+      'other': '00\u00A0mio'
+    },
+    '100000000': {
+      'other': '000\u00A0mio'
+    },
+    '1000000000': {
+      'other': '0\u00A0mia'
+    },
+    '10000000000': {
+      'other': '00\u00A0mia'
+    },
+    '100000000000': {
+      'other': '000\u00A0mia'
+    },
+    '1000000000000': {
+      'other': '0\u00A0bill'
+    },
+    '10000000000000': {
+      'other': '00\u00A0bill'
+    },
+    '100000000000000': {
+      'other': '000\u00A0bill'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 tusind'
+    },
+    '10000': {
+      'other': '00 tusind'
+    },
+    '100000': {
+      'other': '000 tusind'
+    },
+    '1000000': {
+      'other': '0 millioner'
+    },
+    '10000000': {
+      'other': '00 millioner'
+    },
+    '100000000': {
+      'other': '000 millioner'
+    },
+    '1000000000': {
+      'other': '0 milliarder'
+    },
+    '10000000000': {
+      'other': '00 milliarder'
+    },
+    '100000000000': {
+      'other': '000 milliarder'
+    },
+    '1000000000000': {
+      'other': '0 billioner'
+    },
+    '10000000000000': {
+      'other': '00 billioner'
+    },
+    '100000000000000': {
+      'other': '000 billioner'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale da_DK.
+ */
+goog.i18n.CompactNumberFormatSymbols_da_DK =
+    goog.i18n.CompactNumberFormatSymbols_da;
+
+
+/**
+ * Compact number formatting symbols for locale da_GL.
+ */
+goog.i18n.CompactNumberFormatSymbols_da_GL =
+    goog.i18n.CompactNumberFormatSymbols_da;
+
+
+/**
+ * Compact number formatting symbols for locale de.
+ */
+goog.i18n.CompactNumberFormatSymbols_de = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0Tsd.'
+    },
+    '10000': {
+      'other': '00\u00A0Tsd.'
+    },
+    '100000': {
+      'other': '000\u00A0Tsd.'
+    },
+    '1000000': {
+      'other': '0\u00A0Mio.'
+    },
+    '10000000': {
+      'other': '00\u00A0Mio.'
+    },
+    '100000000': {
+      'other': '000\u00A0Mio.'
+    },
+    '1000000000': {
+      'other': '0\u00A0Mrd.'
+    },
+    '10000000000': {
+      'other': '00\u00A0Mrd.'
+    },
+    '100000000000': {
+      'other': '000\u00A0Mrd.'
+    },
+    '1000000000000': {
+      'other': '0\u00A0Bio.'
+    },
+    '10000000000000': {
+      'other': '00\u00A0Bio.'
+    },
+    '100000000000000': {
+      'other': '000\u00A0Bio.'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 Tausend'
+    },
+    '10000': {
+      'other': '00 Tausend'
+    },
+    '100000': {
+      'other': '000 Tausend'
+    },
+    '1000000': {
+      'other': '0 Millionen'
+    },
+    '10000000': {
+      'other': '00 Millionen'
+    },
+    '100000000': {
+      'other': '000 Millionen'
+    },
+    '1000000000': {
+      'other': '0 Milliarden'
+    },
+    '10000000000': {
+      'other': '00 Milliarden'
+    },
+    '100000000000': {
+      'other': '000 Milliarden'
+    },
+    '1000000000000': {
+      'other': '0 Billionen'
+    },
+    '10000000000000': {
+      'other': '00 Billionen'
+    },
+    '100000000000000': {
+      'other': '000 Billionen'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale de_AT.
+ */
+goog.i18n.CompactNumberFormatSymbols_de_AT = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0Tsd.'
+    },
+    '10000': {
+      'other': '00\u00A0Tsd.'
+    },
+    '100000': {
+      'other': '000\u00A0Tsd.'
+    },
+    '1000000': {
+      'other': '0\u00A0Mio.'
+    },
+    '10000000': {
+      'other': '00\u00A0Mio.'
+    },
+    '100000000': {
+      'other': '000\u00A0Mio.'
+    },
+    '1000000000': {
+      'other': '0\u00A0Mrd.'
+    },
+    '10000000000': {
+      'other': '00\u00A0Mrd.'
+    },
+    '100000000000': {
+      'other': '000\u00A0Mrd.'
+    },
+    '1000000000000': {
+      'other': '0\u00A0Bio.'
+    },
+    '10000000000000': {
+      'other': '00\u00A0Bio.'
+    },
+    '100000000000000': {
+      'other': '000\u00A0Bio.'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 Tausend'
+    },
+    '10000': {
+      'other': '00 Tausend'
+    },
+    '100000': {
+      'other': '000 Tausend'
+    },
+    '1000000': {
+      'other': '0 Millionen'
+    },
+    '10000000': {
+      'other': '00 Millionen'
+    },
+    '100000000': {
+      'other': '000 Millionen'
+    },
+    '1000000000': {
+      'other': '0 Milliarden'
+    },
+    '10000000000': {
+      'other': '00 Milliarden'
+    },
+    '100000000000': {
+      'other': '000 Milliarden'
+    },
+    '1000000000000': {
+      'other': '0 Billionen'
+    },
+    '10000000000000': {
+      'other': '00 Billionen'
+    },
+    '100000000000000': {
+      'other': '000 Billionen'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale de_BE.
+ */
+goog.i18n.CompactNumberFormatSymbols_de_BE =
+    goog.i18n.CompactNumberFormatSymbols_de;
+
+
+/**
+ * Compact number formatting symbols for locale de_CH.
+ */
+goog.i18n.CompactNumberFormatSymbols_de_CH = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0Tsd.'
+    },
+    '10000': {
+      'other': '00\u00A0Tsd.'
+    },
+    '100000': {
+      'other': '000\u00A0Tsd.'
+    },
+    '1000000': {
+      'other': '0\u00A0Mio.'
+    },
+    '10000000': {
+      'other': '00\u00A0Mio.'
+    },
+    '100000000': {
+      'other': '000\u00A0Mio.'
+    },
+    '1000000000': {
+      'other': '0\u00A0Mrd.'
+    },
+    '10000000000': {
+      'other': '00\u00A0Mrd.'
+    },
+    '100000000000': {
+      'other': '000\u00A0Mrd.'
+    },
+    '1000000000000': {
+      'other': '0\u00A0Bio.'
+    },
+    '10000000000000': {
+      'other': '00\u00A0Bio.'
+    },
+    '100000000000000': {
+      'other': '000\u00A0Bio.'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 Tausend'
+    },
+    '10000': {
+      'other': '00 Tausend'
+    },
+    '100000': {
+      'other': '000 Tausend'
+    },
+    '1000000': {
+      'other': '0 Millionen'
+    },
+    '10000000': {
+      'other': '00 Millionen'
+    },
+    '100000000': {
+      'other': '000 Millionen'
+    },
+    '1000000000': {
+      'other': '0 Milliarden'
+    },
+    '10000000000': {
+      'other': '00 Milliarden'
+    },
+    '100000000000': {
+      'other': '000 Milliarden'
+    },
+    '1000000000000': {
+      'other': '0 Billionen'
+    },
+    '10000000000000': {
+      'other': '00 Billionen'
+    },
+    '100000000000000': {
+      'other': '000 Billionen'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale de_DE.
+ */
+goog.i18n.CompactNumberFormatSymbols_de_DE =
+    goog.i18n.CompactNumberFormatSymbols_de;
+
+
+/**
+ * Compact number formatting symbols for locale de_LU.
+ */
+goog.i18n.CompactNumberFormatSymbols_de_LU =
+    goog.i18n.CompactNumberFormatSymbols_de;
+
+
+/**
+ * Compact number formatting symbols for locale el.
+ */
+goog.i18n.CompactNumberFormatSymbols_el = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u03C7\u03B9\u03BB.'
+    },
+    '10000': {
+      'other': '00\u00A0\u03C7\u03B9\u03BB.'
+    },
+    '100000': {
+      'other': '000\u00A0\u03C7\u03B9\u03BB.'
+    },
+    '1000000': {
+      'other': '0\u00A0\u03B5\u03BA.'
+    },
+    '10000000': {
+      'other': '00\u00A0\u03B5\u03BA.'
+    },
+    '100000000': {
+      'other': '000\u00A0\u03B5\u03BA.'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u03B4\u03B9\u03C3.'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u03B4\u03B9\u03C3.'
+    },
+    '100000000000': {
+      'other': '000\u00A0\u03B4\u03B9\u03C3.'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u03C4\u03C1\u03B9\u03C3.'
+    },
+    '10000000000000': {
+      'other': '00\u00A0\u03C4\u03C1\u03B9\u03C3.'
+    },
+    '100000000000000': {
+      'other': '000\u00A0\u03C4\u03C1\u03B9\u03C3.'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u03C7\u03B9\u03BB\u03B9\u03AC\u03B4\u03B5\u03C2'
+    },
+    '10000': {
+      'other': '00 \u03C7\u03B9\u03BB\u03B9\u03AC\u03B4\u03B5\u03C2'
+    },
+    '100000': {
+      'other': '000 \u03C7\u03B9\u03BB\u03B9\u03AC\u03B4\u03B5\u03C2'
+    },
+    '1000000': {
+      'other': '0 \u03B5\u03BA\u03B1\u03C4\u03BF\u03BC\u03BC\u03CD\u03C1\u03B9\u03B1'
+    },
+    '10000000': {
+      'other': '00 \u03B5\u03BA\u03B1\u03C4\u03BF\u03BC\u03BC\u03CD\u03C1\u03B9\u03B1'
+    },
+    '100000000': {
+      'other': '000 \u03B5\u03BA\u03B1\u03C4\u03BF\u03BC\u03BC\u03CD\u03C1\u03B9\u03B1'
+    },
+    '1000000000': {
+      'other': '0 \u03B4\u03B9\u03C3\u03B5\u03BA\u03B1\u03C4\u03BF\u03BC\u03BC\u03CD\u03C1\u03B9\u03B1'
+    },
+    '10000000000': {
+      'other': '00 \u03B4\u03B9\u03C3\u03B5\u03BA\u03B1\u03C4\u03BF\u03BC\u03BC\u03CD\u03C1\u03B9\u03B1'
+    },
+    '100000000000': {
+      'other': '000 \u03B4\u03B9\u03C3\u03B5\u03BA\u03B1\u03C4\u03BF\u03BC\u03BC\u03CD\u03C1\u03B9\u03B1'
+    },
+    '1000000000000': {
+      'other': '0 \u03C4\u03C1\u03B9\u03C3\u03B5\u03BA\u03B1\u03C4\u03BF\u03BC\u03BC\u03CD\u03C1\u03B9\u03B1'
+    },
+    '10000000000000': {
+      'other': '00 \u03C4\u03C1\u03B9\u03C3\u03B5\u03BA\u03B1\u03C4\u03BF\u03BC\u03BC\u03CD\u03C1\u03B9\u03B1'
+    },
+    '100000000000000': {
+      'other': '000 \u03C4\u03C1\u03B9\u03C3\u03B5\u03BA\u03B1\u03C4\u03BF\u03BC\u03BC\u03CD\u03C1\u03B9\u03B1'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale el_CY.
+ */
+goog.i18n.CompactNumberFormatSymbols_el_CY =
+    goog.i18n.CompactNumberFormatSymbols_el;
+
+
+/**
+ * Compact number formatting symbols for locale el_GR.
+ */
+goog.i18n.CompactNumberFormatSymbols_el_GR =
+    goog.i18n.CompactNumberFormatSymbols_el;
+
+
+/**
+ * Compact number formatting symbols for locale en.
+ */
+goog.i18n.CompactNumberFormatSymbols_en = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0B'
+    },
+    '10000000000': {
+      'other': '00B'
+    },
+    '100000000000': {
+      'other': '000B'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 thousand'
+    },
+    '10000': {
+      'other': '00 thousand'
+    },
+    '100000': {
+      'other': '000 thousand'
+    },
+    '1000000': {
+      'other': '0 million'
+    },
+    '10000000': {
+      'other': '00 million'
+    },
+    '100000000': {
+      'other': '000 million'
+    },
+    '1000000000': {
+      'other': '0 billion'
+    },
+    '10000000000': {
+      'other': '00 billion'
+    },
+    '100000000000': {
+      'other': '000 billion'
+    },
+    '1000000000000': {
+      'other': '0 trillion'
+    },
+    '10000000000000': {
+      'other': '00 trillion'
+    },
+    '100000000000000': {
+      'other': '000 trillion'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale en_001.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_001 =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_AS.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_AS =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_AU.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_AU = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0B'
+    },
+    '10000000000': {
+      'other': '00B'
+    },
+    '100000000000': {
+      'other': '000B'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 thousand'
+    },
+    '10000': {
+      'other': '00 thousand'
+    },
+    '100000': {
+      'other': '000 thousand'
+    },
+    '1000000': {
+      'other': '0 million'
+    },
+    '10000000': {
+      'other': '00 million'
+    },
+    '100000000': {
+      'other': '000 million'
+    },
+    '1000000000': {
+      'other': '0 billion'
+    },
+    '10000000000': {
+      'other': '00 billion'
+    },
+    '100000000000': {
+      'other': '000 billion'
+    },
+    '1000000000000': {
+      'other': '0 trillion'
+    },
+    '10000000000000': {
+      'other': '00 trillion'
+    },
+    '100000000000000': {
+      'other': '000 trillion'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale en_DG.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_DG =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_FM.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_FM =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_GB.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_GB = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0B'
+    },
+    '10000000000': {
+      'other': '00B'
+    },
+    '100000000000': {
+      'other': '000B'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 thousand'
+    },
+    '10000': {
+      'other': '00 thousand'
+    },
+    '100000': {
+      'other': '000 thousand'
+    },
+    '1000000': {
+      'other': '0 million'
+    },
+    '10000000': {
+      'other': '00 million'
+    },
+    '100000000': {
+      'other': '000 million'
+    },
+    '1000000000': {
+      'other': '0 billion'
+    },
+    '10000000000': {
+      'other': '00 billion'
+    },
+    '100000000000': {
+      'other': '000 billion'
+    },
+    '1000000000000': {
+      'other': '0 trillion'
+    },
+    '10000000000000': {
+      'other': '00 trillion'
+    },
+    '100000000000000': {
+      'other': '000 trillion'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale en_GU.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_GU =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_IE.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_IE = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0B'
+    },
+    '10000000000': {
+      'other': '00B'
+    },
+    '100000000000': {
+      'other': '000B'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 thousand'
+    },
+    '10000': {
+      'other': '00 thousand'
+    },
+    '100000': {
+      'other': '000 thousand'
+    },
+    '1000000': {
+      'other': '0 million'
+    },
+    '10000000': {
+      'other': '00 million'
+    },
+    '100000000': {
+      'other': '000 million'
+    },
+    '1000000000': {
+      'other': '0 billion'
+    },
+    '10000000000': {
+      'other': '00 billion'
+    },
+    '100000000000': {
+      'other': '000 billion'
+    },
+    '1000000000000': {
+      'other': '0 trillion'
+    },
+    '10000000000000': {
+      'other': '00 trillion'
+    },
+    '100000000000000': {
+      'other': '000 trillion'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale en_IN.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_IN = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0B'
+    },
+    '10000000000': {
+      'other': '00B'
+    },
+    '100000000000': {
+      'other': '000B'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 thousand'
+    },
+    '10000': {
+      'other': '00 thousand'
+    },
+    '100000': {
+      'other': '000 thousand'
+    },
+    '1000000': {
+      'other': '0 million'
+    },
+    '10000000': {
+      'other': '00 million'
+    },
+    '100000000': {
+      'other': '000 million'
+    },
+    '1000000000': {
+      'other': '0 billion'
+    },
+    '10000000000': {
+      'other': '00 billion'
+    },
+    '100000000000': {
+      'other': '000 billion'
+    },
+    '1000000000000': {
+      'other': '0 trillion'
+    },
+    '10000000000000': {
+      'other': '00 trillion'
+    },
+    '100000000000000': {
+      'other': '000 trillion'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale en_IO.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_IO =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_MH.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_MH =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_MP.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_MP =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_PR.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_PR =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_PW.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_PW =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_SG.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_SG = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0B'
+    },
+    '10000000000': {
+      'other': '00B'
+    },
+    '100000000000': {
+      'other': '000B'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 thousand'
+    },
+    '10000': {
+      'other': '00 thousand'
+    },
+    '100000': {
+      'other': '000 thousand'
+    },
+    '1000000': {
+      'other': '0 million'
+    },
+    '10000000': {
+      'other': '00 million'
+    },
+    '100000000': {
+      'other': '000 million'
+    },
+    '1000000000': {
+      'other': '0 billion'
+    },
+    '10000000000': {
+      'other': '00 billion'
+    },
+    '100000000000': {
+      'other': '000 billion'
+    },
+    '1000000000000': {
+      'other': '0 trillion'
+    },
+    '10000000000000': {
+      'other': '00 trillion'
+    },
+    '100000000000000': {
+      'other': '000 trillion'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale en_TC.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_TC =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_UM.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_UM =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_US.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_US =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_VG.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_VG =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_VI.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_VI =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale en_ZA.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_ZA = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0B'
+    },
+    '10000000000': {
+      'other': '00B'
+    },
+    '100000000000': {
+      'other': '000B'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 thousand'
+    },
+    '10000': {
+      'other': '00 thousand'
+    },
+    '100000': {
+      'other': '000 thousand'
+    },
+    '1000000': {
+      'other': '0 million'
+    },
+    '10000000': {
+      'other': '00 million'
+    },
+    '100000000': {
+      'other': '000 million'
+    },
+    '1000000000': {
+      'other': '0 billion'
+    },
+    '10000000000': {
+      'other': '00 billion'
+    },
+    '100000000000': {
+      'other': '000 billion'
+    },
+    '1000000000000': {
+      'other': '0 trillion'
+    },
+    '10000000000000': {
+      'other': '00 trillion'
+    },
+    '100000000000000': {
+      'other': '000 trillion'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale en_ZW.
+ */
+goog.i18n.CompactNumberFormatSymbols_en_ZW =
+    goog.i18n.CompactNumberFormatSymbols_en;
+
+
+/**
+ * Compact number formatting symbols for locale es.
+ */
+goog.i18n.CompactNumberFormatSymbols_es = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0K'
+    },
+    '10000': {
+      'other': '00\u00A0K'
+    },
+    '100000': {
+      'other': '000\u00A0K'
+    },
+    '1000000': {
+      'other': '0\u00A0M'
+    },
+    '10000000': {
+      'other': '00\u00A0M'
+    },
+    '100000000': {
+      'other': '000\u00A0M'
+    },
+    '1000000000': {
+      'other': '0000\u00A0M'
+    },
+    '10000000000': {
+      'other': '00\u00A0MRD'
+    },
+    '100000000000': {
+      'other': '000\u00A0MRD'
+    },
+    '1000000000000': {
+      'other': '0\u00A0B'
+    },
+    '10000000000000': {
+      'other': '00\u00A0B'
+    },
+    '100000000000000': {
+      'other': '000\u00A0B'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 mil'
+    },
+    '10000': {
+      'other': '00 mil'
+    },
+    '100000': {
+      'other': '000 mil'
+    },
+    '1000000': {
+      'other': '0 millones'
+    },
+    '10000000': {
+      'other': '00 millones'
+    },
+    '100000000': {
+      'other': '000 millones'
+    },
+    '1000000000': {
+      'other': '0 mil millones'
+    },
+    '10000000000': {
+      'other': '00 mil millones'
+    },
+    '100000000000': {
+      'other': '000 mil millones'
+    },
+    '1000000000000': {
+      'other': '0 billones'
+    },
+    '10000000000000': {
+      'other': '00 billones'
+    },
+    '100000000000000': {
+      'other': '000 billones'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale es_419.
+ */
+goog.i18n.CompactNumberFormatSymbols_es_419 = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0'
+    },
+    '10000': {
+      'other': '00k'
+    },
+    '100000': {
+      'other': '000k'
+    },
+    '1000000': {
+      'other': '0\u00A0M'
+    },
+    '10000000': {
+      'other': '00\u00A0M'
+    },
+    '100000000': {
+      'other': '000\u00A0M'
+    },
+    '1000000000': {
+      'other': '0k\u00A0M'
+    },
+    '10000000000': {
+      'other': '00k\u00A0M'
+    },
+    '100000000000': {
+      'other': '000k\u00A0M'
+    },
+    '1000000000000': {
+      'other': '0\u00A0B'
+    },
+    '10000000000000': {
+      'other': '00\u00A0B'
+    },
+    '100000000000000': {
+      'other': '000\u00A0B'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 mil'
+    },
+    '10000': {
+      'other': '00 mil'
+    },
+    '100000': {
+      'other': '000 mil'
+    },
+    '1000000': {
+      'other': '0 millones'
+    },
+    '10000000': {
+      'other': '00 millones'
+    },
+    '100000000': {
+      'other': '000 millones'
+    },
+    '1000000000': {
+      'other': '0 mil millones'
+    },
+    '10000000000': {
+      'other': '00 mil millones'
+    },
+    '100000000000': {
+      'other': '000 mil millones'
+    },
+    '1000000000000': {
+      'other': '0 billones'
+    },
+    '10000000000000': {
+      'other': '00 billones'
+    },
+    '100000000000000': {
+      'other': '000 billones'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale es_EA.
+ */
+goog.i18n.CompactNumberFormatSymbols_es_EA =
+    goog.i18n.CompactNumberFormatSymbols_es;
+
+
+/**
+ * Compact number formatting symbols for locale es_ES.
+ */
+goog.i18n.CompactNumberFormatSymbols_es_ES =
+    goog.i18n.CompactNumberFormatSymbols_es;
+
+
+/**
+ * Compact number formatting symbols for locale es_IC.
+ */
+goog.i18n.CompactNumberFormatSymbols_es_IC =
+    goog.i18n.CompactNumberFormatSymbols_es;
+
+
+/**
+ * Compact number formatting symbols for locale et.
+ */
+goog.i18n.CompactNumberFormatSymbols_et = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0tuh'
+    },
+    '10000': {
+      'other': '00\u00A0tuh'
+    },
+    '100000': {
+      'other': '000\u00A0tuh'
+    },
+    '1000000': {
+      'other': '0\u00A0mln'
+    },
+    '10000000': {
+      'other': '00\u00A0mln'
+    },
+    '100000000': {
+      'other': '000\u00A0mln'
+    },
+    '1000000000': {
+      'other': '0\u00A0mld'
+    },
+    '10000000000': {
+      'other': '00\u00A0mld'
+    },
+    '100000000000': {
+      'other': '000\u00A0mld'
+    },
+    '1000000000000': {
+      'other': '0\u00A0trl'
+    },
+    '10000000000000': {
+      'other': '00\u00A0trl'
+    },
+    '100000000000000': {
+      'other': '000\u00A0trl'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 tuhat'
+    },
+    '10000': {
+      'other': '00 tuhat'
+    },
+    '100000': {
+      'other': '000 tuhat'
+    },
+    '1000000': {
+      'other': '0 miljonit'
+    },
+    '10000000': {
+      'other': '00 miljonit'
+    },
+    '100000000': {
+      'other': '000 miljonit'
+    },
+    '1000000000': {
+      'other': '0 miljardit'
+    },
+    '10000000000': {
+      'other': '00 miljardit'
+    },
+    '100000000000': {
+      'other': '000 miljardit'
+    },
+    '1000000000000': {
+      'other': '0 triljonit'
+    },
+    '10000000000000': {
+      'other': '00 triljonit'
+    },
+    '100000000000000': {
+      'other': '000 triljonit'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale et_EE.
+ */
+goog.i18n.CompactNumberFormatSymbols_et_EE =
+    goog.i18n.CompactNumberFormatSymbols_et;
+
+
+/**
+ * Compact number formatting symbols for locale eu.
+ */
+goog.i18n.CompactNumberFormatSymbols_eu = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0000'
+    },
+    '10000': {
+      'other': '00000'
+    },
+    '100000': {
+      'other': '000000'
+    },
+    '1000000': {
+      'other': '0\u00A0M'
+    },
+    '10000000': {
+      'other': '00\u00A0M'
+    },
+    '100000000': {
+      'other': '000\u00A0M'
+    },
+    '1000000000': {
+      'other': '0000\u00A0M'
+    },
+    '10000000000': {
+      'other': '00000\u00A0M'
+    },
+    '100000000000': {
+      'other': '000000\u00A0M'
+    },
+    '1000000000000': {
+      'other': '0\u00A0B'
+    },
+    '10000000000000': {
+      'other': '00\u00A0B'
+    },
+    '100000000000000': {
+      'other': '000\u00A0B'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0000'
+    },
+    '10000': {
+      'other': '00000'
+    },
+    '100000': {
+      'other': '000000'
+    },
+    '1000000': {
+      'other': '0 milioi'
+    },
+    '10000000': {
+      'other': '00 milioi'
+    },
+    '100000000': {
+      'other': '000 milioi'
+    },
+    '1000000000': {
+      'other': '0000 milioi'
+    },
+    '10000000000': {
+      'other': '00000 milioi'
+    },
+    '100000000000': {
+      'other': '000000 milioi'
+    },
+    '1000000000000': {
+      'other': '0 bilioi'
+    },
+    '10000000000000': {
+      'other': '00 bilioi'
+    },
+    '100000000000000': {
+      'other': '000 bilioi'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale eu_ES.
+ */
+goog.i18n.CompactNumberFormatSymbols_eu_ES =
+    goog.i18n.CompactNumberFormatSymbols_eu;
+
+
+/**
+ * Compact number formatting symbols for locale fa.
+ */
+goog.i18n.CompactNumberFormatSymbols_fa = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0G'
+    },
+    '10000000000': {
+      'other': '00G'
+    },
+    '100000000000': {
+      'other': '000G'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0647\u0632\u0627\u0631'
+    },
+    '10000': {
+      'other': '00 \u0647\u0632\u0627\u0631'
+    },
+    '100000': {
+      'other': '000 \u0647\u0632\u0627\u0631'
+    },
+    '1000000': {
+      'other': '0 \u0645\u06CC\u0644\u06CC\u0648\u0646'
+    },
+    '10000000': {
+      'other': '00 \u0645\u06CC\u0644\u06CC\u0648\u0646'
+    },
+    '100000000': {
+      'other': '000 \u0645\u06CC\u0644\u06CC\u0648\u0646'
+    },
+    '1000000000': {
+      'other': '0 \u0645\u06CC\u0644\u06CC\u0627\u0631\u062F'
+    },
+    '10000000000': {
+      'other': '00 \u0645\u06CC\u0644\u06CC\u0627\u0631\u062F'
+    },
+    '100000000000': {
+      'other': '000 \u0645\u06CC\u0644\u06CC\u0627\u0631\u062F'
+    },
+    '1000000000000': {
+      'other': '0 \u0647\u0632\u0627\u0631 \u0645\u06CC\u0644\u06CC\u0627\u0631\u062F'
+    },
+    '10000000000000': {
+      'other': '00 \u0647\u0632\u0627\u0631 \u0645\u06CC\u0644\u06CC\u0627\u0631\u062F'
+    },
+    '100000000000000': {
+      'other': '000 \u0647\u0632\u0627\u0631 \u0645\u06CC\u0644\u06CC\u0627\u0631\u062F'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale fa_IR.
+ */
+goog.i18n.CompactNumberFormatSymbols_fa_IR =
+    goog.i18n.CompactNumberFormatSymbols_fa;
+
+
+/**
+ * Compact number formatting symbols for locale fi.
+ */
+goog.i18n.CompactNumberFormatSymbols_fi = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0t.'
+    },
+    '10000': {
+      'other': '00\u00A0t.'
+    },
+    '100000': {
+      'other': '000\u00A0t.'
+    },
+    '1000000': {
+      'other': '0\u00A0milj.'
+    },
+    '10000000': {
+      'other': '00\u00A0milj.'
+    },
+    '100000000': {
+      'other': '000\u00A0milj.'
+    },
+    '1000000000': {
+      'other': '0\u00A0mrd.'
+    },
+    '10000000000': {
+      'other': '00\u00A0mrd.'
+    },
+    '100000000000': {
+      'other': '000\u00A0mrd.'
+    },
+    '1000000000000': {
+      'other': '0\u00A0bilj.'
+    },
+    '10000000000000': {
+      'other': '00\u00A0bilj.'
+    },
+    '100000000000000': {
+      'other': '000\u00A0bilj.'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 tuhatta'
+    },
+    '10000': {
+      'other': '00 tuhatta'
+    },
+    '100000': {
+      'other': '000 tuhatta'
+    },
+    '1000000': {
+      'other': '0 miljoonaa'
+    },
+    '10000000': {
+      'other': '00 miljoonaa'
+    },
+    '100000000': {
+      'other': '000 miljoonaa'
+    },
+    '1000000000': {
+      'other': '0 miljardia'
+    },
+    '10000000000': {
+      'other': '00 miljardia'
+    },
+    '100000000000': {
+      'other': '000 miljardia'
+    },
+    '1000000000000': {
+      'other': '0 biljoonaa'
+    },
+    '10000000000000': {
+      'other': '00 biljoonaa'
+    },
+    '100000000000000': {
+      'other': '000 biljoonaa'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale fi_FI.
+ */
+goog.i18n.CompactNumberFormatSymbols_fi_FI =
+    goog.i18n.CompactNumberFormatSymbols_fi;
+
+
+/**
+ * Compact number formatting symbols for locale fil.
+ */
+goog.i18n.CompactNumberFormatSymbols_fil = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0B'
+    },
+    '10000000000': {
+      'other': '00B'
+    },
+    '100000000000': {
+      'other': '000B'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 libo'
+    },
+    '10000': {
+      'other': '00 libo'
+    },
+    '100000': {
+      'other': '000 libo'
+    },
+    '1000000': {
+      'other': '0 milyon'
+    },
+    '10000000': {
+      'other': '00 milyon'
+    },
+    '100000000': {
+      'other': '000 milyon'
+    },
+    '1000000000': {
+      'other': '0 bilyon'
+    },
+    '10000000000': {
+      'other': '00 bilyon'
+    },
+    '100000000000': {
+      'other': '000 bilyon'
+    },
+    '1000000000000': {
+      'other': '0 trilyon'
+    },
+    '10000000000000': {
+      'other': '00 trilyon'
+    },
+    '100000000000000': {
+      'other': '000 trilyon'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale fil_PH.
+ */
+goog.i18n.CompactNumberFormatSymbols_fil_PH =
+    goog.i18n.CompactNumberFormatSymbols_fil;
+
+
+/**
+ * Compact number formatting symbols for locale fr.
+ */
+goog.i18n.CompactNumberFormatSymbols_fr = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0k'
+    },
+    '10000': {
+      'other': '00\u00A0k'
+    },
+    '100000': {
+      'other': '000\u00A0k'
+    },
+    '1000000': {
+      'other': '0\u00A0M'
+    },
+    '10000000': {
+      'other': '00\u00A0M'
+    },
+    '100000000': {
+      'other': '000\u00A0M'
+    },
+    '1000000000': {
+      'other': '0\u00A0Md'
+    },
+    '10000000000': {
+      'other': '00\u00A0Md'
+    },
+    '100000000000': {
+      'other': '000\u00A0Md'
+    },
+    '1000000000000': {
+      'other': '0\u00A0Bn'
+    },
+    '10000000000000': {
+      'other': '00\u00A0Bn'
+    },
+    '100000000000000': {
+      'other': '000\u00A0Bn'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 mille'
+    },
+    '10000': {
+      'other': '00 mille'
+    },
+    '100000': {
+      'other': '000 mille'
+    },
+    '1000000': {
+      'other': '0 millions'
+    },
+    '10000000': {
+      'other': '00 millions'
+    },
+    '100000000': {
+      'other': '000 millions'
+    },
+    '1000000000': {
+      'other': '0 milliards'
+    },
+    '10000000000': {
+      'other': '00 milliards'
+    },
+    '100000000000': {
+      'other': '000 milliards'
+    },
+    '1000000000000': {
+      'other': '0 billions'
+    },
+    '10000000000000': {
+      'other': '00 billions'
+    },
+    '100000000000000': {
+      'other': '000 billions'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale fr_BL.
+ */
+goog.i18n.CompactNumberFormatSymbols_fr_BL =
+    goog.i18n.CompactNumberFormatSymbols_fr;
+
+
+/**
+ * Compact number formatting symbols for locale fr_CA.
+ */
+goog.i18n.CompactNumberFormatSymbols_fr_CA = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0k'
+    },
+    '10000': {
+      'other': '00\u00A0k'
+    },
+    '100000': {
+      'other': '000\u00A0k'
+    },
+    '1000000': {
+      'other': '0\u00A0M'
+    },
+    '10000000': {
+      'other': '00\u00A0M'
+    },
+    '100000000': {
+      'other': '000\u00A0M'
+    },
+    '1000000000': {
+      'other': '0\u00A0G'
+    },
+    '10000000000': {
+      'other': '00\u00A0G'
+    },
+    '100000000000': {
+      'other': '000\u00A0G'
+    },
+    '1000000000000': {
+      'other': '0\u00A0T'
+    },
+    '10000000000000': {
+      'other': '00\u00A0T'
+    },
+    '100000000000000': {
+      'other': '000\u00A0T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 mille'
+    },
+    '10000': {
+      'other': '00 mille'
+    },
+    '100000': {
+      'other': '000 mille'
+    },
+    '1000000': {
+      'other': '0 millions'
+    },
+    '10000000': {
+      'other': '00 millions'
+    },
+    '100000000': {
+      'other': '000 millions'
+    },
+    '1000000000': {
+      'other': '0 milliards'
+    },
+    '10000000000': {
+      'other': '00 milliards'
+    },
+    '100000000000': {
+      'other': '000 milliards'
+    },
+    '1000000000000': {
+      'other': '0 billions'
+    },
+    '10000000000000': {
+      'other': '00 billions'
+    },
+    '100000000000000': {
+      'other': '000 billions'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale fr_FR.
+ */
+goog.i18n.CompactNumberFormatSymbols_fr_FR =
+    goog.i18n.CompactNumberFormatSymbols_fr;
+
+
+/**
+ * Compact number formatting symbols for locale fr_GF.
+ */
+goog.i18n.CompactNumberFormatSymbols_fr_GF =
+    goog.i18n.CompactNumberFormatSymbols_fr;
+
+
+/**
+ * Compact number formatting symbols for locale fr_GP.
+ */
+goog.i18n.CompactNumberFormatSymbols_fr_GP =
+    goog.i18n.CompactNumberFormatSymbols_fr;
+
+
+/**
+ * Compact number formatting symbols for locale fr_MC.
+ */
+goog.i18n.CompactNumberFormatSymbols_fr_MC =
+    goog.i18n.CompactNumberFormatSymbols_fr;
+
+
+/**
+ * Compact number formatting symbols for locale fr_MF.
+ */
+goog.i18n.CompactNumberFormatSymbols_fr_MF =
+    goog.i18n.CompactNumberFormatSymbols_fr;
+
+
+/**
+ * Compact number formatting symbols for locale fr_MQ.
+ */
+goog.i18n.CompactNumberFormatSymbols_fr_MQ =
+    goog.i18n.CompactNumberFormatSymbols_fr;
+
+
+/**
+ * Compact number formatting symbols for locale fr_PM.
+ */
+goog.i18n.CompactNumberFormatSymbols_fr_PM =
+    goog.i18n.CompactNumberFormatSymbols_fr;
+
+
+/**
+ * Compact number formatting symbols for locale fr_RE.
+ */
+goog.i18n.CompactNumberFormatSymbols_fr_RE =
+    goog.i18n.CompactNumberFormatSymbols_fr;
+
+
+/**
+ * Compact number formatting symbols for locale fr_YT.
+ */
+goog.i18n.CompactNumberFormatSymbols_fr_YT =
+    goog.i18n.CompactNumberFormatSymbols_fr;
+
+
+/**
+ * Compact number formatting symbols for locale ga.
+ */
+goog.i18n.CompactNumberFormatSymbols_ga = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0k'
+    },
+    '10000': {
+      'other': '00k'
+    },
+    '100000': {
+      'other': '000k'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0B'
+    },
+    '10000000000': {
+      'other': '00B'
+    },
+    '100000000000': {
+      'other': '000B'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 m\u00EDle'
+    },
+    '10000': {
+      'other': '00 m\u00EDle'
+    },
+    '100000': {
+      'other': '000 m\u00EDle'
+    },
+    '1000000': {
+      'other': '0 milli\u00FAn'
+    },
+    '10000000': {
+      'other': '00 milli\u00FAn'
+    },
+    '100000000': {
+      'other': '000 milli\u00FAn'
+    },
+    '1000000000': {
+      'other': '0 billi\u00FAn'
+    },
+    '10000000000': {
+      'other': '00 billi\u00FAn'
+    },
+    '100000000000': {
+      'other': '000 billi\u00FAn'
+    },
+    '1000000000000': {
+      'other': '0 trilli\u00FAn'
+    },
+    '10000000000000': {
+      'other': '00 trilli\u00FAn'
+    },
+    '100000000000000': {
+      'other': '000 trilli\u00FAn'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale ga_IE.
+ */
+goog.i18n.CompactNumberFormatSymbols_ga_IE =
+    goog.i18n.CompactNumberFormatSymbols_ga;
+
+
+/**
+ * Compact number formatting symbols for locale gl.
+ */
+goog.i18n.CompactNumberFormatSymbols_gl = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0k\u00A0M'
+    },
+    '10000000000': {
+      'other': '00k\u00A0M'
+    },
+    '100000000000': {
+      'other': '000k\u00A0M'
+    },
+    '1000000000000': {
+      'other': '0\u00A0B'
+    },
+    '10000000000000': {
+      'other': '00\u00A0B'
+    },
+    '100000000000000': {
+      'other': '000\u00A0B'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 mil'
+    },
+    '10000': {
+      'other': '00 mil'
+    },
+    '100000': {
+      'other': '000 mil'
+    },
+    '1000000': {
+      'other': '0 mill\u00F3ns'
+    },
+    '10000000': {
+      'other': '00 mill\u00F3ns'
+    },
+    '100000000': {
+      'other': '000 mill\u00F3ns'
+    },
+    '1000000000': {
+      'other': '0 mil mill\u00F3ns'
+    },
+    '10000000000': {
+      'other': '00 mil mill\u00F3ns'
+    },
+    '100000000000': {
+      'other': '000 mil mill\u00F3ns'
+    },
+    '1000000000000': {
+      'other': '0 bill\u00F3ns'
+    },
+    '10000000000000': {
+      'other': '00 bill\u00F3ns'
+    },
+    '100000000000000': {
+      'other': '000 bill\u00F3ns'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale gl_ES.
+ */
+goog.i18n.CompactNumberFormatSymbols_gl_ES =
+    goog.i18n.CompactNumberFormatSymbols_gl;
+
+
+/**
+ * Compact number formatting symbols for locale gsw.
+ */
+goog.i18n.CompactNumberFormatSymbols_gsw = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0tsd'
+    },
+    '10000': {
+      'other': '00\u00A0tsd'
+    },
+    '100000': {
+      'other': '000\u00A0tsd'
+    },
+    '1000000': {
+      'other': '0\u00A0Mio'
+    },
+    '10000000': {
+      'other': '00\u00A0Mio'
+    },
+    '100000000': {
+      'other': '000\u00A0Mio'
+    },
+    '1000000000': {
+      'other': '0\u00A0Mrd'
+    },
+    '10000000000': {
+      'other': '00\u00A0Mrd'
+    },
+    '100000000000': {
+      'other': '000\u00A0Mrd'
+    },
+    '1000000000000': {
+      'other': '0\u00A0Bio'
+    },
+    '10000000000000': {
+      'other': '00\u00A0Bio'
+    },
+    '100000000000000': {
+      'other': '000\u00A0Bio'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 tausend'
+    },
+    '10000': {
+      'other': '00 tausend'
+    },
+    '100000': {
+      'other': '000 tausend'
+    },
+    '1000000': {
+      'other': '0 Millionen'
+    },
+    '10000000': {
+      'other': '00 Millionen'
+    },
+    '100000000': {
+      'other': '000 Millionen'
+    },
+    '1000000000': {
+      'other': '0 Milliarden'
+    },
+    '10000000000': {
+      'other': '00 Milliarden'
+    },
+    '100000000000': {
+      'other': '000 Milliarden'
+    },
+    '1000000000000': {
+      'other': '0 Billionen'
+    },
+    '10000000000000': {
+      'other': '00 Billionen'
+    },
+    '100000000000000': {
+      'other': '000 Billionen'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale gsw_CH.
+ */
+goog.i18n.CompactNumberFormatSymbols_gsw_CH =
+    goog.i18n.CompactNumberFormatSymbols_gsw;
+
+
+/**
+ * Compact number formatting symbols for locale gsw_LI.
+ */
+goog.i18n.CompactNumberFormatSymbols_gsw_LI =
+    goog.i18n.CompactNumberFormatSymbols_gsw;
+
+
+/**
+ * Compact number formatting symbols for locale gu.
+ */
+goog.i18n.CompactNumberFormatSymbols_gu = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0AB9\u0A9C\u0ABE\u0AB0'
+    },
+    '10000': {
+      'other': '00\u00A0\u0AB9\u0A9C\u0ABE\u0AB0'
+    },
+    '100000': {
+      'other': '0\u00A0\u0AB2\u0ABE\u0A96'
+    },
+    '1000000': {
+      'other': '00\u00A0\u0AB2\u0ABE\u0A96'
+    },
+    '10000000': {
+      'other': '0\u00A0\u0A95\u0AB0\u0ACB\u0AA1'
+    },
+    '100000000': {
+      'other': '00\u00A0\u0A95\u0AB0\u0ACB\u0AA1'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0A85\u0AAC\u0A9C'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0A85\u0AAC\u0A9C'
+    },
+    '100000000000': {
+      'other': '0\u00A0\u0AA8\u0ABF\u0A96\u0AB0\u0ACD\u0AB5'
+    },
+    '1000000000000': {
+      'other': '0\u00A0\u0AAE\u0AB9\u0ABE\u0AAA\u0AA6\u0ACD\u0AAE'
+    },
+    '10000000000000': {
+      'other': '0\u00A0\u0AB6\u0A82\u0A95\u0AC1'
+    },
+    '100000000000000': {
+      'other': '0\u00A0\u0A9C\u0AB2\u0AA7\u0ABF'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0AB9\u0A9C\u0ABE\u0AB0'
+    },
+    '10000': {
+      'other': '00 \u0AB9\u0A9C\u0ABE\u0AB0'
+    },
+    '100000': {
+      'other': '0 \u0AB2\u0ABE\u0A96'
+    },
+    '1000000': {
+      'other': '00 \u0AB2\u0ABE\u0A96'
+    },
+    '10000000': {
+      'other': '0 \u0A95\u0AB0\u0ACB\u0AA1'
+    },
+    '100000000': {
+      'other': '00 \u0A95\u0AB0\u0ACB\u0AA1'
+    },
+    '1000000000': {
+      'other': '0 \u0A85\u0AAC\u0A9C'
+    },
+    '10000000000': {
+      'other': '00 \u0A85\u0AAC\u0A9C'
+    },
+    '100000000000': {
+      'other': '0 \u0AA8\u0ABF\u0A96\u0AB0\u0ACD\u0AB5'
+    },
+    '1000000000000': {
+      'other': '0 \u0AAE\u0AB9\u0ABE\u0AAA\u0AA6\u0ACD\u0AAE'
+    },
+    '10000000000000': {
+      'other': '0 \u0AB6\u0A82\u0A95\u0AC1'
+    },
+    '100000000000000': {
+      'other': '0 \u0A9C\u0AB2\u0AA7\u0ABF'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale gu_IN.
+ */
+goog.i18n.CompactNumberFormatSymbols_gu_IN =
+    goog.i18n.CompactNumberFormatSymbols_gu;
+
+
+/**
+ * Compact number formatting symbols for locale haw.
+ */
+goog.i18n.CompactNumberFormatSymbols_haw = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0K'
+    },
+    '10000': {
+      'other': '00K'
+    },
+    '100000': {
+      'other': '000K'
+    },
+    '1000000': {
+      'other': '0M'
+    },
+    '10000000': {
+      'other': '00M'
+    },
+    '100000000': {
+      'other': '000M'
+    },
+    '1000000000': {
+      'other': '0G'
+    },
+    '10000000000': {
+      'other': '00G'
+    },
+    '100000000000': {
+      'other': '000G'
+    },
+    '1000000000000': {
+      'other': '0T'
+    },
+    '10000000000000': {
+      'other': '00T'
+    },
+    '100000000000000': {
+      'other': '000T'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale haw_US.
+ */
+goog.i18n.CompactNumberFormatSymbols_haw_US =
+    goog.i18n.CompactNumberFormatSymbols_haw;
+
+
+/**
+ * Compact number formatting symbols for locale he.
+ */
+goog.i18n.CompactNumberFormatSymbols_he = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '\u200F0\u00A0\u05D0\u05DC\u05E3'
+    },
+    '10000': {
+      'other': '\u200F00\u00A0\u05D0\u05DC\u05E3'
+    },
+    '100000': {
+      'other': '\u200F000\u00A0\u05D0\u05DC\u05E3'
+    },
+    '1000000': {
+      'other': '\u200F0\u00A0\u05DE\u05D9\u05DC\u05F3'
+    },
+    '10000000': {
+      'other': '\u200F00\u00A0\u05DE\u05D9\u05DC\u05F3'
+    },
+    '100000000': {
+      'other': '\u200F000\u00A0\u05DE\u05D9\u05DC\u05F3'
+    },
+    '1000000000': {
+      'other': '\u200F0\u00A0\u05DE\u05DC\u05E8\u05D3'
+    },
+    '10000000000': {
+      'other': '\u200F00\u00A0\u05DE\u05DC\u05E8\u05D3'
+    },
+    '100000000000': {
+      'other': '\u200F000\u00A0\u05DE\u05DC\u05E8\u05D3'
+    },
+    '1000000000000': {
+      'other': '\u200F0\u00A0\u05D1\u05D9\u05DC\u05F3'
+    },
+    '10000000000000': {
+      'other': '\u200F00\u00A0\u05D1\u05D9\u05DC\u05F3'
+    },
+    '100000000000000': {
+      'other': '\u200F000\u00A0\u05D1\u05D9\u05DC\u05F3'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '\u200F0 \u05D0\u05DC\u05E3'
+    },
+    '10000': {
+      'other': '\u200F00 \u05D0\u05DC\u05E3'
+    },
+    '100000': {
+      'other': '\u200F000 \u05D0\u05DC\u05E3'
+    },
+    '1000000': {
+      'other': '\u200F0 \u05DE\u05D9\u05DC\u05D9\u05D5\u05DF'
+    },
+    '10000000': {
+      'other': '\u200F00 \u05DE\u05D9\u05DC\u05D9\u05D5\u05DF'
+    },
+    '100000000': {
+      'other': '\u200F000 \u05DE\u05D9\u05DC\u05D9\u05D5\u05DF'
+    },
+    '1000000000': {
+      'other': '\u200F0 \u05DE\u05D9\u05DC\u05D9\u05D0\u05E8\u05D3'
+    },
+    '10000000000': {
+      'other': '\u200F00 \u05DE\u05D9\u05DC\u05D9\u05D0\u05E8\u05D3'
+    },
+    '100000000000': {
+      'other': '\u200F000 \u05DE\u05D9\u05DC\u05D9\u05D0\u05E8\u05D3'
+    },
+    '1000000000000': {
+      'other': '\u200F0 \u05D8\u05E8\u05D9\u05DC\u05D9\u05D5\u05DF'
+    },
+    '10000000000000': {
+      'other': '\u200F00 \u05D8\u05E8\u05D9\u05DC\u05D9\u05D5\u05DF'
+    },
+    '100000000000000': {
+      'other': '\u200F000 \u05D8\u05E8\u05D9\u05DC\u05D9\u05D5\u05DF'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale he_IL.
+ */
+goog.i18n.CompactNumberFormatSymbols_he_IL =
+    goog.i18n.CompactNumberFormatSymbols_he;
+
+
+/**
+ * Compact number formatting symbols for locale hi.
+ */
+goog.i18n.CompactNumberFormatSymbols_hi = {
+  COMPACT_DECIMAL_SHORT_PATTERN: {
+    '1000': {
+      'other': '0\u00A0\u0939\u091C\u093C\u093E\u0930'
+    },
+    '10000': {
+      'other': '00\u00A0\u0939\u091C\u093C\u093E\u0930'
+    },
+    '100000': {
+      'other': '0\u00A0\u0932\u093E\u0916'
+    },
+    '1000000': {
+      'other': '00\u00A0\u0932\u093E\u0916'
+    },
+    '10000000': {
+      'other': '0\u00A0\u0915.'
+    },
+    '100000000': {
+      'other': '00\u00A0\u0915.'
+    },
+    '1000000000': {
+      'other': '0\u00A0\u0905.'
+    },
+    '10000000000': {
+      'other': '00\u00A0\u0905.'
+    },
+    '100000000000': {
+      'other': '0\u00A0\u0916.'
+    },
+    '1000000000000': {
+      'other': '00\u00A0\u0916.'
+    },
+    '10000000000000': {
+      'other': '0\u00A0\u0928\u0940\u0932'
+    },
+    '100000000000000': {
+      'other': '00\u00A0\u0928\u0940\u0932'
+    }
+  },
+  COMPACT_DECIMAL_LONG_PATTERN: {
+    '1000': {
+      'other': '0 \u0939\u091C\u093C\u093E\u0930'
+    },
+    '10000': {
+      'other': '00 \u0939\u091C\u093C\u093E\u0930'
+    },
+    '100000': {
+      'other': '0 \u0932\u093E\u0916'
+    },
+    '1000000': {
+      'other': '00 \u0932\u093E\u0916'
+    },
+    '10000000': {
+      'other': '0 \u0915\u0930\u094B\u0921\u093C'
+    },
+    '100000000': {
+      'other': '00 \u0915\u0930\u094B\u0921\u093C'
+    },
+    '1000000000': {
+      'other': '0 \u0905\u0930\u092C'
+    },
+    '10000000000': {
+      'other': '00 \u0905\u0930\u092C'
+    },
+    '100000000000': {
+      'other': '0 \u0916\u0930\u092C'
+    },
+    '1000000000000': {
+      'other': '00 \u0916\u0930\u092C'
+    },
+    '10000000000000': {
+      'other': '000 \u0916\u0930\u092C'
+    },
+    '100000000000000': {
+      'other': '0000 \u0916\u0930\u092C'
+    }
+  }
+};
+
+
+/**
+ * Compact number formatting symbols for locale hi_IN.
+ */
+goog.i18n.CompactNumberFormatSymbols_hi_IN =
+    goog.i18n.CompactNumberFormatSymbols_hi;
+
+
+/**
+ * Compact number formatting symbols for locale hr.

<TRUNCATED>

[18/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/eventtype.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/eventtype.js b/externs/GCL/externs/goog/events/eventtype.js
new file mode 100644
index 0000000..befc372
--- /dev/null
+++ b/externs/GCL/externs/goog/events/eventtype.js
@@ -0,0 +1,233 @@
+// Copyright 2010 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 Event Types.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.events.EventType');
+
+goog.require('goog.userAgent');
+
+
+/**
+ * Returns a prefixed event name for the current browser.
+ * @param {string} eventName The name of the event.
+ * @return {string} The prefixed event name.
+ * @suppress {missingRequire|missingProvide}
+ * @private
+ */
+goog.events.getVendorPrefixedName_ = function(eventName) {
+  return goog.userAgent.WEBKIT ? 'webkit' + eventName :
+      (goog.userAgent.OPERA ? 'o' + eventName.toLowerCase() :
+          eventName.toLowerCase());
+};
+
+
+/**
+ * Constants for event names.
+ * @enum {string}
+ */
+goog.events.EventType = {
+  // Mouse events
+  CLICK: 'click',
+  RIGHTCLICK: 'rightclick',
+  DBLCLICK: 'dblclick',
+  MOUSEDOWN: 'mousedown',
+  MOUSEUP: 'mouseup',
+  MOUSEOVER: 'mouseover',
+  MOUSEOUT: 'mouseout',
+  MOUSEMOVE: 'mousemove',
+  MOUSEENTER: 'mouseenter',
+  MOUSELEAVE: 'mouseleave',
+  // Select start is non-standard.
+  // See http://msdn.microsoft.com/en-us/library/ie/ms536969(v=vs.85).aspx.
+  SELECTSTART: 'selectstart', // IE, Safari, Chrome
+
+  // Wheel events
+  // http://www.w3.org/TR/DOM-Level-3-Events/#events-wheelevents
+  WHEEL: 'wheel',
+
+  // Key events
+  KEYPRESS: 'keypress',
+  KEYDOWN: 'keydown',
+  KEYUP: 'keyup',
+
+  // Focus
+  BLUR: 'blur',
+  FOCUS: 'focus',
+  DEACTIVATE: 'deactivate', // IE only
+  // NOTE: The following two events are not stable in cross-browser usage.
+  //     WebKit and Opera implement DOMFocusIn/Out.
+  //     IE implements focusin/out.
+  //     Gecko implements neither see bug at
+  //     https://bugzilla.mozilla.org/show_bug.cgi?id=396927.
+  // The DOM Events Level 3 Draft deprecates DOMFocusIn in favor of focusin:
+  //     http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html
+  // You can use FOCUS in Capture phase until implementations converge.
+  FOCUSIN: goog.userAgent.IE ? 'focusin' : 'DOMFocusIn',
+  FOCUSOUT: goog.userAgent.IE ? 'focusout' : 'DOMFocusOut',
+
+  // Forms
+  CHANGE: 'change',
+  RESET: 'reset',
+  SELECT: 'select',
+  SUBMIT: 'submit',
+  INPUT: 'input',
+  PROPERTYCHANGE: 'propertychange', // IE only
+
+  // Drag and drop
+  DRAGSTART: 'dragstart',
+  DRAG: 'drag',
+  DRAGENTER: 'dragenter',
+  DRAGOVER: 'dragover',
+  DRAGLEAVE: 'dragleave',
+  DROP: 'drop',
+  DRAGEND: 'dragend',
+
+  // Touch events
+  // Note that other touch events exist, but we should follow the W3C list here.
+  // http://www.w3.org/TR/touch-events/#list-of-touchevent-types
+  TOUCHSTART: 'touchstart',
+  TOUCHMOVE: 'touchmove',
+  TOUCHEND: 'touchend',
+  TOUCHCANCEL: 'touchcancel',
+
+  // Misc
+  BEFOREUNLOAD: 'beforeunload',
+  CONSOLEMESSAGE: 'consolemessage',
+  CONTEXTMENU: 'contextmenu',
+  DOMCONTENTLOADED: 'DOMContentLoaded',
+  ERROR: 'error',
+  HELP: 'help',
+  LOAD: 'load',
+  LOSECAPTURE: 'losecapture',
+  ORIENTATIONCHANGE: 'orientationchange',
+  READYSTATECHANGE: 'readystatechange',
+  RESIZE: 'resize',
+  SCROLL: 'scroll',
+  UNLOAD: 'unload',
+
+  // HTML 5 History events
+  // See http://www.w3.org/TR/html5/history.html#event-definitions
+  HASHCHANGE: 'hashchange',
+  PAGEHIDE: 'pagehide',
+  PAGESHOW: 'pageshow',
+  POPSTATE: 'popstate',
+
+  // Copy and Paste
+  // Support is limited. Make sure it works on your favorite browser
+  // before using.
+  // http://www.quirksmode.org/dom/events/cutcopypaste.html
+  COPY: 'copy',
+  PASTE: 'paste',
+  CUT: 'cut',
+  BEFORECOPY: 'beforecopy',
+  BEFORECUT: 'beforecut',
+  BEFOREPASTE: 'beforepaste',
+
+  // HTML5 online/offline events.
+  // http://www.w3.org/TR/offline-webapps/#related
+  ONLINE: 'online',
+  OFFLINE: 'offline',
+
+  // HTML 5 worker events
+  MESSAGE: 'message',
+  CONNECT: 'connect',
+
+  // CSS animation events.
+  /** @suppress {missingRequire} */
+  ANIMATIONSTART: goog.events.getVendorPrefixedName_('AnimationStart'),
+  /** @suppress {missingRequire} */
+  ANIMATIONEND: goog.events.getVendorPrefixedName_('AnimationEnd'),
+  /** @suppress {missingRequire} */
+  ANIMATIONITERATION: goog.events.getVendorPrefixedName_('AnimationIteration'),
+
+  // CSS transition events. Based on the browser support described at:
+  // https://developer.mozilla.org/en/css/css_transitions#Browser_compatibility
+  /** @suppress {missingRequire} */
+  TRANSITIONEND: goog.events.getVendorPrefixedName_('TransitionEnd'),
+
+  // W3C Pointer Events
+  // http://www.w3.org/TR/pointerevents/
+  POINTERDOWN: 'pointerdown',
+  POINTERUP: 'pointerup',
+  POINTERCANCEL: 'pointercancel',
+  POINTERMOVE: 'pointermove',
+  POINTEROVER: 'pointerover',
+  POINTEROUT: 'pointerout',
+  POINTERENTER: 'pointerenter',
+  POINTERLEAVE: 'pointerleave',
+  GOTPOINTERCAPTURE: 'gotpointercapture',
+  LOSTPOINTERCAPTURE: 'lostpointercapture',
+
+  // IE specific events.
+  // See http://msdn.microsoft.com/en-us/library/ie/hh772103(v=vs.85).aspx
+  // Note: these events will be supplanted in IE11.
+  MSGESTURECHANGE: 'MSGestureChange',
+  MSGESTUREEND: 'MSGestureEnd',
+  MSGESTUREHOLD: 'MSGestureHold',
+  MSGESTURESTART: 'MSGestureStart',
+  MSGESTURETAP: 'MSGestureTap',
+  MSGOTPOINTERCAPTURE: 'MSGotPointerCapture',
+  MSINERTIASTART: 'MSInertiaStart',
+  MSLOSTPOINTERCAPTURE: 'MSLostPointerCapture',
+  MSPOINTERCANCEL: 'MSPointerCancel',
+  MSPOINTERDOWN: 'MSPointerDown',
+  MSPOINTERENTER: 'MSPointerEnter',
+  MSPOINTERHOVER: 'MSPointerHover',
+  MSPOINTERLEAVE: 'MSPointerLeave',
+  MSPOINTERMOVE: 'MSPointerMove',
+  MSPOINTEROUT: 'MSPointerOut',
+  MSPOINTEROVER: 'MSPointerOver',
+  MSPOINTERUP: 'MSPointerUp',
+
+  // Native IMEs/input tools events.
+  TEXT: 'text',
+  TEXTINPUT: 'textInput',
+  COMPOSITIONSTART: 'compositionstart',
+  COMPOSITIONUPDATE: 'compositionupdate',
+  COMPOSITIONEND: 'compositionend',
+
+  // Webview tag events
+  // See http://developer.chrome.com/dev/apps/webview_tag.html
+  EXIT: 'exit',
+  LOADABORT: 'loadabort',
+  LOADCOMMIT: 'loadcommit',
+  LOADREDIRECT: 'loadredirect',
+  LOADSTART: 'loadstart',
+  LOADSTOP: 'loadstop',
+  RESPONSIVE: 'responsive',
+  SIZECHANGED: 'sizechanged',
+  UNRESPONSIVE: 'unresponsive',
+
+  // HTML5 Page Visibility API.  See details at
+  // {@code goog.labs.dom.PageVisibilityMonitor}.
+  VISIBILITYCHANGE: 'visibilitychange',
+
+  // LocalStorage event.
+  STORAGE: 'storage',
+
+  // DOM Level 2 mutation events (deprecated).
+  DOMSUBTREEMODIFIED: 'DOMSubtreeModified',
+  DOMNODEINSERTED: 'DOMNodeInserted',
+  DOMNODEREMOVED: 'DOMNodeRemoved',
+  DOMNODEREMOVEDFROMDOCUMENT: 'DOMNodeRemovedFromDocument',
+  DOMNODEINSERTEDINTODOCUMENT: 'DOMNodeInsertedIntoDocument',
+  DOMATTRMODIFIED: 'DOMAttrModified',
+  DOMCHARACTERDATAMODIFIED: 'DOMCharacterDataModified'
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/eventwrapper.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/eventwrapper.js b/externs/GCL/externs/goog/events/eventwrapper.js
new file mode 100644
index 0000000..1581774
--- /dev/null
+++ b/externs/GCL/externs/goog/events/eventwrapper.js
@@ -0,0 +1,66 @@
+// 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 goog.events.EventWrapper interface.
+ *
+ * @author eae@google.com (Emil A Eklund)
+ */
+
+goog.provide('goog.events.EventWrapper');
+
+
+
+/**
+ * Interface for event wrappers.
+ * @interface
+ */
+goog.events.EventWrapper = function() {
+};
+
+
+/**
+ * Adds an event listener using the wrapper on a DOM Node or an object that has
+ * implemented {@link goog.events.EventTarget}. A listener can only be added
+ * once to an object.
+ *
+ * @param {goog.events.ListenableType} src The node to listen to events on.
+ * @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
+ *     method, or an object with a handleEvent function.
+ * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
+ *     false).
+ * @param {Object=} opt_scope Element in whose scope to call the listener.
+ * @param {goog.events.EventHandler=} opt_eventHandler Event handler to add
+ *     listener to.
+ */
+goog.events.EventWrapper.prototype.listen = function(src, listener, opt_capt,
+    opt_scope, opt_eventHandler) {
+};
+
+
+/**
+ * Removes an event listener added using goog.events.EventWrapper.listen.
+ *
+ * @param {goog.events.ListenableType} src The node to remove listener from.
+ * @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
+ *     method, or an object with a handleEvent function.
+ * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
+ *     false).
+ * @param {Object=} opt_scope Element in whose scope to call the listener.
+ * @param {goog.events.EventHandler=} opt_eventHandler Event handler to remove
+ *     listener from.
+ */
+goog.events.EventWrapper.prototype.unlisten = function(src, listener, opt_capt,
+    opt_scope, opt_eventHandler) {
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/filedrophandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/filedrophandler.js b/externs/GCL/externs/goog/events/filedrophandler.js
new file mode 100644
index 0000000..5678fe3
--- /dev/null
+++ b/externs/GCL/externs/goog/events/filedrophandler.js
@@ -0,0 +1,222 @@
+// Copyright 2010 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 Provides a files drag and drop event detector. It works on
+ * HTML5 browsers.
+ *
+ * @see ../demos/filedrophandler.html
+ */
+
+goog.provide('goog.events.FileDropHandler');
+goog.provide('goog.events.FileDropHandler.EventType');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.events.BrowserEvent');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.log');
+goog.require('goog.log.Level');
+
+
+
+/**
+ * A files drag and drop event detector. Gets an {@code element} as parameter
+ * and fires {@code goog.events.FileDropHandler.EventType.DROP} event when files
+ * are dropped in the {@code element}.
+ *
+ * @param {Element|Document} element The element or document to listen on.
+ * @param {boolean=} opt_preventDropOutside Whether to prevent a drop on the
+ *     area outside the {@code element}. Default false.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @final
+ */
+goog.events.FileDropHandler = function(element, opt_preventDropOutside) {
+  goog.events.EventTarget.call(this);
+
+  /**
+   * Handler for drag/drop events.
+   * @type {!goog.events.EventHandler<!goog.events.FileDropHandler>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+  var doc = element;
+  if (opt_preventDropOutside) {
+    doc = goog.dom.getOwnerDocument(element);
+  }
+
+  // Add dragenter listener to the owner document of the element.
+  this.eventHandler_.listen(doc,
+                            goog.events.EventType.DRAGENTER,
+                            this.onDocDragEnter_);
+
+  // Add dragover listener to the owner document of the element only if the
+  // document is not the element itself.
+  if (doc != element) {
+    this.eventHandler_.listen(doc,
+                              goog.events.EventType.DRAGOVER,
+                              this.onDocDragOver_);
+  }
+
+  // Add dragover and drop listeners to the element.
+  this.eventHandler_.listen(element,
+                            goog.events.EventType.DRAGOVER,
+                            this.onElemDragOver_);
+  this.eventHandler_.listen(element,
+                            goog.events.EventType.DROP,
+                            this.onElemDrop_);
+};
+goog.inherits(goog.events.FileDropHandler, goog.events.EventTarget);
+
+
+/**
+ * Whether the drag event contains files. It is initialized only in the
+ * dragenter event. It is used in all the drag events to prevent default actions
+ * only if the drag contains files. Preventing default actions is necessary to
+ * go from dragenter to dragover and from dragover to drop. However we do not
+ * always want to prevent default actions, e.g. when the user drags text or
+ * links on a text area we should not prevent the browser default action that
+ * inserts the text in the text area. It is also necessary to stop propagation
+ * when handling drag events on the element to prevent them from propagating
+ * to the document.
+ * @private
+ * @type {boolean}
+ */
+goog.events.FileDropHandler.prototype.dndContainsFiles_ = false;
+
+
+/**
+ * A logger, used to help us debug the algorithm.
+ * @type {goog.log.Logger}
+ * @private
+ */
+goog.events.FileDropHandler.prototype.logger_ =
+    goog.log.getLogger('goog.events.FileDropHandler');
+
+
+/**
+ * The types of events fired by this class.
+ * @enum {string}
+ */
+goog.events.FileDropHandler.EventType = {
+  DROP: goog.events.EventType.DROP
+};
+
+
+/** @override */
+goog.events.FileDropHandler.prototype.disposeInternal = function() {
+  goog.events.FileDropHandler.superClass_.disposeInternal.call(this);
+  this.eventHandler_.dispose();
+};
+
+
+/**
+ * Dispatches the DROP event.
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ * @private
+ */
+goog.events.FileDropHandler.prototype.dispatch_ = function(e) {
+  goog.log.fine(this.logger_, 'Firing DROP event...');
+  var event = new goog.events.BrowserEvent(e.getBrowserEvent());
+  event.type = goog.events.FileDropHandler.EventType.DROP;
+  this.dispatchEvent(event);
+};
+
+
+/**
+ * Handles dragenter on the document.
+ * @param {goog.events.BrowserEvent} e The dragenter event.
+ * @private
+ */
+goog.events.FileDropHandler.prototype.onDocDragEnter_ = function(e) {
+  goog.log.log(this.logger_, goog.log.Level.FINER,
+      '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type);
+  var dt = e.getBrowserEvent().dataTransfer;
+  // Check whether the drag event contains files.
+  this.dndContainsFiles_ = !!(dt &&
+      ((dt.types &&
+          (goog.array.contains(dt.types, 'Files') ||
+          goog.array.contains(dt.types, 'public.file-url'))) ||
+      (dt.files && dt.files.length > 0)));
+  // If it does
+  if (this.dndContainsFiles_) {
+    // Prevent default actions.
+    e.preventDefault();
+  }
+  goog.log.log(this.logger_, goog.log.Level.FINER,
+      'dndContainsFiles_: ' + this.dndContainsFiles_);
+};
+
+
+/**
+ * Handles dragging something over the document.
+ * @param {goog.events.BrowserEvent} e The dragover event.
+ * @private
+ */
+goog.events.FileDropHandler.prototype.onDocDragOver_ = function(e) {
+  goog.log.log(this.logger_, goog.log.Level.FINEST,
+      '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type);
+  if (this.dndContainsFiles_) {
+    // Prevent default actions.
+    e.preventDefault();
+    // Disable the drop on the document outside the drop zone.
+    var dt = e.getBrowserEvent().dataTransfer;
+    dt.dropEffect = 'none';
+  }
+};
+
+
+/**
+ * Handles dragging something over the element (drop zone).
+ * @param {goog.events.BrowserEvent} e The dragover event.
+ * @private
+ */
+goog.events.FileDropHandler.prototype.onElemDragOver_ = function(e) {
+  goog.log.log(this.logger_, goog.log.Level.FINEST,
+      '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type);
+  if (this.dndContainsFiles_) {
+    // Prevent default actions and stop the event from propagating further to
+    // the document. Both lines are needed! (See comment above).
+    e.preventDefault();
+    e.stopPropagation();
+    // Allow the drop on the drop zone.
+    var dt = e.getBrowserEvent().dataTransfer;
+    dt.effectAllowed = 'all';
+    dt.dropEffect = 'copy';
+  }
+};
+
+
+/**
+ * Handles dropping something onto the element (drop zone).
+ * @param {goog.events.BrowserEvent} e The drop event.
+ * @private
+ */
+goog.events.FileDropHandler.prototype.onElemDrop_ = function(e) {
+  goog.log.log(this.logger_, goog.log.Level.FINER,
+      '"' + e.target.id + '" (' + e.target + ') dispatched: ' + e.type);
+  // If the drag and drop event contains files.
+  if (this.dndContainsFiles_) {
+    // Prevent default actions and stop the event from propagating further to
+    // the document. Both lines are needed! (See comment above).
+    e.preventDefault();
+    e.stopPropagation();
+    // Dispatch DROP event.
+    this.dispatch_(e);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/focushandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/focushandler.js b/externs/GCL/externs/goog/events/focushandler.js
new file mode 100644
index 0000000..f4e1000
--- /dev/null
+++ b/externs/GCL/externs/goog/events/focushandler.js
@@ -0,0 +1,107 @@
+// 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 This event handler allows you to catch focusin and focusout
+ * events on  descendants. Unlike the "focus" and "blur" events which do not
+ * propagate consistently, and therefore must be added to the element that is
+ * focused, this allows you to attach one listener to an ancester and you will
+ * be notified when the focus state changes of ony of its descendants.
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/focushandler.html
+ */
+
+goog.provide('goog.events.FocusHandler');
+goog.provide('goog.events.FocusHandler.EventType');
+
+goog.require('goog.events');
+goog.require('goog.events.BrowserEvent');
+goog.require('goog.events.EventTarget');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * This event handler allows you to catch focus events when descendants gain or
+ * loses focus.
+ * @param {Element|Document} element  The node to listen on.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @final
+ */
+goog.events.FocusHandler = function(element) {
+  goog.events.EventTarget.call(this);
+
+  /**
+   * This is the element that we will listen to the real focus events on.
+   * @type {Element|Document}
+   * @private
+   */
+  this.element_ = element;
+
+  // In IE we use focusin/focusout and in other browsers we use a capturing
+  // listner for focus/blur
+  var typeIn = goog.userAgent.IE ? 'focusin' : 'focus';
+  var typeOut = goog.userAgent.IE ? 'focusout' : 'blur';
+
+  /**
+   * Store the listen key so it easier to unlisten in dispose.
+   * @private
+   * @type {goog.events.Key}
+   */
+  this.listenKeyIn_ =
+      goog.events.listen(this.element_, typeIn, this, !goog.userAgent.IE);
+
+  /**
+   * Store the listen key so it easier to unlisten in dispose.
+   * @private
+   * @type {goog.events.Key}
+   */
+  this.listenKeyOut_ =
+      goog.events.listen(this.element_, typeOut, this, !goog.userAgent.IE);
+};
+goog.inherits(goog.events.FocusHandler, goog.events.EventTarget);
+
+
+/**
+ * Enum type for the events fired by the focus handler
+ * @enum {string}
+ */
+goog.events.FocusHandler.EventType = {
+  FOCUSIN: 'focusin',
+  FOCUSOUT: 'focusout'
+};
+
+
+/**
+ * This handles the underlying events and dispatches a new event.
+ * @param {goog.events.BrowserEvent} e  The underlying browser event.
+ */
+goog.events.FocusHandler.prototype.handleEvent = function(e) {
+  var be = e.getBrowserEvent();
+  var event = new goog.events.BrowserEvent(be);
+  event.type = e.type == 'focusin' || e.type == 'focus' ?
+      goog.events.FocusHandler.EventType.FOCUSIN :
+      goog.events.FocusHandler.EventType.FOCUSOUT;
+  this.dispatchEvent(event);
+};
+
+
+/** @override */
+goog.events.FocusHandler.prototype.disposeInternal = function() {
+  goog.events.FocusHandler.superClass_.disposeInternal.call(this);
+  goog.events.unlistenByKey(this.listenKeyIn_);
+  goog.events.unlistenByKey(this.listenKeyOut_);
+  delete this.element_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/imehandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/imehandler.js b/externs/GCL/externs/goog/events/imehandler.js
new file mode 100644
index 0000000..661f91f
--- /dev/null
+++ b/externs/GCL/externs/goog/events/imehandler.js
@@ -0,0 +1,369 @@
+// Copyright 2010 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 Input Method Editors (IMEs) are OS-level widgets that make
+ * it easier to type non-ascii characters on ascii keyboards (in particular,
+ * characters that require more than one keystroke).
+ *
+ * When the user wants to type such a character, a modal menu pops up and
+ * suggests possible "next" characters in the IME character sequence. After
+ * typing N characters, the user hits "enter" to commit the IME to the field.
+ * N differs from language to language.
+ *
+ * This class offers high-level events for how the user is interacting with the
+ * IME in editable regions.
+ *
+ * Known Issues:
+ *
+ * Firefox always fires an extra pair of compositionstart/compositionend events.
+ * We do not normalize for this.
+ *
+ * Opera does not fire any IME events.
+ *
+ * Spurious UPDATE events are common on all browsers.
+ *
+ * We currently do a bad job detecting when the IME closes on IE, and
+ * make a "best effort" guess on when we know it's closed.
+ *
+ * @author nicksantos@google.com (Nick Santos) (Ported to Closure)
+ */
+
+goog.provide('goog.events.ImeHandler');
+goog.provide('goog.events.ImeHandler.Event');
+goog.provide('goog.events.ImeHandler.EventType');
+
+goog.require('goog.events.Event');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Dispatches high-level events for IMEs.
+ * @param {Element} el The element to listen on.
+ * @extends {goog.events.EventTarget}
+ * @constructor
+ * @final
+ */
+goog.events.ImeHandler = function(el) {
+  goog.events.ImeHandler.base(this, 'constructor');
+
+  /**
+   * The element to listen on.
+   * @type {Element}
+   * @private
+   */
+  this.el_ = el;
+
+  /**
+   * Tracks the keyup event only, because it has a different life-cycle from
+   * other events.
+   * @type {goog.events.EventHandler<!goog.events.ImeHandler>}
+   * @private
+   */
+  this.keyUpHandler_ = new goog.events.EventHandler(this);
+
+  /**
+   * Tracks all the browser events.
+   * @type {goog.events.EventHandler<!goog.events.ImeHandler>}
+   * @private
+   */
+  this.handler_ = new goog.events.EventHandler(this);
+
+  if (goog.events.ImeHandler.USES_COMPOSITION_EVENTS) {
+    this.handler_.
+        listen(el, goog.events.EventType.COMPOSITIONSTART,
+            this.handleCompositionStart_).
+        listen(el, goog.events.EventType.COMPOSITIONEND,
+            this.handleCompositionEnd_).
+        listen(el, goog.events.EventType.COMPOSITIONUPDATE,
+            this.handleTextModifyingInput_);
+  }
+
+  this.handler_.
+      listen(el, goog.events.EventType.TEXTINPUT, this.handleTextInput_).
+      listen(el, goog.events.EventType.TEXT, this.handleTextModifyingInput_).
+      listen(el, goog.events.EventType.KEYDOWN, this.handleKeyDown_);
+};
+goog.inherits(goog.events.ImeHandler, goog.events.EventTarget);
+
+
+/**
+ * Event types fired by ImeHandler. These events do not make any guarantees
+ * about whether they were fired before or after the event in question.
+ * @enum {string}
+ */
+goog.events.ImeHandler.EventType = {
+  // After the IME opens.
+  START: 'startIme',
+
+  // An update to the state of the IME. An 'update' does not necessarily mean
+  // that the text contents of the field were modified in any way.
+  UPDATE: 'updateIme',
+
+  // After the IME closes.
+  END: 'endIme'
+};
+
+
+
+/**
+ * An event fired by ImeHandler.
+ * @param {goog.events.ImeHandler.EventType} type The type.
+ * @param {goog.events.BrowserEvent} reason The trigger for this event.
+ * @constructor
+ * @extends {goog.events.Event}
+ * @final
+ */
+goog.events.ImeHandler.Event = function(type, reason) {
+  goog.events.ImeHandler.Event.base(this, 'constructor', type);
+
+  /**
+   * The event that triggered this.
+   * @type {goog.events.BrowserEvent}
+   */
+  this.reason = reason;
+};
+goog.inherits(goog.events.ImeHandler.Event, goog.events.Event);
+
+
+/**
+ * Whether to use the composition events.
+ * @type {boolean}
+ */
+goog.events.ImeHandler.USES_COMPOSITION_EVENTS =
+    goog.userAgent.GECKO ||
+    (goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher(532));
+
+
+/**
+ * Stores whether IME mode is active.
+ * @type {boolean}
+ * @private
+ */
+goog.events.ImeHandler.prototype.imeMode_ = false;
+
+
+/**
+ * The keyCode value of the last keyDown event. This value is used for
+ * identiying whether or not a textInput event is sent by an IME.
+ * @type {number}
+ * @private
+ */
+goog.events.ImeHandler.prototype.lastKeyCode_ = 0;
+
+
+/**
+ * @return {boolean} Whether an IME is active.
+ */
+goog.events.ImeHandler.prototype.isImeMode = function() {
+  return this.imeMode_;
+};
+
+
+/**
+ * Handles the compositionstart event.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.events.ImeHandler.prototype.handleCompositionStart_ =
+    function(e) {
+  this.handleImeActivate_(e);
+};
+
+
+/**
+ * Handles the compositionend event.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.events.ImeHandler.prototype.handleCompositionEnd_ = function(e) {
+  this.handleImeDeactivate_(e);
+};
+
+
+/**
+ * Handles the compositionupdate and text events.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.events.ImeHandler.prototype.handleTextModifyingInput_ =
+    function(e) {
+  if (this.isImeMode()) {
+    this.processImeComposition_(e);
+  }
+};
+
+
+/**
+ * Handles IME activation.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.events.ImeHandler.prototype.handleImeActivate_ = function(e) {
+  if (this.imeMode_) {
+    return;
+  }
+
+  // Listens for keyup events to handle unexpected IME keydown events on older
+  // versions of webkit.
+  //
+  // In those versions, we currently use textInput events deactivate IME
+  // (see handleTextInput_() for the reason). However,
+  // Safari fires a keydown event (as a result of pressing keys to commit IME
+  // text) with keyCode == WIN_IME after textInput event. This activates IME
+  // mode again unnecessarily. To prevent this problem, listens keyup events
+  // which can use to determine whether IME text has been committed.
+  if (goog.userAgent.WEBKIT &&
+      !goog.events.ImeHandler.USES_COMPOSITION_EVENTS) {
+    this.keyUpHandler_.listen(this.el_,
+        goog.events.EventType.KEYUP, this.handleKeyUpSafari4_);
+  }
+
+  this.imeMode_ = true;
+  this.dispatchEvent(
+      new goog.events.ImeHandler.Event(
+          goog.events.ImeHandler.EventType.START, e));
+};
+
+
+/**
+ * Handles the IME compose changes.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.events.ImeHandler.prototype.processImeComposition_ = function(e) {
+  this.dispatchEvent(
+      new goog.events.ImeHandler.Event(
+          goog.events.ImeHandler.EventType.UPDATE, e));
+};
+
+
+/**
+ * Handles IME deactivation.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.events.ImeHandler.prototype.handleImeDeactivate_ = function(e) {
+  this.imeMode_ = false;
+  this.keyUpHandler_.removeAll();
+  this.dispatchEvent(
+      new goog.events.ImeHandler.Event(
+          goog.events.ImeHandler.EventType.END, e));
+};
+
+
+/**
+ * Handles a key down event.
+ * @param {!goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.events.ImeHandler.prototype.handleKeyDown_ = function(e) {
+  // Firefox and Chrome have a separate event for IME composition ('text'
+  // and 'compositionupdate', respectively), other browsers do not.
+  if (!goog.events.ImeHandler.USES_COMPOSITION_EVENTS) {
+    var imeMode = this.isImeMode();
+    // If we're in IE and we detect an IME input on keyDown then activate
+    // the IME, otherwise if the imeMode was previously active, deactivate.
+    if (!imeMode && e.keyCode == goog.events.KeyCodes.WIN_IME) {
+      this.handleImeActivate_(e);
+    } else if (imeMode && e.keyCode != goog.events.KeyCodes.WIN_IME) {
+      if (goog.events.ImeHandler.isImeDeactivateKeyEvent_(e)) {
+        this.handleImeDeactivate_(e);
+      }
+    } else if (imeMode) {
+      this.processImeComposition_(e);
+    }
+  }
+
+  // Safari on Mac doesn't send IME events in the right order so that we must
+  // ignore some modifier key events to insert IME text correctly.
+  if (goog.events.ImeHandler.isImeDeactivateKeyEvent_(e)) {
+    this.lastKeyCode_ = e.keyCode;
+  }
+};
+
+
+/**
+ * Handles a textInput event.
+ * @param {!goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.events.ImeHandler.prototype.handleTextInput_ = function(e) {
+  // Some WebKit-based browsers including Safari 4 don't send composition
+  // events. So, we turn down IME mode when it's still there.
+  if (!goog.events.ImeHandler.USES_COMPOSITION_EVENTS &&
+      goog.userAgent.WEBKIT &&
+      this.lastKeyCode_ == goog.events.KeyCodes.WIN_IME &&
+      this.isImeMode()) {
+    this.handleImeDeactivate_(e);
+  }
+};
+
+
+/**
+ * Handles the key up event for any IME activity. This handler is just used to
+ * prevent activating IME unnecessary in Safari at this time.
+ * @param {!goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.events.ImeHandler.prototype.handleKeyUpSafari4_ = function(e) {
+  if (this.isImeMode()) {
+    switch (e.keyCode) {
+      // These keyup events indicates that IME text has been committed or
+      // cancelled. We should turn off IME mode when these keyup events
+      // received.
+      case goog.events.KeyCodes.ENTER:
+      case goog.events.KeyCodes.TAB:
+      case goog.events.KeyCodes.ESC:
+        this.handleImeDeactivate_(e);
+        break;
+    }
+  }
+};
+
+
+/**
+ * Returns whether the given event should be treated as an IME
+ * deactivation trigger.
+ * @param {!goog.events.Event} e The event.
+ * @return {boolean} Whether the given event is an IME deactivate trigger.
+ * @private
+ */
+goog.events.ImeHandler.isImeDeactivateKeyEvent_ = function(e) {
+  // Which key events involve IME deactivation depends on the user's
+  // environment (i.e. browsers, platforms, and IMEs). Usually Shift key
+  // and Ctrl key does not involve IME deactivation, so we currently assume
+  // that these keys are not IME deactivation trigger.
+  switch (e.keyCode) {
+    case goog.events.KeyCodes.SHIFT:
+    case goog.events.KeyCodes.CTRL:
+      return false;
+    default:
+      return true;
+  }
+};
+
+
+/** @override */
+goog.events.ImeHandler.prototype.disposeInternal = function() {
+  this.handler_.dispose();
+  this.keyUpHandler_.dispose();
+  this.el_ = null;
+  goog.events.ImeHandler.base(this, 'disposeInternal');
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/inputhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/inputhandler.js b/externs/GCL/externs/goog/events/inputhandler.js
new file mode 100644
index 0000000..b4d8740
--- /dev/null
+++ b/externs/GCL/externs/goog/events/inputhandler.js
@@ -0,0 +1,212 @@
+// 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 An object that encapsulates text changed events for textareas
+ * and input element of type text and password. The event occurs after the value
+ * has been changed. The event does not occur if value was changed
+ * programmatically.<br>
+ * <br>
+ * Note: this does not guarantee the correctness of {@code keyCode} or
+ * {@code charCode}, or attempt to unify them across browsers. See
+ * {@code goog.events.KeyHandler} for that functionality<br>
+ * <br>
+ * Known issues:
+ * <ul>
+ * <li>IE doesn't have native support for input event. WebKit before version 531
+ *     doesn't have support for textareas. For those browsers an emulation mode
+ *     based on key, clipboard and drop events is used. Thus this event won't
+ *     trigger in emulation mode if text was modified by context menu commands
+ *     such as 'Undo' and 'Delete'.
+ * </ul>
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/inputhandler.html
+ */
+
+goog.provide('goog.events.InputHandler');
+goog.provide('goog.events.InputHandler.EventType');
+
+goog.require('goog.Timer');
+goog.require('goog.dom.TagName');
+goog.require('goog.events.BrowserEvent');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * This event handler will dispatch events when the user types into a text
+ * input, password input or a textarea
+ * @param {Element} element  The element that you want to listen for input
+ *     events on.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.events.InputHandler = function(element) {
+  goog.events.InputHandler.base(this, 'constructor');
+
+  /**
+   * Id of a timer used to postpone firing input event in emulation mode.
+   * @type {?number}
+   * @private
+   */
+  this.timer_ = null;
+
+  /**
+   * The element that you want to listen for input events on.
+   * @type {Element}
+   * @private
+   */
+  this.element_ = element;
+
+  // Determine whether input event should be emulated.
+  // IE8 doesn't support input events. We could use property change events but
+  // they are broken in many ways:
+  // - Fire even if value was changed programmatically.
+  // - Aren't always delivered. For example, if you change value or even width
+  //   of input programmatically, next value change made by user won't fire an
+  //   event.
+  // IE9 supports input events when characters are inserted, but not deleted.
+  // WebKit before version 531 did not support input events for textareas.
+  var emulateInputEvents = goog.userAgent.IE ||
+      (goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('531') &&
+          element.tagName == goog.dom.TagName.TEXTAREA);
+
+  /**
+   * @type {goog.events.EventHandler<!goog.events.InputHandler>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+  // Even if input event emulation is enabled, still listen for input events
+  // since they may be partially supported by the browser (such as IE9).
+  // If the input event does fire, we will be able to dispatch synchronously.
+  // (InputHandler events being asynchronous for IE is a common issue for
+  // cases like auto-grow textareas where they result in a quick flash of
+  // scrollbars between the textarea content growing and it being resized to
+  // fit.)
+  this.eventHandler_.listen(
+      this.element_,
+      emulateInputEvents ?
+          ['keydown', 'paste', 'cut', 'drop', 'input'] :
+          'input',
+      this);
+};
+goog.inherits(goog.events.InputHandler, goog.events.EventTarget);
+
+
+/**
+ * Enum type for the events fired by the input handler
+ * @enum {string}
+ */
+goog.events.InputHandler.EventType = {
+  INPUT: 'input'
+};
+
+
+/**
+ * This handles the underlying events and dispatches a new event as needed.
+ * @param {goog.events.BrowserEvent} e The underlying browser event.
+ */
+goog.events.InputHandler.prototype.handleEvent = function(e) {
+  if (e.type == 'input') {
+    // http://stackoverflow.com/questions/18389732/changing-placeholder-triggers-input-event-in-ie-10
+    // IE 10+ fires an input event when there are inputs with placeholders.
+    // It fires the event with keycode 0, so if we detect it we don't
+    // propagate the input event.
+    if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher(10) &&
+        e.keyCode == 0 && e.charCode == 0) {
+      return;
+    }
+    // This event happens after all the other events we listen to, so cancel
+    // an asynchronous event dispatch if we have it queued up.  Otherwise, we
+    // will end up firing an extra event.
+    this.cancelTimerIfSet_();
+
+    this.dispatchEvent(this.createInputEvent_(e));
+  } else {
+    // Filter out key events that don't modify text.
+    if (e.type == 'keydown' &&
+        !goog.events.KeyCodes.isTextModifyingKeyEvent(e)) {
+      return;
+    }
+
+    // It is still possible that pressed key won't modify the value of an
+    // element. Storing old value will help us to detect modification but is
+    // also a little bit dangerous. If value is changed programmatically in
+    // another key down handler, we will detect it as user-initiated change.
+    var valueBeforeKey = e.type == 'keydown' ? this.element_.value : null;
+
+    // In IE on XP, IME the element's value has already changed when we get
+    // keydown events when the user is using an IME. In this case, we can't
+    // check the current value normally, so we assume that it's a modifying key
+    // event. This means that ENTER when used to commit will fire a spurious
+    // input event, but it's better to have a false positive than let some input
+    // slip through the cracks.
+    if (goog.userAgent.IE && e.keyCode == goog.events.KeyCodes.WIN_IME) {
+      valueBeforeKey = null;
+    }
+
+    // Create an input event now, because when we fire it on timer, the
+    // underlying event will already be disposed.
+    var inputEvent = this.createInputEvent_(e);
+
+    // Since key down, paste, cut and drop events are fired before actual value
+    // of the element has changed, we need to postpone dispatching input event
+    // until value is updated.
+    this.cancelTimerIfSet_();
+    this.timer_ = goog.Timer.callOnce(function() {
+      this.timer_ = null;
+      if (this.element_.value != valueBeforeKey) {
+        this.dispatchEvent(inputEvent);
+      }
+    }, 0, this);
+  }
+};
+
+
+/**
+ * Cancels timer if it is set, does nothing otherwise.
+ * @private
+ */
+goog.events.InputHandler.prototype.cancelTimerIfSet_ = function() {
+  if (this.timer_ != null) {
+    goog.Timer.clear(this.timer_);
+    this.timer_ = null;
+  }
+};
+
+
+/**
+ * Creates an input event from the browser event.
+ * @param {goog.events.BrowserEvent} be A browser event.
+ * @return {!goog.events.BrowserEvent} An input event.
+ * @private
+ */
+goog.events.InputHandler.prototype.createInputEvent_ = function(be) {
+  var e = new goog.events.BrowserEvent(be.getBrowserEvent());
+  e.type = goog.events.InputHandler.EventType.INPUT;
+  return e;
+};
+
+
+/** @override */
+goog.events.InputHandler.prototype.disposeInternal = function() {
+  goog.events.InputHandler.base(this, 'disposeInternal');
+  this.eventHandler_.dispose();
+  this.cancelTimerIfSet_();
+  delete this.element_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/keycodes.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/keycodes.js b/externs/GCL/externs/goog/events/keycodes.js
new file mode 100644
index 0000000..ec269ae
--- /dev/null
+++ b/externs/GCL/externs/goog/events/keycodes.js
@@ -0,0 +1,420 @@
+// 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 Constant declarations for common key codes.
+ *
+ * @author eae@google.com (Emil A Eklund)
+ * @see ../demos/keyhandler.html
+ */
+
+goog.provide('goog.events.KeyCodes');
+
+goog.require('goog.userAgent');
+
+
+/**
+ * Key codes for common characters.
+ *
+ * This list is not localized and therefore some of the key codes are not
+ * correct for non US keyboard layouts. See comments below.
+ *
+ * @enum {number}
+ */
+goog.events.KeyCodes = {
+  WIN_KEY_FF_LINUX: 0,
+  MAC_ENTER: 3,
+  BACKSPACE: 8,
+  TAB: 9,
+  NUM_CENTER: 12,  // NUMLOCK on FF/Safari Mac
+  ENTER: 13,
+  SHIFT: 16,
+  CTRL: 17,
+  ALT: 18,
+  PAUSE: 19,
+  CAPS_LOCK: 20,
+  ESC: 27,
+  SPACE: 32,
+  PAGE_UP: 33,     // also NUM_NORTH_EAST
+  PAGE_DOWN: 34,   // also NUM_SOUTH_EAST
+  END: 35,         // also NUM_SOUTH_WEST
+  HOME: 36,        // also NUM_NORTH_WEST
+  LEFT: 37,        // also NUM_WEST
+  UP: 38,          // also NUM_NORTH
+  RIGHT: 39,       // also NUM_EAST
+  DOWN: 40,        // also NUM_SOUTH
+  PRINT_SCREEN: 44,
+  INSERT: 45,      // also NUM_INSERT
+  DELETE: 46,      // also NUM_DELETE
+  ZERO: 48,
+  ONE: 49,
+  TWO: 50,
+  THREE: 51,
+  FOUR: 52,
+  FIVE: 53,
+  SIX: 54,
+  SEVEN: 55,
+  EIGHT: 56,
+  NINE: 57,
+  FF_SEMICOLON: 59, // Firefox (Gecko) fires this for semicolon instead of 186
+  FF_EQUALS: 61, // Firefox (Gecko) fires this for equals instead of 187
+  FF_DASH: 173, // Firefox (Gecko) fires this for dash instead of 189
+  QUESTION_MARK: 63, // needs localization
+  A: 65,
+  B: 66,
+  C: 67,
+  D: 68,
+  E: 69,
+  F: 70,
+  G: 71,
+  H: 72,
+  I: 73,
+  J: 74,
+  K: 75,
+  L: 76,
+  M: 77,
+  N: 78,
+  O: 79,
+  P: 80,
+  Q: 81,
+  R: 82,
+  S: 83,
+  T: 84,
+  U: 85,
+  V: 86,
+  W: 87,
+  X: 88,
+  Y: 89,
+  Z: 90,
+  META: 91, // WIN_KEY_LEFT
+  WIN_KEY_RIGHT: 92,
+  CONTEXT_MENU: 93,
+  NUM_ZERO: 96,
+  NUM_ONE: 97,
+  NUM_TWO: 98,
+  NUM_THREE: 99,
+  NUM_FOUR: 100,
+  NUM_FIVE: 101,
+  NUM_SIX: 102,
+  NUM_SEVEN: 103,
+  NUM_EIGHT: 104,
+  NUM_NINE: 105,
+  NUM_MULTIPLY: 106,
+  NUM_PLUS: 107,
+  NUM_MINUS: 109,
+  NUM_PERIOD: 110,
+  NUM_DIVISION: 111,
+  F1: 112,
+  F2: 113,
+  F3: 114,
+  F4: 115,
+  F5: 116,
+  F6: 117,
+  F7: 118,
+  F8: 119,
+  F9: 120,
+  F10: 121,
+  F11: 122,
+  F12: 123,
+  NUMLOCK: 144,
+  SCROLL_LOCK: 145,
+
+  // OS-specific media keys like volume controls and browser controls.
+  FIRST_MEDIA_KEY: 166,
+  LAST_MEDIA_KEY: 183,
+
+  SEMICOLON: 186,            // needs localization
+  DASH: 189,                 // needs localization
+  EQUALS: 187,               // needs localization
+  COMMA: 188,                // needs localization
+  PERIOD: 190,               // needs localization
+  SLASH: 191,                // needs localization
+  APOSTROPHE: 192,           // needs localization
+  TILDE: 192,                // needs localization
+  SINGLE_QUOTE: 222,         // needs localization
+  OPEN_SQUARE_BRACKET: 219,  // needs localization
+  BACKSLASH: 220,            // needs localization
+  CLOSE_SQUARE_BRACKET: 221, // needs localization
+  WIN_KEY: 224,
+  MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91
+  MAC_WK_CMD_LEFT: 91,  // WebKit Left Command key fired, same as META
+  MAC_WK_CMD_RIGHT: 93, // WebKit Right Command key fired, different from META
+  WIN_IME: 229,
+
+  // "Reserved for future use". Some programs (e.g. the SlingPlayer 2.4 ActiveX
+  // control) fire this as a hacky way to disable screensavers.
+  VK_NONAME: 252,
+
+  // We've seen users whose machines fire this keycode at regular one
+  // second intervals. The common thread among these users is that
+  // they're all using Dell Inspiron laptops, so we suspect that this
+  // indicates a hardware/bios problem.
+  // http://en.community.dell.com/support-forums/laptop/f/3518/p/19285957/19523128.aspx
+  PHANTOM: 255
+};
+
+
+/**
+ * Returns true if the event contains a text modifying key.
+ * @param {goog.events.BrowserEvent} e A key event.
+ * @return {boolean} Whether it's a text modifying key.
+ */
+goog.events.KeyCodes.isTextModifyingKeyEvent = function(e) {
+  if (e.altKey && !e.ctrlKey ||
+      e.metaKey ||
+      // Function keys don't generate text
+      e.keyCode >= goog.events.KeyCodes.F1 &&
+      e.keyCode <= goog.events.KeyCodes.F12) {
+    return false;
+  }
+
+  // The following keys are quite harmless, even in combination with
+  // CTRL, ALT or SHIFT.
+  switch (e.keyCode) {
+    case goog.events.KeyCodes.ALT:
+    case goog.events.KeyCodes.CAPS_LOCK:
+    case goog.events.KeyCodes.CONTEXT_MENU:
+    case goog.events.KeyCodes.CTRL:
+    case goog.events.KeyCodes.DOWN:
+    case goog.events.KeyCodes.END:
+    case goog.events.KeyCodes.ESC:
+    case goog.events.KeyCodes.HOME:
+    case goog.events.KeyCodes.INSERT:
+    case goog.events.KeyCodes.LEFT:
+    case goog.events.KeyCodes.MAC_FF_META:
+    case goog.events.KeyCodes.META:
+    case goog.events.KeyCodes.NUMLOCK:
+    case goog.events.KeyCodes.NUM_CENTER:
+    case goog.events.KeyCodes.PAGE_DOWN:
+    case goog.events.KeyCodes.PAGE_UP:
+    case goog.events.KeyCodes.PAUSE:
+    case goog.events.KeyCodes.PHANTOM:
+    case goog.events.KeyCodes.PRINT_SCREEN:
+    case goog.events.KeyCodes.RIGHT:
+    case goog.events.KeyCodes.SCROLL_LOCK:
+    case goog.events.KeyCodes.SHIFT:
+    case goog.events.KeyCodes.UP:
+    case goog.events.KeyCodes.VK_NONAME:
+    case goog.events.KeyCodes.WIN_KEY:
+    case goog.events.KeyCodes.WIN_KEY_RIGHT:
+      return false;
+    case goog.events.KeyCodes.WIN_KEY_FF_LINUX:
+      return !goog.userAgent.GECKO;
+    default:
+      return e.keyCode < goog.events.KeyCodes.FIRST_MEDIA_KEY ||
+          e.keyCode > goog.events.KeyCodes.LAST_MEDIA_KEY;
+  }
+};
+
+
+/**
+ * Returns true if the key fires a keypress event in the current browser.
+ *
+ * Accoridng to MSDN [1] IE only fires keypress events for the following keys:
+ * - Letters: A - Z (uppercase and lowercase)
+ * - Numerals: 0 - 9
+ * - Symbols: ! @ # $ % ^ & * ( ) _ - + = < [ ] { } , . / ? \ | ' ` " ~
+ * - System: ESC, SPACEBAR, ENTER
+ *
+ * That's not entirely correct though, for instance there's no distinction
+ * between upper and lower case letters.
+ *
+ * [1] http://msdn2.microsoft.com/en-us/library/ms536939(VS.85).aspx)
+ *
+ * Safari is similar to IE, but does not fire keypress for ESC.
+ *
+ * Additionally, IE6 does not fire keydown or keypress events for letters when
+ * the control or alt keys are held down and the shift key is not. IE7 does
+ * fire keydown in these cases, though, but not keypress.
+ *
+ * @param {number} keyCode A key code.
+ * @param {number=} opt_heldKeyCode Key code of a currently-held key.
+ * @param {boolean=} opt_shiftKey Whether the shift key is held down.
+ * @param {boolean=} opt_ctrlKey Whether the control key is held down.
+ * @param {boolean=} opt_altKey Whether the alt key is held down.
+ * @return {boolean} Whether it's a key that fires a keypress event.
+ */
+goog.events.KeyCodes.firesKeyPressEvent = function(keyCode, opt_heldKeyCode,
+    opt_shiftKey, opt_ctrlKey, opt_altKey) {
+  if (!goog.userAgent.IE &&
+      !(goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('525'))) {
+    return true;
+  }
+
+  if (goog.userAgent.MAC && opt_altKey) {
+    return goog.events.KeyCodes.isCharacterKey(keyCode);
+  }
+
+  // Alt but not AltGr which is represented as Alt+Ctrl.
+  if (opt_altKey && !opt_ctrlKey) {
+    return false;
+  }
+
+  // Saves Ctrl or Alt + key for IE and WebKit 525+, which won't fire keypress.
+  // Non-IE browsers and WebKit prior to 525 won't get this far so no need to
+  // check the user agent.
+  if (goog.isNumber(opt_heldKeyCode)) {
+    opt_heldKeyCode = goog.events.KeyCodes.normalizeKeyCode(opt_heldKeyCode);
+  }
+  if (!opt_shiftKey &&
+      (opt_heldKeyCode == goog.events.KeyCodes.CTRL ||
+       opt_heldKeyCode == goog.events.KeyCodes.ALT ||
+       goog.userAgent.MAC &&
+       opt_heldKeyCode == goog.events.KeyCodes.META)) {
+    return false;
+  }
+
+  // Some keys with Ctrl/Shift do not issue keypress in WEBKIT.
+  if (goog.userAgent.WEBKIT && opt_ctrlKey && opt_shiftKey) {
+    switch (keyCode) {
+      case goog.events.KeyCodes.BACKSLASH:
+      case goog.events.KeyCodes.OPEN_SQUARE_BRACKET:
+      case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET:
+      case goog.events.KeyCodes.TILDE:
+      case goog.events.KeyCodes.SEMICOLON:
+      case goog.events.KeyCodes.DASH:
+      case goog.events.KeyCodes.EQUALS:
+      case goog.events.KeyCodes.COMMA:
+      case goog.events.KeyCodes.PERIOD:
+      case goog.events.KeyCodes.SLASH:
+      case goog.events.KeyCodes.APOSTROPHE:
+      case goog.events.KeyCodes.SINGLE_QUOTE:
+        return false;
+    }
+  }
+
+  // When Ctrl+<somekey> is held in IE, it only fires a keypress once, but it
+  // continues to fire keydown events as the event repeats.
+  if (goog.userAgent.IE && opt_ctrlKey && opt_heldKeyCode == keyCode) {
+    return false;
+  }
+
+  switch (keyCode) {
+    case goog.events.KeyCodes.ENTER:
+      return true;
+    case goog.events.KeyCodes.ESC:
+      return !goog.userAgent.WEBKIT;
+  }
+
+  return goog.events.KeyCodes.isCharacterKey(keyCode);
+};
+
+
+/**
+ * Returns true if the key produces a character.
+ * This does not cover characters on non-US keyboards (Russian, Hebrew, etc.).
+ *
+ * @param {number} keyCode A key code.
+ * @return {boolean} Whether it's a character key.
+ */
+goog.events.KeyCodes.isCharacterKey = function(keyCode) {
+  if (keyCode >= goog.events.KeyCodes.ZERO &&
+      keyCode <= goog.events.KeyCodes.NINE) {
+    return true;
+  }
+
+  if (keyCode >= goog.events.KeyCodes.NUM_ZERO &&
+      keyCode <= goog.events.KeyCodes.NUM_MULTIPLY) {
+    return true;
+  }
+
+  if (keyCode >= goog.events.KeyCodes.A &&
+      keyCode <= goog.events.KeyCodes.Z) {
+    return true;
+  }
+
+  // Safari sends zero key code for non-latin characters.
+  if (goog.userAgent.WEBKIT && keyCode == 0) {
+    return true;
+  }
+
+  switch (keyCode) {
+    case goog.events.KeyCodes.SPACE:
+    case goog.events.KeyCodes.QUESTION_MARK:
+    case goog.events.KeyCodes.NUM_PLUS:
+    case goog.events.KeyCodes.NUM_MINUS:
+    case goog.events.KeyCodes.NUM_PERIOD:
+    case goog.events.KeyCodes.NUM_DIVISION:
+    case goog.events.KeyCodes.SEMICOLON:
+    case goog.events.KeyCodes.FF_SEMICOLON:
+    case goog.events.KeyCodes.DASH:
+    case goog.events.KeyCodes.EQUALS:
+    case goog.events.KeyCodes.FF_EQUALS:
+    case goog.events.KeyCodes.COMMA:
+    case goog.events.KeyCodes.PERIOD:
+    case goog.events.KeyCodes.SLASH:
+    case goog.events.KeyCodes.APOSTROPHE:
+    case goog.events.KeyCodes.SINGLE_QUOTE:
+    case goog.events.KeyCodes.OPEN_SQUARE_BRACKET:
+    case goog.events.KeyCodes.BACKSLASH:
+    case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET:
+      return true;
+    default:
+      return false;
+  }
+};
+
+
+/**
+ * Normalizes key codes from OS/Browser-specific value to the general one.
+ * @param {number} keyCode The native key code.
+ * @return {number} The normalized key code.
+ */
+goog.events.KeyCodes.normalizeKeyCode = function(keyCode) {
+  if (goog.userAgent.GECKO) {
+    return goog.events.KeyCodes.normalizeGeckoKeyCode(keyCode);
+  } else if (goog.userAgent.MAC && goog.userAgent.WEBKIT) {
+    return goog.events.KeyCodes.normalizeMacWebKitKeyCode(keyCode);
+  } else {
+    return keyCode;
+  }
+};
+
+
+/**
+ * Normalizes key codes from their Gecko-specific value to the general one.
+ * @param {number} keyCode The native key code.
+ * @return {number} The normalized key code.
+ */
+goog.events.KeyCodes.normalizeGeckoKeyCode = function(keyCode) {
+  switch (keyCode) {
+    case goog.events.KeyCodes.FF_EQUALS:
+      return goog.events.KeyCodes.EQUALS;
+    case goog.events.KeyCodes.FF_SEMICOLON:
+      return goog.events.KeyCodes.SEMICOLON;
+    case goog.events.KeyCodes.FF_DASH:
+      return goog.events.KeyCodes.DASH;
+    case goog.events.KeyCodes.MAC_FF_META:
+      return goog.events.KeyCodes.META;
+    case goog.events.KeyCodes.WIN_KEY_FF_LINUX:
+      return goog.events.KeyCodes.WIN_KEY;
+    default:
+      return keyCode;
+  }
+};
+
+
+/**
+ * Normalizes key codes from their Mac WebKit-specific value to the general one.
+ * @param {number} keyCode The native key code.
+ * @return {number} The normalized key code.
+ */
+goog.events.KeyCodes.normalizeMacWebKitKeyCode = function(keyCode) {
+  switch (keyCode) {
+    case goog.events.KeyCodes.MAC_WK_CMD_RIGHT:  // 93
+      return goog.events.KeyCodes.META;          // 91
+    default:
+      return keyCode;
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/keyhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/keyhandler.js b/externs/GCL/externs/goog/events/keyhandler.js
new file mode 100644
index 0000000..9f20250
--- /dev/null
+++ b/externs/GCL/externs/goog/events/keyhandler.js
@@ -0,0 +1,556 @@
+// 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 This file contains a class for working with keyboard events
+ * that repeat consistently across browsers and platforms. It also unifies the
+ * key code so that it is the same in all browsers and platforms.
+ *
+ * Different web browsers have very different keyboard event handling. Most
+ * importantly is that only certain browsers repeat keydown events:
+ * IE, Opera, FF/Win32, and Safari 3 repeat keydown events.
+ * FF/Mac and Safari 2 do not.
+ *
+ * For the purposes of this code, "Safari 3" means WebKit 525+, when WebKit
+ * decided that they should try to match IE's key handling behavior.
+ * Safari 3.0.4, which shipped with Leopard (WebKit 523), has the
+ * Safari 2 behavior.
+ *
+ * Firefox, Safari, Opera prevent on keypress
+ *
+ * IE prevents on keydown
+ *
+ * Firefox does not fire keypress for shift, ctrl, alt
+ * Firefox does fire keydown for shift, ctrl, alt, meta
+ * Firefox does not repeat keydown for shift, ctrl, alt, meta
+ *
+ * Firefox does not fire keypress for up and down in an input
+ *
+ * Opera fires keypress for shift, ctrl, alt, meta
+ * Opera does not repeat keypress for shift, ctrl, alt, meta
+ *
+ * Safari 2 and 3 do not fire keypress for shift, ctrl, alt
+ * Safari 2 does not fire keydown for shift, ctrl, alt
+ * Safari 3 *does* fire keydown for shift, ctrl, alt
+ *
+ * IE provides the keycode for keyup/down events and the charcode (in the
+ * keycode field) for keypress.
+ *
+ * Mozilla provides the keycode for keyup/down and the charcode for keypress
+ * unless it's a non text modifying key in which case the keycode is provided.
+ *
+ * Safari 3 provides the keycode and charcode for all events.
+ *
+ * Opera provides the keycode for keyup/down event and either the charcode or
+ * the keycode (in the keycode field) for keypress events.
+ *
+ * Firefox x11 doesn't fire keydown events if a another key is already held down
+ * until the first key is released. This can cause a key event to be fired with
+ * a keyCode for the first key and a charCode for the second key.
+ *
+ * Safari in keypress
+ *
+ *        charCode keyCode which
+ * ENTER:       13      13    13
+ * F1:       63236   63236 63236
+ * F8:       63243   63243 63243
+ * ...
+ * p:          112     112   112
+ * P:           80      80    80
+ *
+ * Firefox, keypress:
+ *
+ *        charCode keyCode which
+ * ENTER:        0      13    13
+ * F1:           0     112     0
+ * F8:           0     119     0
+ * ...
+ * p:          112       0   112
+ * P:           80       0    80
+ *
+ * Opera, Mac+Win32, keypress:
+ *
+ *         charCode keyCode which
+ * ENTER: undefined      13    13
+ * F1:    undefined     112     0
+ * F8:    undefined     119     0
+ * ...
+ * p:     undefined     112   112
+ * P:     undefined      80    80
+ *
+ * IE7, keydown
+ *
+ *         charCode keyCode     which
+ * ENTER: undefined      13 undefined
+ * F1:    undefined     112 undefined
+ * F8:    undefined     119 undefined
+ * ...
+ * p:     undefined      80 undefined
+ * P:     undefined      80 undefined
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ * @author eae@google.com (Emil A Eklund)
+ * @see ../demos/keyhandler.html
+ */
+
+goog.provide('goog.events.KeyEvent');
+goog.provide('goog.events.KeyHandler');
+goog.provide('goog.events.KeyHandler.EventType');
+
+goog.require('goog.events');
+goog.require('goog.events.BrowserEvent');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * A wrapper around an element that you want to listen to keyboard events on.
+ * @param {Element|Document=} opt_element The element or document to listen on.
+ * @param {boolean=} opt_capture Whether to listen for browser events in
+ *     capture phase (defaults to false).
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @final
+ */
+goog.events.KeyHandler = function(opt_element, opt_capture) {
+  goog.events.EventTarget.call(this);
+
+  if (opt_element) {
+    this.attach(opt_element, opt_capture);
+  }
+};
+goog.inherits(goog.events.KeyHandler, goog.events.EventTarget);
+
+
+/**
+ * This is the element that we will listen to the real keyboard events on.
+ * @type {Element|Document|null}
+ * @private
+ */
+goog.events.KeyHandler.prototype.element_ = null;
+
+
+/**
+ * The key for the key press listener.
+ * @type {goog.events.Key}
+ * @private
+ */
+goog.events.KeyHandler.prototype.keyPressKey_ = null;
+
+
+/**
+ * The key for the key down listener.
+ * @type {goog.events.Key}
+ * @private
+ */
+goog.events.KeyHandler.prototype.keyDownKey_ = null;
+
+
+/**
+ * The key for the key up listener.
+ * @type {goog.events.Key}
+ * @private
+ */
+goog.events.KeyHandler.prototype.keyUpKey_ = null;
+
+
+/**
+ * Used to detect keyboard repeat events.
+ * @private
+ * @type {number}
+ */
+goog.events.KeyHandler.prototype.lastKey_ = -1;
+
+
+/**
+ * Keycode recorded for key down events. As most browsers don't report the
+ * keycode in the key press event we need to record it in the key down phase.
+ * @private
+ * @type {number}
+ */
+goog.events.KeyHandler.prototype.keyCode_ = -1;
+
+
+/**
+ * Alt key recorded for key down events. FF on Mac does not report the alt key
+ * flag in the key press event, we need to record it in the key down phase.
+ * @type {boolean}
+ * @private
+ */
+goog.events.KeyHandler.prototype.altKey_ = false;
+
+
+/**
+ * Enum type for the events fired by the key handler
+ * @enum {string}
+ */
+goog.events.KeyHandler.EventType = {
+  KEY: 'key'
+};
+
+
+/**
+ * An enumeration of key codes that Safari 2 does incorrectly
+ * @type {Object}
+ * @private
+ */
+goog.events.KeyHandler.safariKey_ = {
+  '3': goog.events.KeyCodes.ENTER, // 13
+  '12': goog.events.KeyCodes.NUMLOCK, // 144
+  '63232': goog.events.KeyCodes.UP, // 38
+  '63233': goog.events.KeyCodes.DOWN, // 40
+  '63234': goog.events.KeyCodes.LEFT, // 37
+  '63235': goog.events.KeyCodes.RIGHT, // 39
+  '63236': goog.events.KeyCodes.F1, // 112
+  '63237': goog.events.KeyCodes.F2, // 113
+  '63238': goog.events.KeyCodes.F3, // 114
+  '63239': goog.events.KeyCodes.F4, // 115
+  '63240': goog.events.KeyCodes.F5, // 116
+  '63241': goog.events.KeyCodes.F6, // 117
+  '63242': goog.events.KeyCodes.F7, // 118
+  '63243': goog.events.KeyCodes.F8, // 119
+  '63244': goog.events.KeyCodes.F9, // 120
+  '63245': goog.events.KeyCodes.F10, // 121
+  '63246': goog.events.KeyCodes.F11, // 122
+  '63247': goog.events.KeyCodes.F12, // 123
+  '63248': goog.events.KeyCodes.PRINT_SCREEN, // 44
+  '63272': goog.events.KeyCodes.DELETE, // 46
+  '63273': goog.events.KeyCodes.HOME, // 36
+  '63275': goog.events.KeyCodes.END, // 35
+  '63276': goog.events.KeyCodes.PAGE_UP, // 33
+  '63277': goog.events.KeyCodes.PAGE_DOWN, // 34
+  '63289': goog.events.KeyCodes.NUMLOCK, // 144
+  '63302': goog.events.KeyCodes.INSERT // 45
+};
+
+
+/**
+ * An enumeration of key identifiers currently part of the W3C draft for DOM3
+ * and their mappings to keyCodes.
+ * http://www.w3.org/TR/DOM-Level-3-Events/keyset.html#KeySet-Set
+ * This is currently supported in Safari and should be platform independent.
+ * @type {Object}
+ * @private
+ */
+goog.events.KeyHandler.keyIdentifier_ = {
+  'Up': goog.events.KeyCodes.UP, // 38
+  'Down': goog.events.KeyCodes.DOWN, // 40
+  'Left': goog.events.KeyCodes.LEFT, // 37
+  'Right': goog.events.KeyCodes.RIGHT, // 39
+  'Enter': goog.events.KeyCodes.ENTER, // 13
+  'F1': goog.events.KeyCodes.F1, // 112
+  'F2': goog.events.KeyCodes.F2, // 113
+  'F3': goog.events.KeyCodes.F3, // 114
+  'F4': goog.events.KeyCodes.F4, // 115
+  'F5': goog.events.KeyCodes.F5, // 116
+  'F6': goog.events.KeyCodes.F6, // 117
+  'F7': goog.events.KeyCodes.F7, // 118
+  'F8': goog.events.KeyCodes.F8, // 119
+  'F9': goog.events.KeyCodes.F9, // 120
+  'F10': goog.events.KeyCodes.F10, // 121
+  'F11': goog.events.KeyCodes.F11, // 122
+  'F12': goog.events.KeyCodes.F12, // 123
+  'U+007F': goog.events.KeyCodes.DELETE, // 46
+  'Home': goog.events.KeyCodes.HOME, // 36
+  'End': goog.events.KeyCodes.END, // 35
+  'PageUp': goog.events.KeyCodes.PAGE_UP, // 33
+  'PageDown': goog.events.KeyCodes.PAGE_DOWN, // 34
+  'Insert': goog.events.KeyCodes.INSERT // 45
+};
+
+
+/**
+ * If true, the KeyEvent fires on keydown. Otherwise, it fires on keypress.
+ *
+ * @type {boolean}
+ * @private
+ */
+goog.events.KeyHandler.USES_KEYDOWN_ = goog.userAgent.IE ||
+    goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('525');
+
+
+/**
+ * If true, the alt key flag is saved during the key down and reused when
+ * handling the key press. FF on Mac does not set the alt flag in the key press
+ * event.
+ * @type {boolean}
+ * @private
+ */
+goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_ = goog.userAgent.MAC &&
+    goog.userAgent.GECKO;
+
+
+/**
+ * Records the keycode for browsers that only returns the keycode for key up/
+ * down events. For browser/key combinations that doesn't trigger a key pressed
+ * event it also fires the patched key event.
+ * @param {goog.events.BrowserEvent} e The key down event.
+ * @private
+ */
+goog.events.KeyHandler.prototype.handleKeyDown_ = function(e) {
+  // Ctrl-Tab and Alt-Tab can cause the focus to be moved to another window
+  // before we've caught a key-up event.  If the last-key was one of these we
+  // reset the state.
+  if (goog.userAgent.WEBKIT) {
+    if (this.lastKey_ == goog.events.KeyCodes.CTRL && !e.ctrlKey ||
+        this.lastKey_ == goog.events.KeyCodes.ALT && !e.altKey ||
+        goog.userAgent.MAC &&
+        this.lastKey_ == goog.events.KeyCodes.META && !e.metaKey) {
+      this.lastKey_ = -1;
+      this.keyCode_ = -1;
+    }
+  }
+
+  if (this.lastKey_ == -1) {
+    if (e.ctrlKey && e.keyCode != goog.events.KeyCodes.CTRL) {
+      this.lastKey_ = goog.events.KeyCodes.CTRL;
+    } else if (e.altKey && e.keyCode != goog.events.KeyCodes.ALT) {
+      this.lastKey_ = goog.events.KeyCodes.ALT;
+    } else if (e.metaKey && e.keyCode != goog.events.KeyCodes.META) {
+      this.lastKey_ = goog.events.KeyCodes.META;
+    }
+  }
+
+  if (goog.events.KeyHandler.USES_KEYDOWN_ &&
+      !goog.events.KeyCodes.firesKeyPressEvent(e.keyCode,
+          this.lastKey_, e.shiftKey, e.ctrlKey, e.altKey)) {
+    this.handleEvent(e);
+  } else {
+    this.keyCode_ = goog.events.KeyCodes.normalizeKeyCode(e.keyCode);
+    if (goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_) {
+      this.altKey_ = e.altKey;
+    }
+  }
+};
+
+
+/**
+ * Resets the stored previous values. Needed to be called for webkit which will
+ * not generate a key up for meta key operations. This should only be called
+ * when having finished with repeat key possiblities.
+ */
+goog.events.KeyHandler.prototype.resetState = function() {
+  this.lastKey_ = -1;
+  this.keyCode_ = -1;
+};
+
+
+/**
+ * Clears the stored previous key value, resetting the key repeat status. Uses
+ * -1 because the Safari 3 Windows beta reports 0 for certain keys (like Home
+ * and End.)
+ * @param {goog.events.BrowserEvent} e The keyup event.
+ * @private
+ */
+goog.events.KeyHandler.prototype.handleKeyup_ = function(e) {
+  this.resetState();
+  this.altKey_ = e.altKey;
+};
+
+
+/**
+ * Handles the events on the element.
+ * @param {goog.events.BrowserEvent} e  The keyboard event sent from the
+ *     browser.
+ */
+goog.events.KeyHandler.prototype.handleEvent = function(e) {
+  var be = e.getBrowserEvent();
+  var keyCode, charCode;
+  var altKey = be.altKey;
+
+  // IE reports the character code in the keyCode field for keypress events.
+  // There are two exceptions however, Enter and Escape.
+  if (goog.userAgent.IE && e.type == goog.events.EventType.KEYPRESS) {
+    keyCode = this.keyCode_;
+    charCode = keyCode != goog.events.KeyCodes.ENTER &&
+        keyCode != goog.events.KeyCodes.ESC ?
+            be.keyCode : 0;
+
+  // Safari reports the character code in the keyCode field for keypress
+  // events but also has a charCode field.
+  } else if (goog.userAgent.WEBKIT &&
+      e.type == goog.events.EventType.KEYPRESS) {
+    keyCode = this.keyCode_;
+    charCode = be.charCode >= 0 && be.charCode < 63232 &&
+        goog.events.KeyCodes.isCharacterKey(keyCode) ?
+            be.charCode : 0;
+
+  // Opera reports the keycode or the character code in the keyCode field.
+  } else if (goog.userAgent.OPERA && !goog.userAgent.WEBKIT) {
+    keyCode = this.keyCode_;
+    charCode = goog.events.KeyCodes.isCharacterKey(keyCode) ?
+        be.keyCode : 0;
+
+  // Mozilla reports the character code in the charCode field.
+  } else {
+    keyCode = be.keyCode || this.keyCode_;
+    charCode = be.charCode || 0;
+    if (goog.events.KeyHandler.SAVE_ALT_FOR_KEYPRESS_) {
+      altKey = this.altKey_;
+    }
+    // On the Mac, shift-/ triggers a question mark char code and no key code
+    // (normalized to WIN_KEY), so we synthesize the latter.
+    if (goog.userAgent.MAC &&
+        charCode == goog.events.KeyCodes.QUESTION_MARK &&
+        keyCode == goog.events.KeyCodes.WIN_KEY) {
+      keyCode = goog.events.KeyCodes.SLASH;
+    }
+  }
+
+  keyCode = goog.events.KeyCodes.normalizeKeyCode(keyCode);
+  var key = keyCode;
+  var keyIdentifier = be.keyIdentifier;
+
+  // Correct the key value for certain browser-specific quirks.
+  if (keyCode) {
+    if (keyCode >= 63232 && keyCode in goog.events.KeyHandler.safariKey_) {
+      // NOTE(nicksantos): Safari 3 has fixed this problem,
+      // this is only needed for Safari 2.
+      key = goog.events.KeyHandler.safariKey_[keyCode];
+    } else {
+
+      // Safari returns 25 for Shift+Tab instead of 9.
+      if (keyCode == 25 && e.shiftKey) {
+        key = 9;
+      }
+    }
+  } else if (keyIdentifier &&
+             keyIdentifier in goog.events.KeyHandler.keyIdentifier_) {
+    // This is needed for Safari Windows because it currently doesn't give a
+    // keyCode/which for non printable keys.
+    key = goog.events.KeyHandler.keyIdentifier_[keyIdentifier];
+  }
+
+  // If we get the same keycode as a keydown/keypress without having seen a
+  // keyup event, then this event was caused by key repeat.
+  var repeat = key == this.lastKey_;
+  this.lastKey_ = key;
+
+  var event = new goog.events.KeyEvent(key, charCode, repeat, be);
+  event.altKey = altKey;
+  this.dispatchEvent(event);
+};
+
+
+/**
+ * Returns the element listened on for the real keyboard events.
+ * @return {Element|Document|null} The element listened on for the real
+ *     keyboard events.
+ */
+goog.events.KeyHandler.prototype.getElement = function() {
+  return this.element_;
+};
+
+
+/**
+ * Adds the proper key event listeners to the element.
+ * @param {Element|Document} element The element to listen on.
+ * @param {boolean=} opt_capture Whether to listen for browser events in
+ *     capture phase (defaults to false).
+ */
+goog.events.KeyHandler.prototype.attach = function(element, opt_capture) {
+  if (this.keyUpKey_) {
+    this.detach();
+  }
+
+  this.element_ = element;
+
+  this.keyPressKey_ = goog.events.listen(this.element_,
+                                         goog.events.EventType.KEYPRESS,
+                                         this,
+                                         opt_capture);
+
+  // Most browsers (Safari 2 being the notable exception) doesn't include the
+  // keyCode in keypress events (IE has the char code in the keyCode field and
+  // Mozilla only included the keyCode if there's no charCode). Thus we have to
+  // listen for keydown to capture the keycode.
+  this.keyDownKey_ = goog.events.listen(this.element_,
+                                        goog.events.EventType.KEYDOWN,
+                                        this.handleKeyDown_,
+                                        opt_capture,
+                                        this);
+
+
+  this.keyUpKey_ = goog.events.listen(this.element_,
+                                      goog.events.EventType.KEYUP,
+                                      this.handleKeyup_,
+                                      opt_capture,
+                                      this);
+};
+
+
+/**
+ * Removes the listeners that may exist.
+ */
+goog.events.KeyHandler.prototype.detach = function() {
+  if (this.keyPressKey_) {
+    goog.events.unlistenByKey(this.keyPressKey_);
+    goog.events.unlistenByKey(this.keyDownKey_);
+    goog.events.unlistenByKey(this.keyUpKey_);
+    this.keyPressKey_ = null;
+    this.keyDownKey_ = null;
+    this.keyUpKey_ = null;
+  }
+  this.element_ = null;
+  this.lastKey_ = -1;
+  this.keyCode_ = -1;
+};
+
+
+/** @override */
+goog.events.KeyHandler.prototype.disposeInternal = function() {
+  goog.events.KeyHandler.superClass_.disposeInternal.call(this);
+  this.detach();
+};
+
+
+
+/**
+ * This class is used for the goog.events.KeyHandler.EventType.KEY event and
+ * it overrides the key code with the fixed key code.
+ * @param {number} keyCode The adjusted key code.
+ * @param {number} charCode The unicode character code.
+ * @param {boolean} repeat Whether this event was generated by keyboard repeat.
+ * @param {Event} browserEvent Browser event object.
+ * @constructor
+ * @extends {goog.events.BrowserEvent}
+ * @final
+ */
+goog.events.KeyEvent = function(keyCode, charCode, repeat, browserEvent) {
+  goog.events.BrowserEvent.call(this, browserEvent);
+  this.type = goog.events.KeyHandler.EventType.KEY;
+
+  /**
+   * Keycode of key press.
+   * @type {number}
+   */
+  this.keyCode = keyCode;
+
+  /**
+   * Unicode character code.
+   * @type {number}
+   */
+  this.charCode = charCode;
+
+  /**
+   * True if this event was generated by keyboard auto-repeat (i.e., the user is
+   * holding the key down.)
+   * @type {boolean}
+   */
+  this.repeat = repeat;
+};
+goog.inherits(goog.events.KeyEvent, goog.events.BrowserEvent);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/keynames.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/keynames.js b/externs/GCL/externs/goog/events/keynames.js
new file mode 100644
index 0000000..b8e36af
--- /dev/null
+++ b/externs/GCL/externs/goog/events/keynames.js
@@ -0,0 +1,139 @@
+// 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 Constant declarations for common key codes.
+ *
+ * @author eae@google.com (Emil A Eklund)
+ */
+
+goog.provide('goog.events.KeyNames');
+
+
+/**
+ * Key names for common characters. These should be used with keyup/keydown
+ * events, since the .keyCode property on those is meant to indicate the
+ * *physical key* the user held down on the keyboard. Hence the mapping uses
+ * only the unshifted version of each key (e.g. no '#', since that's shift+3).
+ * Keypress events on the other hand generate (mostly) ASCII codes since they
+ * correspond to *characters* the user typed.
+ *
+ * For further reference: http://unixpapa.com/js/key.html
+ *
+ * This list is not localized and therefore some of the key codes are not
+ * correct for non-US keyboard layouts.
+ *
+ * @see goog.events.KeyCodes
+ * @enum {string}
+ */
+goog.events.KeyNames = {
+  8: 'backspace',
+  9: 'tab',
+  13: 'enter',
+  16: 'shift',
+  17: 'ctrl',
+  18: 'alt',
+  19: 'pause',
+  20: 'caps-lock',
+  27: 'esc',
+  32: 'space',
+  33: 'pg-up',
+  34: 'pg-down',
+  35: 'end',
+  36: 'home',
+  37: 'left',
+  38: 'up',
+  39: 'right',
+  40: 'down',
+  45: 'insert',
+  46: 'delete',
+  48: '0',
+  49: '1',
+  50: '2',
+  51: '3',
+  52: '4',
+  53: '5',
+  54: '6',
+  55: '7',
+  56: '8',
+  57: '9',
+  59: 'semicolon',
+  61: 'equals',
+  65: 'a',
+  66: 'b',
+  67: 'c',
+  68: 'd',
+  69: 'e',
+  70: 'f',
+  71: 'g',
+  72: 'h',
+  73: 'i',
+  74: 'j',
+  75: 'k',
+  76: 'l',
+  77: 'm',
+  78: 'n',
+  79: 'o',
+  80: 'p',
+  81: 'q',
+  82: 'r',
+  83: 's',
+  84: 't',
+  85: 'u',
+  86: 'v',
+  87: 'w',
+  88: 'x',
+  89: 'y',
+  90: 'z',
+  93: 'context',
+  96: 'num-0',
+  97: 'num-1',
+  98: 'num-2',
+  99: 'num-3',
+  100: 'num-4',
+  101: 'num-5',
+  102: 'num-6',
+  103: 'num-7',
+  104: 'num-8',
+  105: 'num-9',
+  106: 'num-multiply',
+  107: 'num-plus',
+  109: 'num-minus',
+  110: 'num-period',
+  111: 'num-division',
+  112: 'f1',
+  113: 'f2',
+  114: 'f3',
+  115: 'f4',
+  116: 'f5',
+  117: 'f6',
+  118: 'f7',
+  119: 'f8',
+  120: 'f9',
+  121: 'f10',
+  122: 'f11',
+  123: 'f12',
+  186: 'semicolon',
+  187: 'equals',
+  189: 'dash',
+  188: ',',
+  190: '.',
+  191: '/',
+  192: '`',
+  219: 'open-square-bracket',
+  220: '\\',
+  221: 'close-square-bracket',
+  222: 'single-quote',
+  224: 'win'
+};


[26/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/field.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/field.js b/externs/GCL/externs/goog/editor/field.js
new file mode 100644
index 0000000..349aca8
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/field.js
@@ -0,0 +1,2750 @@
+// 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.
+// All Rights Reserved.
+
+/**
+ * @fileoverview Class to encapsulate an editable field.  Always uses an
+ * iframe to contain the editable area, never inherits the style of the
+ * surrounding page, and is always a fixed height.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ * @see ../demos/editor/editor.html
+ * @see ../demos/editor/field_basic.html
+ */
+
+goog.provide('goog.editor.Field');
+goog.provide('goog.editor.Field.EventType');
+
+goog.require('goog.a11y.aria');
+goog.require('goog.a11y.aria.Role');
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.async.Delay');
+goog.require('goog.dom');
+goog.require('goog.dom.Range');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.BrowserFeature');
+goog.require('goog.editor.Command');
+goog.require('goog.editor.Plugin');
+goog.require('goog.editor.icontent');
+goog.require('goog.editor.icontent.FieldFormatInfo');
+goog.require('goog.editor.icontent.FieldStyleInfo');
+goog.require('goog.editor.node');
+goog.require('goog.editor.range');
+goog.require('goog.events');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.functions');
+goog.require('goog.log');
+goog.require('goog.log.Level');
+goog.require('goog.string');
+goog.require('goog.string.Unicode');
+goog.require('goog.style');
+goog.require('goog.userAgent');
+goog.require('goog.userAgent.product');
+
+
+
+/**
+ * This class encapsulates an editable field.
+ *
+ * event: load Fires when the field is loaded
+ * event: unload Fires when the field is unloaded (made not editable)
+ *
+ * event: beforechange Fires before the content of the field might change
+ *
+ * event: delayedchange Fires a short time after field has changed. If multiple
+ *                      change events happen really close to each other only
+ *                      the last one will trigger the delayedchange event.
+ *
+ * event: beforefocus Fires before the field becomes active
+ * event: focus Fires when the field becomes active. Fires after the blur event
+ * event: blur Fires when the field becomes inactive
+ *
+ * TODO: figure out if blur or beforefocus fires first in IE and make FF match
+ *
+ * @param {string} id An identifer for the field. This is used to find the
+ *    field and the element associated with this field.
+ * @param {Document=} opt_doc The document that the element with the given
+ *     id can be found in.  If not provided, the default document is used.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.editor.Field = function(id, opt_doc) {
+  goog.events.EventTarget.call(this);
+
+  /**
+   * The id for this editable field, which must match the id of the element
+   * associated with this field.
+   * @type {string}
+   */
+  this.id = id;
+
+  /**
+   * The hash code for this field. Should be equal to the id.
+   * @type {string}
+   * @private
+   */
+  this.hashCode_ = id;
+
+  /**
+   * Dom helper for the editable node.
+   * @type {goog.dom.DomHelper}
+   * @protected
+   */
+  this.editableDomHelper = null;
+
+  /**
+   * Map of class id to registered plugin.
+   * @type {Object}
+   * @private
+   */
+  this.plugins_ = {};
+
+
+  /**
+   * Plugins registered on this field, indexed by the goog.editor.Plugin.Op
+   * that they support.
+   * @type {Object<Array<goog.editor.Plugin>>}
+   * @private
+   */
+  this.indexedPlugins_ = {};
+
+  for (var op in goog.editor.Plugin.OPCODE) {
+    this.indexedPlugins_[op] = [];
+  }
+
+
+  /**
+   * Additional styles to install for the editable field.
+   * @type {string}
+   * @protected
+   */
+  this.cssStyles = '';
+
+  // The field will not listen to change events until it has finished loading
+  this.stoppedEvents_ = {};
+  this.stopEvent(goog.editor.Field.EventType.CHANGE);
+  this.stopEvent(goog.editor.Field.EventType.DELAYEDCHANGE);
+  this.isModified_ = false;
+  this.isEverModified_ = false;
+  this.delayedChangeTimer_ = new goog.async.Delay(this.dispatchDelayedChange_,
+      goog.editor.Field.DELAYED_CHANGE_FREQUENCY, this);
+
+  this.debouncedEvents_ = {};
+  for (var key in goog.editor.Field.EventType) {
+    this.debouncedEvents_[goog.editor.Field.EventType[key]] = 0;
+  }
+
+  if (goog.editor.BrowserFeature.USE_MUTATION_EVENTS) {
+    this.changeTimerGecko_ = new goog.async.Delay(this.handleChange,
+        goog.editor.Field.CHANGE_FREQUENCY, this);
+  }
+
+  /**
+   * @type {goog.events.EventHandler<!goog.editor.Field>}
+   * @protected
+   */
+  this.eventRegister = new goog.events.EventHandler(this);
+
+  // Wrappers around this field, to be disposed when the field is disposed.
+  this.wrappers_ = [];
+
+  this.loadState_ = goog.editor.Field.LoadState_.UNEDITABLE;
+
+  var doc = opt_doc || document;
+
+  /**
+   * @type {!goog.dom.DomHelper}
+   * @protected
+   */
+  this.originalDomHelper = goog.dom.getDomHelper(doc);
+
+  /**
+   * @type {Element}
+   * @protected
+   */
+  this.originalElement = this.originalDomHelper.getElement(this.id);
+
+  /**
+   * @private {boolean}
+   */
+  this.followLinkInNewWindow_ =
+      goog.editor.BrowserFeature.FOLLOWS_EDITABLE_LINKS;
+
+  // Default to the same window as the field is in.
+  this.appWindow_ = this.originalDomHelper.getWindow();
+};
+goog.inherits(goog.editor.Field, goog.events.EventTarget);
+
+
+/**
+ * The editable dom node.
+ * @type {Element}
+ * TODO(user): Make this private!
+ */
+goog.editor.Field.prototype.field = null;
+
+
+/**
+ * The original node that is being made editable, or null if it has
+ * not yet been found.
+ * @type {Element}
+ * @protected
+ */
+goog.editor.Field.prototype.originalElement = null;
+
+
+/**
+ * Logging object.
+ * @type {goog.log.Logger}
+ * @protected
+ */
+goog.editor.Field.prototype.logger =
+    goog.log.getLogger('goog.editor.Field');
+
+
+/**
+ * Event types that can be stopped/started.
+ * @enum {string}
+ */
+goog.editor.Field.EventType = {
+  /**
+   * Dispatched when the command state of the selection may have changed. This
+   * event should be listened to for updating toolbar state.
+   */
+  COMMAND_VALUE_CHANGE: 'cvc',
+  /**
+   * Dispatched when the field is loaded and ready to use.
+   */
+  LOAD: 'load',
+  /**
+   * Dispatched when the field is fully unloaded and uneditable.
+   */
+  UNLOAD: 'unload',
+  /**
+   * Dispatched before the field contents are changed.
+   */
+  BEFORECHANGE: 'beforechange',
+  /**
+   * Dispatched when the field contents change, in FF only.
+   * Used for internal resizing, please do not use.
+   */
+  CHANGE: 'change',
+  /**
+   * Dispatched on a slight delay after changes are made.
+   * Use for autosave, or other times your app needs to know
+   * that the field contents changed.
+   */
+  DELAYEDCHANGE: 'delayedchange',
+  /**
+   * Dispatched before focus in moved into the field.
+   */
+  BEFOREFOCUS: 'beforefocus',
+  /**
+   * Dispatched when focus is moved into the field.
+   */
+  FOCUS: 'focus',
+  /**
+   * Dispatched when the field is blurred.
+   */
+  BLUR: 'blur',
+  /**
+   * Dispatched before tab is handled by the field.  This is a legacy way
+   * of controlling tab behavior.  Use trog.plugins.AbstractTabHandler now.
+   */
+  BEFORETAB: 'beforetab',
+  /**
+   * Dispatched after the iframe containing the field is resized, so that UI
+   * components which contain it can respond.
+   */
+  IFRAME_RESIZED: 'ifrsz',
+  /**
+   * Dispatched when the selection changes.
+   * Use handleSelectionChange from plugin API instead of listening
+   * directly to this event.
+   */
+  SELECTIONCHANGE: 'selectionchange'
+};
+
+
+/**
+ * The load state of the field.
+ * @enum {number}
+ * @private
+ */
+goog.editor.Field.LoadState_ = {
+  UNEDITABLE: 0,
+  LOADING: 1,
+  EDITABLE: 2
+};
+
+
+/**
+ * The amount of time that a debounce blocks an event.
+ * TODO(nicksantos): As of 9/30/07, this is only used for blocking
+ * a keyup event after a keydown. We might need to tweak this for other
+ * types of events. Maybe have a per-event debounce time?
+ * @type {number}
+ * @private
+ */
+goog.editor.Field.DEBOUNCE_TIME_MS_ = 500;
+
+
+/**
+ * There is at most one "active" field at a time.  By "active" field, we mean
+ * a field that has focus and is being used.
+ * @type {?string}
+ * @private
+ */
+goog.editor.Field.activeFieldId_ = null;
+
+
+/**
+ * Whether this field is in "modal interaction" mode. This usually
+ * means that it's being edited by a dialog.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.Field.prototype.inModalMode_ = false;
+
+
+/**
+ * The window where dialogs and bubbles should be rendered.
+ * @type {!Window}
+ * @private
+ */
+goog.editor.Field.prototype.appWindow_;
+
+
+/**
+ * The dom helper for the node to be made editable.
+ * @type {goog.dom.DomHelper}
+ * @protected
+ */
+goog.editor.Field.prototype.originalDomHelper;
+
+
+/**
+ * Target node to be used when dispatching SELECTIONCHANGE asynchronously on
+ * mouseup (to avoid IE quirk). Should be set just before starting the timer and
+ * nulled right after consuming.
+ * @type {Node}
+ * @private
+ */
+goog.editor.Field.prototype.selectionChangeTarget_;
+
+
+/**
+ * Flag controlling wether to capture mouse up events on the window or not.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.Field.prototype.useWindowMouseUp_ = false;
+
+
+/**
+ * FLag indicating the handling of a mouse event sequence.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.Field.prototype.waitingForMouseUp_ = false;
+
+
+/**
+ * Sets the active field id.
+ * @param {?string} fieldId The active field id.
+ */
+goog.editor.Field.setActiveFieldId = function(fieldId) {
+  goog.editor.Field.activeFieldId_ = fieldId;
+};
+
+
+/**
+ * @return {?string} The id of the active field.
+ */
+goog.editor.Field.getActiveFieldId = function() {
+  return goog.editor.Field.activeFieldId_;
+};
+
+
+/**
+ * Sets flag to control whether to use window mouse up after seeing
+ * a mouse down operation on the field.
+ * @param {boolean} flag True to track window mouse up.
+ */
+goog.editor.Field.prototype.setUseWindowMouseUp = function(flag) {
+  goog.asserts.assert(!flag || !this.usesIframe(),
+      'procssing window mouse up should only be enabled when not using iframe');
+  this.useWindowMouseUp_ = flag;
+};
+
+
+/**
+ * @return {boolean} Whether we're in modal interaction mode. When this
+ *     returns true, another plugin is interacting with the field contents
+ *     in a synchronous way, and expects you not to make changes to
+ *     the field's DOM structure or selection.
+ */
+goog.editor.Field.prototype.inModalMode = function() {
+  return this.inModalMode_;
+};
+
+
+/**
+ * @param {boolean} inModalMode Sets whether we're in modal interaction mode.
+ */
+goog.editor.Field.prototype.setModalMode = function(inModalMode) {
+  this.inModalMode_ = inModalMode;
+};
+
+
+/**
+ * Returns a string usable as a hash code for this field. For field's
+ * that were created with an id, the hash code is guaranteed to be the id.
+ * TODO(user): I think we can get rid of this.  Seems only used from editor.
+ * @return {string} The hash code for this editable field.
+ */
+goog.editor.Field.prototype.getHashCode = function() {
+  return this.hashCode_;
+};
+
+
+/**
+ * Returns the editable DOM element or null if this field
+ * is not editable.
+ * <p>On IE or Safari this is the element with contentEditable=true
+ * (in whitebox mode, the iFrame body).
+ * <p>On Gecko this is the iFrame body
+ * TODO(user): How do we word this for subclass version?
+ * @return {Element} The editable DOM element, defined as above.
+ */
+goog.editor.Field.prototype.getElement = function() {
+  return this.field;
+};
+
+
+/**
+ * Returns original DOM element that is being made editable by Trogedit or
+ * null if that element has not yet been found in the appropriate document.
+ * @return {Element} The original element.
+ */
+goog.editor.Field.prototype.getOriginalElement = function() {
+  return this.originalElement;
+};
+
+
+/**
+ * Registers a keyboard event listener on the field.  This is necessary for
+ * Gecko since the fields are contained in an iFrame and there is no way to
+ * auto-propagate key events up to the main window.
+ * @param {string|Array<string>} type Event type to listen for or array of
+ *    event types, for example goog.events.EventType.KEYDOWN.
+ * @param {Function} listener Function to be used as the listener.
+ * @param {boolean=} opt_capture Whether to use capture phase (optional,
+ *    defaults to false).
+ * @param {Object=} opt_handler Object in whose scope to call the listener.
+ */
+goog.editor.Field.prototype.addListener = function(type, listener, opt_capture,
+                                                   opt_handler) {
+  var elem = this.getElement();
+  // On Gecko, keyboard events only reliably fire on the document element when
+  // using an iframe.
+  if (goog.editor.BrowserFeature.USE_DOCUMENT_FOR_KEY_EVENTS && elem &&
+      this.usesIframe()) {
+    elem = elem.ownerDocument;
+  }
+  if (opt_handler) {
+    this.eventRegister.listenWithScope(
+        elem, type, listener, opt_capture, opt_handler);
+  } else {
+    this.eventRegister.listen(elem, type, listener, opt_capture);
+  }
+};
+
+
+/**
+ * Returns the registered plugin with the given classId.
+ * @param {string} classId classId of the plugin.
+ * @return {goog.editor.Plugin} Registered plugin with the given classId.
+ */
+goog.editor.Field.prototype.getPluginByClassId = function(classId) {
+  return this.plugins_[classId];
+};
+
+
+/**
+ * Registers the plugin with the editable field.
+ * @param {goog.editor.Plugin} plugin The plugin to register.
+ */
+goog.editor.Field.prototype.registerPlugin = function(plugin) {
+  var classId = plugin.getTrogClassId();
+  if (this.plugins_[classId]) {
+    goog.log.error(this.logger,
+        'Cannot register the same class of plugin twice.');
+  }
+  this.plugins_[classId] = plugin;
+
+  // Only key events and execute should have these has* functions with a custom
+  // handler array since they need to be very careful about performance.
+  // The rest of the plugin hooks should be event-based.
+  for (var op in goog.editor.Plugin.OPCODE) {
+    var opcode = goog.editor.Plugin.OPCODE[op];
+    if (plugin[opcode]) {
+      this.indexedPlugins_[op].push(plugin);
+    }
+  }
+  plugin.registerFieldObject(this);
+
+  // By default we enable all plugins for fields that are currently loaded.
+  if (this.isLoaded()) {
+    plugin.enable(this);
+  }
+};
+
+
+/**
+ * Unregisters the plugin with this field.
+ * @param {goog.editor.Plugin} plugin The plugin to unregister.
+ */
+goog.editor.Field.prototype.unregisterPlugin = function(plugin) {
+  var classId = plugin.getTrogClassId();
+  if (!this.plugins_[classId]) {
+    goog.log.error(this.logger,
+        'Cannot unregister a plugin that isn\'t registered.');
+  }
+  delete this.plugins_[classId];
+
+  for (var op in goog.editor.Plugin.OPCODE) {
+    var opcode = goog.editor.Plugin.OPCODE[op];
+    if (plugin[opcode]) {
+      goog.array.remove(this.indexedPlugins_[op], plugin);
+    }
+  }
+
+  plugin.unregisterFieldObject(this);
+};
+
+
+/**
+ * Sets the value that will replace the style attribute of this field's
+ * element when the field is made non-editable. This method is called with the
+ * current value of the style attribute when the field is made editable.
+ * @param {string} cssText The value of the style attribute.
+ */
+goog.editor.Field.prototype.setInitialStyle = function(cssText) {
+  this.cssText = cssText;
+};
+
+
+/**
+ * Reset the properties on the original field element to how it was before
+ * it was made editable.
+ */
+goog.editor.Field.prototype.resetOriginalElemProperties = function() {
+  var field = this.getOriginalElement();
+  field.removeAttribute('contentEditable');
+  field.removeAttribute('g_editable');
+  field.removeAttribute('role');
+
+  if (!this.id) {
+    field.removeAttribute('id');
+  } else {
+    field.id = this.id;
+  }
+
+  field.className = this.savedClassName_ || '';
+
+  var cssText = this.cssText;
+  if (!cssText) {
+    field.removeAttribute('style');
+  } else {
+    goog.dom.setProperties(field, {'style' : cssText});
+  }
+
+  if (goog.isString(this.originalFieldLineHeight_)) {
+    goog.style.setStyle(field, 'lineHeight', this.originalFieldLineHeight_);
+    this.originalFieldLineHeight_ = null;
+  }
+};
+
+
+/**
+ * Checks the modified state of the field.
+ * Note: Changes that take place while the goog.editor.Field.EventType.CHANGE
+ * event is stopped do not effect the modified state.
+ * @param {boolean=} opt_useIsEverModified Set to true to check if the field
+ *   has ever been modified since it was created, otherwise checks if the field
+ *   has been modified since the last goog.editor.Field.EventType.DELAYEDCHANGE
+ *   event was dispatched.
+ * @return {boolean} Whether the field has been modified.
+ */
+goog.editor.Field.prototype.isModified = function(opt_useIsEverModified) {
+  return opt_useIsEverModified ? this.isEverModified_ : this.isModified_;
+};
+
+
+/**
+ * Number of milliseconds after a change when the change event should be fired.
+ * @type {number}
+ */
+goog.editor.Field.CHANGE_FREQUENCY = 15;
+
+
+/**
+ * Number of milliseconds between delayed change events.
+ * @type {number}
+ */
+goog.editor.Field.DELAYED_CHANGE_FREQUENCY = 250;
+
+
+/**
+ * @return {boolean} Whether the field is implemented as an iframe.
+ */
+goog.editor.Field.prototype.usesIframe = goog.functions.TRUE;
+
+
+/**
+ * @return {boolean} Whether the field should be rendered with a fixed
+ *     height, or should expand to fit its contents.
+ */
+goog.editor.Field.prototype.isFixedHeight = goog.functions.TRUE;
+
+
+/**
+ * @return {boolean} Whether the field should be refocused on input.
+ *    This is a workaround for the iOS bug that text input doesn't work
+ *    when the main window listens touch events.
+ */
+goog.editor.Field.prototype.shouldRefocusOnInputMobileSafari =
+    goog.functions.FALSE;
+
+
+/**
+ * Map of keyCodes (not charCodes) that cause changes in the field contents.
+ * @type {Object}
+ * @private
+ */
+goog.editor.Field.KEYS_CAUSING_CHANGES_ = {
+  46: true, // DEL
+  8: true // BACKSPACE
+};
+
+if (!goog.userAgent.IE) {
+  // Only IE doesn't change the field by default upon tab.
+  // TODO(user): This really isn't right now that we have tab plugins.
+  goog.editor.Field.KEYS_CAUSING_CHANGES_[9] = true; // TAB
+}
+
+
+/**
+ * Map of keyCodes (not charCodes) that when used in conjunction with the
+ * Ctrl key cause changes in the field contents. These are the keys that are
+ * not handled by basic formatting trogedit plugins.
+ * @type {Object}
+ * @private
+ */
+goog.editor.Field.CTRL_KEYS_CAUSING_CHANGES_ = {
+  86: true, // V
+  88: true // X
+};
+
+if (goog.userAgent.WINDOWS && !goog.userAgent.GECKO) {
+  // In IE and Webkit, input from IME (Input Method Editor) does not generate a
+  // keypress event so we have to rely on the keydown event. This way we have
+  // false positives while the user is using keyboard to select the
+  // character to input, but it is still better than the false negatives
+  // that ignores user's final input at all.
+  goog.editor.Field.KEYS_CAUSING_CHANGES_[229] = true; // from IME;
+}
+
+
+/**
+ * Returns true if the keypress generates a change in contents.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @param {boolean} testAllKeys True to test for all types of generating keys.
+ *     False to test for only the keys found in
+ *     goog.editor.Field.KEYS_CAUSING_CHANGES_.
+ * @return {boolean} Whether the keypress generates a change in contents.
+ * @private
+ */
+goog.editor.Field.isGeneratingKey_ = function(e, testAllKeys) {
+  if (goog.editor.Field.isSpecialGeneratingKey_(e)) {
+    return true;
+  }
+
+  return !!(testAllKeys && !(e.ctrlKey || e.metaKey) &&
+      (!goog.userAgent.GECKO || e.charCode));
+};
+
+
+/**
+ * Returns true if the keypress generates a change in the contents.
+ * due to a special key listed in goog.editor.Field.KEYS_CAUSING_CHANGES_
+ * @param {goog.events.BrowserEvent} e The event.
+ * @return {boolean} Whether the keypress generated a change in the contents.
+ * @private
+ */
+goog.editor.Field.isSpecialGeneratingKey_ = function(e) {
+  var testCtrlKeys = (e.ctrlKey || e.metaKey) &&
+      e.keyCode in goog.editor.Field.CTRL_KEYS_CAUSING_CHANGES_;
+  var testRegularKeys = !(e.ctrlKey || e.metaKey) &&
+      e.keyCode in goog.editor.Field.KEYS_CAUSING_CHANGES_;
+
+  return testCtrlKeys || testRegularKeys;
+};
+
+
+/**
+ * Sets the application window.
+ * @param {!Window} appWindow The window where dialogs and bubbles should be
+ *     rendered.
+ */
+goog.editor.Field.prototype.setAppWindow = function(appWindow) {
+  this.appWindow_ = appWindow;
+};
+
+
+/**
+ * Returns the "application" window, where dialogs and bubbles
+ * should be rendered.
+ * @return {!Window} The window.
+ */
+goog.editor.Field.prototype.getAppWindow = function() {
+  return this.appWindow_;
+};
+
+
+/**
+ * Sets the zIndex that the field should be based off of.
+ * TODO(user): Get rid of this completely.  Here for Sites.
+ *     Should this be set directly on UI plugins?
+ *
+ * @param {number} zindex The base zIndex of the editor.
+ */
+goog.editor.Field.prototype.setBaseZindex = function(zindex) {
+  this.baseZindex_ = zindex;
+};
+
+
+/**
+ * Returns the zindex of the base level of the field.
+ *
+ * @return {number} The base zindex of the editor.
+ */
+goog.editor.Field.prototype.getBaseZindex = function() {
+  return this.baseZindex_ || 0;
+};
+
+
+/**
+ * Sets up the field object and window util of this field, and enables this
+ * editable field with all registered plugins.
+ * This is essential to the initialization of the field.
+ * It must be called when the field becomes fully loaded and editable.
+ * @param {Element} field The field property.
+ * @protected
+ */
+goog.editor.Field.prototype.setupFieldObject = function(field) {
+  this.loadState_ = goog.editor.Field.LoadState_.EDITABLE;
+  this.field = field;
+  this.editableDomHelper = goog.dom.getDomHelper(field);
+  this.isModified_ = false;
+  this.isEverModified_ = false;
+  field.setAttribute('g_editable', 'true');
+  goog.a11y.aria.setRole(field, goog.a11y.aria.Role.TEXTBOX);
+};
+
+
+/**
+ * Help make the field not editable by setting internal data structures to null,
+ * and disabling this field with all registered plugins.
+ * @private
+ */
+goog.editor.Field.prototype.tearDownFieldObject_ = function() {
+  this.loadState_ = goog.editor.Field.LoadState_.UNEDITABLE;
+
+  for (var classId in this.plugins_) {
+    var plugin = this.plugins_[classId];
+    if (!plugin.activeOnUneditableFields()) {
+      plugin.disable(this);
+    }
+  }
+
+  this.field = null;
+  this.editableDomHelper = null;
+};
+
+
+/**
+ * Initialize listeners on the field.
+ * @private
+ */
+goog.editor.Field.prototype.setupChangeListeners_ = function() {
+  if ((goog.userAgent.product.IPHONE || goog.userAgent.product.IPAD) &&
+      this.usesIframe() && this.shouldRefocusOnInputMobileSafari()) {
+    // This is a workaround for the iOS bug that text input doesn't work
+    // when the main window listens touch events.
+    var editWindow = this.getEditableDomHelper().getWindow();
+    this.boundRefocusListenerMobileSafari_ =
+        goog.bind(editWindow.focus, editWindow);
+    editWindow.addEventListener(goog.events.EventType.KEYDOWN,
+        this.boundRefocusListenerMobileSafari_, false);
+    editWindow.addEventListener(goog.events.EventType.TOUCHEND,
+        this.boundRefocusListenerMobileSafari_, false);
+  }
+  if (goog.userAgent.OPERA && this.usesIframe()) {
+    // We can't use addListener here because we need to listen on the window,
+    // and removing listeners on window objects from the event register throws
+    // an exception if the window is closed.
+    this.boundFocusListenerOpera_ =
+        goog.bind(this.dispatchFocusAndBeforeFocus_, this);
+    this.boundBlurListenerOpera_ =
+        goog.bind(this.dispatchBlur, this);
+    var editWindow = this.getEditableDomHelper().getWindow();
+    editWindow.addEventListener(goog.events.EventType.FOCUS,
+        this.boundFocusListenerOpera_, false);
+    editWindow.addEventListener(goog.events.EventType.BLUR,
+        this.boundBlurListenerOpera_, false);
+  } else {
+    if (goog.editor.BrowserFeature.SUPPORTS_FOCUSIN) {
+      this.addListener(goog.events.EventType.FOCUS, this.dispatchFocus_);
+      this.addListener(goog.events.EventType.FOCUSIN,
+                       this.dispatchBeforeFocus_);
+    } else {
+      this.addListener(goog.events.EventType.FOCUS,
+                       this.dispatchFocusAndBeforeFocus_);
+    }
+    this.addListener(goog.events.EventType.BLUR, this.dispatchBlur,
+                     goog.editor.BrowserFeature.USE_MUTATION_EVENTS);
+  }
+
+  if (goog.editor.BrowserFeature.USE_MUTATION_EVENTS) {
+    // Ways to detect changes in Mozilla:
+    //
+    // keypress - check event.charCode (only typable characters has a
+    //            charCode), but also keyboard commands lile Ctrl+C will
+    //            return a charCode.
+    // dragdrop - fires when the user drops something. This does not necessary
+    //            lead to a change but we cannot detect if it will or not
+    //
+    // Known Issues: We cannot detect cut and paste using menus
+    //               We cannot detect when someone moves something out of the
+    //               field using drag and drop.
+    //
+    this.setupMutationEventHandlersGecko();
+  } else {
+    // Ways to detect that a change is about to happen in other browsers.
+    // (IE and Safari have these events. Opera appears to work, but we haven't
+    //  researched it.)
+    //
+    // onbeforepaste
+    // onbeforecut
+    // ondrop - happens when the user drops something on the editable text
+    //          field the value at this time does not contain the dropped text
+    // ondragleave - when the user drags something from the current document.
+    //               This might not cause a change if the action was copy
+    //               instead of move
+    // onkeypress - IE only fires keypress events if the key will generate
+    //              output. It will not trigger for delete and backspace
+    // onkeydown - For delete and backspace
+    //
+    // known issues: IE triggers beforepaste just by opening the edit menu
+    //               delete at the end should not cause beforechange
+    //               backspace at the beginning should not cause beforechange
+    //               see above in ondragleave
+    // TODO(user): Why don't we dispatchBeforeChange from the
+    // handleDrop event for all browsers?
+    this.addListener(['beforecut', 'beforepaste', 'drop', 'dragend'],
+        this.dispatchBeforeChange);
+    this.addListener(['cut', 'paste'],
+        goog.functions.lock(this.dispatchChange));
+    this.addListener('drop', this.handleDrop_);
+  }
+
+  // TODO(user): Figure out why we use dragend vs dragdrop and
+  // document this better.
+  var dropEventName = goog.userAgent.WEBKIT ? 'dragend' : 'dragdrop';
+  this.addListener(dropEventName, this.handleDrop_);
+
+  this.addListener(goog.events.EventType.KEYDOWN, this.handleKeyDown_);
+  this.addListener(goog.events.EventType.KEYPRESS, this.handleKeyPress_);
+  this.addListener(goog.events.EventType.KEYUP, this.handleKeyUp_);
+
+  this.selectionChangeTimer_ =
+      new goog.async.Delay(this.handleSelectionChangeTimer_,
+                           goog.editor.Field.SELECTION_CHANGE_FREQUENCY_, this);
+
+  if (this.followLinkInNewWindow_) {
+    this.addListener(
+        goog.events.EventType.CLICK, goog.editor.Field.cancelLinkClick_);
+  }
+
+  this.addListener(goog.events.EventType.MOUSEDOWN, this.handleMouseDown_);
+  if (this.useWindowMouseUp_) {
+    this.eventRegister.listen(this.editableDomHelper.getDocument(),
+        goog.events.EventType.MOUSEUP, this.handleMouseUp_);
+    this.addListener(goog.events.EventType.DRAGSTART, this.handleDragStart_);
+  } else {
+    this.addListener(goog.events.EventType.MOUSEUP, this.handleMouseUp_);
+  }
+};
+
+
+/**
+ * Frequency to check for selection changes.
+ * @type {number}
+ * @private
+ */
+goog.editor.Field.SELECTION_CHANGE_FREQUENCY_ = 250;
+
+
+/**
+ * Stops all listeners and timers.
+ * @protected
+ */
+goog.editor.Field.prototype.clearListeners = function() {
+  if (this.eventRegister) {
+    this.eventRegister.removeAll();
+  }
+
+  if ((goog.userAgent.product.IPHONE || goog.userAgent.product.IPAD) &&
+      this.usesIframe() && this.shouldRefocusOnInputMobileSafari()) {
+    try {
+      var editWindow = this.getEditableDomHelper().getWindow();
+      editWindow.removeEventListener(goog.events.EventType.KEYDOWN,
+          this.boundRefocusListenerMobileSafari_, false);
+      editWindow.removeEventListener(goog.events.EventType.TOUCHEND,
+          this.boundRefocusListenerMobileSafari_, false);
+    } catch (e) {
+      // The editWindow no longer exists, or has been navigated to a different-
+      // origin URL. Either way, the event listeners have already been removed
+      // for us.
+    }
+    delete this.boundRefocusListenerMobileSafari_;
+  }
+  if (goog.userAgent.OPERA && this.usesIframe()) {
+    try {
+      var editWindow = this.getEditableDomHelper().getWindow();
+      editWindow.removeEventListener(goog.events.EventType.FOCUS,
+          this.boundFocusListenerOpera_, false);
+      editWindow.removeEventListener(goog.events.EventType.BLUR,
+          this.boundBlurListenerOpera_, false);
+    } catch (e) {
+      // The editWindow no longer exists, or has been navigated to a different-
+      // origin URL. Either way, the event listeners have already been removed
+      // for us.
+    }
+    delete this.boundFocusListenerOpera_;
+    delete this.boundBlurListenerOpera_;
+  }
+
+  if (this.changeTimerGecko_) {
+    this.changeTimerGecko_.stop();
+  }
+  this.delayedChangeTimer_.stop();
+};
+
+
+/** @override */
+goog.editor.Field.prototype.disposeInternal = function() {
+  if (this.isLoading() || this.isLoaded()) {
+    goog.log.warning(this.logger, 'Disposing a field that is in use.');
+  }
+
+  if (this.getOriginalElement()) {
+    this.execCommand(goog.editor.Command.CLEAR_LOREM);
+  }
+
+  this.tearDownFieldObject_();
+  this.clearListeners();
+  this.clearFieldLoadListener_();
+  this.originalDomHelper = null;
+
+  if (this.eventRegister) {
+    this.eventRegister.dispose();
+    this.eventRegister = null;
+  }
+
+  this.removeAllWrappers();
+
+  if (goog.editor.Field.getActiveFieldId() == this.id) {
+    goog.editor.Field.setActiveFieldId(null);
+  }
+
+  for (var classId in this.plugins_) {
+    var plugin = this.plugins_[classId];
+    if (plugin.isAutoDispose()) {
+      plugin.dispose();
+    }
+  }
+  delete(this.plugins_);
+
+  goog.editor.Field.superClass_.disposeInternal.call(this);
+};
+
+
+/**
+ * Attach an wrapper to this field, to be thrown out when the field
+ * is disposed.
+ * @param {goog.Disposable} wrapper The wrapper to attach.
+ */
+goog.editor.Field.prototype.attachWrapper = function(wrapper) {
+  this.wrappers_.push(wrapper);
+};
+
+
+/**
+ * Removes all wrappers and destroys them.
+ */
+goog.editor.Field.prototype.removeAllWrappers = function() {
+  var wrapper;
+  while (wrapper = this.wrappers_.pop()) {
+    wrapper.dispose();
+  }
+};
+
+
+/**
+ * Sets whether activating a hyperlink in this editable field will open a new
+ *     window or not.
+ * @param {boolean} followLinkInNewWindow
+ */
+goog.editor.Field.prototype.setFollowLinkInNewWindow =
+    function(followLinkInNewWindow) {
+  this.followLinkInNewWindow_ = followLinkInNewWindow;
+};
+
+
+/**
+ * List of mutation events in Gecko browsers.
+ * @type {Array<string>}
+ * @protected
+ */
+goog.editor.Field.MUTATION_EVENTS_GECKO = [
+  'DOMNodeInserted',
+  'DOMNodeRemoved',
+  'DOMNodeRemovedFromDocument',
+  'DOMNodeInsertedIntoDocument',
+  'DOMCharacterDataModified'
+];
+
+
+/**
+ * Mutation events tell us when something has changed for mozilla.
+ * @protected
+ */
+goog.editor.Field.prototype.setupMutationEventHandlersGecko = function() {
+  // Always use DOMSubtreeModified on Gecko when not using an iframe so that
+  // DOM mutations outside the Field do not trigger handleMutationEventGecko_.
+  if (goog.editor.BrowserFeature.HAS_DOM_SUBTREE_MODIFIED_EVENT ||
+      !this.usesIframe()) {
+    this.eventRegister.listen(this.getElement(), 'DOMSubtreeModified',
+        this.handleMutationEventGecko_);
+  } else {
+    var doc = this.getEditableDomHelper().getDocument();
+    this.eventRegister.listen(doc, goog.editor.Field.MUTATION_EVENTS_GECKO,
+        this.handleMutationEventGecko_, true);
+
+    // DOMAttrModified fires for a lot of events we want to ignore.  This goes
+    // through a different handler so that we can ignore many of these.
+    this.eventRegister.listen(doc, 'DOMAttrModified',
+        goog.bind(this.handleDomAttrChange, this,
+            this.handleMutationEventGecko_),
+        true);
+  }
+};
+
+
+/**
+ * Handle before change key events and fire the beforetab event if appropriate.
+ * This needs to happen on keydown in IE and keypress in FF.
+ * @param {goog.events.BrowserEvent} e The browser event.
+ * @return {boolean} Whether to still perform the default key action.  Only set
+ *     to true if the actual event has already been canceled.
+ * @private
+ */
+goog.editor.Field.prototype.handleBeforeChangeKeyEvent_ = function(e) {
+  // There are two reasons to block a key:
+  var block =
+      // #1: to intercept a tab
+      // TODO: possibly don't allow clients to intercept tabs outside of LIs and
+      // maybe tables as well?
+      (e.keyCode == goog.events.KeyCodes.TAB && !this.dispatchBeforeTab_(e)) ||
+      // #2: to block a Firefox-specific bug where Macs try to navigate
+      // back a page when you hit command+left arrow or comamnd-right arrow.
+      // See https://bugzilla.mozilla.org/show_bug.cgi?id=341886
+      // This was fixed in Firefox 29, but still exists in older versions.
+      (goog.userAgent.GECKO && e.metaKey &&
+       !goog.userAgent.isVersionOrHigher(29) &&
+       (e.keyCode == goog.events.KeyCodes.LEFT ||
+        e.keyCode == goog.events.KeyCodes.RIGHT));
+
+  if (block) {
+    e.preventDefault();
+    return false;
+  } else {
+    // In Gecko we have both keyCode and charCode. charCode is for human
+    // readable characters like a, b and c. However pressing ctrl+c and so on
+    // also causes charCode to be set.
+
+    // TODO(arv): Del at end of field or backspace at beginning should be
+    // ignored.
+    this.gotGeneratingKey_ = e.charCode ||
+        goog.editor.Field.isGeneratingKey_(e, goog.userAgent.GECKO);
+    if (this.gotGeneratingKey_) {
+      this.dispatchBeforeChange();
+      // TODO(robbyw): Should we return the value of the above?
+    }
+  }
+
+  return true;
+};
+
+
+/**
+ * Keycodes that result in a selectionchange event (e.g. the cursor moving).
+ * @type {!Object<number, number>}
+ */
+goog.editor.Field.SELECTION_CHANGE_KEYCODES = {
+  8: 1,  // backspace
+  9: 1,  // tab
+  13: 1, // enter
+  33: 1, // page up
+  34: 1, // page down
+  35: 1, // end
+  36: 1, // home
+  37: 1, // left
+  38: 1, // up
+  39: 1, // right
+  40: 1, // down
+  46: 1  // delete
+};
+
+
+/**
+ * Map of keyCodes (not charCodes) that when used in conjunction with the
+ * Ctrl key cause selection changes in the field contents. These are the keys
+ * that are not handled by the basic formatting trogedit plugins. Note that
+ * combinations like Ctrl-left etc are already handled in
+ * SELECTION_CHANGE_KEYCODES
+ * @type {Object}
+ * @private
+ */
+goog.editor.Field.CTRL_KEYS_CAUSING_SELECTION_CHANGES_ = {
+  65: true, // A
+  86: true, // V
+  88: true // X
+};
+
+
+/**
+ * Map of keyCodes (not charCodes) that might need to be handled as a keyboard
+ * shortcut (even when ctrl/meta key is not pressed) by some plugin. Currently
+ * it is a small list. If it grows too big we can optimize it by using ranges
+ * or extending it from SELECTION_CHANGE_KEYCODES
+ * @type {Object}
+ * @private
+ */
+goog.editor.Field.POTENTIAL_SHORTCUT_KEYCODES_ = {
+  8: 1,  // backspace
+  9: 1,  // tab
+  13: 1, // enter
+  27: 1, // esc
+  33: 1, // page up
+  34: 1, // page down
+  37: 1, // left
+  38: 1, // up
+  39: 1, // right
+  40: 1  // down
+};
+
+
+/**
+ * Calls all the plugins of the given operation, in sequence, with the
+ * given arguments. This is short-circuiting: once one plugin cancels
+ * the event, no more plugins will be invoked.
+ * @param {goog.editor.Plugin.Op} op A plugin op.
+ * @param {...*} var_args The arguments to the plugin.
+ * @return {boolean} True if one of the plugins cancel the event, false
+ *    otherwise.
+ * @private
+ */
+goog.editor.Field.prototype.invokeShortCircuitingOp_ = function(op, var_args) {
+  var plugins = this.indexedPlugins_[op];
+  var argList = goog.array.slice(arguments, 1);
+  for (var i = 0; i < plugins.length; ++i) {
+    // If the plugin returns true, that means it handled the event and
+    // we shouldn't propagate to the other plugins.
+    var plugin = plugins[i];
+    if ((plugin.isEnabled(this) ||
+         goog.editor.Plugin.IRREPRESSIBLE_OPS[op]) &&
+        plugin[goog.editor.Plugin.OPCODE[op]].apply(plugin, argList)) {
+      // Only one plugin is allowed to handle the event. If for some reason
+      // a plugin wants to handle it and still allow other plugins to handle
+      // it, it shouldn't return true.
+      return true;
+    }
+  }
+
+  return false;
+};
+
+
+/**
+ * Invoke this operation on all plugins with the given arguments.
+ * @param {goog.editor.Plugin.Op} op A plugin op.
+ * @param {...*} var_args The arguments to the plugin.
+ * @private
+ */
+goog.editor.Field.prototype.invokeOp_ = function(op, var_args) {
+  var plugins = this.indexedPlugins_[op];
+  var argList = goog.array.slice(arguments, 1);
+  for (var i = 0; i < plugins.length; ++i) {
+    var plugin = plugins[i];
+    if (plugin.isEnabled(this) ||
+        goog.editor.Plugin.IRREPRESSIBLE_OPS[op]) {
+      plugin[goog.editor.Plugin.OPCODE[op]].apply(plugin, argList);
+    }
+  }
+};
+
+
+/**
+ * Reduce this argument over all plugins. The result of each plugin invocation
+ * will be passed to the next plugin invocation. See goog.array.reduce.
+ * @param {goog.editor.Plugin.Op} op A plugin op.
+ * @param {string} arg The argument to reduce. For now, we assume it's a
+ *     string, but we should widen this later if there are reducing
+ *     plugins that don't operate on strings.
+ * @param {...*} var_args Any extra arguments to pass to the plugin. These args
+ *     will not be reduced.
+ * @return {string} The reduced argument.
+ * @private
+ */
+goog.editor.Field.prototype.reduceOp_ = function(op, arg, var_args) {
+  var plugins = this.indexedPlugins_[op];
+  var argList = goog.array.slice(arguments, 1);
+  for (var i = 0; i < plugins.length; ++i) {
+    var plugin = plugins[i];
+    if (plugin.isEnabled(this) ||
+        goog.editor.Plugin.IRREPRESSIBLE_OPS[op]) {
+      argList[0] = plugin[goog.editor.Plugin.OPCODE[op]].apply(
+          plugin, argList);
+    }
+  }
+  return argList[0];
+};
+
+
+/**
+ * Prepare the given contents, then inject them into the editable field.
+ * @param {?string} contents The contents to prepare.
+ * @param {Element} field The field element.
+ * @protected
+ */
+goog.editor.Field.prototype.injectContents = function(contents, field) {
+  var styles = {};
+  var newHtml = this.getInjectableContents(contents, styles);
+  goog.style.setStyle(field, styles);
+  goog.editor.node.replaceInnerHtml(field, newHtml);
+};
+
+
+/**
+ * Returns prepared contents that can be injected into the editable field.
+ * @param {?string} contents The contents to prepare.
+ * @param {Object} styles A map that will be populated with styles that should
+ *     be applied to the field element together with the contents.
+ * @return {string} The prepared contents.
+ */
+goog.editor.Field.prototype.getInjectableContents = function(contents, styles) {
+  return this.reduceOp_(
+      goog.editor.Plugin.Op.PREPARE_CONTENTS_HTML, contents || '', styles);
+};
+
+
+/**
+ * Handles keydown on the field.
+ * @param {goog.events.BrowserEvent} e The browser event.
+ * @private
+ */
+goog.editor.Field.prototype.handleKeyDown_ = function(e) {
+  if (!goog.editor.BrowserFeature.USE_MUTATION_EVENTS) {
+    if (!this.handleBeforeChangeKeyEvent_(e)) {
+      return;
+    }
+  }
+
+  if (!this.invokeShortCircuitingOp_(goog.editor.Plugin.Op.KEYDOWN, e) &&
+      goog.editor.BrowserFeature.USES_KEYDOWN) {
+    this.handleKeyboardShortcut_(e);
+  }
+};
+
+
+/**
+ * Handles keypress on the field.
+ * @param {goog.events.BrowserEvent} e The browser event.
+ * @private
+ */
+goog.editor.Field.prototype.handleKeyPress_ = function(e) {
+  if (goog.editor.BrowserFeature.USE_MUTATION_EVENTS) {
+    if (!this.handleBeforeChangeKeyEvent_(e)) {
+      return;
+    }
+  } else {
+    // In IE only keys that generate output trigger keypress
+    // In Mozilla charCode is set for keys generating content.
+    this.gotGeneratingKey_ = true;
+    this.dispatchBeforeChange();
+  }
+
+  if (!this.invokeShortCircuitingOp_(goog.editor.Plugin.Op.KEYPRESS, e) &&
+      !goog.editor.BrowserFeature.USES_KEYDOWN) {
+    this.handleKeyboardShortcut_(e);
+  }
+};
+
+
+/**
+ * Handles keyup on the field.
+ * @param {goog.events.BrowserEvent} e The browser event.
+ * @private
+ */
+goog.editor.Field.prototype.handleKeyUp_ = function(e) {
+  if (!goog.editor.BrowserFeature.USE_MUTATION_EVENTS &&
+      (this.gotGeneratingKey_ ||
+       goog.editor.Field.isSpecialGeneratingKey_(e))) {
+    // The special keys won't have set the gotGeneratingKey flag, so we check
+    // for them explicitly
+    this.handleChange();
+  }
+
+  this.invokeShortCircuitingOp_(goog.editor.Plugin.Op.KEYUP, e);
+
+  if (this.isEventStopped(goog.editor.Field.EventType.SELECTIONCHANGE)) {
+    return;
+  }
+
+  if (goog.editor.Field.SELECTION_CHANGE_KEYCODES[e.keyCode] ||
+      ((e.ctrlKey || e.metaKey) &&
+       goog.editor.Field.CTRL_KEYS_CAUSING_SELECTION_CHANGES_[e.keyCode])) {
+    this.selectionChangeTimer_.start();
+  }
+};
+
+
+/**
+ * Handles keyboard shortcuts on the field.  Note that we bake this into our
+ * handleKeyPress/handleKeyDown rather than using goog.events.KeyHandler or
+ * goog.ui.KeyboardShortcutHandler for performance reasons.  Since these
+ * are handled on every key stroke, we do not want to be going out to the
+ * event system every time.
+ * @param {goog.events.BrowserEvent} e The browser event.
+ * @private
+ */
+goog.editor.Field.prototype.handleKeyboardShortcut_ = function(e) {
+  // Alt key is used for i18n languages to enter certain characters. like
+  // control + alt + z (used for IMEs) and control + alt + s for Polish.
+  // So we don't invoke handleKeyboardShortcut at all for alt keys.
+  if (e.altKey) {
+    return;
+  }
+
+  var isModifierPressed = goog.userAgent.MAC ? e.metaKey : e.ctrlKey;
+  if (isModifierPressed ||
+      goog.editor.Field.POTENTIAL_SHORTCUT_KEYCODES_[e.keyCode]) {
+    // TODO(user): goog.events.KeyHandler uses much more complicated logic
+    // to determine key.  Consider changing to what they do.
+    var key = e.charCode || e.keyCode;
+
+    if (key == 17) { // Ctrl key
+      // In IE and Webkit pressing Ctrl key itself results in this event.
+      return;
+    }
+
+    var stringKey = String.fromCharCode(key).toLowerCase();
+    if (this.invokeShortCircuitingOp_(goog.editor.Plugin.Op.SHORTCUT,
+                                      e, stringKey, isModifierPressed)) {
+      e.preventDefault();
+      // We don't call stopPropagation as some other handler outside of
+      // trogedit might need it.
+    }
+  }
+};
+
+
+/**
+ * Executes an editing command as per the registered plugins.
+ * @param {string} command The command to execute.
+ * @param {...*} var_args Any additional parameters needed to execute the
+ *     command.
+ * @return {*} False if the command wasn't handled, otherwise, the result of
+ *     the command.
+ */
+goog.editor.Field.prototype.execCommand = function(command, var_args) {
+  var args = arguments;
+  var result;
+
+  var plugins = this.indexedPlugins_[goog.editor.Plugin.Op.EXEC_COMMAND];
+  for (var i = 0; i < plugins.length; ++i) {
+    // If the plugin supports the command, that means it handled the
+    // event and we shouldn't propagate to the other plugins.
+    var plugin = plugins[i];
+    if (plugin.isEnabled(this) && plugin.isSupportedCommand(command)) {
+      result = plugin.execCommand.apply(plugin, args);
+      break;
+    }
+  }
+
+  return result;
+};
+
+
+/**
+ * Gets the value of command(s).
+ * @param {string|Array<string>} commands String name(s) of the command.
+ * @return {*} Value of each command. Returns false (or array of falses)
+ *     if designMode is off or the field is otherwise uneditable, and
+ *     there are no activeOnUneditable plugins for the command.
+ */
+goog.editor.Field.prototype.queryCommandValue = function(commands) {
+  var isEditable = this.isLoaded() && this.isSelectionEditable();
+  if (goog.isString(commands)) {
+    return this.queryCommandValueInternal_(commands, isEditable);
+  } else {
+    var state = {};
+    for (var i = 0; i < commands.length; i++) {
+      state[commands[i]] = this.queryCommandValueInternal_(commands[i],
+          isEditable);
+    }
+    return state;
+  }
+};
+
+
+/**
+ * Gets the value of this command.
+ * @param {string} command The command to check.
+ * @param {boolean} isEditable Whether the field is currently editable.
+ * @return {*} The state of this command. Null if not handled.
+ *     False if the field is uneditable and there are no handlers for
+ *     uneditable commands.
+ * @private
+ */
+goog.editor.Field.prototype.queryCommandValueInternal_ = function(command,
+    isEditable) {
+  var plugins = this.indexedPlugins_[goog.editor.Plugin.Op.QUERY_COMMAND];
+  for (var i = 0; i < plugins.length; ++i) {
+    var plugin = plugins[i];
+    if (plugin.isEnabled(this) && plugin.isSupportedCommand(command) &&
+        (isEditable || plugin.activeOnUneditableFields())) {
+      return plugin.queryCommandValue(command);
+    }
+  }
+  return isEditable ? null : false;
+};
+
+
+/**
+ * Fires a change event only if the attribute change effects the editiable
+ * field. We ignore events that are internal browser events (ie scrollbar
+ * state change)
+ * @param {Function} handler The function to call if this is not an internal
+ *     browser event.
+ * @param {goog.events.BrowserEvent} browserEvent The browser event.
+ * @protected
+ */
+goog.editor.Field.prototype.handleDomAttrChange =
+    function(handler, browserEvent) {
+  if (this.isEventStopped(goog.editor.Field.EventType.CHANGE)) {
+    return;
+  }
+
+  var e = browserEvent.getBrowserEvent();
+
+  // For XUL elements, since we don't care what they are doing
+  try {
+    if (e.originalTarget.prefix || e.originalTarget.nodeName == 'scrollbar') {
+      return;
+    }
+  } catch (ex1) {
+    // Some XUL nodes don't like you reading their properties.  If we got
+    // the exception, this implies  a XUL node so we can return.
+    return;
+  }
+
+  // Check if prev and new values are different, sometimes this fires when
+  // nothing has really changed.
+  if (e.prevValue == e.newValue) {
+    return;
+  }
+  handler.call(this, e);
+};
+
+
+/**
+ * Handle a mutation event.
+ * @param {goog.events.BrowserEvent|Event} e The browser event.
+ * @private
+ */
+goog.editor.Field.prototype.handleMutationEventGecko_ = function(e) {
+  if (this.isEventStopped(goog.editor.Field.EventType.CHANGE)) {
+    return;
+  }
+
+  e = e.getBrowserEvent ? e.getBrowserEvent() : e;
+  // For people with firebug, firebug sets this property on elements it is
+  // inserting into the dom.
+  if (e.target.firebugIgnore) {
+    return;
+  }
+
+  this.isModified_ = true;
+  this.isEverModified_ = true;
+  this.changeTimerGecko_.start();
+};
+
+
+/**
+ * Handle drop events. Deal with focus/selection issues and set the document
+ * as changed.
+ * @param {goog.events.BrowserEvent} e The browser event.
+ * @private
+ */
+goog.editor.Field.prototype.handleDrop_ = function(e) {
+  if (goog.userAgent.IE) {
+    // TODO(user): This should really be done in the loremipsum plugin.
+    this.execCommand(goog.editor.Command.CLEAR_LOREM, true);
+  }
+
+  // TODO(user): I just moved this code to this location, but I wonder why
+  // it is only done for this case.  Investigate.
+  if (goog.editor.BrowserFeature.USE_MUTATION_EVENTS) {
+    this.dispatchFocusAndBeforeFocus_();
+  }
+
+  this.dispatchChange();
+};
+
+
+/**
+ * @return {HTMLIFrameElement} The iframe that's body is editable.
+ * @protected
+ */
+goog.editor.Field.prototype.getEditableIframe = function() {
+  var dh;
+  if (this.usesIframe() && (dh = this.getEditableDomHelper())) {
+    // If the iframe has been destroyed, the dh could still exist since the
+    // node may not be gc'ed, but fetching the window can fail.
+    var win = dh.getWindow();
+    return /** @type {HTMLIFrameElement} */ (win && win.frameElement);
+  }
+  return null;
+};
+
+
+/**
+ * @return {goog.dom.DomHelper?} The dom helper for the editable node.
+ */
+goog.editor.Field.prototype.getEditableDomHelper = function() {
+  return this.editableDomHelper;
+};
+
+
+/**
+ * @return {goog.dom.AbstractRange?} Closure range object wrapping the selection
+ *     in this field or null if this field is not currently editable.
+ */
+goog.editor.Field.prototype.getRange = function() {
+  var win = this.editableDomHelper && this.editableDomHelper.getWindow();
+  return win && goog.dom.Range.createFromWindow(win);
+};
+
+
+/**
+ * Dispatch a selection change event, optionally caused by the given browser
+ * event or selecting the given target.
+ * @param {goog.events.BrowserEvent=} opt_e Optional browser event causing this
+ *     event.
+ * @param {Node=} opt_target The node the selection changed to.
+ */
+goog.editor.Field.prototype.dispatchSelectionChangeEvent = function(
+    opt_e, opt_target) {
+  if (this.isEventStopped(goog.editor.Field.EventType.SELECTIONCHANGE)) {
+    return;
+  }
+
+  // The selection is editable only if the selection is inside the
+  // editable field.
+  var range = this.getRange();
+  var rangeContainer = range && range.getContainerElement();
+  this.isSelectionEditable_ = !!rangeContainer &&
+      goog.dom.contains(this.getElement(), rangeContainer);
+
+  this.dispatchCommandValueChange();
+  this.dispatchEvent({
+    type: goog.editor.Field.EventType.SELECTIONCHANGE,
+    originalType: opt_e && opt_e.type
+  });
+
+  this.invokeShortCircuitingOp_(goog.editor.Plugin.Op.SELECTION,
+                                opt_e, opt_target);
+};
+
+
+/**
+ * Dispatch a selection change event using a browser event that was
+ * asynchronously saved earlier.
+ * @private
+ */
+goog.editor.Field.prototype.handleSelectionChangeTimer_ = function() {
+  var t = this.selectionChangeTarget_;
+  this.selectionChangeTarget_ = null;
+  this.dispatchSelectionChangeEvent(undefined, t);
+};
+
+
+/**
+ * This dispatches the beforechange event on the editable field
+ */
+goog.editor.Field.prototype.dispatchBeforeChange = function() {
+  if (this.isEventStopped(goog.editor.Field.EventType.BEFORECHANGE)) {
+    return;
+  }
+
+  this.dispatchEvent(goog.editor.Field.EventType.BEFORECHANGE);
+};
+
+
+/**
+ * This dispatches the beforetab event on the editable field. If this event is
+ * cancelled, then the default tab behavior is prevented.
+ * @param {goog.events.BrowserEvent} e The tab event.
+ * @private
+ * @return {boolean} The result of dispatchEvent.
+ */
+goog.editor.Field.prototype.dispatchBeforeTab_ = function(e) {
+  return this.dispatchEvent({
+    type: goog.editor.Field.EventType.BEFORETAB,
+    shiftKey: e.shiftKey,
+    altKey: e.altKey,
+    ctrlKey: e.ctrlKey
+  });
+};
+
+
+/**
+ * Temporarily ignore change events. If the time has already been set, it will
+ * fire immediately now.  Further setting of the timer is stopped and
+ * dispatching of events is stopped until startChangeEvents is called.
+ * @param {boolean=} opt_stopChange Whether to ignore base change events.
+ * @param {boolean=} opt_stopDelayedChange Whether to ignore delayed change
+ *     events.
+ */
+goog.editor.Field.prototype.stopChangeEvents = function(opt_stopChange,
+    opt_stopDelayedChange) {
+  if (opt_stopChange) {
+    if (this.changeTimerGecko_) {
+      this.changeTimerGecko_.fireIfActive();
+    }
+
+    this.stopEvent(goog.editor.Field.EventType.CHANGE);
+  }
+  if (opt_stopDelayedChange) {
+    this.clearDelayedChange();
+    this.stopEvent(goog.editor.Field.EventType.DELAYEDCHANGE);
+  }
+};
+
+
+/**
+ * Start change events again and fire once if desired.
+ * @param {boolean=} opt_fireChange Whether to fire the change event
+ *      immediately.
+ * @param {boolean=} opt_fireDelayedChange Whether to fire the delayed change
+ *      event immediately.
+ */
+goog.editor.Field.prototype.startChangeEvents = function(opt_fireChange,
+    opt_fireDelayedChange) {
+
+  if (!opt_fireChange && this.changeTimerGecko_) {
+    // In the case where change events were stopped and we're not firing
+    // them on start, the user was trying to suppress all change or delayed
+    // change events. Clear the change timer now while the events are still
+    // stopped so that its firing doesn't fire a stopped change event, or
+    // queue up a delayed change event that we were trying to stop.
+    this.changeTimerGecko_.fireIfActive();
+  }
+
+  this.startEvent(goog.editor.Field.EventType.CHANGE);
+  this.startEvent(goog.editor.Field.EventType.DELAYEDCHANGE);
+  if (opt_fireChange) {
+    this.handleChange();
+  }
+
+  if (opt_fireDelayedChange) {
+    this.dispatchDelayedChange_();
+  }
+};
+
+
+/**
+ * Stops the event of the given type from being dispatched.
+ * @param {goog.editor.Field.EventType} eventType type of event to stop.
+ */
+goog.editor.Field.prototype.stopEvent = function(eventType) {
+  this.stoppedEvents_[eventType] = 1;
+};
+
+
+/**
+ * Re-starts the event of the given type being dispatched, if it had
+ * previously been stopped with stopEvent().
+ * @param {goog.editor.Field.EventType} eventType type of event to start.
+ */
+goog.editor.Field.prototype.startEvent = function(eventType) {
+  // Toggling this bit on/off instead of deleting it/re-adding it
+  // saves array allocations.
+  this.stoppedEvents_[eventType] = 0;
+};
+
+
+/**
+ * Block an event for a short amount of time. Intended
+ * for the situation where an event pair fires in quick succession
+ * (e.g., mousedown/mouseup, keydown/keyup, focus/blur),
+ * and we want the second event in the pair to get "debounced."
+ *
+ * WARNING: This should never be used to solve race conditions or for
+ * mission-critical actions. It should only be used for UI improvements,
+ * where it's okay if the behavior is non-deterministic.
+ *
+ * @param {goog.editor.Field.EventType} eventType type of event to debounce.
+ */
+goog.editor.Field.prototype.debounceEvent = function(eventType) {
+  this.debouncedEvents_[eventType] = goog.now();
+};
+
+
+/**
+ * Checks if the event of the given type has stopped being dispatched
+ * @param {goog.editor.Field.EventType} eventType type of event to check.
+ * @return {boolean} true if the event has been stopped with stopEvent().
+ * @protected
+ */
+goog.editor.Field.prototype.isEventStopped = function(eventType) {
+  return !!this.stoppedEvents_[eventType] ||
+      (this.debouncedEvents_[eventType] &&
+       (goog.now() - this.debouncedEvents_[eventType] <=
+        goog.editor.Field.DEBOUNCE_TIME_MS_));
+};
+
+
+/**
+ * Calls a function to manipulate the dom of this field. This method should be
+ * used whenever Trogedit clients need to modify the dom of the field, so that
+ * delayed change events are handled appropriately. Extra delayed change events
+ * will cause undesired states to be added to the undo-redo stack. This method
+ * will always fire at most one delayed change event, depending on the value of
+ * {@code opt_preventDelayedChange}.
+ *
+ * @param {function()} func The function to call that will manipulate the dom.
+ * @param {boolean=} opt_preventDelayedChange Whether delayed change should be
+ *      prevented after calling {@code func}. Defaults to always firing
+ *      delayed change.
+ * @param {Object=} opt_handler Object in whose scope to call the listener.
+ */
+goog.editor.Field.prototype.manipulateDom = function(func,
+    opt_preventDelayedChange, opt_handler) {
+
+  this.stopChangeEvents(true, true);
+  // We don't want any problems with the passed in function permanently
+  // stopping change events. That would break Trogedit.
+  try {
+    func.call(opt_handler);
+  } finally {
+    // If the field isn't loaded then change and delayed change events will be
+    // started as part of the onload behavior.
+    if (this.isLoaded()) {
+      // We assume that func always modified the dom and so fire a single change
+      // event. Delayed change is only fired if not prevented by the user.
+      if (opt_preventDelayedChange) {
+        this.startEvent(goog.editor.Field.EventType.CHANGE);
+        this.handleChange();
+        this.startEvent(goog.editor.Field.EventType.DELAYEDCHANGE);
+      } else {
+        this.dispatchChange();
+      }
+    }
+  }
+};
+
+
+/**
+ * Dispatches a command value change event.
+ * @param {Array<string>=} opt_commands Commands whose state has
+ *     changed.
+ */
+goog.editor.Field.prototype.dispatchCommandValueChange =
+    function(opt_commands) {
+  if (opt_commands) {
+    this.dispatchEvent({
+      type: goog.editor.Field.EventType.COMMAND_VALUE_CHANGE,
+      commands: opt_commands
+    });
+  } else {
+    this.dispatchEvent(goog.editor.Field.EventType.COMMAND_VALUE_CHANGE);
+  }
+};
+
+
+/**
+ * Dispatches the appropriate set of change events. This only fires
+ * synchronous change events in blended-mode, iframe-using mozilla. It just
+ * starts the appropriate timer for goog.editor.Field.EventType.DELAYEDCHANGE.
+ * This also starts up change events again if they were stopped.
+ *
+ * @param {boolean=} opt_noDelay True if
+ *      goog.editor.Field.EventType.DELAYEDCHANGE should be fired syncronously.
+ */
+goog.editor.Field.prototype.dispatchChange = function(opt_noDelay) {
+  this.startChangeEvents(true, opt_noDelay);
+};
+
+
+/**
+ * Handle a change in the Editable Field.  Marks the field has modified,
+ * dispatches the change event on the editable field (moz only), starts the
+ * timer for the delayed change event.  Note that these actions only occur if
+ * the proper events are not stopped.
+ */
+goog.editor.Field.prototype.handleChange = function() {
+  if (this.isEventStopped(goog.editor.Field.EventType.CHANGE)) {
+    return;
+  }
+
+  // Clear the changeTimerGecko_ if it's active, since any manual call to
+  // handle change is equiavlent to changeTimerGecko_.fire().
+  if (this.changeTimerGecko_) {
+    this.changeTimerGecko_.stop();
+  }
+
+  this.isModified_ = true;
+  this.isEverModified_ = true;
+
+  if (this.isEventStopped(goog.editor.Field.EventType.DELAYEDCHANGE)) {
+    return;
+  }
+
+  this.delayedChangeTimer_.start();
+};
+
+
+/**
+ * Dispatch a delayed change event.
+ * @private
+ */
+goog.editor.Field.prototype.dispatchDelayedChange_ = function() {
+  if (this.isEventStopped(goog.editor.Field.EventType.DELAYEDCHANGE)) {
+    return;
+  }
+  // Clear the delayedChangeTimer_ if it's active, since any manual call to
+  // dispatchDelayedChange_ is equivalent to delayedChangeTimer_.fire().
+  this.delayedChangeTimer_.stop();
+  this.isModified_ = false;
+  this.dispatchEvent(goog.editor.Field.EventType.DELAYEDCHANGE);
+};
+
+
+/**
+ * Don't wait for the timer and just fire the delayed change event if it's
+ * pending.
+ */
+goog.editor.Field.prototype.clearDelayedChange = function() {
+  // The changeTimerGecko_ will queue up a delayed change so to fully clear
+  // delayed change we must also clear this timer.
+  if (this.changeTimerGecko_) {
+    this.changeTimerGecko_.fireIfActive();
+  }
+  this.delayedChangeTimer_.fireIfActive();
+};
+
+
+/**
+ * Dispatch beforefocus and focus for FF. Note that both of these actually
+ * happen in the document's "focus" event. Unfortunately, we don't actually
+ * have a way of getting in before the focus event in FF (boo! hiss!).
+ * In IE, we use onfocusin for before focus and onfocus for focus.
+ * @private
+ */
+goog.editor.Field.prototype.dispatchFocusAndBeforeFocus_ = function() {
+  this.dispatchBeforeFocus_();
+  this.dispatchFocus_();
+};
+
+
+/**
+ * Dispatches a before focus event.
+ * @private
+ */
+goog.editor.Field.prototype.dispatchBeforeFocus_ = function() {
+  if (this.isEventStopped(goog.editor.Field.EventType.BEFOREFOCUS)) {
+    return;
+  }
+
+  this.execCommand(goog.editor.Command.CLEAR_LOREM, true);
+  this.dispatchEvent(goog.editor.Field.EventType.BEFOREFOCUS);
+};
+
+
+/**
+ * Dispatches a focus event.
+ * @private
+ */
+goog.editor.Field.prototype.dispatchFocus_ = function() {
+  if (this.isEventStopped(goog.editor.Field.EventType.FOCUS)) {
+    return;
+  }
+  goog.editor.Field.setActiveFieldId(this.id);
+
+  this.isSelectionEditable_ = true;
+
+  this.dispatchEvent(goog.editor.Field.EventType.FOCUS);
+
+  if (goog.editor.BrowserFeature.
+      PUTS_CURSOR_BEFORE_FIRST_BLOCK_ELEMENT_ON_FOCUS) {
+    // If the cursor is at the beginning of the field, make sure that it is
+    // in the first user-visible line break, e.g.,
+    // no selection: <div><p>...</p></div> --> <div><p>|cursor|...</p></div>
+    // <div>|cursor|<p>...</p></div> --> <div><p>|cursor|...</p></div>
+    // <body>|cursor|<p>...</p></body> --> <body><p>|cursor|...</p></body>
+    var field = this.getElement();
+    var range = this.getRange();
+
+    if (range) {
+      var focusNode = range.getFocusNode();
+      if (range.getFocusOffset() == 0 && (!focusNode || focusNode == field ||
+          focusNode.tagName == goog.dom.TagName.BODY)) {
+        goog.editor.range.selectNodeStart(field);
+      }
+    }
+  }
+
+  if (!goog.editor.BrowserFeature.CLEARS_SELECTION_WHEN_FOCUS_LEAVES &&
+      this.usesIframe()) {
+    var parent = this.getEditableDomHelper().getWindow().parent;
+    parent.getSelection().removeAllRanges();
+  }
+};
+
+
+/**
+ * Dispatches a blur event.
+ * @protected
+ */
+goog.editor.Field.prototype.dispatchBlur = function() {
+  if (this.isEventStopped(goog.editor.Field.EventType.BLUR)) {
+    return;
+  }
+
+  // Another field may have already been registered as active, so only
+  // clear out the active field id if we still think this field is active.
+  if (goog.editor.Field.getActiveFieldId() == this.id) {
+    goog.editor.Field.setActiveFieldId(null);
+  }
+
+  this.isSelectionEditable_ = false;
+  this.dispatchEvent(goog.editor.Field.EventType.BLUR);
+};
+
+
+/**
+ * @return {boolean} Whether the selection is editable.
+ */
+goog.editor.Field.prototype.isSelectionEditable = function() {
+  return this.isSelectionEditable_;
+};
+
+
+/**
+ * Event handler for clicks in browsers that will follow a link when the user
+ * clicks, even if it's editable. We stop the click manually
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.editor.Field.cancelLinkClick_ = function(e) {
+  if (goog.dom.getAncestorByTagNameAndClass(
+      /** @type {Node} */ (e.target), goog.dom.TagName.A)) {
+    e.preventDefault();
+  }
+};
+
+
+/**
+ * Handle mouse down inside the editable field.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.editor.Field.prototype.handleMouseDown_ = function(e) {
+  goog.editor.Field.setActiveFieldId(this.id);
+
+  // Open links in a new window if the user control + clicks.
+  if (goog.userAgent.IE) {
+    var targetElement = e.target;
+    if (targetElement &&
+        targetElement.tagName == goog.dom.TagName.A && e.ctrlKey) {
+      this.originalDomHelper.getWindow().open(targetElement.href);
+    }
+  }
+  this.waitingForMouseUp_ = true;
+};
+
+
+/**
+ * Handle drag start. Needs to cancel listening for the mouse up event on the
+ * window.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.editor.Field.prototype.handleDragStart_ = function(e) {
+  this.waitingForMouseUp_ = false;
+};
+
+
+/**
+ * Handle mouse up inside the editable field.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.editor.Field.prototype.handleMouseUp_ = function(e) {
+  if (this.useWindowMouseUp_ && !this.waitingForMouseUp_) {
+    return;
+  }
+  this.waitingForMouseUp_ = false;
+
+  /*
+   * We fire a selection change event immediately for listeners that depend on
+   * the native browser event object (e).  On IE, a listener that tries to
+   * retrieve the selection with goog.dom.Range may see an out-of-date
+   * selection range.
+   */
+  this.dispatchSelectionChangeEvent(e);
+  if (goog.userAgent.IE) {
+    /*
+     * Fire a second selection change event for listeners that need an
+     * up-to-date selection range. Save the event's target to be sent with it
+     * (it's safer than saving a copy of the event itself).
+     */
+    this.selectionChangeTarget_ = /** @type {Node} */ (e.target);
+    this.selectionChangeTimer_.start();
+  }
+};
+
+
+/**
+ * Retrieve the HTML contents of a field.
+ *
+ * Do NOT just get the innerHTML of a field directly--there's a lot of
+ * processing that needs to happen.
+  * @return {string} The scrubbed contents of the field.
+ */
+goog.editor.Field.prototype.getCleanContents = function() {
+  if (this.queryCommandValue(goog.editor.Command.USING_LOREM)) {
+    return goog.string.Unicode.NBSP;
+  }
+
+  if (!this.isLoaded()) {
+    // The field is uneditable, so it's ok to read contents directly.
+    var elem = this.getOriginalElement();
+    if (!elem) {
+      goog.log.log(this.logger, goog.log.Level.SHOUT,
+          "Couldn't get the field element to read the contents");
+    }
+    return elem.innerHTML;
+  }
+
+  var fieldCopy = this.getFieldCopy();
+
+  // Allow the plugins to handle their cleanup.
+  this.invokeOp_(goog.editor.Plugin.Op.CLEAN_CONTENTS_DOM, fieldCopy);
+  return this.reduceOp_(
+      goog.editor.Plugin.Op.CLEAN_CONTENTS_HTML, fieldCopy.innerHTML);
+};
+
+
+/**
+ * Get the copy of the editable field element, which has the innerHTML set
+ * correctly.
+ * @return {!Element} The copy of the editable field.
+ * @protected
+ */
+goog.editor.Field.prototype.getFieldCopy = function() {
+  var field = this.getElement();
+  // Deep cloneNode strips some script tag contents in IE, so we do this.
+  var fieldCopy = /** @type {Element} */(field.cloneNode(false));
+
+  // For some reason, when IE sets innerHtml of the cloned node, it strips
+  // script tags that fall at the beginning of an element. Appending a
+  // non-breaking space prevents this.
+  var html = field.innerHTML;
+  if (goog.userAgent.IE && html.match(/^\s*<script/i)) {
+    html = goog.string.Unicode.NBSP + html;
+  }
+  fieldCopy.innerHTML = html;
+  return fieldCopy;
+};
+
+
+/**
+ * Sets the contents of the field.
+ * @param {boolean} addParas Boolean to specify whether to add paragraphs
+ *    to long fields.
+ * @param {?string} html html to insert.  If html=null, then this defaults
+ *    to a nsbp for mozilla and an empty string for IE.
+ * @param {boolean=} opt_dontFireDelayedChange True to make this content change
+ *    not fire a delayed change event.
+ * @param {boolean=} opt_applyLorem Whether to apply lorem ipsum styles.
+ */
+goog.editor.Field.prototype.setHtml = function(
+    addParas, html, opt_dontFireDelayedChange, opt_applyLorem) {
+  if (this.isLoading()) {
+    goog.log.error(this.logger, "Can't set html while loading Trogedit");
+    return;
+  }
+
+  // Clear the lorem ipsum style, always.
+  if (opt_applyLorem) {
+    this.execCommand(goog.editor.Command.CLEAR_LOREM);
+  }
+
+  if (html && addParas) {
+    html = '<p>' + html + '</p>';
+  }
+
+  // If we don't want change events to fire, we have to turn off change events
+  // before setting the field contents, since that causes mutation events.
+  if (opt_dontFireDelayedChange) {
+    this.stopChangeEvents(false, true);
+  }
+
+  this.setInnerHtml_(html);
+
+  // Set the lorem ipsum style, if the element is empty.
+  if (opt_applyLorem) {
+    this.execCommand(goog.editor.Command.UPDATE_LOREM);
+  }
+
+  // TODO(user): This check should probably be moved to isEventStopped and
+  // startEvent.
+  if (this.isLoaded()) {
+    if (opt_dontFireDelayedChange) { // Turn back on change events
+      // We must fire change timer if necessary before restarting change events!
+      // Otherwise, the change timer firing after we restart events will cause
+      // the delayed change we were trying to stop. Flow:
+      //   Stop delayed change
+      //   setInnerHtml_, this starts the change timer
+      //   start delayed change
+      //   change timer fires
+      //   starts delayed change timer since event was not stopped
+      //   delayed change fires for the delayed change we tried to stop.
+      if (goog.editor.BrowserFeature.USE_MUTATION_EVENTS) {
+        this.changeTimerGecko_.fireIfActive();
+      }
+      this.startChangeEvents();
+    } else { // Mark the document as changed and fire change events.
+      this.dispatchChange();
+    }
+  }
+};
+
+
+/**
+ * Sets the inner HTML of the field. Works on both editable and
+ * uneditable fields.
+ * @param {?string} html The new inner HTML of the field.
+ * @private
+ */
+goog.editor.Field.prototype.setInnerHtml_ = function(html) {
+  var field = this.getElement();
+  if (field) {
+    // Safari will put <style> tags into *new* <head> elements. When setting
+    // HTML, we need to remove these spare <head>s to make sure there's a
+    // clean slate, but keep the first <head>.
+    // Note:  We punt on this issue for the non iframe case since
+    // we don't want to screw with the main document.
+    if (this.usesIframe() && goog.editor.BrowserFeature.MOVES_STYLE_TO_HEAD) {
+      var heads = field.ownerDocument.getElementsByTagName(
+          goog.dom.TagName.HEAD);
+      for (var i = heads.length - 1; i >= 1; --i) {
+        heads[i].parentNode.removeChild(heads[i]);
+      }
+    }
+  } else {
+    field = this.getOriginalElement();
+  }
+
+  if (field) {
+    this.injectContents(html, field);
+  }
+};
+
+
+/**
+ * Attemps to turn on designMode for a document.  This function can fail under
+ * certain circumstances related to the load event, and will throw an exception.
+ * @protected
+ */
+goog.editor.Field.prototype.turnOnDesignModeGecko = function() {
+  var doc = this.getEditableDomHelper().getDocument();
+
+  // NOTE(nicksantos): This will fail under certain conditions, like
+  // when the node has display: none. It's up to clients to ensure that
+  // their fields are valid when they try to make them editable.
+  doc.designMode = 'on';
+
+  if (goog.editor.BrowserFeature.HAS_STYLE_WITH_CSS) {
+    doc.execCommand('styleWithCSS', false, false);
+  }
+};
+
+
+/**
+ * Installs styles if needed. Only writes styles when they can't be written
+ * inline directly into the field.
+ * @protected
+ */
+goog.editor.Field.prototype.installStyles = function() {
+  if (this.cssStyles && this.shouldLoadAsynchronously()) {
+    goog.style.installStyles(this.cssStyles, this.getElement());
+  }
+};
+
+
+/**
+ * Signal that the field is loaded and ready to use.  Change events now are
+ * in effect.
+ * @private
+ */
+goog.editor.Field.prototype.dispatchLoadEvent_ = function() {
+  var field = this.getElement();
+
+  this.installStyles();
+  this.startChangeEvents();
+  goog.log.info(this.logger, 'Dispatching load ' + this.id);
+  this.dispatchEvent(goog.editor.Field.EventType.LOAD);
+};
+
+
+/**
+ * @return {boolean} Whether the field is uneditable.
+ */
+goog.editor.Field.prototype.isUneditable = function() {
+  return this.loadState_ == goog.editor.Field.LoadState_.UNEDITABLE;
+};
+
+
+/**
+ * @return {boolean} Whether the field has finished loading.
+ */
+goog.editor.Field.prototype.isLoaded = function() {
+  return this.loadState_ == goog.editor.Field.LoadState_.EDITABLE;
+};
+
+
+/**
+ * @return {boolean} Whether the field is in the process of loading.
+ */
+goog.editor.Field.prototype.isLoading = function() {
+  return this.loadState_ == goog.editor.Field.LoadState_.LOADING;
+};
+
+
+/**
+ * Gives the field focus.
+ */
+goog.editor.Field.prototype.focus = function() {
+  if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE &&
+      this.usesIframe()) {
+    // In designMode, only the window itself can be focused; not the element.
+    this.getEditableDomHelper().getWindow().focus();
+  } else {
+    if (goog.userAgent.OPERA) {
+      // Opera will scroll to the bottom of the focused document, even
+      // if it is contained in an iframe that is scrolled to the top and
+      // the bottom flows past the end of it. To prevent this,
+      // save the scroll position of the document containing the editor
+      // iframe, then restore it after the focus.
+      var scrollX = this.appWindow_.pageXOffset;
+      var scrollY = this.appWindow_.pageYOffset;
+    }
+    this.getElement().focus();
+    if (goog.userAgent.OPERA) {
+      this.appWindow_.scrollTo(
+          /** @type {number} */ (scrollX), /** @type {number} */ (scrollY));
+    }
+  }
+};
+
+
+/**
+ * Gives the field focus and places the cursor at the start of the field.
+ */
+goog.editor.Field.prototype.focusAndPlaceCursorAtStart = function() {
+  // NOTE(user): Excluding Gecko to maintain existing behavior post refactoring
+  // placeCursorAtStart into its own method. In Gecko browsers that currently
+  // have a selection the existing selection will be restored, otherwise it
+  // will go to the start.
+  // TODO(user): Refactor the code using this and related methods. We should
+  // only mess with the selection in the case where there is not an existing
+  // selection in the field.
+  if (goog.editor.BrowserFeature.HAS_IE_RANGES || !goog.userAgent.GECKO) {
+    this.placeCursorAtStart();
+  }
+  this.focus();
+};
+
+
+/**
+ * Place the cursor at the start of this field. It's recommended that you only
+ * use this method (and manipulate the selection in general) when there is not
+ * an existing selection in the field.
+ */
+goog.editor.Field.prototype.placeCursorAtStart = function() {
+  this.placeCursorAtStartOrEnd_(true);
+};
+
+
+/**
+ * Place the cursor at the start of this field. It's recommended that you only
+ * use this method (and manipulate the selection in general) when there is not
+ * an existing selection in the field.
+ */
+goog.editor.Field.prototype.placeCursorAtEnd = function() {
+  this.placeCursorAtStartOrEnd_(false);
+};
+
+
+/**
+ * Helper method to place the cursor at the start or end of this field.
+ * @param {boolean} isStart True for start, false for end.
+ * @private
+ */
+goog.editor.Field.prototype.placeCursorAtStartOrEnd_ = function(isStart) {
+  var field = this.getElement();
+  if (field) {
+    var cursorPosition = isStart ? goog.editor.node.getLeftMostLeaf(field) :
+        goog.editor.node.getRightMostLeaf(field);
+    if (field == cursorPosition) {
+      // The rightmost leaf we found was the field element itself (which likely
+      // means the field element is empty). We can't place the cursor next to
+      // the field element, so just place it at the beginning.
+      goog.dom.Range.createCaret(field, 0).select();
+    } else {
+      goog.editor.range.placeCursorNextTo(cursorPosition, isStart);
+    }
+    this.dispatchSelectionChangeEvent();
+  }
+};
+
+
+/**
+ * Restore a saved range, and set the focus on the field.
+ * If no range is specified, we simply set the focus.
+ * @param {goog.dom.SavedRange=} opt_range A previously saved selected range.
+ */
+goog.editor.Field.prototype.restoreSavedRange = function(opt_range) {
+  if (goog.userAgent.IE) {
+    this.focus();
+  }
+  if (opt_range) {
+    opt_range.restore();
+  }
+  if (!goog.userAgent.IE) {
+    this.focus();
+  }
+};
+
+
+/**
+ * Makes a field editable.
+ *
+ * @param {string=} opt_iframeSrc URL to set the iframe src to if necessary.
+ */
+goog.editor.Field.prototype.makeEditable = function(opt_iframeSrc) {
+  this.loadState_ = goog.editor.Field.LoadState_.LOADING;
+
+  var field = this.getOriginalElement();
+
+  // TODO: In the fieldObj, save the field's id, className, cssText
+  // in order to reset it on closeField. That way, we can muck with the field's
+  // css, id, class and restore to how it was at the end.
+  this.nodeName = field.nodeName;
+  this.savedClassName_ = field.className;
+  this.setInitialStyle(field.style.cssText);
+
+  field.className += ' editable';
+
+  this.makeEditableInternal(opt_iframeSrc);
+};
+
+
+/**
+ * Handles actually making something editable - creating necessary nodes,
+ * injecting content, etc.
+ * @param {string=} opt_iframeSrc URL to set the iframe src to if necessary.
+ * @protected
+ */
+goog.editor.Field.prototype.makeEditableInternal = function(opt_iframeSrc) {
+  this.makeIframeField_(opt_iframeSrc);
+};
+
+
+/**
+ * Handle the loading of the field (e.g. once the field is ready to setup).
+ * TODO(user): this should probably just be moved into dispatchLoadEvent_.
+ * @protected
+ */
+goog.editor.Field.prototype.handleFieldLoad = function() {
+  if (goog.userAgent.IE) {
+    // This sometimes fails if the selection is invalid. This can happen, for
+    // example, if you attach a CLICK handler to the field that causes the
+    // field to be removed from the DOM and replaced with an editor
+    // -- however, listening to another event like MOUSEDOWN does not have this
+    // issue since no mouse selection has happened at that time.
+    goog.dom.Range.clearSelection(this.editableDomHelper.getWindow());
+  }
+
+  if (goog.editor.Field.getActiveFieldId() != this.id) {
+    this.execCommand(goog.editor.Command.UPDATE_LOREM);
+  }
+
+  this.setupChangeListeners_();
+  this.dispatchLoadEvent_();
+
+  // Enabling plugins after we fire the load event so that clients have a
+  // chance to set initial field contents before we start mucking with
+  // everything.
+  for (var classId in this.plugins_) {
+    this.plugins_[classId].enable(this);
+  }
+};
+
+
+/**
+ * Closes the field and cancels all pending change timers.  Note that this
+ * means that if a change event has not fired yet, it will not fire.  Clients
+ * should check fieldOj.isModified() if they depend on the final change event.
+ * Throws an error if the field is already uneditable.
+ *
+ * @param {boolean=} opt_skipRestore True to prevent copying of editable field
+ *     contents back into the original node.
+ */
+goog.editor.Field.prototype.makeUneditable = function(opt_skipRestore) {
+  if (this.isUneditable()) {
+    throw Error('makeUneditable: Field is already uneditable');
+  }
+
+  // Fire any events waiting on a timeout.
+  // Clearing delayed change also clears changeTimerGecko_.
+  this.clearDelayedChange();
+  this.selectionChangeTimer_.fireIfActive();
+  this.execCommand(goog.editor.Command.CLEAR_LOREM);
+
+  var html = null;
+  if (!opt_skipRestore && this.getElement()) {
+    // Rest of cleanup is simpler if field was never initialized.
+    html = this.getCleanContents();
+  }
+
+  // First clean up anything that happens in makeFieldEditable
+  // (i.e. anything that needs cleanup even if field has not loaded).
+  this.clearFieldLoadListener_();
+
+  var field = this.getOriginalElement();
+  if (goog.editor.Field.getActiveFieldId() == field.id) {
+    goog.editor.Field.setActiveFieldId(null);
+  }
+
+  // Clear all listeners before removing the nodes from the dom - if
+  // there are listeners on the iframe window, Firefox throws errors trying
+  // to unlisten once the iframe is no longer in the dom.
+  this.clearListeners();
+
+  // For fields that have loaded, clean up anything that happened in
+  // handleFieldOpen or later.
+  // If html is provided, copy it back and reset the properties on the field
+  // so that the original node will have the same properties as it did before
+  // it was made editable.
+  if (goog.isString(html)) {
+    goog.editor.node.replaceInnerHtml(field, html);
+    this.resetOriginalElemProperties();
+  }
+
+  this.restoreDom();
+  this.tearDownFieldObject_();
+
+  // On Safari, make sure to un-focus the field so that the
+  // native "current field" highlight style gets removed.
+  if (goog.userAgent.WEBKIT) {
+    field.blur();
+  }
+
+  this.execCommand(goog.editor.Command.UPDATE_LOREM);
+  this.dispatchEvent(goog.editor.Field.EventType.UNLOAD);
+};
+
+
+/**
+ * Restores the dom to how it was before being made editable.
+ * @protected
+ */
+goog.editor.Field.prototype.restoreDom = function() {
+  // TODO(user): Consider only removing the iframe if we are
+  // restoring the original node, aka, if opt_html.
+  var field = this.getOriginalElement();
+  // TODO(robbyw): Consider throwing an error if !field.
+  if (field) {
+    // If the field is in the process of loading when it starts getting torn
+    // up, the iframe will not exist.
+    var iframe = this.getEditableIframe();
+    if (iframe) {
+      goog.dom.replaceNode(field, iframe);
+    }
+  }
+};
+
+
+/**
+ * Returns true if the field needs to be loaded asynchrnously.
+ * @return {boolean} True if loads are async.
+ * @protected
+ */
+goog.editor.Field.prototype.shouldLoadAsynchronously = function() {
+  if (!goog.isDef(this.isHttps_)) {
+    this.isHttps_ = false;
+
+    if (goog.userAgent.IE && this.usesIframe()) {
+      // IE iframes need to load asynchronously if they are in https as we need
+      // to set an actual src on the iframe and wait for it to load.
+
+      // Find the top-most window we have access to and see if it's https.
+      // Technically this could fail if we have an http frame in an https frame
+      // on the same domain (or vice versa), but walking up the window heirarchy
+      // to find the first window that has an http* protocol seems like
+      // overkill.
+      var win = this.originalDomHelper.getWindow();
+      while (win != win.parent) {
+        try {
+          win = win.parent;
+        } catch (e) {
+          break;
+        }
+      }
+      var loc = win.location;
+      this.isHttps_ = loc.protocol == 'https:' &&
+          loc.search.indexOf('nocheckhttps') == -1;
+    }
+  }
+  return this.isHttps_;
+};
+
+
+/**
+ * Start the editable iframe creation process for Mozilla or IE whitebox.
+ * The iframes load asynchronously.
+ *
+ * @param {string=} opt_iframeSrc URL to set the iframe src to if necessary.
+ * @private
+ */
+goog.editor.Field.prototype.makeIframeField_ = function(opt_iframeSrc) {
+  var field = this.getOriginalElement();
+  // TODO(robbyw): Consider throwing an error if !field.
+  if (field) {
+    var html = field.innerHTML;
+
+    // Invoke prepareContentsHtml on all plugins to prepare html for editing.
+    // Make sure this is done before calling this.attachFrame which removes the
+    // original element from DOM tree. Plugins may assume that the original
+    // element is still in its original position in DOM.
+    var styles = {};
+    html = this.reduceOp_(goog.editor.Plugin.Op.PREPARE_CONTENTS_HTML,
+        html, styles);
+
+    var iframe = /** @type {!HTMLIFrameElement} */(
+        this.originalDomHelper.createDom(goog.dom.TagName.IFRAME,
+            this.getIframeAttributes()));
+
+    // TODO(nicksantos): Figure out if this is ever needed in SAFARI?
+    // In IE over HTTPS we need to wait for a load event before we set up the
+    // iframe, this is to prevent a security prompt or access is denied
+    // errors.
+    // NOTE(user): This hasn't been confirmed.  isHttps_ allows a query
+    // param, nocheckhttps, which we can use to ascertain if this is actually
+    // needed.  It was originally thought to be needed for IE6 SP1, but
+    // errors have been seen in IE7 as well.
+    if (this.shouldLoadAsynchronously()) {
+      // onLoad is the function to call once the iframe is ready to continue
+      // loading.
+      var onLoad = goog.bind(this.iframeFieldLoadHandler, this, iframe,
+          html, styles);
+
+      this.fieldLoadListenerKey_ = goog.events.listen(iframe,
+          goog.events.EventType.LOAD, onLoad, true);
+
+      if (opt_iframeSrc) {
+        iframe.src = opt_iframeSrc;
+      }
+    }
+
+    this.attachIframe(iframe);
+
+    // Only continue if its not IE HTTPS in which case we're waiting for load.
+    if (!this.shouldLoadAsynchronously()) {
+      this.iframeFieldLoadHandler(iframe, html, styles);
+    }
+  }
+};
+
+
+/**
+ * Given the original field element, and the iframe that is destined to
+ * become the editable field, styles them appropriately and add the iframe
+ * to the dom.
+ *
+ * @param {HTMLIFrameElement} iframe The iframe element.
+ * @protected
+ */
+goog.editor.Field.prototype.attachIframe = function(iframe) {
+  var field = this.getOriginalElement();
+  // TODO(user): Why do we do these two lines .. and why whitebox only?
+  iframe.className = field.className;
+  iframe.id = field.id;
+  goog.dom.replaceNode(iframe, field);
+};
+
+
+/**
+ * @param {Object} extraStyles A map of extra styles.
+ * @return {!goog.editor.icontent.FieldFormatInfo} The FieldFormatInfo
+ *     object for this field's configuration.
+ * @protected
+ */
+goog.editor.Field.prototype.getFieldFormatInfo = function(extraStyles) {
+  var originalElement = this.getOriginalElement();
+  var isStandardsMode = goog.editor.node.isStandardsMode(originalElement);
+
+  return new goog.editor.icontent.FieldFormatInfo(
+      this.id,
+      isStandardsMode,
+      false,
+      false,
+      extraStyles);
+};
+
+
+/**
+ * Writes the html content into the iframe.  Handles writing any aditional
+ * styling as well.
+ * @param {HTMLIFrameElement} iframe Iframe to write contents into.
+ * @param {string} innerHtml The html content to write into the iframe.
+ * @param {Object} extraStyles A map of extra style attributes.
+ * @protected
+ */
+goog.editor.Field.prototype.writeIframeContent = function(
+    iframe, innerHtml, extraStyles) {
+  var formatInfo = this.getFieldFormatInfo(extraStyles);
+
+  if (this.shouldLoadAsynchronously()) {
+    var doc = goog.dom.getFrameContentDocument(iframe);
+    goog.editor.icontent.writeHttpsInitialIframe(formatInfo, doc, innerHtml);
+  } else {
+    var styleInfo = new goog.editor.icontent.FieldStyleInfo(
+        this.getElement(), this.cssStyles);
+    goog.editor.icontent.writeNormalInitialIframe(formatInfo, innerHtml,
+        styleInfo, iframe);
+  }
+};
+
+
+/**
+ * The function to call when the editable iframe loads.
+ *
+ * @param {HTMLIFrameElement} iframe Iframe that just loaded.
+ * @param {string} innerHtml Html to put inside the body of the iframe.
+ * @param {Object} styles Property-value map of CSS styles to install on
+ *     editable field.
+ * @protected
+ */
+goog.editor.Field.prototype.iframeFieldLoadHandler = function(iframe,
+    innerHtml, styles) {
+  this.clearFieldLoadListener_();
+
+  iframe.allowTransparency = 'true';
+  this.writeIframeContent(iframe, innerHtml, styles);
+  var doc = goog.dom.getFrameContentDocument(iframe);
+
+  // Make sure to get this pointer after the doc.write as the doc.write
+  // clobbers all the document contents.
+  var body = doc.body;
+  this.setupFieldObject(body);
+
+  if (!goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE &&
+      this.usesIframe()) {
+    this.turnOnDesignModeGecko();
+  }
+
+  this.handleFieldLoad();
+};
+
+
+/**
+ * Clears fieldLoadListener for a field. Must be called even (especially?) if
+ * the field is not yet loaded and therefore not in this.fieldMap_
+ * @private
+ */
+goog.editor.Field.prototype.clearFieldLoadListener_ = function() {
+  if (this.fieldLoadListenerKey_) {
+    goog.events.unlistenByKey(this.fieldLoadListenerKey_);
+    this.fieldLoadListenerKey_ = null;
+  }
+};
+
+
+/**
+ * @return {!Object} Get the HTML attributes for this field's iframe.
+ * @protected
+ */
+goog.editor.Field.

<TRUNCATED>

[22/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/linkdialogplugin.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/linkdialogplugin.js b/externs/GCL/externs/goog/editor/plugins/linkdialogplugin.js
new file mode 100644
index 0000000..9c804a6
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/linkdialogplugin.js
@@ -0,0 +1,438 @@
+// Copyright 2008 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 plugin for the LinkDialog.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.editor.plugins.LinkDialogPlugin');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.editor.Command');
+goog.require('goog.editor.plugins.AbstractDialogPlugin');
+goog.require('goog.events.EventHandler');
+goog.require('goog.functions');
+goog.require('goog.ui.editor.AbstractDialog');
+goog.require('goog.ui.editor.LinkDialog');
+goog.require('goog.uri.utils');
+
+
+
+/**
+ * A plugin that opens the link dialog.
+ * @constructor
+ * @extends {goog.editor.plugins.AbstractDialogPlugin}
+ */
+goog.editor.plugins.LinkDialogPlugin = function() {
+  goog.editor.plugins.LinkDialogPlugin.base(
+      this, 'constructor', goog.editor.Command.MODAL_LINK_EDITOR);
+
+  /**
+   * Event handler for this object.
+   * @type {goog.events.EventHandler<!goog.editor.plugins.LinkDialogPlugin>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+
+  /**
+   * A list of whitelisted URL schemes which are safe to open.
+   * @type {Array<string>}
+   * @private
+   */
+  this.safeToOpenSchemes_ = ['http', 'https', 'ftp'];
+};
+goog.inherits(goog.editor.plugins.LinkDialogPlugin,
+    goog.editor.plugins.AbstractDialogPlugin);
+
+
+/**
+ * Link object that the dialog is editing.
+ * @type {goog.editor.Link}
+ * @protected
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.currentLink_;
+
+
+/**
+ * Optional warning to show about email addresses.
+ * @type {goog.html.SafeHtml}
+ * @private
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.emailWarning_;
+
+
+/**
+ * Whether to show a checkbox where the user can choose to have the link open in
+ * a new window.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.showOpenLinkInNewWindow_ = false;
+
+
+/**
+ * Whether the "open link in new window" checkbox should be checked when the
+ * dialog is shown, and also whether it was checked last time the dialog was
+ * closed.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.isOpenLinkInNewWindowChecked_ =
+    false;
+
+
+/**
+ * Weather to show a checkbox where the user can choose to add 'rel=nofollow'
+ * attribute added to the link.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.showRelNoFollow_ = false;
+
+
+/**
+ * Whether to stop referrer leaks.  Defaults to false.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.stopReferrerLeaks_ = false;
+
+
+/**
+ * Whether to block opening links with a non-whitelisted URL scheme.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.blockOpeningUnsafeSchemes_ =
+    true;
+
+
+/** @override */
+goog.editor.plugins.LinkDialogPlugin.prototype.getTrogClassId =
+    goog.functions.constant('LinkDialogPlugin');
+
+
+/**
+ * Tells the plugin whether to block URLs with schemes not in the whitelist.
+ * If blocking is enabled, this plugin will stop the 'Test Link' popup
+ * window from being created. Blocking doesn't affect link creation--if the
+ * user clicks the 'OK' button with an unsafe URL, the link will still be
+ * created as normal.
+ * @param {boolean} blockOpeningUnsafeSchemes Whether to block non-whitelisted
+ *     schemes.
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.setBlockOpeningUnsafeSchemes =
+    function(blockOpeningUnsafeSchemes) {
+  this.blockOpeningUnsafeSchemes_ = blockOpeningUnsafeSchemes;
+};
+
+
+/**
+ * Sets a whitelist of allowed URL schemes that are safe to open.
+ * Schemes should all be in lowercase. If the plugin is set to block opening
+ * unsafe schemes, user-entered URLs will be converted to lowercase and checked
+ * against this list. The whitelist has no effect if blocking is not enabled.
+ * @param {Array<string>} schemes String array of URL schemes to allow (http,
+ *     https, etc.).
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.setSafeToOpenSchemes =
+    function(schemes) {
+  this.safeToOpenSchemes_ = schemes;
+};
+
+
+/**
+ * Tells the dialog to show a checkbox where the user can choose to have the
+ * link open in a new window.
+ * @param {boolean} startChecked Whether to check the checkbox the first
+ *     time the dialog is shown. Subesquent times the checkbox will remember its
+ *     previous state.
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.showOpenLinkInNewWindow =
+    function(startChecked) {
+  this.showOpenLinkInNewWindow_ = true;
+  this.isOpenLinkInNewWindowChecked_ = startChecked;
+};
+
+
+/**
+ * Tells the dialog to show a checkbox where the user can choose to have
+ * 'rel=nofollow' attribute added to the link.
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.showRelNoFollow = function() {
+  this.showRelNoFollow_ = true;
+};
+
+
+/**
+ * Returns whether the"open link in new window" checkbox was checked last time
+ * the dialog was closed.
+ * @return {boolean} Whether the"open link in new window" checkbox was checked
+ *     last time the dialog was closed.
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.
+    getOpenLinkInNewWindowCheckedState = function() {
+  return this.isOpenLinkInNewWindowChecked_;
+};
+
+
+/**
+ * Tells the plugin to stop leaking the page's url via the referrer header when
+ * the "test this link" link is clicked. When the user clicks on a link, the
+ * browser makes a request for the link url, passing the url of the current page
+ * in the request headers. If the user wants the current url to be kept secret
+ * (e.g. an unpublished document), the owner of the url that was clicked will
+ * see the secret url in the request headers, and it will no longer be a secret.
+ * Calling this method will not send a referrer header in the request, just as
+ * if the user had opened a blank window and typed the url in themselves.
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.stopReferrerLeaks = function() {
+  this.stopReferrerLeaks_ = true;
+};
+
+
+/**
+ * Sets the warning message to show to users about including email addresses on
+ * public web pages.
+ * @param {!goog.html.SafeHtml} emailWarning Warning message to show users about
+ *     including email addresses on the web.
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.setEmailWarning = function(
+    emailWarning) {
+  this.emailWarning_ = emailWarning;
+};
+
+
+/**
+ * Handles execCommand by opening the dialog.
+ * @param {string} command The command to execute.
+ * @param {*=} opt_arg {@link A goog.editor.Link} object representing the link
+ *     being edited.
+ * @return {*} Always returns true, indicating the dialog was shown.
+ * @protected
+ * @override
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.execCommandInternal = function(
+    command, opt_arg) {
+  this.currentLink_ = /** @type {goog.editor.Link} */(opt_arg);
+  return goog.editor.plugins.LinkDialogPlugin.base(
+      this, 'execCommandInternal', command, opt_arg);
+};
+
+
+/**
+ * Handles when the dialog closes.
+ * @param {goog.events.Event} e The AFTER_HIDE event object.
+ * @override
+ * @protected
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.handleAfterHide = function(e) {
+  goog.editor.plugins.LinkDialogPlugin.base(this, 'handleAfterHide', e);
+  this.currentLink_ = null;
+};
+
+
+/**
+ * @return {goog.events.EventHandler<T>} The event handler.
+ * @protected
+ * @this T
+ * @template T
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.getEventHandler = function() {
+  return this.eventHandler_;
+};
+
+
+/**
+ * @return {goog.editor.Link} The link being edited.
+ * @protected
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.getCurrentLink = function() {
+  return this.currentLink_;
+};
+
+
+/**
+ * Creates a new instance of the dialog and registers for the relevant events.
+ * @param {goog.dom.DomHelper} dialogDomHelper The dom helper to be used to
+ *     create the dialog.
+ * @param {*=} opt_link The target link (should be a goog.editor.Link).
+ * @return {!goog.ui.editor.LinkDialog} The dialog.
+ * @override
+ * @protected
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.createDialog = function(
+    dialogDomHelper, opt_link) {
+  var dialog = new goog.ui.editor.LinkDialog(dialogDomHelper,
+      /** @type {goog.editor.Link} */ (opt_link));
+  if (this.emailWarning_) {
+    dialog.setEmailWarning(this.emailWarning_);
+  }
+  if (this.showOpenLinkInNewWindow_) {
+    dialog.showOpenLinkInNewWindow(this.isOpenLinkInNewWindowChecked_);
+  }
+  if (this.showRelNoFollow_) {
+    dialog.showRelNoFollow();
+  }
+  dialog.setStopReferrerLeaks(this.stopReferrerLeaks_);
+  this.eventHandler_.
+      listen(dialog, goog.ui.editor.AbstractDialog.EventType.OK,
+          this.handleOk).
+      listen(dialog, goog.ui.editor.AbstractDialog.EventType.CANCEL,
+          this.handleCancel_).
+      listen(dialog, goog.ui.editor.LinkDialog.EventType.BEFORE_TEST_LINK,
+          this.handleBeforeTestLink);
+  return dialog;
+};
+
+
+/** @override */
+goog.editor.plugins.LinkDialogPlugin.prototype.disposeInternal = function() {
+  goog.editor.plugins.LinkDialogPlugin.base(this, 'disposeInternal');
+  this.eventHandler_.dispose();
+};
+
+
+/**
+ * Handles the OK event from the dialog by updating the link in the field.
+ * @param {goog.ui.editor.LinkDialog.OkEvent} e OK event object.
+ * @protected
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.handleOk = function(e) {
+  // We're not restoring the original selection, so clear it out.
+  this.disposeOriginalSelection();
+
+  this.currentLink_.setTextAndUrl(e.linkText, e.linkUrl);
+  if (this.showOpenLinkInNewWindow_) {
+    // Save checkbox state for next time.
+    this.isOpenLinkInNewWindowChecked_ = e.openInNewWindow;
+  }
+
+  var anchor = this.currentLink_.getAnchor();
+  this.touchUpAnchorOnOk_(anchor, e);
+  var extraAnchors = this.currentLink_.getExtraAnchors();
+  for (var i = 0; i < extraAnchors.length; ++i) {
+    extraAnchors[i].href = anchor.href;
+    this.touchUpAnchorOnOk_(extraAnchors[i], e);
+  }
+
+  // Place cursor to the right of the modified link.
+  this.currentLink_.placeCursorRightOf();
+
+  this.getFieldObject().focus();
+
+  this.getFieldObject().dispatchSelectionChangeEvent();
+  this.getFieldObject().dispatchChange();
+
+  this.eventHandler_.removeAll();
+};
+
+
+/**
+ * Apply the necessary properties to a link upon Ok being clicked in the dialog.
+ * @param {HTMLAnchorElement} anchor The anchor to set properties on.
+ * @param {goog.events.Event} e Event object.
+ * @private
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.touchUpAnchorOnOk_ =
+    function(anchor, e) {
+  if (this.showOpenLinkInNewWindow_) {
+    if (e.openInNewWindow) {
+      anchor.target = '_blank';
+    } else {
+      if (anchor.target == '_blank') {
+        anchor.target = '';
+      }
+      // If user didn't indicate to open in a new window but the link already
+      // had a target other than '_blank', let's leave what they had before.
+    }
+  }
+
+  if (this.showRelNoFollow_) {
+    var alreadyPresent = goog.ui.editor.LinkDialog.hasNoFollow(anchor.rel);
+    if (alreadyPresent && !e.noFollow) {
+      anchor.rel = goog.ui.editor.LinkDialog.removeNoFollow(anchor.rel);
+    } else if (!alreadyPresent && e.noFollow) {
+      anchor.rel = anchor.rel ? anchor.rel + ' nofollow' : 'nofollow';
+    }
+  }
+};
+
+
+/**
+ * Handles the CANCEL event from the dialog by clearing the anchor if needed.
+ * @param {goog.events.Event} e Event object.
+ * @private
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.handleCancel_ = function(e) {
+  if (this.currentLink_.isNew()) {
+    goog.dom.flattenElement(this.currentLink_.getAnchor());
+    var extraAnchors = this.currentLink_.getExtraAnchors();
+    for (var i = 0; i < extraAnchors.length; ++i) {
+      goog.dom.flattenElement(extraAnchors[i]);
+    }
+    // Make sure listeners know the anchor was flattened out.
+    this.getFieldObject().dispatchChange();
+  }
+
+  this.eventHandler_.removeAll();
+};
+
+
+/**
+ * Handles the BeforeTestLink event fired when the 'test' link is clicked.
+ * @param {goog.ui.editor.LinkDialog.BeforeTestLinkEvent} e BeforeTestLink event
+ *     object.
+ * @protected
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.handleBeforeTestLink =
+    function(e) {
+  if (!this.shouldOpenUrl(e.url)) {
+    /** @desc Message when the user tries to test (preview) a link, but the
+     * link cannot be tested. */
+    var MSG_UNSAFE_LINK = goog.getMsg('This link cannot be tested.');
+    alert(MSG_UNSAFE_LINK);
+    e.preventDefault();
+  }
+};
+
+
+/**
+ * Checks whether the plugin should open the given url in a new window.
+ * @param {string} url The url to check.
+ * @return {boolean} If the plugin should open the given url in a new window.
+ * @protected
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.shouldOpenUrl = function(url) {
+  return !this.blockOpeningUnsafeSchemes_ || this.isSafeSchemeToOpen_(url);
+};
+
+
+/**
+ * Determines whether or not a url has a scheme which is safe to open.
+ * Schemes like javascript are unsafe due to the possibility of XSS.
+ * @param {string} url A url.
+ * @return {boolean} Whether the url has a safe scheme.
+ * @private
+ */
+goog.editor.plugins.LinkDialogPlugin.prototype.isSafeSchemeToOpen_ =
+    function(url) {
+  var scheme = goog.uri.utils.getScheme(url) || 'http';
+  return goog.array.contains(this.safeToOpenSchemes_, scheme.toLowerCase());
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/linkshortcutplugin.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/linkshortcutplugin.js b/externs/GCL/externs/goog/editor/plugins/linkshortcutplugin.js
new file mode 100644
index 0000000..b77910c
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/linkshortcutplugin.js
@@ -0,0 +1,61 @@
+// Copyright 2011 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 Adds a keyboard shortcut for the link command.
+ *
+ */
+
+goog.provide('goog.editor.plugins.LinkShortcutPlugin');
+
+goog.require('goog.editor.Command');
+goog.require('goog.editor.Plugin');
+
+
+
+/**
+ * Plugin to add a keyboard shortcut for the link command
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ * @final
+ */
+goog.editor.plugins.LinkShortcutPlugin = function() {
+  goog.editor.plugins.LinkShortcutPlugin.base(this, 'constructor');
+};
+goog.inherits(goog.editor.plugins.LinkShortcutPlugin, goog.editor.Plugin);
+
+
+/** @override */
+goog.editor.plugins.LinkShortcutPlugin.prototype.getTrogClassId = function() {
+  return 'LinkShortcutPlugin';
+};
+
+
+/**
+ * @override
+ */
+goog.editor.plugins.LinkShortcutPlugin.prototype.handleKeyboardShortcut =
+    function(e, key, isModifierPressed) {
+  if (isModifierPressed && key == 'k' && !e.shiftKey) {
+    var link = /** @type {goog.editor.Link?} */ (
+        this.getFieldObject().execCommand(goog.editor.Command.LINK));
+    if (link) {
+      link.finishLinkCreation(this.getFieldObject());
+    }
+    return true;
+  }
+
+  return false;
+};
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/listtabhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/listtabhandler.js b/externs/GCL/externs/goog/editor/plugins/listtabhandler.js
new file mode 100644
index 0000000..03f78ca
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/listtabhandler.js
@@ -0,0 +1,68 @@
+// Copyright 2008 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 Editor plugin to handle tab keys in lists to indent and
+ * outdent.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.editor.plugins.ListTabHandler');
+
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.Command');
+goog.require('goog.editor.plugins.AbstractTabHandler');
+goog.require('goog.iter');
+
+
+
+/**
+ * Plugin to handle tab keys in lists to indent and outdent.
+ * @constructor
+ * @extends {goog.editor.plugins.AbstractTabHandler}
+ * @final
+ */
+goog.editor.plugins.ListTabHandler = function() {
+  goog.editor.plugins.AbstractTabHandler.call(this);
+};
+goog.inherits(goog.editor.plugins.ListTabHandler,
+    goog.editor.plugins.AbstractTabHandler);
+
+
+/** @override */
+goog.editor.plugins.ListTabHandler.prototype.getTrogClassId = function() {
+  return 'ListTabHandler';
+};
+
+
+/** @override */
+goog.editor.plugins.ListTabHandler.prototype.handleTabKey = function(e) {
+  var range = this.getFieldObject().getRange();
+  if (goog.dom.getAncestorByTagNameAndClass(range.getContainerElement(),
+                                            goog.dom.TagName.LI) ||
+      goog.iter.some(range, function(node) {
+        return node.tagName == goog.dom.TagName.LI;
+      })) {
+    this.getFieldObject().execCommand(e.shiftKey ?
+        goog.editor.Command.OUTDENT :
+        goog.editor.Command.INDENT);
+    e.preventDefault();
+    return true;
+  }
+
+  return false;
+};
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/loremipsum.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/loremipsum.js b/externs/GCL/externs/goog/editor/plugins/loremipsum.js
new file mode 100644
index 0000000..90ba31d
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/loremipsum.js
@@ -0,0 +1,192 @@
+// Copyright 2008 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 plugin that fills the field with lorem ipsum text when it's
+ * empty and does not have the focus. Applies to both editable and uneditable
+ * fields.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.editor.plugins.LoremIpsum');
+
+goog.require('goog.asserts');
+goog.require('goog.dom');
+goog.require('goog.editor.Command');
+goog.require('goog.editor.Field');
+goog.require('goog.editor.Plugin');
+goog.require('goog.editor.node');
+goog.require('goog.functions');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * A plugin that manages lorem ipsum state of editable fields.
+ * @param {string} message The lorem ipsum message.
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ * @final
+ */
+goog.editor.plugins.LoremIpsum = function(message) {
+  goog.editor.Plugin.call(this);
+
+  /**
+   * The lorem ipsum message.
+   * @type {string}
+   * @private
+   */
+  this.message_ = message;
+};
+goog.inherits(goog.editor.plugins.LoremIpsum, goog.editor.Plugin);
+
+
+/** @override */
+goog.editor.plugins.LoremIpsum.prototype.getTrogClassId =
+    goog.functions.constant('LoremIpsum');
+
+
+/** @override */
+goog.editor.plugins.LoremIpsum.prototype.activeOnUneditableFields =
+    goog.functions.TRUE;
+
+
+/**
+ * Whether the field is currently filled with lorem ipsum text.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.plugins.LoremIpsum.prototype.usingLorem_ = false;
+
+
+/**
+ * Handles queryCommandValue.
+ * @param {string} command The command to query.
+ * @return {boolean} The result.
+ * @override
+ */
+goog.editor.plugins.LoremIpsum.prototype.queryCommandValue = function(command) {
+  return command == goog.editor.Command.USING_LOREM && this.usingLorem_;
+};
+
+
+/**
+ * Handles execCommand.
+ * @param {string} command The command to execute.
+ *     Should be CLEAR_LOREM or UPDATE_LOREM.
+ * @param {*=} opt_placeCursor Whether to place the cursor in the field
+ *     after clearing lorem. Should be a boolean.
+ * @override
+ */
+goog.editor.plugins.LoremIpsum.prototype.execCommand = function(command,
+    opt_placeCursor) {
+  if (command == goog.editor.Command.CLEAR_LOREM) {
+    this.clearLorem_(!!opt_placeCursor);
+  } else if (command == goog.editor.Command.UPDATE_LOREM) {
+    this.updateLorem_();
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.LoremIpsum.prototype.isSupportedCommand =
+    function(command) {
+  return command == goog.editor.Command.CLEAR_LOREM ||
+      command == goog.editor.Command.UPDATE_LOREM ||
+      command == goog.editor.Command.USING_LOREM;
+};
+
+
+/**
+ * Set the lorem ipsum text in a goog.editor.Field if needed.
+ * @private
+ */
+goog.editor.plugins.LoremIpsum.prototype.updateLorem_ = function() {
+  // Try to apply lorem ipsum if:
+  // 1) We have lorem ipsum text
+  // 2) There's not a dialog open, as that screws
+  //    with the dialog's ability to properly restore the selection
+  //    on dialog close (since the DOM nodes would get clobbered in FF)
+  // 3) We're not using lorem already
+  // 4) The field is not currently active (doesn't have focus).
+  var fieldObj = this.getFieldObject();
+  if (!this.usingLorem_ &&
+      !fieldObj.inModalMode() &&
+      goog.editor.Field.getActiveFieldId() != fieldObj.id) {
+    var field = fieldObj.getElement();
+    if (!field) {
+      // Fallback on the original element. This is needed by
+      // fields managed by click-to-edit.
+      field = fieldObj.getOriginalElement();
+    }
+
+    goog.asserts.assert(field);
+    if (goog.editor.node.isEmpty(field)) {
+      this.usingLorem_ = true;
+
+      // Save the old font style so it can be restored when we
+      // clear the lorem ipsum style.
+      this.oldFontStyle_ = field.style.fontStyle;
+      field.style.fontStyle = 'italic';
+      fieldObj.setHtml(true, this.message_, true);
+    }
+  }
+};
+
+
+/**
+ * Clear an EditableField's lorem ipsum and put in initial text if needed.
+ *
+ * If using click-to-edit mode (where Trogedit manages whether the field
+ * is editable), this works for both editable and uneditable fields.
+ *
+ * TODO(user): Is this really necessary? See TODO below.
+ * @param {boolean=} opt_placeCursor Whether to place the cursor in the field
+ *     after clearing lorem.
+ * @private
+ */
+goog.editor.plugins.LoremIpsum.prototype.clearLorem_ = function(
+    opt_placeCursor) {
+  // Don't mess with lorem state when a dialog is open as that screws
+  // with the dialog's ability to properly restore the selection
+  // on dialog close (since the DOM nodes would get clobbered)
+  var fieldObj = this.getFieldObject();
+  if (this.usingLorem_ && !fieldObj.inModalMode()) {
+    var field = fieldObj.getElement();
+    if (!field) {
+      // Fallback on the original element. This is needed by
+      // fields managed by click-to-edit.
+      field = fieldObj.getOriginalElement();
+    }
+
+    goog.asserts.assert(field);
+    this.usingLorem_ = false;
+    field.style.fontStyle = this.oldFontStyle_;
+    fieldObj.setHtml(true, null, true);
+
+    // TODO(nicksantos): I'm pretty sure that this is a hack, but talk to
+    // Julie about why this is necessary and what to do with it. Really,
+    // we need to figure out where it's necessary and remove it where it's
+    // not. Safari never places the cursor on its own willpower.
+    if (opt_placeCursor && fieldObj.isLoaded()) {
+      if (goog.userAgent.WEBKIT) {
+        goog.dom.getOwnerDocument(fieldObj.getElement()).body.focus();
+        fieldObj.focusAndPlaceCursorAtStart();
+      } else if (goog.userAgent.OPERA) {
+        fieldObj.placeCursorAtStart();
+      }
+    }
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/removeformatting.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/removeformatting.js b/externs/GCL/externs/goog/editor/plugins/removeformatting.js
new file mode 100644
index 0000000..dd73a31
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/removeformatting.js
@@ -0,0 +1,780 @@
+// Copyright 2008 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.
+// All Rights Reserved.
+
+/**
+ * @fileoverview Plugin to handle Remove Formatting.
+ *
+ */
+
+goog.provide('goog.editor.plugins.RemoveFormatting');
+
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.Range');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.BrowserFeature');
+goog.require('goog.editor.Plugin');
+goog.require('goog.editor.node');
+goog.require('goog.editor.range');
+goog.require('goog.string');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * A plugin to handle removing formatting from selected text.
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ * @final
+ */
+goog.editor.plugins.RemoveFormatting = function() {
+  goog.editor.Plugin.call(this);
+
+  /**
+   * Optional function to perform remove formatting in place of the
+   * provided removeFormattingWorker_.
+   * @type {?function(string): string}
+   * @private
+   */
+  this.optRemoveFormattingFunc_ = null;
+};
+goog.inherits(goog.editor.plugins.RemoveFormatting, goog.editor.Plugin);
+
+
+/**
+ * The editor command this plugin in handling.
+ * @type {string}
+ */
+goog.editor.plugins.RemoveFormatting.REMOVE_FORMATTING_COMMAND =
+    '+removeFormat';
+
+
+/**
+ * Regular expression that matches a block tag name.
+ * @type {RegExp}
+ * @private
+ */
+goog.editor.plugins.RemoveFormatting.BLOCK_RE_ =
+    /^(DIV|TR|LI|BLOCKQUOTE|H\d|PRE|XMP)/;
+
+
+/**
+ * Appends a new line to a string buffer.
+ * @param {Array<string>} sb The string buffer to add to.
+ * @private
+ */
+goog.editor.plugins.RemoveFormatting.appendNewline_ = function(sb) {
+  sb.push('<br>');
+};
+
+
+/**
+ * Create a new range delimited by the start point of the first range and
+ * the end point of the second range.
+ * @param {goog.dom.AbstractRange} startRange Use the start point of this
+ *    range as the beginning of the new range.
+ * @param {goog.dom.AbstractRange} endRange Use the end point of this
+ *    range as the end of the new range.
+ * @return {!goog.dom.AbstractRange} The new range.
+ * @private
+ */
+goog.editor.plugins.RemoveFormatting.createRangeDelimitedByRanges_ = function(
+    startRange, endRange) {
+  return goog.dom.Range.createFromNodes(
+      startRange.getStartNode(), startRange.getStartOffset(),
+      endRange.getEndNode(), endRange.getEndOffset());
+};
+
+
+/** @override */
+goog.editor.plugins.RemoveFormatting.prototype.getTrogClassId = function() {
+  return 'RemoveFormatting';
+};
+
+
+/** @override */
+goog.editor.plugins.RemoveFormatting.prototype.isSupportedCommand = function(
+    command) {
+  return command ==
+      goog.editor.plugins.RemoveFormatting.REMOVE_FORMATTING_COMMAND;
+};
+
+
+/** @override */
+goog.editor.plugins.RemoveFormatting.prototype.execCommandInternal =
+    function(command, var_args) {
+  if (command ==
+      goog.editor.plugins.RemoveFormatting.REMOVE_FORMATTING_COMMAND) {
+    this.removeFormatting_();
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.RemoveFormatting.prototype.handleKeyboardShortcut =
+    function(e, key, isModifierPressed) {
+  if (!isModifierPressed) {
+    return false;
+  }
+
+  if (key == ' ') {
+    this.getFieldObject().execCommand(
+        goog.editor.plugins.RemoveFormatting.REMOVE_FORMATTING_COMMAND);
+    return true;
+  }
+
+  return false;
+};
+
+
+/**
+ * Removes formatting from the current selection.  Removes basic formatting
+ * (B/I/U) using the browser's execCommand.  Then extracts the html from the
+ * selection to convert, calls either a client's specified removeFormattingFunc
+ * callback or trogedit's general built-in removeFormattingWorker_,
+ * and then replaces the current selection with the converted text.
+ * @private
+ */
+goog.editor.plugins.RemoveFormatting.prototype.removeFormatting_ = function() {
+  var range = this.getFieldObject().getRange();
+  if (range.isCollapsed()) {
+    return;
+  }
+
+  // Get the html to format and send it off for formatting. Built in
+  // removeFormat only strips some inline elements and some inline CSS styles
+  var convFunc = this.optRemoveFormattingFunc_ ||
+                 goog.bind(this.removeFormattingWorker_, this);
+  this.convertSelectedHtmlText_(convFunc);
+
+  // Do the execCommand last as it needs block elements removed to work
+  // properly on background/fontColor in FF. There are, unfortunately, still
+  // cases where background/fontColor are not removed here.
+  var doc = this.getFieldDomHelper().getDocument();
+  doc.execCommand('RemoveFormat', false, undefined);
+
+  if (goog.editor.BrowserFeature.ADDS_NBSPS_IN_REMOVE_FORMAT) {
+    // WebKit converts spaces to non-breaking spaces when doing a RemoveFormat.
+    // See: https://bugs.webkit.org/show_bug.cgi?id=14062
+    this.convertSelectedHtmlText_(function(text) {
+      // This loses anything that might have legitimately been a non-breaking
+      // space, but that's better than the alternative of only having non-
+      // breaking spaces.
+      // Old versions of WebKit (Safari 3, Chrome 1) incorrectly match /u00A0
+      // and newer versions properly match &nbsp;.
+      var nbspRegExp =
+          goog.userAgent.isVersionOrHigher('528') ? /&nbsp;/g : /\u00A0/g;
+      return text.replace(nbspRegExp, ' ');
+    });
+  }
+};
+
+
+/**
+ * Finds the nearest ancestor of the node that is a table.
+ * @param {Node} nodeToCheck Node to search from.
+ * @return {Node} The table, or null if one was not found.
+ * @private
+ */
+goog.editor.plugins.RemoveFormatting.prototype.getTableAncestor_ = function(
+    nodeToCheck) {
+  var fieldElement = this.getFieldObject().getElement();
+  while (nodeToCheck && nodeToCheck != fieldElement) {
+    if (nodeToCheck.tagName == goog.dom.TagName.TABLE) {
+      return nodeToCheck;
+    }
+    nodeToCheck = nodeToCheck.parentNode;
+  }
+  return null;
+};
+
+
+/**
+ * Replaces the contents of the selection with html. Does its best to maintain
+ * the original selection. Also does its best to result in a valid DOM.
+ *
+ * TODO(user): See if there's any way to make this work on Ranges, and then
+ * move it into goog.editor.range. The Firefox implementation uses execCommand
+ * on the document, so must work on the actual selection.
+ *
+ * @param {string} html The html string to insert into the range.
+ * @private
+ */
+goog.editor.plugins.RemoveFormatting.prototype.pasteHtml_ = function(html) {
+  var range = this.getFieldObject().getRange();
+
+  var dh = this.getFieldDomHelper();
+  // Use markers to set the extent of the selection so that we can reselect it
+  // afterwards. This works better than builtin range manipulation in FF and IE
+  // because their implementations are so self-inconsistent and buggy.
+  var startSpanId = goog.string.createUniqueString();
+  var endSpanId = goog.string.createUniqueString();
+  html = '<span id="' + startSpanId + '"></span>' + html +
+      '<span id="' + endSpanId + '"></span>';
+  var dummyNodeId = goog.string.createUniqueString();
+  var dummySpanText = '<span id="' + dummyNodeId + '"></span>';
+
+  if (goog.editor.BrowserFeature.HAS_IE_RANGES) {
+    // IE's selection often doesn't include the outermost tags.
+    // We want to use pasteHTML to replace the range contents with the newly
+    // unformatted text, so we have to check to make sure we aren't just
+    // pasting into some stray tags.  To do this, we first clear out the
+    // contents of the range and then delete all empty nodes parenting the now
+    // empty range. This way, the pasted contents are never re-embedded into
+    // formated nodes. Pasting purely empty html does not work, since IE moves
+    // the selection inside the next node, so we insert a dummy span.
+    var textRange = range.getTextRange(0).getBrowserRangeObject();
+    textRange.pasteHTML(dummySpanText);
+    var parent;
+    while ((parent = textRange.parentElement()) &&
+           goog.editor.node.isEmpty(parent) &&
+           !goog.editor.node.isEditableContainer(parent)) {
+      var tag = parent.nodeName;
+      // We can't remove these table tags as it will invalidate the table dom.
+      if (tag == goog.dom.TagName.TD ||
+          tag == goog.dom.TagName.TR ||
+          tag == goog.dom.TagName.TH) {
+        break;
+      }
+
+      goog.dom.removeNode(parent);
+    }
+    textRange.pasteHTML(html);
+    var dummySpan = dh.getElement(dummyNodeId);
+    // If we entered the while loop above, the node has already been removed
+    // since it was a child of parent and parent was removed.
+    if (dummySpan) {
+      goog.dom.removeNode(dummySpan);
+    }
+  } else if (goog.editor.BrowserFeature.HAS_W3C_RANGES) {
+    // insertHtml and range.insertNode don't merge blocks correctly.
+    // (e.g. if your selection spans two paragraphs)
+    dh.getDocument().execCommand('insertImage', false, dummyNodeId);
+    var dummyImageNodePattern = new RegExp('<[^<]*' + dummyNodeId + '[^>]*>');
+    var parent = this.getFieldObject().getRange().getContainerElement();
+    if (parent.nodeType == goog.dom.NodeType.TEXT) {
+      // Opera sometimes returns a text node here.
+      // TODO(user): perhaps we should modify getParentContainer?
+      parent = parent.parentNode;
+    }
+
+    // We have to search up the DOM because in some cases, notably when
+    // selecting li's within a list, execCommand('insertImage') actually splits
+    // tags in such a way that parent that used to contain the selection does
+    // not contain inserted image.
+    while (!dummyImageNodePattern.test(parent.innerHTML)) {
+      parent = parent.parentNode;
+    }
+
+    // Like the IE case above, sometimes the selection does not include the
+    // outermost tags.  For Gecko, we have already expanded the range so that
+    // it does, so we can just replace the dummy image with the final html.
+    // For WebKit, we use the same approach as we do with IE  - we
+    // inject a dummy span where we will eventually place the contents, and
+    // remove parentNodes of the span while they are empty.
+
+    if (goog.userAgent.GECKO) {
+      goog.editor.node.replaceInnerHtml(parent,
+          parent.innerHTML.replace(dummyImageNodePattern, html));
+    } else {
+      goog.editor.node.replaceInnerHtml(parent,
+          parent.innerHTML.replace(dummyImageNodePattern, dummySpanText));
+      var dummySpan = dh.getElement(dummyNodeId);
+      parent = dummySpan;
+      while ((parent = dummySpan.parentNode) &&
+             goog.editor.node.isEmpty(parent) &&
+             !goog.editor.node.isEditableContainer(parent)) {
+        var tag = parent.nodeName;
+        // We can't remove these table tags as it will invalidate the table dom.
+        if (tag == goog.dom.TagName.TD ||
+            tag == goog.dom.TagName.TR ||
+            tag == goog.dom.TagName.TH) {
+          break;
+        }
+
+        // We can't just remove parent since dummySpan is inside it, and we need
+        // to keep dummy span around for the replacement.  So we move the
+        // dummySpan up as we go.
+        goog.dom.insertSiblingAfter(dummySpan, parent);
+        goog.dom.removeNode(parent);
+      }
+      goog.editor.node.replaceInnerHtml(parent,
+          parent.innerHTML.replace(new RegExp(dummySpanText, 'i'), html));
+    }
+  }
+
+  var startSpan = dh.getElement(startSpanId);
+  var endSpan = dh.getElement(endSpanId);
+  goog.dom.Range.createFromNodes(startSpan, 0, endSpan,
+      endSpan.childNodes.length).select();
+  goog.dom.removeNode(startSpan);
+  goog.dom.removeNode(endSpan);
+};
+
+
+/**
+ * Gets the html inside the selection to send off for further processing.
+ *
+ * TODO(user): Make this general so that it can be moved into
+ * goog.editor.range.  The main reason it can't be moved is becuase we need to
+ * get the range before we do the execCommand and continue to operate on that
+ * same range (reasons are documented above).
+ *
+ * @param {goog.dom.AbstractRange} range The selection.
+ * @return {string} The html string to format.
+ * @private
+ */
+goog.editor.plugins.RemoveFormatting.prototype.getHtmlText_ = function(range) {
+  var div = this.getFieldDomHelper().createDom(goog.dom.TagName.DIV);
+  var textRange = range.getBrowserRangeObject();
+
+  if (goog.editor.BrowserFeature.HAS_W3C_RANGES) {
+    // Get the text to convert.
+    div.appendChild(textRange.cloneContents());
+  } else if (goog.editor.BrowserFeature.HAS_IE_RANGES) {
+    // Trim the whitespace on the ends of the range, so that it the container
+    // will be the container of only the text content that we are changing.
+    // This gets around issues in IE where the spaces are included in the
+    // selection, but ignored sometimes by execCommand, and left orphaned.
+    var rngText = range.getText();
+
+    // BRs get reported as \r\n, but only count as one character for moves.
+    // Adjust the string so our move counter is correct.
+    rngText = rngText.replace(/\r\n/g, '\r');
+
+    var rngTextLength = rngText.length;
+    var left = rngTextLength - goog.string.trimLeft(rngText).length;
+    var right = rngTextLength - goog.string.trimRight(rngText).length;
+
+    textRange.moveStart('character', left);
+    textRange.moveEnd('character', -right);
+
+    var htmlText = textRange.htmlText;
+    // Check if in pretag and fix up formatting so that new lines are preserved.
+    if (textRange.queryCommandValue('formatBlock') == 'Formatted') {
+      htmlText = goog.string.newLineToBr(textRange.htmlText);
+    }
+    div.innerHTML = htmlText;
+  }
+
+  // Get the innerHTML of the node instead of just returning the text above
+  // so that its properly html escaped.
+  return div.innerHTML;
+};
+
+
+/**
+ * Move the range so that it doesn't include any partially selected tables.
+ * @param {goog.dom.AbstractRange} range The range to adjust.
+ * @param {Node} startInTable Table node that the range starts in.
+ * @param {Node} endInTable Table node that the range ends in.
+ * @return {!goog.dom.SavedCaretRange} Range to use to restore the
+ *     selection after we run our custom remove formatting.
+ * @private
+ */
+goog.editor.plugins.RemoveFormatting.prototype.adjustRangeForTables_ =
+    function(range, startInTable, endInTable) {
+  // Create placeholders for the current selection so we can restore it
+  // later.
+  var savedCaretRange = goog.editor.range.saveUsingNormalizedCarets(range);
+
+  var startNode = range.getStartNode();
+  var startOffset = range.getStartOffset();
+  var endNode = range.getEndNode();
+  var endOffset = range.getEndOffset();
+  var dh = this.getFieldDomHelper();
+
+  // Move start after the table.
+  if (startInTable) {
+    var textNode = dh.createTextNode('');
+    goog.dom.insertSiblingAfter(textNode, startInTable);
+    startNode = textNode;
+    startOffset = 0;
+  }
+  // Move end before the table.
+  if (endInTable) {
+    var textNode = dh.createTextNode('');
+    goog.dom.insertSiblingBefore(textNode, endInTable);
+    endNode = textNode;
+    endOffset = 0;
+  }
+
+  goog.dom.Range.createFromNodes(startNode, startOffset,
+      endNode, endOffset).select();
+
+  return savedCaretRange;
+};
+
+
+/**
+ * Remove a caret from the dom and hide it in a safe place, so it can
+ * be restored later via restoreCaretsFromCave.
+ * @param {goog.dom.SavedCaretRange} caretRange The caret range to
+ *     get the carets from.
+ * @param {boolean} isStart Whether this is the start or end caret.
+ * @private
+ */
+goog.editor.plugins.RemoveFormatting.prototype.putCaretInCave_ = function(
+    caretRange, isStart) {
+  var cavedCaret = goog.dom.removeNode(caretRange.getCaret(isStart));
+  if (isStart) {
+    this.startCaretInCave_ = cavedCaret;
+  } else {
+    this.endCaretInCave_ = cavedCaret;
+  }
+};
+
+
+/**
+ * Restore carets that were hidden away by adding them back into the dom.
+ * Note: this does not restore to the original dom location, as that
+ * will likely have been modified with remove formatting.  The only
+ * guarentees here are that start will still be before end, and that
+ * they will be in the editable region.  This should only be used when
+ * you don't actually intend to USE the caret again.
+ * @private
+ */
+goog.editor.plugins.RemoveFormatting.prototype.restoreCaretsFromCave_ =
+    function() {
+  // To keep start before end, we put the end caret at the bottom of the field
+  // and the start caret at the start of the field.
+  var field = this.getFieldObject().getElement();
+  if (this.startCaretInCave_) {
+    field.insertBefore(this.startCaretInCave_, field.firstChild);
+    this.startCaretInCave_ = null;
+  }
+  if (this.endCaretInCave_) {
+    field.appendChild(this.endCaretInCave_);
+    this.endCaretInCave_ = null;
+  }
+};
+
+
+/**
+ * Gets the html inside the current selection, passes it through the given
+ * conversion function, and puts it back into the selection.
+ *
+ * @param {function(string): string} convertFunc A conversion function that
+ *    transforms an html string to new html string.
+ * @private
+ */
+goog.editor.plugins.RemoveFormatting.prototype.convertSelectedHtmlText_ =
+    function(convertFunc) {
+  var range = this.getFieldObject().getRange();
+
+  // For multiple ranges, it is really hard to do our custom remove formatting
+  // without invalidating other ranges. So instead of always losing the
+  // content, this solution at least lets the browser do its own remove
+  // formatting which works correctly most of the time.
+  if (range.getTextRangeCount() > 1) {
+    return;
+  }
+
+  if (goog.userAgent.GECKO) {
+    // Determine if we need to handle tables, since they are special cases.
+    // If the selection is entirely within a table, there is no extra
+    // formatting removal we can do.  If a table is fully selected, we will
+    // just blow it away. If a table is only partially selected, we can
+    // perform custom remove formatting only on the non table parts, since we
+    // we can't just remove the parts and paste back into it (eg. we can't
+    // inject html where a TR used to be).
+    // If the selection contains the table and more, this is automatically
+    // handled, but if just the table is selected, it can be tricky to figure
+    // this case out, because of the numerous ways selections can be formed -
+    // ex. if a table has a single tr with a single td with a single text node
+    // in it, and the selection is (textNode: 0), (textNode: nextNode.length)
+    // then the entire table is selected, even though the start and end aren't
+    // the table itself. We are truly inside a table if the expanded endpoints
+    // are still inside the table.
+
+    // Expand the selection to include any outermost tags that weren't included
+    // in the selection, but have the same visible selection. Stop expanding
+    // if we reach the top level field.
+    var expandedRange = goog.editor.range.expand(range,
+        this.getFieldObject().getElement());
+
+    var startInTable = this.getTableAncestor_(expandedRange.getStartNode());
+    var endInTable = this.getTableAncestor_(expandedRange.getEndNode());
+
+    if (startInTable || endInTable) {
+      if (startInTable == endInTable) {
+        // We are fully contained in the same table, there is no extra
+        // remove formatting that we can do, just return and run browser
+        // formatting only.
+        return;
+      }
+
+      // Adjust the range to not contain any partially selected tables, since
+      // we don't want to run our custom remove formatting on them.
+      var savedCaretRange = this.adjustRangeForTables_(range,
+          startInTable, endInTable);
+
+      // Hack alert!!
+      // If start is not in a table, then the saved caret will get sent out
+      // for uber remove formatting, and it will get blown away.  This is
+      // fine, except that we need to be able to re-create a range from the
+      // savedCaretRange later on.  So, we just remove it from the dom, and
+      // put it back later so we can create a range later (not exactly in the
+      // same spot, but don't worry we don't actually try to use it later)
+      // and then it will be removed when we dispose the range.
+      if (!startInTable) {
+        this.putCaretInCave_(savedCaretRange, true);
+      }
+      if (!endInTable) {
+        this.putCaretInCave_(savedCaretRange, false);
+      }
+
+      // Re-fetch the range, and re-expand it, since we just modified it.
+      range = this.getFieldObject().getRange();
+      expandedRange = goog.editor.range.expand(range,
+          this.getFieldObject().getElement());
+    }
+
+    expandedRange.select();
+    range = expandedRange;
+  }
+
+  // Convert the selected text to the format-less version, paste back into
+  // the selection.
+  var text = this.getHtmlText_(range);
+  this.pasteHtml_(convertFunc(text));
+
+  if (goog.userAgent.GECKO && savedCaretRange) {
+    // If we moved the selection, move it back so the user can't tell we did
+    // anything crazy and so the browser removeFormat that we call next
+    // will operate on the entire originally selected range.
+    range = this.getFieldObject().getRange();
+    this.restoreCaretsFromCave_();
+    var realSavedCaretRange = savedCaretRange.toAbstractRange();
+    var startRange = startInTable ? realSavedCaretRange : range;
+    var endRange = endInTable ? realSavedCaretRange : range;
+    var restoredRange =
+        goog.editor.plugins.RemoveFormatting.createRangeDelimitedByRanges_(
+            startRange, endRange);
+    restoredRange.select();
+    savedCaretRange.dispose();
+  }
+};
+
+
+/**
+ * Does a best-effort attempt at clobbering all formatting that the
+ * browser's execCommand couldn't clobber without being totally inefficient.
+ * Attempts to convert visual line breaks to BRs. Leaves anchors that contain an
+ * href and images.
+ * Adapted from Gmail's MessageUtil's htmlToPlainText. http://go/messageutil.js
+ * @param {string} html The original html of the message.
+ * @return {string} The unformatted html, which is just text, br's, anchors and
+ *     images.
+ * @private
+ */
+goog.editor.plugins.RemoveFormatting.prototype.removeFormattingWorker_ =
+    function(html) {
+  var el = goog.dom.createElement(goog.dom.TagName.DIV);
+  el.innerHTML = html;
+
+  // Put everything into a string buffer to avoid lots of expensive string
+  // concatenation along the way.
+  var sb = [];
+  var stack = [el.childNodes, 0];
+
+  // Keep separate stacks for places where we need to keep track of
+  // how deeply embedded we are.  These are analogous to the general stack.
+  var preTagStack = [];
+  var preTagLevel = 0;  // Length of the prestack.
+  var tableStack = [];
+  var tableLevel = 0;
+
+  // sp = stack pointer, pointing to the stack array.
+  // decrement by 2 since the stack alternates node lists and
+  // processed node counts
+  for (var sp = 0; sp >= 0; sp -= 2) {
+    // Check if we should pop the table level.
+    var changedLevel = false;
+    while (tableLevel > 0 && sp <= tableStack[tableLevel - 1]) {
+      tableLevel--;
+      changedLevel = true;
+    }
+    if (changedLevel) {
+      goog.editor.plugins.RemoveFormatting.appendNewline_(sb);
+    }
+
+
+    // Check if we should pop the <pre>/<xmp> level.
+    changedLevel = false;
+    while (preTagLevel > 0 && sp <= preTagStack[preTagLevel - 1]) {
+      preTagLevel--;
+      changedLevel = true;
+    }
+    if (changedLevel) {
+      goog.editor.plugins.RemoveFormatting.appendNewline_(sb);
+    }
+
+    // The list of of nodes to process at the current stack level.
+    var nodeList = stack[sp];
+    // The number of nodes processed so far, stored in the stack immediately
+    // following the node list for that stack level.
+    var numNodesProcessed = stack[sp + 1];
+
+    while (numNodesProcessed < nodeList.length) {
+      var node = nodeList[numNodesProcessed++];
+      var nodeName = node.nodeName;
+
+      var formatted = this.getValueForNode(node);
+      if (goog.isDefAndNotNull(formatted)) {
+        sb.push(formatted);
+        continue;
+      }
+
+      // TODO(user): Handle case 'EMBED' and case 'OBJECT'.
+      switch (nodeName) {
+        case '#text':
+          // Note that IE does not preserve whitespace in the dom
+          // values, even in a pre tag, so this is useless for IE.
+          var nodeValue = preTagLevel > 0 ?
+              node.nodeValue :
+              goog.string.stripNewlines(node.nodeValue);
+          nodeValue = goog.string.htmlEscape(nodeValue);
+          sb.push(nodeValue);
+          continue;
+
+        case goog.dom.TagName.P:
+          goog.editor.plugins.RemoveFormatting.appendNewline_(sb);
+          goog.editor.plugins.RemoveFormatting.appendNewline_(sb);
+          break;  // break (not continue) so that child nodes are processed.
+
+        case goog.dom.TagName.BR:
+          goog.editor.plugins.RemoveFormatting.appendNewline_(sb);
+          continue;
+
+        case goog.dom.TagName.TABLE:
+          goog.editor.plugins.RemoveFormatting.appendNewline_(sb);
+          tableStack[tableLevel++] = sp;
+          break;
+
+        case goog.dom.TagName.PRE:
+        case 'XMP':
+          // This doesn't fully handle xmp, since
+          // it doesn't actually ignore tags within the xmp tag.
+          preTagStack[preTagLevel++] = sp;
+          break;
+
+        case goog.dom.TagName.STYLE:
+        case goog.dom.TagName.SCRIPT:
+        case goog.dom.TagName.SELECT:
+          continue;
+
+        case goog.dom.TagName.A:
+          if (node.href && node.href != '') {
+            sb.push("<a href='");
+            sb.push(node.href);
+            sb.push("'>");
+            sb.push(this.removeFormattingWorker_(node.innerHTML));
+            sb.push('</a>');
+            continue; // Children taken care of.
+          } else {
+            break; // Take care of the children.
+          }
+
+        case goog.dom.TagName.IMG:
+          sb.push("<img src='");
+          sb.push(node.src);
+          sb.push("'");
+          // border=0 is a common way to not show a blue border around an image
+          // that is wrapped by a link. If we remove that, the blue border will
+          // show up, which to the user looks like adding format, not removing.
+          if (node.border == '0') {
+            sb.push(" border='0'");
+          }
+          sb.push('>');
+          continue;
+
+        case goog.dom.TagName.TD:
+          // Don't add a space for the first TD, we only want spaces to
+          // separate td's.
+          if (node.previousSibling) {
+            sb.push(' ');
+          }
+          break;
+
+        case goog.dom.TagName.TR:
+          // Don't add a newline for the first TR.
+          if (node.previousSibling) {
+            goog.editor.plugins.RemoveFormatting.appendNewline_(sb);
+          }
+          break;
+
+        case goog.dom.TagName.DIV:
+          var parent = node.parentNode;
+          if (parent.firstChild == node &&
+              goog.editor.plugins.RemoveFormatting.BLOCK_RE_.test(
+                  parent.tagName)) {
+            // If a DIV is the first child of another element that itself is a
+            // block element, the DIV does not add a new line.
+            break;
+          }
+          // Otherwise, the DIV does add a new line.  Fall through.
+
+        default:
+          if (goog.editor.plugins.RemoveFormatting.BLOCK_RE_.test(nodeName)) {
+            goog.editor.plugins.RemoveFormatting.appendNewline_(sb);
+          }
+      }
+
+      // Recurse down the node.
+      var children = node.childNodes;
+      if (children.length > 0) {
+        // Push the current state on the stack.
+        stack[sp++] = nodeList;
+        stack[sp++] = numNodesProcessed;
+
+        // Iterate through the children nodes.
+        nodeList = children;
+        numNodesProcessed = 0;
+      }
+    }
+  }
+
+  // Replace &nbsp; with white space.
+  return goog.string.normalizeSpaces(sb.join(''));
+};
+
+
+/**
+ * Handle per node special processing if neccessary. If this function returns
+ * null then standard cleanup is applied. Otherwise this node and all children
+ * are assumed to be cleaned.
+ * NOTE(user): If an alternate RemoveFormatting processor is provided
+ * (setRemoveFormattingFunc()), this will no longer work.
+ * @param {Element} node The node to clean.
+ * @return {?string} The HTML strig representation of the cleaned data.
+ */
+goog.editor.plugins.RemoveFormatting.prototype.getValueForNode = function(
+    node) {
+  return null;
+};
+
+
+/**
+ * Sets a function to be used for remove formatting.
+ * @param {function(string): string} removeFormattingFunc - A function that
+ *     takes  a string of html and returns a string of html that does any other
+ *     formatting changes desired.  Use this only if trogedit's behavior doesn't
+ *     meet your needs.
+ */
+goog.editor.plugins.RemoveFormatting.prototype.setRemoveFormattingFunc =
+    function(removeFormattingFunc) {
+  this.optRemoveFormattingFunc_ = removeFormattingFunc;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/spacestabhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/spacestabhandler.js b/externs/GCL/externs/goog/editor/plugins/spacestabhandler.js
new file mode 100644
index 0000000..47fcf7a
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/spacestabhandler.js
@@ -0,0 +1,92 @@
+// Copyright 2008 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 Editor plugin to handle tab keys not in lists to add 4 spaces.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.editor.plugins.SpacesTabHandler');
+
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.plugins.AbstractTabHandler');
+goog.require('goog.editor.range');
+
+
+
+/**
+ * Plugin to handle tab keys when not in lists to add 4 spaces.
+ * @constructor
+ * @extends {goog.editor.plugins.AbstractTabHandler}
+ * @final
+ */
+goog.editor.plugins.SpacesTabHandler = function() {
+  goog.editor.plugins.AbstractTabHandler.call(this);
+};
+goog.inherits(goog.editor.plugins.SpacesTabHandler,
+    goog.editor.plugins.AbstractTabHandler);
+
+
+/** @override */
+goog.editor.plugins.SpacesTabHandler.prototype.getTrogClassId = function() {
+  return 'SpacesTabHandler';
+};
+
+
+/** @override */
+goog.editor.plugins.SpacesTabHandler.prototype.handleTabKey = function(e) {
+  var dh = this.getFieldDomHelper();
+  var range = this.getFieldObject().getRange();
+  if (!goog.editor.range.intersectsTag(range, goog.dom.TagName.LI)) {
+    // In the shift + tab case we don't want to insert spaces, but we don't
+    // want focus to move either so skip the spacing logic and just prevent
+    // default.
+    if (!e.shiftKey) {
+      // Not in a list but we want to insert 4 spaces.
+
+      // Stop change events while we make multiple field changes.
+      this.getFieldObject().stopChangeEvents(true, true);
+
+      // Inserting nodes below completely messes up the selection, doing the
+      // deletion here before it's messed up. Only delete if text is selected,
+      // otherwise we would remove the character to the right of the cursor.
+      if (!range.isCollapsed()) {
+        dh.getDocument().execCommand('delete', false, null);
+        // Safari 3 has some DOM exceptions if we don't reget the range here,
+        // doing it all the time just to be safe.
+        range = this.getFieldObject().getRange();
+      }
+
+      // Emulate tab by removing selection and inserting 4 spaces
+      // Two breaking spaces in a row can be collapsed by the browser into one
+      // space. Inserting the string below because it is guaranteed to never
+      // collapse to less than four spaces, regardless of what is adjacent to
+      // the inserted spaces. This might make line wrapping slightly
+      // sub-optimal around a grouping of non-breaking spaces.
+      var elem = dh.createDom(goog.dom.TagName.SPAN, null,
+                              '\u00a0\u00a0 \u00a0');
+      elem = range.insertNode(elem, false);
+
+      this.getFieldObject().dispatchChange();
+      goog.editor.range.placeCursorNextTo(elem, false);
+      this.getFieldObject().dispatchSelectionChangeEvent();
+    }
+
+    e.preventDefault();
+    return true;
+  }
+
+  return false;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/tableeditor.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/tableeditor.js b/externs/GCL/externs/goog/editor/plugins/tableeditor.js
new file mode 100644
index 0000000..be7cad0
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/tableeditor.js
@@ -0,0 +1,475 @@
+// Copyright 2008 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 Plugin that enables table editing.
+ *
+ * @see ../../demos/editor/tableeditor.html
+ */
+
+goog.provide('goog.editor.plugins.TableEditor');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.Range');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.Plugin');
+goog.require('goog.editor.Table');
+goog.require('goog.editor.node');
+goog.require('goog.editor.range');
+goog.require('goog.object');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Plugin that adds support for table creation and editing commands.
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ * @final
+ */
+goog.editor.plugins.TableEditor = function() {
+  goog.editor.plugins.TableEditor.base(this, 'constructor');
+
+  /**
+   * The array of functions that decide whether a table element could be
+   * editable by the user or not.
+   * @type {Array<function(Element):boolean>}
+   * @private
+   */
+  this.isTableEditableFunctions_ = [];
+
+  /**
+   * The pre-bound function that decides whether a table element could be
+   * editable by the user or not overall.
+   * @type {function(Node):boolean}
+   * @private
+   */
+  this.isUserEditableTableBound_ = goog.bind(this.isUserEditableTable_, this);
+};
+goog.inherits(goog.editor.plugins.TableEditor, goog.editor.Plugin);
+
+
+/** @override */
+// TODO(user): remove this once there's a sensible default
+// implementation in the base Plugin.
+goog.editor.plugins.TableEditor.prototype.getTrogClassId = function() {
+  return String(goog.getUid(this.constructor));
+};
+
+
+/**
+ * Commands supported by goog.editor.plugins.TableEditor.
+ * @enum {string}
+ */
+goog.editor.plugins.TableEditor.COMMAND = {
+  TABLE: '+table',
+  INSERT_ROW_AFTER: '+insertRowAfter',
+  INSERT_ROW_BEFORE: '+insertRowBefore',
+  INSERT_COLUMN_AFTER: '+insertColumnAfter',
+  INSERT_COLUMN_BEFORE: '+insertColumnBefore',
+  REMOVE_ROWS: '+removeRows',
+  REMOVE_COLUMNS: '+removeColumns',
+  SPLIT_CELL: '+splitCell',
+  MERGE_CELLS: '+mergeCells',
+  REMOVE_TABLE: '+removeTable'
+};
+
+
+/**
+ * Inverse map of execCommand strings to
+ * {@link goog.editor.plugins.TableEditor.COMMAND} constants. Used to
+ * determine whether a string corresponds to a command this plugin handles
+ * in O(1) time.
+ * @type {Object}
+ * @private
+ */
+goog.editor.plugins.TableEditor.SUPPORTED_COMMANDS_ =
+    goog.object.transpose(goog.editor.plugins.TableEditor.COMMAND);
+
+
+/**
+ * Whether the string corresponds to a command this plugin handles.
+ * @param {string} command Command string to check.
+ * @return {boolean} Whether the string corresponds to a command
+ *     this plugin handles.
+ * @override
+ */
+goog.editor.plugins.TableEditor.prototype.isSupportedCommand =
+    function(command) {
+  return command in goog.editor.plugins.TableEditor.SUPPORTED_COMMANDS_;
+};
+
+
+/** @override */
+goog.editor.plugins.TableEditor.prototype.enable = function(fieldObject) {
+  goog.editor.plugins.TableEditor.base(this, 'enable', fieldObject);
+
+  // enableObjectResizing is supported only for Gecko.
+  // You can refer to http://qooxdoo.org/contrib/project/htmlarea/html_editing
+  // for a compatibility chart.
+  if (goog.userAgent.GECKO) {
+    var doc = this.getFieldDomHelper().getDocument();
+    doc.execCommand('enableObjectResizing', false, 'true');
+  }
+};
+
+
+/**
+ * Returns the currently selected table.
+ * @return {Element?} The table in which the current selection is
+ *     contained, or null if there isn't such a table.
+ * @private
+ */
+goog.editor.plugins.TableEditor.prototype.getCurrentTable_ = function() {
+  var selectedElement = this.getFieldObject().getRange().getContainer();
+  return this.getAncestorTable_(selectedElement);
+};
+
+
+/**
+ * Finds the first user-editable table element in the input node's ancestors.
+ * @param {Node?} node The node to start with.
+ * @return {Element?} The table element that is closest ancestor of the node.
+ * @private
+ */
+goog.editor.plugins.TableEditor.prototype.getAncestorTable_ = function(node) {
+  var ancestor = goog.dom.getAncestor(node, this.isUserEditableTableBound_,
+      true);
+  if (goog.editor.node.isEditable(ancestor)) {
+    return /** @type {Element?} */(ancestor);
+  } else {
+    return null;
+  }
+};
+
+
+/**
+ * Returns the current value of a given command. Currently this plugin
+ * only returns a value for goog.editor.plugins.TableEditor.COMMAND.TABLE.
+ * @override
+ */
+goog.editor.plugins.TableEditor.prototype.queryCommandValue =
+    function(command) {
+  if (command == goog.editor.plugins.TableEditor.COMMAND.TABLE) {
+    return !!this.getCurrentTable_();
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.TableEditor.prototype.execCommandInternal = function(
+    command, opt_arg) {
+  var result = null;
+  // TD/TH in which to place the cursor, if the command destroys the current
+  // cursor position.
+  var cursorCell = null;
+  var range = this.getFieldObject().getRange();
+  if (command == goog.editor.plugins.TableEditor.COMMAND.TABLE) {
+    // Don't create a table if the cursor isn't in an editable region.
+    if (!goog.editor.range.isEditable(range)) {
+      return null;
+    }
+    // Create the table.
+    var tableProps = opt_arg || {width: 4, height: 2};
+    var doc = this.getFieldDomHelper().getDocument();
+    var table = goog.editor.Table.createDomTable(
+        doc, tableProps.width, tableProps.height);
+    range.replaceContentsWithNode(table);
+    // In IE, replaceContentsWithNode uses pasteHTML, so we lose our reference
+    // to the inserted table.
+    // TODO(user): use the reference to the table element returned from
+    // replaceContentsWithNode.
+    if (!goog.userAgent.IE) {
+      cursorCell = table.getElementsByTagName(goog.dom.TagName.TD)[0];
+    }
+  } else {
+    var cellSelection = new goog.editor.plugins.TableEditor.CellSelection_(
+        range, goog.bind(this.getAncestorTable_, this));
+    var table = cellSelection.getTable();
+    if (!table) {
+      return null;
+    }
+    switch (command) {
+      case goog.editor.plugins.TableEditor.COMMAND.INSERT_ROW_BEFORE:
+        table.insertRow(cellSelection.getFirstRowIndex());
+        break;
+      case goog.editor.plugins.TableEditor.COMMAND.INSERT_ROW_AFTER:
+        table.insertRow(cellSelection.getLastRowIndex() + 1);
+        break;
+      case goog.editor.plugins.TableEditor.COMMAND.INSERT_COLUMN_BEFORE:
+        table.insertColumn(cellSelection.getFirstColumnIndex());
+        break;
+      case goog.editor.plugins.TableEditor.COMMAND.INSERT_COLUMN_AFTER:
+        table.insertColumn(cellSelection.getLastColumnIndex() + 1);
+        break;
+      case goog.editor.plugins.TableEditor.COMMAND.REMOVE_ROWS:
+        var startRow = cellSelection.getFirstRowIndex();
+        var endRow = cellSelection.getLastRowIndex();
+        if (startRow == 0 && endRow == (table.rows.length - 1)) {
+          // Instead of deleting all rows, delete the entire table.
+          return this.execCommandInternal(
+              goog.editor.plugins.TableEditor.COMMAND.REMOVE_TABLE);
+        }
+        var startColumn = cellSelection.getFirstColumnIndex();
+        var rowCount = (endRow - startRow) + 1;
+        for (var i = 0; i < rowCount; i++) {
+          table.removeRow(startRow);
+        }
+        if (table.rows.length > 0) {
+          // Place cursor in the previous/first row.
+          var closestRow = Math.min(startRow, table.rows.length - 1);
+          cursorCell = table.rows[closestRow].columns[startColumn].element;
+        }
+        break;
+      case goog.editor.plugins.TableEditor.COMMAND.REMOVE_COLUMNS:
+        var startCol = cellSelection.getFirstColumnIndex();
+        var endCol = cellSelection.getLastColumnIndex();
+        if (startCol == 0 && endCol == (table.rows[0].columns.length - 1)) {
+          // Instead of deleting all columns, delete the entire table.
+          return this.execCommandInternal(
+              goog.editor.plugins.TableEditor.COMMAND.REMOVE_TABLE);
+        }
+        var startRow = cellSelection.getFirstRowIndex();
+        var removeCount = (endCol - startCol) + 1;
+        for (var i = 0; i < removeCount; i++) {
+          table.removeColumn(startCol);
+        }
+        var currentRow = table.rows[startRow];
+        if (currentRow) {
+          // Place cursor in the previous/first column.
+          var closestCol = Math.min(startCol, currentRow.columns.length - 1);
+          cursorCell = currentRow.columns[closestCol].element;
+        }
+        break;
+      case goog.editor.plugins.TableEditor.COMMAND.MERGE_CELLS:
+        if (cellSelection.isRectangle()) {
+          table.mergeCells(cellSelection.getFirstRowIndex(),
+                           cellSelection.getFirstColumnIndex(),
+                           cellSelection.getLastRowIndex(),
+                           cellSelection.getLastColumnIndex());
+        }
+        break;
+      case goog.editor.plugins.TableEditor.COMMAND.SPLIT_CELL:
+        if (cellSelection.containsSingleCell()) {
+          table.splitCell(cellSelection.getFirstRowIndex(),
+                          cellSelection.getFirstColumnIndex());
+        }
+        break;
+      case goog.editor.plugins.TableEditor.COMMAND.REMOVE_TABLE:
+        table.element.parentNode.removeChild(table.element);
+        break;
+      default:
+    }
+  }
+  if (cursorCell) {
+    range = goog.dom.Range.createFromNodeContents(cursorCell);
+    range.collapse(false);
+    range.select();
+  }
+  return result;
+};
+
+
+/**
+ * Checks whether the element is a table editable by the user.
+ * @param {Node} element The element in question.
+ * @return {boolean} Whether the element is a table editable by the user.
+ * @private
+ */
+goog.editor.plugins.TableEditor.prototype.isUserEditableTable_ =
+    function(element) {
+  // Default implementation.
+  if (element.tagName != goog.dom.TagName.TABLE) {
+    return false;
+  }
+
+  // Check for extra user-editable filters.
+  return goog.array.every(this.isTableEditableFunctions_, function(func) {
+    return func(/** @type {Element} */ (element));
+  });
+};
+
+
+/**
+ * Adds a function to filter out non-user-editable tables.
+ * @param {function(Element):boolean} func A function to decide whether the
+ *   table element could be editable by the user or not.
+ */
+goog.editor.plugins.TableEditor.prototype.addIsTableEditableFunction =
+    function(func) {
+  goog.array.insert(this.isTableEditableFunctions_, func);
+};
+
+
+
+/**
+ * Class representing the selected cell objects within a single  table.
+ * @param {goog.dom.AbstractRange} range Selected range from which to calculate
+ *     selected cells.
+ * @param {function(Element):Element?} getParentTableFunction A function that
+ *     finds the user-editable table from a given element.
+ * @constructor
+ * @private
+ */
+goog.editor.plugins.TableEditor.CellSelection_ =
+    function(range, getParentTableFunction) {
+  this.cells_ = [];
+
+  // Mozilla lets users select groups of cells, with each cell showing
+  // up as a separate range in the selection. goog.dom.Range doesn't
+  // currently support this.
+  // TODO(user): support this case in range.js
+  var selectionContainer = range.getContainerElement();
+  var elementInSelection = function(node) {
+    // TODO(user): revert to the more liberal containsNode(node, true),
+    // which will match partially-selected cells. We're using
+    // containsNode(node, false) at the moment because otherwise it's
+    // broken in WebKit due to a closure range bug.
+    return selectionContainer == node ||
+        selectionContainer.parentNode == node ||
+        range.containsNode(node, false);
+  };
+
+  var parentTableElement = selectionContainer &&
+      getParentTableFunction(selectionContainer);
+  if (!parentTableElement) {
+    return;
+  }
+
+  var parentTable = new goog.editor.Table(parentTableElement);
+  // It's probably not possible to select a table with no cells, but
+  // do a sanity check anyway.
+  if (!parentTable.rows.length || !parentTable.rows[0].columns.length) {
+    return;
+  }
+  // Loop through cells to calculate dimensions for this CellSelection.
+  for (var i = 0, row; row = parentTable.rows[i]; i++) {
+    for (var j = 0, cell; cell = row.columns[j]; j++) {
+      if (elementInSelection(cell.element)) {
+        // Update dimensions based on cell.
+        if (!this.cells_.length) {
+          this.firstRowIndex_ = cell.startRow;
+          this.lastRowIndex_ = cell.endRow;
+          this.firstColIndex_ = cell.startCol;
+          this.lastColIndex_ = cell.endCol;
+        } else {
+          this.firstRowIndex_ = Math.min(this.firstRowIndex_, cell.startRow);
+          this.lastRowIndex_ = Math.max(this.lastRowIndex_, cell.endRow);
+          this.firstColIndex_ = Math.min(this.firstColIndex_, cell.startCol);
+          this.lastColIndex_ = Math.max(this.lastColIndex_, cell.endCol);
+        }
+        this.cells_.push(cell);
+      }
+    }
+  }
+  this.parentTable_ = parentTable;
+};
+
+
+/**
+ * Returns the EditableTable object of which this selection's cells are a
+ * subset.
+ * @return {!goog.editor.Table} the table.
+ */
+goog.editor.plugins.TableEditor.CellSelection_.prototype.getTable =
+    function() {
+  return this.parentTable_;
+};
+
+
+/**
+ * Returns the row index of the uppermost cell in this selection.
+ * @return {number} The row index.
+ */
+goog.editor.plugins.TableEditor.CellSelection_.prototype.getFirstRowIndex =
+    function() {
+  return this.firstRowIndex_;
+};
+
+
+/**
+ * Returns the row index of the lowermost cell in this selection.
+ * @return {number} The row index.
+ */
+goog.editor.plugins.TableEditor.CellSelection_.prototype.getLastRowIndex =
+    function() {
+  return this.lastRowIndex_;
+};
+
+
+/**
+ * Returns the column index of the farthest left cell in this selection.
+ * @return {number} The column index.
+ */
+goog.editor.plugins.TableEditor.CellSelection_.prototype.getFirstColumnIndex =
+    function() {
+  return this.firstColIndex_;
+};
+
+
+/**
+ * Returns the column index of the farthest right cell in this selection.
+ * @return {number} The column index.
+ */
+goog.editor.plugins.TableEditor.CellSelection_.prototype.getLastColumnIndex =
+    function() {
+  return this.lastColIndex_;
+};
+
+
+/**
+ * Returns the cells in this selection.
+ * @return {!Array<Element>} Cells in this selection.
+ */
+goog.editor.plugins.TableEditor.CellSelection_.prototype.getCells = function() {
+  return this.cells_;
+};
+
+
+/**
+ * Returns a boolean value indicating whether or not the cells in this
+ * selection form a rectangle.
+ * @return {boolean} Whether the selection forms a rectangle.
+ */
+goog.editor.plugins.TableEditor.CellSelection_.prototype.isRectangle =
+    function() {
+  // TODO(user): check for missing cells. Right now this returns
+  // whether all cells in the selection are in the rectangle, but doesn't
+  // verify that every expected cell is present.
+  if (!this.cells_.length) {
+    return false;
+  }
+  var firstCell = this.cells_[0];
+  var lastCell = this.cells_[this.cells_.length - 1];
+  return !(this.firstRowIndex_ < firstCell.startRow ||
+           this.lastRowIndex_ > lastCell.endRow ||
+           this.firstColIndex_ < firstCell.startCol ||
+           this.lastColIndex_ > lastCell.endCol);
+};
+
+
+/**
+ * Returns a boolean value indicating whether or not there is exactly
+ * one cell in this selection. Note that this may not be the same as checking
+ * whether getCells().length == 1; if there is a single cell with
+ * rowSpan/colSpan set it will appear multiple times.
+ * @return {boolean} Whether there is exatly one cell in this selection.
+ */
+goog.editor.plugins.TableEditor.CellSelection_.prototype.containsSingleCell =
+    function() {
+  var cellCount = this.cells_.length;
+  return cellCount > 0 &&
+      (this.cells_[0] == this.cells_[cellCount - 1]);
+};


[27/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/tagname.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/tagname.js b/externs/GCL/externs/goog/dom/tagname.js
new file mode 100644
index 0000000..ad44d85
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/tagname.js
@@ -0,0 +1,160 @@
+// 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 Defines the goog.dom.TagName enum.  This enumerates
+ * all HTML tag names specified in either the the W3C HTML 4.01 index of
+ * elements or the HTML5 draft specification.
+ *
+ * References:
+ * http://www.w3.org/TR/html401/index/elements.html
+ * http://dev.w3.org/html5/spec/section-index.html
+ *
+ */
+goog.provide('goog.dom.TagName');
+
+
+/**
+ * Enum of all html tag names specified by the W3C HTML4.01 and HTML5
+ * specifications.
+ * @enum {string}
+ */
+goog.dom.TagName = {
+  A: 'A',
+  ABBR: 'ABBR',
+  ACRONYM: 'ACRONYM',
+  ADDRESS: 'ADDRESS',
+  APPLET: 'APPLET',
+  AREA: 'AREA',
+  ARTICLE: 'ARTICLE',
+  ASIDE: 'ASIDE',
+  AUDIO: 'AUDIO',
+  B: 'B',
+  BASE: 'BASE',
+  BASEFONT: 'BASEFONT',
+  BDI: 'BDI',
+  BDO: 'BDO',
+  BIG: 'BIG',
+  BLOCKQUOTE: 'BLOCKQUOTE',
+  BODY: 'BODY',
+  BR: 'BR',
+  BUTTON: 'BUTTON',
+  CANVAS: 'CANVAS',
+  CAPTION: 'CAPTION',
+  CENTER: 'CENTER',
+  CITE: 'CITE',
+  CODE: 'CODE',
+  COL: 'COL',
+  COLGROUP: 'COLGROUP',
+  COMMAND: 'COMMAND',
+  DATA: 'DATA',
+  DATALIST: 'DATALIST',
+  DD: 'DD',
+  DEL: 'DEL',
+  DETAILS: 'DETAILS',
+  DFN: 'DFN',
+  DIALOG: 'DIALOG',
+  DIR: 'DIR',
+  DIV: 'DIV',
+  DL: 'DL',
+  DT: 'DT',
+  EM: 'EM',
+  EMBED: 'EMBED',
+  FIELDSET: 'FIELDSET',
+  FIGCAPTION: 'FIGCAPTION',
+  FIGURE: 'FIGURE',
+  FONT: 'FONT',
+  FOOTER: 'FOOTER',
+  FORM: 'FORM',
+  FRAME: 'FRAME',
+  FRAMESET: 'FRAMESET',
+  H1: 'H1',
+  H2: 'H2',
+  H3: 'H3',
+  H4: 'H4',
+  H5: 'H5',
+  H6: 'H6',
+  HEAD: 'HEAD',
+  HEADER: 'HEADER',
+  HGROUP: 'HGROUP',
+  HR: 'HR',
+  HTML: 'HTML',
+  I: 'I',
+  IFRAME: 'IFRAME',
+  IMG: 'IMG',
+  INPUT: 'INPUT',
+  INS: 'INS',
+  ISINDEX: 'ISINDEX',
+  KBD: 'KBD',
+  KEYGEN: 'KEYGEN',
+  LABEL: 'LABEL',
+  LEGEND: 'LEGEND',
+  LI: 'LI',
+  LINK: 'LINK',
+  MAP: 'MAP',
+  MARK: 'MARK',
+  MATH: 'MATH',
+  MENU: 'MENU',
+  META: 'META',
+  METER: 'METER',
+  NAV: 'NAV',
+  NOFRAMES: 'NOFRAMES',
+  NOSCRIPT: 'NOSCRIPT',
+  OBJECT: 'OBJECT',
+  OL: 'OL',
+  OPTGROUP: 'OPTGROUP',
+  OPTION: 'OPTION',
+  OUTPUT: 'OUTPUT',
+  P: 'P',
+  PARAM: 'PARAM',
+  PRE: 'PRE',
+  PROGRESS: 'PROGRESS',
+  Q: 'Q',
+  RP: 'RP',
+  RT: 'RT',
+  RUBY: 'RUBY',
+  S: 'S',
+  SAMP: 'SAMP',
+  SCRIPT: 'SCRIPT',
+  SECTION: 'SECTION',
+  SELECT: 'SELECT',
+  SMALL: 'SMALL',
+  SOURCE: 'SOURCE',
+  SPAN: 'SPAN',
+  STRIKE: 'STRIKE',
+  STRONG: 'STRONG',
+  STYLE: 'STYLE',
+  SUB: 'SUB',
+  SUMMARY: 'SUMMARY',
+  SUP: 'SUP',
+  SVG: 'SVG',
+  TABLE: 'TABLE',
+  TBODY: 'TBODY',
+  TD: 'TD',
+  TEMPLATE: 'TEMPLATE',
+  TEXTAREA: 'TEXTAREA',
+  TFOOT: 'TFOOT',
+  TH: 'TH',
+  THEAD: 'THEAD',
+  TIME: 'TIME',
+  TITLE: 'TITLE',
+  TR: 'TR',
+  TRACK: 'TRACK',
+  TT: 'TT',
+  U: 'U',
+  UL: 'UL',
+  VAR: 'VAR',
+  VIDEO: 'VIDEO',
+  WBR: 'WBR'
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/tags.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/tags.js b/externs/GCL/externs/goog/dom/tags.js
new file mode 100644
index 0000000..159abe0
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/tags.js
@@ -0,0 +1,42 @@
+// Copyright 2014 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 HTML element tag names.
+ */
+goog.provide('goog.dom.tags');
+
+goog.require('goog.object');
+
+
+/**
+ * The void elements specified by
+ * http://www.w3.org/TR/html-markup/syntax.html#void-elements.
+ * @const
+ * @type {!Object}
+ * @private
+ */
+goog.dom.tags.VOID_TAGS_ = goog.object.createSet(('area,base,br,col,command,' +
+    'embed,hr,img,input,keygen,link,meta,param,source,track,wbr').split(','));
+
+
+/**
+ * Checks whether the tag is void (with no contents allowed and no legal end
+ * tag), for example 'br'.
+ * @param {string} tagName The tag name in lower case.
+ * @return {boolean}
+ */
+goog.dom.tags.isVoidTag = function(tagName) {
+  return goog.dom.tags.VOID_TAGS_[tagName] === true;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/textrange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/textrange.js b/externs/GCL/externs/goog/dom/textrange.js
new file mode 100644
index 0000000..f5cfee0
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/textrange.js
@@ -0,0 +1,615 @@
+// 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 Utilities for working with text ranges in HTML documents.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.TextRange');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.AbstractRange');
+goog.require('goog.dom.RangeType');
+goog.require('goog.dom.SavedRange');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.TextRangeIterator');
+goog.require('goog.dom.browserrange');
+goog.require('goog.string');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Create a new text selection with no properties.  Do not use this constructor:
+ * use one of the goog.dom.Range.createFrom* methods instead.
+ * @constructor
+ * @extends {goog.dom.AbstractRange}
+ * @final
+ */
+goog.dom.TextRange = function() {
+  /**
+   * The browser specific range wrapper.  This can be null if one of the other
+   * representations of the range is specified.
+   * @private {goog.dom.browserrange.AbstractRange?}
+   */
+  this.browserRangeWrapper_ = null;
+
+  /**
+   * The start node of the range.  This can be null if one of the other
+   * representations of the range is specified.
+   * @private {Node}
+   */
+  this.startNode_ = null;
+
+  /**
+   * The start offset of the range.  This can be null if one of the other
+   * representations of the range is specified.
+   * @private {?number}
+   */
+  this.startOffset_ = null;
+
+  /**
+   * The end node of the range.  This can be null if one of the other
+   * representations of the range is specified.
+   * @private {Node}
+   */
+  this.endNode_ = null;
+
+  /**
+   * The end offset of the range.  This can be null if one of the other
+   * representations of the range is specified.
+   * @private {?number}
+   */
+  this.endOffset_ = null;
+
+  /**
+   * Whether the focus node is before the anchor node.
+   * @private {boolean}
+   */
+  this.isReversed_ = false;
+};
+goog.inherits(goog.dom.TextRange, goog.dom.AbstractRange);
+
+
+/**
+ * Create a new range wrapper from the given browser range object.  Do not use
+ * this method directly - please use goog.dom.Range.createFrom* instead.
+ * @param {Range|TextRange} range The browser range object.
+ * @param {boolean=} opt_isReversed Whether the focus node is before the anchor
+ *     node.
+ * @return {!goog.dom.TextRange} A range wrapper object.
+ */
+goog.dom.TextRange.createFromBrowserRange = function(range, opt_isReversed) {
+  return goog.dom.TextRange.createFromBrowserRangeWrapper_(
+      goog.dom.browserrange.createRange(range), opt_isReversed);
+};
+
+
+/**
+ * Create a new range wrapper from the given browser range wrapper.
+ * @param {goog.dom.browserrange.AbstractRange} browserRange The browser range
+ *     wrapper.
+ * @param {boolean=} opt_isReversed Whether the focus node is before the anchor
+ *     node.
+ * @return {!goog.dom.TextRange} A range wrapper object.
+ * @private
+ */
+goog.dom.TextRange.createFromBrowserRangeWrapper_ = function(browserRange,
+    opt_isReversed) {
+  var range = new goog.dom.TextRange();
+
+  // Initialize the range as a browser range wrapper type range.
+  range.browserRangeWrapper_ = browserRange;
+  range.isReversed_ = !!opt_isReversed;
+
+  return range;
+};
+
+
+/**
+ * Create a new range wrapper that selects the given node's text.  Do not use
+ * this method directly - please use goog.dom.Range.createFrom* instead.
+ * @param {Node} node The node to select.
+ * @param {boolean=} opt_isReversed Whether the focus node is before the anchor
+ *     node.
+ * @return {!goog.dom.TextRange} A range wrapper object.
+ */
+goog.dom.TextRange.createFromNodeContents = function(node, opt_isReversed) {
+  return goog.dom.TextRange.createFromBrowserRangeWrapper_(
+      goog.dom.browserrange.createRangeFromNodeContents(node),
+      opt_isReversed);
+};
+
+
+/**
+ * Create a new range wrapper that selects the area between the given nodes,
+ * accounting for the given offsets.  Do not use this method directly - please
+ * use goog.dom.Range.createFrom* instead.
+ * @param {Node} anchorNode The node to start with.
+ * @param {number} anchorOffset The offset within the node to start.
+ * @param {Node} focusNode The node to end with.
+ * @param {number} focusOffset The offset within the node to end.
+ * @return {!goog.dom.TextRange} A range wrapper object.
+ */
+goog.dom.TextRange.createFromNodes = function(anchorNode, anchorOffset,
+    focusNode, focusOffset) {
+  var range = new goog.dom.TextRange();
+  range.isReversed_ = /** @suppress {missingRequire} */ (
+      goog.dom.Range.isReversed(anchorNode, anchorOffset,
+                                focusNode, focusOffset));
+
+  // Avoid selecting terminal elements directly
+  if (goog.dom.isElement(anchorNode) && !goog.dom.canHaveChildren(anchorNode)) {
+    var parent = anchorNode.parentNode;
+    anchorOffset = goog.array.indexOf(parent.childNodes, anchorNode);
+    anchorNode = parent;
+  }
+
+  if (goog.dom.isElement(focusNode) && !goog.dom.canHaveChildren(focusNode)) {
+    var parent = focusNode.parentNode;
+    focusOffset = goog.array.indexOf(parent.childNodes, focusNode);
+    focusNode = parent;
+  }
+
+  // Initialize the range as a W3C style range.
+  if (range.isReversed_) {
+    range.startNode_ = focusNode;
+    range.startOffset_ = focusOffset;
+    range.endNode_ = anchorNode;
+    range.endOffset_ = anchorOffset;
+  } else {
+    range.startNode_ = anchorNode;
+    range.startOffset_ = anchorOffset;
+    range.endNode_ = focusNode;
+    range.endOffset_ = focusOffset;
+  }
+
+  return range;
+};
+
+
+// Method implementations
+
+
+/**
+ * @return {!goog.dom.TextRange} A clone of this range.
+ * @override
+ */
+goog.dom.TextRange.prototype.clone = function() {
+  var range = new goog.dom.TextRange();
+  range.browserRangeWrapper_ =
+      this.browserRangeWrapper_ && this.browserRangeWrapper_.clone();
+  range.startNode_ = this.startNode_;
+  range.startOffset_ = this.startOffset_;
+  range.endNode_ = this.endNode_;
+  range.endOffset_ = this.endOffset_;
+  range.isReversed_ = this.isReversed_;
+
+  return range;
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getType = function() {
+  return goog.dom.RangeType.TEXT;
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getBrowserRangeObject = function() {
+  return this.getBrowserRangeWrapper_().getBrowserRange();
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.setBrowserRangeObject = function(nativeRange) {
+  // Test if it's a control range by seeing if a control range only method
+  // exists.
+  if (goog.dom.AbstractRange.isNativeControlRange(nativeRange)) {
+    return false;
+  }
+  this.browserRangeWrapper_ = goog.dom.browserrange.createRange(
+      nativeRange);
+  this.clearCachedValues_();
+  return true;
+};
+
+
+/**
+ * Clear all cached values.
+ * @private
+ */
+goog.dom.TextRange.prototype.clearCachedValues_ = function() {
+  this.startNode_ = this.startOffset_ = this.endNode_ = this.endOffset_ = null;
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getTextRangeCount = function() {
+  return 1;
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getTextRange = function(i) {
+  return this;
+};
+
+
+/**
+ * @return {!goog.dom.browserrange.AbstractRange} The range wrapper object.
+ * @private
+ */
+goog.dom.TextRange.prototype.getBrowserRangeWrapper_ = function() {
+  return this.browserRangeWrapper_ ||
+      (this.browserRangeWrapper_ = goog.dom.browserrange.createRangeFromNodes(
+          this.getStartNode(), this.getStartOffset(),
+          this.getEndNode(), this.getEndOffset()));
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getContainer = function() {
+  return this.getBrowserRangeWrapper_().getContainer();
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getStartNode = function() {
+  return this.startNode_ ||
+      (this.startNode_ = this.getBrowserRangeWrapper_().getStartNode());
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getStartOffset = function() {
+  return this.startOffset_ != null ? this.startOffset_ :
+      (this.startOffset_ = this.getBrowserRangeWrapper_().getStartOffset());
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getStartPosition = function() {
+  return this.isReversed() ?
+      this.getBrowserRangeWrapper_().getEndPosition() :
+      this.getBrowserRangeWrapper_().getStartPosition();
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getEndNode = function() {
+  return this.endNode_ ||
+      (this.endNode_ = this.getBrowserRangeWrapper_().getEndNode());
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getEndOffset = function() {
+  return this.endOffset_ != null ? this.endOffset_ :
+      (this.endOffset_ = this.getBrowserRangeWrapper_().getEndOffset());
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getEndPosition = function() {
+  return this.isReversed() ?
+      this.getBrowserRangeWrapper_().getStartPosition() :
+      this.getBrowserRangeWrapper_().getEndPosition();
+};
+
+
+/**
+ * Moves a TextRange to the provided nodes and offsets.
+ * @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.
+ * @param {boolean} isReversed Whether the range is reversed.
+ */
+goog.dom.TextRange.prototype.moveToNodes = function(startNode, startOffset,
+                                                    endNode, endOffset,
+                                                    isReversed) {
+  this.startNode_ = startNode;
+  this.startOffset_ = startOffset;
+  this.endNode_ = endNode;
+  this.endOffset_ = endOffset;
+  this.isReversed_ = isReversed;
+  this.browserRangeWrapper_ = null;
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.isReversed = function() {
+  return this.isReversed_;
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.containsRange = function(otherRange,
+                                                      opt_allowPartial) {
+  var otherRangeType = otherRange.getType();
+  if (otherRangeType == goog.dom.RangeType.TEXT) {
+    return this.getBrowserRangeWrapper_().containsRange(
+        otherRange.getBrowserRangeWrapper_(), opt_allowPartial);
+  } else if (otherRangeType == goog.dom.RangeType.CONTROL) {
+    var elements = otherRange.getElements();
+    var fn = opt_allowPartial ? goog.array.some : goog.array.every;
+    return fn(elements, function(el) {
+      return this.containsNode(el, opt_allowPartial);
+    }, this);
+  }
+  return false;
+};
+
+
+/**
+ * Tests if the given node is in a document.
+ * @param {Node} node The node to check.
+ * @return {boolean} Whether the given node is in the given document.
+ */
+goog.dom.TextRange.isAttachedNode = function(node) {
+  if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) {
+    var returnValue = false;
+    /** @preserveTry */
+    try {
+      returnValue = node.parentNode;
+    } catch (e) {
+      // IE sometimes throws Invalid Argument errors when a node is detached.
+      // Note: trying to return a value from the above try block can cause IE
+      // to crash.  It is necessary to use the local returnValue
+    }
+    return !!returnValue;
+  } else {
+    return goog.dom.contains(node.ownerDocument.body, node);
+  }
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.isRangeInDocument = function() {
+  // Ensure any cached nodes are in the document.  IE also allows ranges to
+  // become detached, so we check if the range is still in the document as
+  // well for IE.
+  return (!this.startNode_ ||
+          goog.dom.TextRange.isAttachedNode(this.startNode_)) &&
+         (!this.endNode_ ||
+          goog.dom.TextRange.isAttachedNode(this.endNode_)) &&
+         (!(goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) ||
+          this.getBrowserRangeWrapper_().isRangeInDocument());
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.isCollapsed = function() {
+  return this.getBrowserRangeWrapper_().isCollapsed();
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getText = function() {
+  return this.getBrowserRangeWrapper_().getText();
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getHtmlFragment = function() {
+  // TODO(robbyw): Generalize the code in browserrange so it is static and
+  // just takes an iterator.  This would mean we don't always have to create a
+  // browser range.
+  return this.getBrowserRangeWrapper_().getHtmlFragment();
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getValidHtml = function() {
+  return this.getBrowserRangeWrapper_().getValidHtml();
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.getPastableHtml = function() {
+  // TODO(robbyw): Get any attributes the table or tr has.
+
+  var html = this.getValidHtml();
+
+  if (html.match(/^\s*<td\b/i)) {
+    // Match html starting with a TD.
+    html = '<table><tbody><tr>' + html + '</tr></tbody></table>';
+  } else if (html.match(/^\s*<tr\b/i)) {
+    // Match html starting with a TR.
+    html = '<table><tbody>' + html + '</tbody></table>';
+  } else if (html.match(/^\s*<tbody\b/i)) {
+    // Match html starting with a TBODY.
+    html = '<table>' + html + '</table>';
+  } else if (html.match(/^\s*<li\b/i)) {
+    // Match html starting with an LI.
+    var container = this.getContainer();
+    var tagType = goog.dom.TagName.UL;
+    while (container) {
+      if (container.tagName == goog.dom.TagName.OL) {
+        tagType = goog.dom.TagName.OL;
+        break;
+      } else if (container.tagName == goog.dom.TagName.UL) {
+        break;
+      }
+      container = container.parentNode;
+    }
+    html = goog.string.buildString('<', tagType, '>', html, '</', tagType, '>');
+  }
+
+  return html;
+};
+
+
+/**
+ * Returns a TextRangeIterator over the contents of the range.  Regardless of
+ * the direction of the range, the iterator will move in document order.
+ * @param {boolean=} opt_keys Unused for this iterator.
+ * @return {!goog.dom.TextRangeIterator} An iterator over tags in the range.
+ * @override
+ */
+goog.dom.TextRange.prototype.__iterator__ = function(opt_keys) {
+  return new goog.dom.TextRangeIterator(this.getStartNode(),
+      this.getStartOffset(), this.getEndNode(), this.getEndOffset());
+};
+
+
+// RANGE ACTIONS
+
+
+/** @override */
+goog.dom.TextRange.prototype.select = function() {
+  this.getBrowserRangeWrapper_().select(this.isReversed_);
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.removeContents = function() {
+  this.getBrowserRangeWrapper_().removeContents();
+  this.clearCachedValues_();
+};
+
+
+/**
+ * Surrounds the text range with the specified element (on Mozilla) or with a
+ * clone of the specified element (on IE).  Returns a reference to the
+ * surrounding element if the operation was successful; returns null if the
+ * operation failed.
+ * @param {Element} element The element with which the selection is to be
+ *    surrounded.
+ * @return {Element} The surrounding element (same as the argument on Mozilla,
+ *    but not on IE), or null if unsuccessful.
+ */
+goog.dom.TextRange.prototype.surroundContents = function(element) {
+  var output = this.getBrowserRangeWrapper_().surroundContents(element);
+  this.clearCachedValues_();
+  return output;
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.insertNode = function(node, before) {
+  var output = this.getBrowserRangeWrapper_().insertNode(node, before);
+  this.clearCachedValues_();
+  return output;
+};
+
+
+/** @override */
+goog.dom.TextRange.prototype.surroundWithNodes = function(startNode, endNode) {
+  this.getBrowserRangeWrapper_().surroundWithNodes(startNode, endNode);
+  this.clearCachedValues_();
+};
+
+
+// SAVE/RESTORE
+
+
+/** @override */
+goog.dom.TextRange.prototype.saveUsingDom = function() {
+  return new goog.dom.DomSavedTextRange_(this);
+};
+
+
+// RANGE MODIFICATION
+
+
+/** @override */
+goog.dom.TextRange.prototype.collapse = function(toAnchor) {
+  var toStart = this.isReversed() ? !toAnchor : toAnchor;
+
+  if (this.browserRangeWrapper_) {
+    this.browserRangeWrapper_.collapse(toStart);
+  }
+
+  if (toStart) {
+    this.endNode_ = this.startNode_;
+    this.endOffset_ = this.startOffset_;
+  } else {
+    this.startNode_ = this.endNode_;
+    this.startOffset_ = this.endOffset_;
+  }
+
+  // Collapsed ranges can't be reversed
+  this.isReversed_ = false;
+};
+
+
+// SAVED RANGE OBJECTS
+
+
+
+/**
+ * A SavedRange implementation using DOM endpoints.
+ * @param {goog.dom.AbstractRange} range The range to save.
+ * @constructor
+ * @extends {goog.dom.SavedRange}
+ * @private
+ */
+goog.dom.DomSavedTextRange_ = function(range) {
+  goog.dom.DomSavedTextRange_.base(this, 'constructor');
+
+  /**
+   * The anchor node.
+   * @type {Node}
+   * @private
+   */
+  this.anchorNode_ = range.getAnchorNode();
+
+  /**
+   * The anchor node offset.
+   * @type {number}
+   * @private
+   */
+  this.anchorOffset_ = range.getAnchorOffset();
+
+  /**
+   * The focus node.
+   * @type {Node}
+   * @private
+   */
+  this.focusNode_ = range.getFocusNode();
+
+  /**
+   * The focus node offset.
+   * @type {number}
+   * @private
+   */
+  this.focusOffset_ = range.getFocusOffset();
+};
+goog.inherits(goog.dom.DomSavedTextRange_, goog.dom.SavedRange);
+
+
+/**
+ * @return {!goog.dom.AbstractRange} The restored range.
+ * @override
+ */
+goog.dom.DomSavedTextRange_.prototype.restoreInternal = function() {
+  return /** @suppress {missingRequire} */ (
+      goog.dom.Range.createFromNodes(this.anchorNode_, this.anchorOffset_,
+                                     this.focusNode_, this.focusOffset_));
+};
+
+
+/** @override */
+goog.dom.DomSavedTextRange_.prototype.disposeInternal = function() {
+  goog.dom.DomSavedTextRange_.superClass_.disposeInternal.call(this);
+
+  this.anchorNode_ = null;
+  this.focusNode_ = null;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/textrangeiterator.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/textrangeiterator.js b/externs/GCL/externs/goog/dom/textrangeiterator.js
new file mode 100644
index 0000000..efb5221
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/textrangeiterator.js
@@ -0,0 +1,239 @@
+// 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 Iterator between two DOM text range positions.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.TextRangeIterator');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.RangeIterator');
+goog.require('goog.dom.TagName');
+goog.require('goog.iter.StopIteration');
+
+
+
+/**
+ * Subclass of goog.dom.TagIterator that iterates over a DOM range.  It
+ * adds functions to determine the portion of each text node that is selected.
+ *
+ * @param {Node} startNode The starting node position.
+ * @param {number} startOffset The offset in to startNode.  If startNode is
+ *     an element, indicates an offset in to childNodes.  If startNode is a
+ *     text node, indicates an offset in to nodeValue.
+ * @param {Node} endNode The ending node position.
+ * @param {number} endOffset The offset in to endNode.  If endNode is
+ *     an element, indicates an offset in to childNodes.  If endNode is a
+ *     text node, indicates an offset in to nodeValue.
+ * @param {boolean=} opt_reverse Whether to traverse nodes in reverse.
+ * @constructor
+ * @extends {goog.dom.RangeIterator}
+ * @final
+ */
+goog.dom.TextRangeIterator = function(startNode, startOffset, endNode,
+    endOffset, opt_reverse) {
+  /**
+   * The first node in the selection.
+   * @private {Node}
+   */
+  this.startNode_ = null;
+
+  /**
+   * The last node in the selection.
+   * @private {Node}
+   */
+  this.endNode_ = null;
+
+  /**
+   * The offset within the first node in the selection.
+   * @private {number}
+   */
+  this.startOffset_ = 0;
+
+  /**
+   * The offset within the last node in the selection.
+   * @private {number}
+   */
+  this.endOffset_ = 0;
+
+  var goNext;
+
+  if (startNode) {
+    this.startNode_ = startNode;
+    this.startOffset_ = startOffset;
+    this.endNode_ = endNode;
+    this.endOffset_ = endOffset;
+
+    // Skip to the offset nodes - being careful to special case BRs since these
+    // have no children but still can appear as the startContainer of a range.
+    if (startNode.nodeType == goog.dom.NodeType.ELEMENT &&
+        startNode.tagName != goog.dom.TagName.BR) {
+      var startChildren = startNode.childNodes;
+      var candidate = startChildren[startOffset];
+      if (candidate) {
+        this.startNode_ = candidate;
+        this.startOffset_ = 0;
+      } else {
+        if (startChildren.length) {
+          this.startNode_ =
+              /** @type {Node} */ (goog.array.peek(startChildren));
+        }
+        goNext = true;
+      }
+    }
+
+    if (endNode.nodeType == goog.dom.NodeType.ELEMENT) {
+      this.endNode_ = endNode.childNodes[endOffset];
+      if (this.endNode_) {
+        this.endOffset_ = 0;
+      } else {
+        // The offset was past the last element.
+        this.endNode_ = endNode;
+      }
+    }
+  }
+
+  goog.dom.TextRangeIterator.base(
+      this, 'constructor', opt_reverse ? this.endNode_ : this.startNode_,
+      opt_reverse);
+
+  if (goNext) {
+    try {
+      this.next();
+    } catch (e) {
+      if (e != goog.iter.StopIteration) {
+        throw e;
+      }
+    }
+  }
+};
+goog.inherits(goog.dom.TextRangeIterator, goog.dom.RangeIterator);
+
+
+/** @override */
+goog.dom.TextRangeIterator.prototype.getStartTextOffset = function() {
+  // Offsets only apply to text nodes.  If our current node is the start node,
+  // return the saved offset.  Otherwise, return 0.
+  return this.node.nodeType != goog.dom.NodeType.TEXT ? -1 :
+         this.node == this.startNode_ ? this.startOffset_ : 0;
+};
+
+
+/** @override */
+goog.dom.TextRangeIterator.prototype.getEndTextOffset = function() {
+  // Offsets only apply to text nodes.  If our current node is the end node,
+  // return the saved offset.  Otherwise, return the length of the node.
+  return this.node.nodeType != goog.dom.NodeType.TEXT ? -1 :
+      this.node == this.endNode_ ? this.endOffset_ : this.node.nodeValue.length;
+};
+
+
+/** @override */
+goog.dom.TextRangeIterator.prototype.getStartNode = function() {
+  return this.startNode_;
+};
+
+
+/**
+ * Change the start node of the iterator.
+ * @param {Node} node The new start node.
+ */
+goog.dom.TextRangeIterator.prototype.setStartNode = function(node) {
+  if (!this.isStarted()) {
+    this.setPosition(node);
+  }
+
+  this.startNode_ = node;
+  this.startOffset_ = 0;
+};
+
+
+/** @override */
+goog.dom.TextRangeIterator.prototype.getEndNode = function() {
+  return this.endNode_;
+};
+
+
+/**
+ * Change the end node of the iterator.
+ * @param {Node} node The new end node.
+ */
+goog.dom.TextRangeIterator.prototype.setEndNode = function(node) {
+  this.endNode_ = node;
+  this.endOffset_ = 0;
+};
+
+
+/** @override */
+goog.dom.TextRangeIterator.prototype.isLast = function() {
+  return this.isStarted() && this.node == this.endNode_ &&
+      (!this.endOffset_ || !this.isStartTag());
+};
+
+
+/**
+ * Move to the next position in the selection.
+ * Throws {@code goog.iter.StopIteration} when it passes the end of the range.
+ * @return {Node} The node at the next position.
+ * @override
+ */
+goog.dom.TextRangeIterator.prototype.next = function() {
+  if (this.isLast()) {
+    throw goog.iter.StopIteration;
+  }
+
+  // Call the super function.
+  return goog.dom.TextRangeIterator.superClass_.next.call(this);
+};
+
+
+/** @override */
+goog.dom.TextRangeIterator.prototype.skipTag = function() {
+  goog.dom.TextRangeIterator.superClass_.skipTag.apply(this);
+
+  // If the node we are skipping contains the end node, we just skipped past
+  // the end, so we stop the iteration.
+  if (goog.dom.contains(this.node, this.endNode_)) {
+    throw goog.iter.StopIteration;
+  }
+};
+
+
+/** @override */
+goog.dom.TextRangeIterator.prototype.copyFrom = function(other) {
+  this.startNode_ = other.startNode_;
+  this.endNode_ = other.endNode_;
+  this.startOffset_ = other.startOffset_;
+  this.endOffset_ = other.endOffset_;
+  this.isReversed_ = other.isReversed_;
+
+  goog.dom.TextRangeIterator.superClass_.copyFrom.call(this, other);
+};
+
+
+/**
+ * @return {!goog.dom.TextRangeIterator} An identical iterator.
+ * @override
+ */
+goog.dom.TextRangeIterator.prototype.clone = function() {
+  var copy = new goog.dom.TextRangeIterator(this.startNode_,
+      this.startOffset_, this.endNode_, this.endOffset_, this.isReversed_);
+  copy.copyFrom(this);
+  return copy;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/vendor.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/vendor.js b/externs/GCL/externs/goog/dom/vendor.js
new file mode 100644
index 0000000..7c1123e
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/vendor.js
@@ -0,0 +1,96 @@
+// 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 Vendor prefix getters.
+ */
+
+goog.provide('goog.dom.vendor');
+
+goog.require('goog.string');
+goog.require('goog.userAgent');
+
+
+/**
+ * Returns the JS vendor prefix used in CSS properties. Different vendors
+ * use different methods of changing the case of the property names.
+ *
+ * @return {?string} The JS vendor prefix or null if there is none.
+ */
+goog.dom.vendor.getVendorJsPrefix = function() {
+  if (goog.userAgent.WEBKIT) {
+    return 'Webkit';
+  } else if (goog.userAgent.GECKO) {
+    return 'Moz';
+  } else if (goog.userAgent.IE) {
+    return 'ms';
+  } else if (goog.userAgent.OPERA) {
+    return 'O';
+  }
+
+  return null;
+};
+
+
+/**
+ * Returns the vendor prefix used in CSS properties.
+ *
+ * @return {?string} The vendor prefix or null if there is none.
+ */
+goog.dom.vendor.getVendorPrefix = function() {
+  if (goog.userAgent.WEBKIT) {
+    return '-webkit';
+  } else if (goog.userAgent.GECKO) {
+    return '-moz';
+  } else if (goog.userAgent.IE) {
+    return '-ms';
+  } else if (goog.userAgent.OPERA) {
+    return '-o';
+  }
+
+  return null;
+};
+
+
+/**
+ * @param {string} propertyName A property name.
+ * @param {!Object=} opt_object If provided, we verify if the property exists in
+ *     the object.
+ * @return {?string} A vendor prefixed property name, or null if it does not
+ *     exist.
+ */
+goog.dom.vendor.getPrefixedPropertyName = function(propertyName, opt_object) {
+  // We first check for a non-prefixed property, if available.
+  if (opt_object && propertyName in opt_object) {
+    return propertyName;
+  }
+  var prefix = goog.dom.vendor.getVendorJsPrefix();
+  if (prefix) {
+    prefix = prefix.toLowerCase();
+    var prefixedPropertyName = prefix + goog.string.toTitleCase(propertyName);
+    return (!goog.isDef(opt_object) || prefixedPropertyName in opt_object) ?
+        prefixedPropertyName : null;
+  }
+  return null;
+};
+
+
+/**
+ * @param {string} eventType An event type.
+ * @return {string} A lower-cased vendor prefixed event type.
+ */
+goog.dom.vendor.getPrefixedEventType = function(eventType) {
+  var prefix = goog.dom.vendor.getVendorJsPrefix() || '';
+  return (prefix + eventType).toLowerCase();
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/viewportsizemonitor.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/viewportsizemonitor.js b/externs/GCL/externs/goog/dom/viewportsizemonitor.js
new file mode 100644
index 0000000..2f5f30e
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/viewportsizemonitor.js
@@ -0,0 +1,165 @@
+// 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 Utility class that monitors viewport size changes.
+ *
+ * @author attila@google.com (Attila Bodis)
+ * @see ../demos/viewportsizemonitor.html
+ */
+
+goog.provide('goog.dom.ViewportSizeMonitor');
+
+goog.require('goog.dom');
+goog.require('goog.events');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.math.Size');
+
+
+
+/**
+ * This class can be used to monitor changes in the viewport size.  Instances
+ * dispatch a {@link goog.events.EventType.RESIZE} event when the viewport size
+ * changes.  Handlers can call {@link goog.dom.ViewportSizeMonitor#getSize} to
+ * get the new viewport size.
+ *
+ * Use this class if you want to execute resize/reflow logic each time the
+ * user resizes the browser window.  This class is guaranteed to only dispatch
+ * {@code RESIZE} events when the pixel dimensions of the viewport change.
+ * (Internet Explorer fires resize events if any element on the page is resized,
+ * even if the viewport dimensions are unchanged, which can lead to infinite
+ * resize loops.)
+ *
+ * Example usage:
+ *  <pre>
+ *    var vsm = new goog.dom.ViewportSizeMonitor();
+ *    goog.events.listen(vsm, goog.events.EventType.RESIZE, function(e) {
+ *      alert('Viewport size changed to ' + vsm.getSize());
+ *    });
+ *  </pre>
+ *
+ * Manually verified on IE6, IE7, FF2, Opera 11, Safari 4 and Chrome.
+ *
+ * @param {Window=} opt_window The window to monitor; defaults to the window in
+ *    which this code is executing.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.dom.ViewportSizeMonitor = function(opt_window) {
+  goog.dom.ViewportSizeMonitor.base(this, 'constructor');
+
+  /**
+   * The window to monitor. Defaults to the window in which the code is running.
+   * @private {Window}
+   */
+  this.window_ = opt_window || window;
+
+  /**
+   * Event listener key for window the window resize handler, as returned by
+   * {@link goog.events.listen}.
+   * @private {goog.events.Key}
+   */
+  this.listenerKey_ = goog.events.listen(this.window_,
+      goog.events.EventType.RESIZE, this.handleResize_, false, this);
+
+  /**
+   * The most recently recorded size of the viewport, in pixels.
+   * @private {goog.math.Size}
+   */
+  this.size_ = goog.dom.getViewportSize(this.window_);
+};
+goog.inherits(goog.dom.ViewportSizeMonitor, goog.events.EventTarget);
+
+
+/**
+ * Returns a viewport size monitor for the given window.  A new one is created
+ * if it doesn't exist already.  This prevents the unnecessary creation of
+ * multiple spooling monitors for a window.
+ * @param {Window=} opt_window The window to monitor; defaults to the window in
+ *     which this code is executing.
+ * @return {!goog.dom.ViewportSizeMonitor} Monitor for the given window.
+ */
+goog.dom.ViewportSizeMonitor.getInstanceForWindow = function(opt_window) {
+  var currentWindow = opt_window || window;
+  var uid = goog.getUid(currentWindow);
+
+  return goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid] =
+      goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid] ||
+      new goog.dom.ViewportSizeMonitor(currentWindow);
+};
+
+
+/**
+ * Removes and disposes a viewport size monitor for the given window if one
+ * exists.
+ * @param {Window=} opt_window The window whose monitor should be removed;
+ *     defaults to the window in which this code is executing.
+ */
+goog.dom.ViewportSizeMonitor.removeInstanceForWindow = function(opt_window) {
+  var uid = goog.getUid(opt_window || window);
+
+  goog.dispose(goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid]);
+  delete goog.dom.ViewportSizeMonitor.windowInstanceMap_[uid];
+};
+
+
+/**
+ * Map of window hash code to viewport size monitor for that window, if
+ * created.
+ * @type {Object<number,goog.dom.ViewportSizeMonitor>}
+ * @private
+ */
+goog.dom.ViewportSizeMonitor.windowInstanceMap_ = {};
+
+
+/**
+ * Returns the most recently recorded size of the viewport, in pixels.  May
+ * return null if no window resize event has been handled yet.
+ * @return {goog.math.Size} The viewport dimensions, in pixels.
+ */
+goog.dom.ViewportSizeMonitor.prototype.getSize = function() {
+  // Return a clone instead of the original to preserve encapsulation.
+  return this.size_ ? this.size_.clone() : null;
+};
+
+
+/** @override */
+goog.dom.ViewportSizeMonitor.prototype.disposeInternal = function() {
+  goog.dom.ViewportSizeMonitor.superClass_.disposeInternal.call(this);
+
+  if (this.listenerKey_) {
+    goog.events.unlistenByKey(this.listenerKey_);
+    this.listenerKey_ = null;
+  }
+
+  this.window_ = null;
+  this.size_ = null;
+};
+
+
+/**
+ * Handles window resize events by measuring the dimensions of the
+ * viewport and dispatching a {@link goog.events.EventType.RESIZE} event if the
+ * current dimensions are different from the previous ones.
+ * @param {goog.events.Event} event The window resize event to handle.
+ * @private
+ */
+goog.dom.ViewportSizeMonitor.prototype.handleResize_ = function(event) {
+  var size = goog.dom.getViewportSize(this.window_);
+  if (!goog.math.Size.equals(size, this.size_)) {
+    this.size_ = size;
+    this.dispatchEvent(goog.events.EventType.RESIZE);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/xml.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/xml.js b/externs/GCL/externs/goog/dom/xml.js
new file mode 100644
index 0000000..59f123a
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/xml.js
@@ -0,0 +1,204 @@
+// 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
+ * XML utilities.
+ *
+ */
+
+goog.provide('goog.dom.xml');
+
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+
+
+/**
+ * Max XML size for MSXML2.  Used to prevent potential DoS attacks.
+ * @type {number}
+ */
+goog.dom.xml.MAX_XML_SIZE_KB = 2 * 1024;  // In kB
+
+
+/**
+ * Max XML size for MSXML2.  Used to prevent potential DoS attacks.
+ * @type {number}
+ */
+goog.dom.xml.MAX_ELEMENT_DEPTH = 256; // Same default as MSXML6.
+
+
+/**
+ * Creates an XML document appropriate for the current JS runtime
+ * @param {string=} opt_rootTagName The root tag name.
+ * @param {string=} opt_namespaceUri Namespace URI of the document element.
+ * @return {Document} The new document.
+ */
+goog.dom.xml.createDocument = function(opt_rootTagName, opt_namespaceUri) {
+  if (opt_namespaceUri && !opt_rootTagName) {
+    throw Error("Can't create document with namespace and no root tag");
+  }
+  if (document.implementation && document.implementation.createDocument) {
+    return document.implementation.createDocument(opt_namespaceUri || '',
+                                                  opt_rootTagName || '',
+                                                  null);
+  } else if (typeof ActiveXObject != 'undefined') {
+    var doc = goog.dom.xml.createMsXmlDocument_();
+    if (doc) {
+      if (opt_rootTagName) {
+        doc.appendChild(doc.createNode(goog.dom.NodeType.ELEMENT,
+                                       opt_rootTagName,
+                                       opt_namespaceUri || ''));
+      }
+      return doc;
+    }
+  }
+  throw Error('Your browser does not support creating new documents');
+};
+
+
+/**
+ * Creates an XML document from a string
+ * @param {string} xml The text.
+ * @return {Document} XML document from the text.
+ */
+goog.dom.xml.loadXml = function(xml) {
+  if (typeof DOMParser != 'undefined') {
+    return new DOMParser().parseFromString(xml, 'application/xml');
+  } else if (typeof ActiveXObject != 'undefined') {
+    var doc = goog.dom.xml.createMsXmlDocument_();
+    doc.loadXML(xml);
+    return doc;
+  }
+  throw Error('Your browser does not support loading xml documents');
+};
+
+
+/**
+ * Serializes an XML document or subtree to string.
+ * @param {Document|Element} xml The document or the root node of the subtree.
+ * @return {string} The serialized XML.
+ */
+goog.dom.xml.serialize = function(xml) {
+  // Compatible with Firefox, Opera and WebKit.
+  if (typeof XMLSerializer != 'undefined') {
+    return new XMLSerializer().serializeToString(xml);
+  }
+  // Compatible with Internet Explorer.
+  var text = xml.xml;
+  if (text) {
+    return text;
+  }
+  throw Error('Your browser does not support serializing XML documents');
+};
+
+
+/**
+ * Selects a single node using an Xpath expression and a root node
+ * @param {Node} node The root node.
+ * @param {string} path Xpath selector.
+ * @return {Node} The selected node, or null if no matching node.
+ */
+goog.dom.xml.selectSingleNode = function(node, path) {
+  if (typeof node.selectSingleNode != 'undefined') {
+    var doc = goog.dom.getOwnerDocument(node);
+    if (typeof doc.setProperty != 'undefined') {
+      doc.setProperty('SelectionLanguage', 'XPath');
+    }
+    return node.selectSingleNode(path);
+  } else if (document.implementation.hasFeature('XPath', '3.0')) {
+    var doc = goog.dom.getOwnerDocument(node);
+    var resolver = doc.createNSResolver(doc.documentElement);
+    var result = doc.evaluate(path, node, resolver,
+        XPathResult.FIRST_ORDERED_NODE_TYPE, null);
+    return result.singleNodeValue;
+  }
+  return null;
+};
+
+
+/**
+ * Selects multiple nodes using an Xpath expression and a root node
+ * @param {Node} node The root node.
+ * @param {string} path Xpath selector.
+ * @return {(NodeList|Array<Node>)} The selected nodes, or empty array if no
+ *     matching nodes.
+ */
+goog.dom.xml.selectNodes = function(node, path) {
+  if (typeof node.selectNodes != 'undefined') {
+    var doc = goog.dom.getOwnerDocument(node);
+    if (typeof doc.setProperty != 'undefined') {
+      doc.setProperty('SelectionLanguage', 'XPath');
+    }
+    return node.selectNodes(path);
+  } else if (document.implementation.hasFeature('XPath', '3.0')) {
+    var doc = goog.dom.getOwnerDocument(node);
+    var resolver = doc.createNSResolver(doc.documentElement);
+    var nodes = doc.evaluate(path, node, resolver,
+        XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+    var results = [];
+    var count = nodes.snapshotLength;
+    for (var i = 0; i < count; i++) {
+      results.push(nodes.snapshotItem(i));
+    }
+    return results;
+  } else {
+    return [];
+  }
+};
+
+
+/**
+ * Sets multiple attributes on an element. Differs from goog.dom.setProperties
+ * in that it exclusively uses the element's setAttributes method. Use this
+ * when you need to ensure that the exact property is available as an attribute
+ * and can be read later by the native getAttribute method.
+ * @param {!Element} element XML or DOM element to set attributes on.
+ * @param {!Object<string, string>} attributes Map of property:value pairs.
+ */
+goog.dom.xml.setAttributes = function(element, attributes) {
+  for (var key in attributes) {
+    if (attributes.hasOwnProperty(key)) {
+      element.setAttribute(key, attributes[key]);
+    }
+  }
+};
+
+
+/**
+ * Creates an instance of the MSXML2.DOMDocument.
+ * @return {Document} The new document.
+ * @private
+ */
+goog.dom.xml.createMsXmlDocument_ = function() {
+  var doc = new ActiveXObject('MSXML2.DOMDocument');
+  if (doc) {
+    // Prevent potential vulnerabilities exposed by MSXML2, see
+    // http://b/1707300 and http://wiki/Main/ISETeamXMLAttacks for details.
+    doc.resolveExternals = false;
+    doc.validateOnParse = false;
+    // Add a try catch block because accessing these properties will throw an
+    // error on unsupported MSXML versions. This affects Windows machines
+    // running IE6 or IE7 that are on XP SP2 or earlier without MSXML updates.
+    // See http://msdn.microsoft.com/en-us/library/ms766391(VS.85).aspx for
+    // specific details on which MSXML versions support these properties.
+    try {
+      doc.setProperty('ProhibitDTD', true);
+      doc.setProperty('MaxXMLSize', goog.dom.xml.MAX_XML_SIZE_KB);
+      doc.setProperty('MaxElementDepth', goog.dom.xml.MAX_ELEMENT_DEPTH);
+    } catch (e) {
+      // No-op.
+    }
+  }
+  return doc;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/browserfeature2.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/browserfeature2.js b/externs/GCL/externs/goog/editor/browserfeature2.js
new file mode 100644
index 0000000..10ac05e
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/browserfeature2.js
@@ -0,0 +1,273 @@
+// Copyright 2005 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 Trogedit constants for browser features and quirks that should
+ * be used by the rich text editor.
+ */
+
+goog.provide('goog.editor.BrowserFeature');
+
+goog.require('goog.editor.defines');
+goog.require('goog.userAgent');
+goog.require('goog.userAgent.product');
+goog.require('goog.userAgent.product.isVersion');
+
+
+/**
+ * Maps browser quirks to boolean values, detailing what the current
+ * browser supports.
+ * @const
+ */
+goog.editor.BrowserFeature = {
+  // Whether this browser uses the IE TextRange object.
+  HAS_IE_RANGES: goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9),
+
+  // Whether this browser uses the W3C standard Range object.
+  // Assumes IE higher versions will be compliance with W3C standard.
+  HAS_W3C_RANGES: goog.userAgent.GECKO || goog.userAgent.WEBKIT ||
+      goog.userAgent.OPERA ||
+      (goog.userAgent.IE && goog.userAgent.isDocumentModeOrHigher(9)),
+
+  // Has the contentEditable attribute, which makes nodes editable.
+  //
+  // NOTE(nicksantos): FF3 has contentEditable, but there are 3 major reasons
+  // why we don't use it:
+  // 1) In FF3, we listen for key events on the document, and we'd have to
+  //    filter them properly. See TR_Browser.USE_DOCUMENT_FOR_KEY_EVENTS.
+  // 2) In FF3, we listen for focus/blur events on the document, which
+  //    simply doesn't make sense in contentEditable. focus/blur
+  //    on contentEditable elements still has some quirks, which we're
+  //    talking to Firefox-team about.
+  // 3) We currently use Mutation events in FF3 to detect changes,
+  //    and these are dispatched on the document only.
+  // If we ever hope to support FF3/contentEditable, all 3 of these issues
+  // will need answers. Most just involve refactoring at our end.
+  HAS_CONTENT_EDITABLE: goog.userAgent.IE || goog.userAgent.WEBKIT ||
+      goog.userAgent.OPERA ||
+      (goog.editor.defines.USE_CONTENTEDITABLE_IN_FIREFOX_3 &&
+       goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9')),
+
+  // Whether to use mutation event types to detect changes
+  // in the field contents.
+  USE_MUTATION_EVENTS: goog.userAgent.GECKO,
+
+  // Whether the browser has a functional DOMSubtreeModified event.
+  // TODO(user): Enable for all FF3 once we're confident this event fires
+  // reliably. Currently it's only enabled if using contentEditable in FF as
+  // we have no other choice in that case but to use this event.
+  HAS_DOM_SUBTREE_MODIFIED_EVENT: goog.userAgent.WEBKIT ||
+      (goog.editor.defines.USE_CONTENTEDITABLE_IN_FIREFOX_3 &&
+       goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9')),
+
+  // Whether nodes can be copied from one document to another
+  HAS_DOCUMENT_INDEPENDENT_NODES: goog.userAgent.GECKO,
+
+  // Whether the cursor goes before or inside the first block element on
+  // focus, e.g., <body><p>foo</p></body>. FF will put the cursor before the
+  // paragraph on focus, which is wrong.
+  PUTS_CURSOR_BEFORE_FIRST_BLOCK_ELEMENT_ON_FOCUS: goog.userAgent.GECKO,
+
+  // Whether the selection of one frame is cleared when another frame
+  // is focused.
+  CLEARS_SELECTION_WHEN_FOCUS_LEAVES:
+      goog.userAgent.IE || goog.userAgent.WEBKIT || goog.userAgent.OPERA,
+
+  // Whether "unselectable" is supported as an element style.
+  HAS_UNSELECTABLE_STYLE: goog.userAgent.GECKO || goog.userAgent.WEBKIT,
+
+  // Whether this browser's "FormatBlock" command does not suck.
+  FORMAT_BLOCK_WORKS_FOR_BLOCKQUOTES: goog.userAgent.GECKO ||
+      goog.userAgent.WEBKIT || goog.userAgent.OPERA,
+
+  // Whether this browser's "FormatBlock" command may create multiple
+  // blockquotes.
+  CREATES_MULTIPLE_BLOCKQUOTES:
+      (goog.userAgent.WEBKIT &&
+       !goog.userAgent.isVersionOrHigher('534.16')) ||
+      goog.userAgent.OPERA,
+
+  // Whether this browser's "FormatBlock" command will wrap blockquotes
+  // inside of divs, instead of replacing divs with blockquotes.
+  WRAPS_BLOCKQUOTE_IN_DIVS: goog.userAgent.OPERA,
+
+  // Whether the readystatechange event is more reliable than load.
+  PREFERS_READY_STATE_CHANGE_EVENT: goog.userAgent.IE,
+
+  // Whether hitting the tab key will fire a keypress event.
+  // see http://www.quirksmode.org/js/keys.html
+  TAB_FIRES_KEYPRESS: !goog.userAgent.IE,
+
+  // Has a standards mode quirk where width=100% doesn't do the right thing,
+  // but width=99% does.
+  // TODO(user|user): This should be fixable by less hacky means
+  NEEDS_99_WIDTH_IN_STANDARDS_MODE: goog.userAgent.IE,
+
+  // Whether keyboard events only reliably fire on the document.
+  // On Gecko without contentEditable, keyboard events only fire reliably on the
+  // document element. With contentEditable, the field itself is focusable,
+  // which means that it will fire key events. This does not apply if
+  // application is using ContentEditableField or otherwise overriding Field
+  // not to use an iframe.
+  USE_DOCUMENT_FOR_KEY_EVENTS: goog.userAgent.GECKO &&
+      !goog.editor.defines.USE_CONTENTEDITABLE_IN_FIREFOX_3,
+
+  // Whether this browser shows non-standard attributes in innerHTML.
+  SHOWS_CUSTOM_ATTRS_IN_INNER_HTML: goog.userAgent.IE,
+
+  // Whether this browser shrinks empty nodes away to nothing.
+  // (If so, we need to insert some space characters into nodes that
+  //  shouldn't be collapsed)
+  COLLAPSES_EMPTY_NODES:
+      goog.userAgent.GECKO || goog.userAgent.WEBKIT || goog.userAgent.OPERA,
+
+  // Whether we must convert <strong> and <em> tags to <b>, <i>.
+  CONVERT_TO_B_AND_I_TAGS: goog.userAgent.GECKO || goog.userAgent.OPERA,
+
+  // Whether this browser likes to tab through images in contentEditable mode,
+  // and we like to disable this feature.
+  TABS_THROUGH_IMAGES: goog.userAgent.IE,
+
+  // Whether this browser unescapes urls when you extract it from the href tag.
+  UNESCAPES_URLS_WITHOUT_ASKING: goog.userAgent.IE &&
+      !goog.userAgent.isVersionOrHigher('7.0'),
+
+  // Whether this browser supports execCommand("styleWithCSS") to toggle between
+  // inserting html tags or inline styling for things like bold, italic, etc.
+  HAS_STYLE_WITH_CSS:
+      goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.8') ||
+      goog.userAgent.WEBKIT || goog.userAgent.OPERA,
+
+  // Whether clicking on an editable link will take you to that site.
+  FOLLOWS_EDITABLE_LINKS: goog.userAgent.WEBKIT ||
+      goog.userAgent.IE && goog.userAgent.isVersionOrHigher('9'),
+
+  // Whether this browser has document.activeElement available.
+  HAS_ACTIVE_ELEMENT:
+      goog.userAgent.IE || goog.userAgent.OPERA ||
+      goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9'),
+
+  // Whether this browser supports the setCapture method on DOM elements.
+  HAS_SET_CAPTURE: goog.userAgent.IE,
+
+  // Whether this browser can't set background color when the selection
+  // is collapsed.
+  EATS_EMPTY_BACKGROUND_COLOR: goog.userAgent.GECKO ||
+      goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('527'),
+
+  // Whether this browser supports the "focusin" or "DOMFocusIn" event
+  // consistently.
+  // NOTE(nicksantos): FF supports DOMFocusIn, but doesn't seem to do so
+  // consistently.
+  SUPPORTS_FOCUSIN: goog.userAgent.IE || goog.userAgent.OPERA,
+
+  // Whether clicking on an image will cause the selection to move to the image.
+  // Note: Gecko moves the selection, but it won't always go to the image.
+  // For example, if the image is wrapped in a div, and you click on the img,
+  // anchorNode = focusNode = div, anchorOffset = 0, focusOffset = 1, so this
+  // is another way of "selecting" the image, but there are too many special
+  // cases like this so we will do the work manually.
+  SELECTS_IMAGES_ON_CLICK: goog.userAgent.IE || goog.userAgent.OPERA,
+
+  // Whether this browser moves <style> tags into new <head> elements.
+  MOVES_STYLE_TO_HEAD: goog.userAgent.WEBKIT,
+
+  // Whether this browser collapses the selection in a contenteditable when the
+  // mouse is pressed in a non-editable portion of the same frame, even if
+  // Event.preventDefault is called. This field is deprecated and unused -- only
+  // old versions of Opera have this bug.
+  COLLAPSES_SELECTION_ONMOUSEDOWN: false,
+
+  // Whether the user can actually create a selection in this browser with the
+  // caret in the MIDDLE of the selection by double-clicking.
+  CARET_INSIDE_SELECTION: goog.userAgent.OPERA,
+
+  // Whether the browser focuses <body contenteditable> automatically when
+  // the user clicks on <html>. This field is deprecated and unused -- only old
+  // versions of Opera don't have this behavior.
+  FOCUSES_EDITABLE_BODY_ON_HTML_CLICK: true,
+
+  // Whether to use keydown for key listening (uses keypress otherwise). Taken
+  // from goog.events.KeyHandler.
+  USES_KEYDOWN: goog.userAgent.IE ||
+      goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('525'),
+
+  // Whether this browser converts spaces to non-breaking spaces when calling
+  // execCommand's RemoveFormat.
+  // See: https://bugs.webkit.org/show_bug.cgi?id=14062
+  ADDS_NBSPS_IN_REMOVE_FORMAT:
+      goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('531'),
+
+  // Whether the browser will get stuck inside a link.  That is, if your cursor
+  // is after a link and you type, does your text go inside the link tag.
+  // Bug: http://bugs.webkit.org/show_bug.cgi?id=17697
+  GETS_STUCK_IN_LINKS:
+      goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('528'),
+
+  // Whether the browser corrupts empty text nodes in Node#normalize,
+  // removing them from the Document instead of merging them.
+  NORMALIZE_CORRUPTS_EMPTY_TEXT_NODES: goog.userAgent.GECKO &&
+      goog.userAgent.isVersionOrHigher('1.9') || goog.userAgent.IE ||
+      goog.userAgent.OPERA ||
+      goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('531'),
+
+  // Whether the browser corrupts all text nodes in Node#normalize,
+  // removing them from the Document instead of merging them.
+  NORMALIZE_CORRUPTS_ALL_TEXT_NODES: goog.userAgent.IE,
+
+  // Browsers where executing subscript then superscript (or vv) will cause both
+  // to be applied in a nested fashion instead of the first being overwritten by
+  // the second.
+  NESTS_SUBSCRIPT_SUPERSCRIPT: goog.userAgent.IE || goog.userAgent.GECKO ||
+      goog.userAgent.OPERA,
+
+  // Whether this browser can place a cursor in an empty element natively.
+  CAN_SELECT_EMPTY_ELEMENT: !goog.userAgent.IE && !goog.userAgent.WEBKIT,
+
+  FORGETS_FORMATTING_WHEN_LISTIFYING: goog.userAgent.GECKO ||
+      goog.userAgent.WEBKIT && !goog.userAgent.isVersionOrHigher('526'),
+
+  LEAVES_P_WHEN_REMOVING_LISTS: goog.userAgent.IE || goog.userAgent.OPERA,
+
+  CAN_LISTIFY_BR: !goog.userAgent.IE && !goog.userAgent.OPERA,
+
+  // See bug 1286408. When somewhere inside your selection there is an element
+  // with a style attribute that sets the font size, if you change the font
+  // size, the browser creates a font tag, but the font size in the style attr
+  // overrides the font tag. Only webkit removes that font size from the style
+  // attr.
+  DOESNT_OVERRIDE_FONT_SIZE_IN_STYLE_ATTR: !goog.userAgent.WEBKIT,
+
+  // Implements this spec about dragging files from the filesystem to the
+  // browser: http://www.whatwg/org/specs/web-apps/current-work/#dnd
+  SUPPORTS_HTML5_FILE_DRAGGING: (goog.userAgent.product.CHROME &&
+                                 goog.userAgent.product.isVersion('4')) ||
+      (goog.userAgent.product.SAFARI &&
+       goog.userAgent.isVersionOrHigher('533')) ||
+      (goog.userAgent.GECKO &&
+       goog.userAgent.isVersionOrHigher('2.0')) ||
+      (goog.userAgent.IE &&
+       goog.userAgent.isVersionOrHigher('10')),
+
+  // Version of Opera that supports the opera-defaultBlock execCommand to change
+  // the default block inserted when [return] is pressed. Note that this only is
+  // used if the caret is not already in a block that can be repeated.
+  // TODO(user): Link to public documentation of this feature if Opera puts
+  // something up about it.
+  SUPPORTS_OPERA_DEFAULTBLOCK_COMMAND:
+      goog.userAgent.OPERA && goog.userAgent.isVersionOrHigher('11.10'),
+
+  SUPPORTS_FILE_PASTING: goog.userAgent.product.CHROME &&
+      goog.userAgent.product.isVersion('12')
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/clicktoeditwrapper.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/clicktoeditwrapper.js b/externs/GCL/externs/goog/editor/clicktoeditwrapper.js
new file mode 100644
index 0000000..1623f0d
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/clicktoeditwrapper.js
@@ -0,0 +1,423 @@
+// 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 A wrapper around a goog.editor.Field
+ * that listens to mouse events on the specified un-editable field, and makes
+ * the field editable if the user clicks on it. Clients are still responsible
+ * for determining when to make the field un-editable again.
+ *
+ * Clients can still determine when the field has loaded by listening to
+ * field's load event.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.editor.ClickToEditWrapper');
+
+goog.require('goog.Disposable');
+goog.require('goog.dom');
+goog.require('goog.dom.Range');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.BrowserFeature');
+goog.require('goog.editor.Command');
+goog.require('goog.editor.Field');
+goog.require('goog.editor.range');
+goog.require('goog.events.BrowserEvent');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventType');
+
+
+
+/**
+ * Initialize the wrapper, and begin listening to mouse events immediately.
+ * @param {goog.editor.Field} fieldObj The editable field being wrapped.
+ * @constructor
+ * @extends {goog.Disposable}
+ */
+goog.editor.ClickToEditWrapper = function(fieldObj) {
+  goog.Disposable.call(this);
+
+  /**
+   * The field this wrapper interacts with.
+   * @type {goog.editor.Field}
+   * @private
+   */
+  this.fieldObj_ = fieldObj;
+
+  /**
+   * DOM helper for the field's original element.
+   * @type {goog.dom.DomHelper}
+   * @private
+   */
+  this.originalDomHelper_ = goog.dom.getDomHelper(
+      fieldObj.getOriginalElement());
+
+  /**
+   * @type {goog.dom.SavedCaretRange}
+   * @private
+   */
+  this.savedCaretRange_ = null;
+
+  /**
+   * Event handler for field related events.
+   * @type {!goog.events.EventHandler<!goog.editor.ClickToEditWrapper>}
+   * @private
+   */
+  this.fieldEventHandler_ = new goog.events.EventHandler(this);
+
+  /**
+   * Bound version of the finishMouseUp method.
+   * @type {Function}
+   * @private
+   */
+  this.finishMouseUpBound_ = goog.bind(this.finishMouseUp_, this);
+
+  /**
+   * Event handler for mouse events.
+   * @type {!goog.events.EventHandler<!goog.editor.ClickToEditWrapper>}
+   * @private
+   */
+  this.mouseEventHandler_ = new goog.events.EventHandler(this);
+
+  // Start listening to mouse events immediately if necessary.
+  if (!this.fieldObj_.isLoaded()) {
+    this.enterDocument();
+  }
+
+  this.fieldEventHandler_.
+      // Whenever the field is made editable, we need to check if there
+      // are any carets in it, and if so, use them to render the selection.
+      listen(
+          this.fieldObj_, goog.editor.Field.EventType.LOAD,
+          this.renderSelection_).
+      // Whenever the field is made uneditable, we need to set up
+      // the click-to-edit listeners.
+      listen(
+          this.fieldObj_, goog.editor.Field.EventType.UNLOAD,
+          this.enterDocument);
+};
+goog.inherits(goog.editor.ClickToEditWrapper, goog.Disposable);
+
+
+
+/** @return {goog.editor.Field} The field. */
+goog.editor.ClickToEditWrapper.prototype.getFieldObject = function() {
+  return this.fieldObj_;
+};
+
+
+/** @return {goog.dom.DomHelper} The dom helper of the uneditable element. */
+goog.editor.ClickToEditWrapper.prototype.getOriginalDomHelper = function() {
+  return this.originalDomHelper_;
+};
+
+
+/** @override */
+goog.editor.ClickToEditWrapper.prototype.disposeInternal = function() {
+  goog.editor.ClickToEditWrapper.base(this, 'disposeInternal');
+  this.exitDocument();
+
+  if (this.savedCaretRange_) {
+    this.savedCaretRange_.dispose();
+  }
+
+  this.fieldEventHandler_.dispose();
+  this.mouseEventHandler_.dispose();
+  this.savedCaretRange_ = null;
+  delete this.fieldEventHandler_;
+  delete this.mouseEventHandler_;
+};
+
+
+/**
+ * Initialize listeners when the uneditable field is added to the document.
+ * Also sets up lorem ipsum text.
+ */
+goog.editor.ClickToEditWrapper.prototype.enterDocument = function() {
+  if (this.isInDocument_) {
+    return;
+  }
+
+  this.isInDocument_ = true;
+
+  this.mouseEventTriggeredLoad_ = false;
+  var field = this.fieldObj_.getOriginalElement();
+
+  // To do artificial selection preservation, we have to listen to mouseup,
+  // get the current selection, and re-select the same text in the iframe.
+  //
+  // NOTE(nicksantos): Artificial selection preservation is needed in all cases
+  // where we set the field contents by setting innerHTML. There are a few
+  // rare cases where we don't need it. But these cases are highly
+  // implementation-specific, and computationally hard to detect (bidi
+  // and ig modules both set innerHTML), so we just do it in all cases.
+  this.savedAnchorClicked_ = null;
+  this.mouseEventHandler_.
+      listen(field, goog.events.EventType.MOUSEUP, this.handleMouseUp_).
+      listen(field, goog.events.EventType.CLICK, this.handleClick_);
+
+  // manage lorem ipsum text, if necessary
+  this.fieldObj_.execCommand(goog.editor.Command.UPDATE_LOREM);
+};
+
+
+/**
+ * Destroy listeners when the field is removed from the document.
+ */
+goog.editor.ClickToEditWrapper.prototype.exitDocument = function() {
+  this.mouseEventHandler_.removeAll();
+  this.isInDocument_ = false;
+};
+
+
+/**
+ * Returns the uneditable field element if the field is not yet editable
+ * (equivalent to EditableField.getOriginalElement()), and the editable DOM
+ * element if the field is currently editable (equivalent to
+ * EditableField.getElement()).
+ * @return {Element} The element containing the editable field contents.
+ */
+goog.editor.ClickToEditWrapper.prototype.getElement = function() {
+  return this.fieldObj_.isLoaded() ?
+      this.fieldObj_.getElement() : this.fieldObj_.getOriginalElement();
+};
+
+
+/**
+ * True if a mouse event should be handled, false if it should be ignored.
+ * @param {goog.events.BrowserEvent} e The mouse event.
+ * @return {boolean} Wether or not this mouse event should be handled.
+ * @private
+ */
+goog.editor.ClickToEditWrapper.prototype.shouldHandleMouseEvent_ = function(e) {
+  return e.isButton(goog.events.BrowserEvent.MouseButton.LEFT) &&
+      !(e.shiftKey || e.ctrlKey || e.altKey || e.metaKey);
+};
+
+
+/**
+ * Handle mouse click events on the field.
+ * @param {goog.events.BrowserEvent} e The click event.
+ * @private
+ */
+goog.editor.ClickToEditWrapper.prototype.handleClick_ = function(e) {
+  // If the user clicked on a link in an uneditable field,
+  // we want to cancel the click.
+  var anchorAncestor = goog.dom.getAncestorByTagNameAndClass(
+      /** @type {Node} */ (e.target),
+      goog.dom.TagName.A);
+  if (anchorAncestor) {
+    e.preventDefault();
+
+    if (!goog.editor.BrowserFeature.HAS_ACTIVE_ELEMENT) {
+      this.savedAnchorClicked_ = anchorAncestor;
+    }
+  }
+};
+
+
+/**
+ * Handle a mouse up event on the field.
+ * @param {goog.events.BrowserEvent} e The mouseup event.
+ * @private
+ */
+goog.editor.ClickToEditWrapper.prototype.handleMouseUp_ = function(e) {
+  // Only respond to the left mouse button.
+  if (this.shouldHandleMouseEvent_(e)) {
+    // We need to get the selection when the user mouses up, but the
+    // selection doesn't actually change until after the mouseup event has
+    // propagated. So we need to do this asynchronously.
+    this.originalDomHelper_.getWindow().setTimeout(this.finishMouseUpBound_, 0);
+  }
+};
+
+
+/**
+ * A helper function for handleMouseUp_ -- does the actual work
+ * when the event is finished propagating.
+ * @private
+ */
+goog.editor.ClickToEditWrapper.prototype.finishMouseUp_ = function() {
+  // Make sure that the field is still not editable.
+  if (!this.fieldObj_.isLoaded()) {
+    if (this.savedCaretRange_) {
+      this.savedCaretRange_.dispose();
+      this.savedCaretRange_ = null;
+    }
+
+    if (!this.fieldObj_.queryCommandValue(goog.editor.Command.USING_LOREM)) {
+      // We need carets (blank span nodes) to maintain the selection when
+      // the html is copied into an iframe. However, because our code
+      // clears the selection to make the behavior consistent, we need to do
+      // this even when we're not using an iframe.
+      this.insertCarets_();
+    }
+
+    this.ensureFieldEditable_();
+  }
+
+  this.exitDocument();
+  this.savedAnchorClicked_ = null;
+};
+
+
+/**
+ * Ensure that the field is editable. If the field is not editable,
+ * make it so, and record the fact that it was done by a user mouse event.
+ * @private
+ */
+goog.editor.ClickToEditWrapper.prototype.ensureFieldEditable_ = function() {
+  if (!this.fieldObj_.isLoaded()) {
+    this.mouseEventTriggeredLoad_ = true;
+    this.makeFieldEditable(this.fieldObj_);
+  }
+};
+
+
+/**
+ * Once the field has loaded in an iframe, re-create the selection
+ * as marked by the carets.
+ * @private
+ */
+goog.editor.ClickToEditWrapper.prototype.renderSelection_ = function() {
+  if (this.savedCaretRange_) {
+    // Make sure that the restoration document is inside the iframe
+    // if we're using one.
+    this.savedCaretRange_.setRestorationDocument(
+        this.fieldObj_.getEditableDomHelper().getDocument());
+
+    var startCaret = this.savedCaretRange_.getCaret(true);
+    var endCaret = this.savedCaretRange_.getCaret(false);
+    var hasCarets = startCaret && endCaret;
+  }
+
+  // There are two reasons why we might want to focus the field:
+  // 1) makeFieldEditable was triggered by the click-to-edit wrapper.
+  //    In this case, the mouse event should have triggered a focus, but
+  //    the editor might have taken the focus away to create lorem ipsum
+  //    text or create an iframe for the field. So we make sure the focus
+  //    is restored.
+  // 2) somebody placed carets, and we need to select those carets. The field
+  //    needs focus to ensure that the selection appears.
+  if (this.mouseEventTriggeredLoad_ || hasCarets) {
+    this.focusOnFieldObj(this.fieldObj_);
+  }
+
+  if (hasCarets) {
+
+    this.savedCaretRange_.restore();
+    this.fieldObj_.dispatchSelectionChangeEvent();
+
+    // NOTE(nicksantos): Bubbles aren't actually enabled until the end
+    // if the load sequence, so if the user clicked on a link, the bubble
+    // will not pop up.
+  }
+
+  if (this.savedCaretRange_) {
+    this.savedCaretRange_.dispose();
+    this.savedCaretRange_ = null;
+  }
+
+  this.mouseEventTriggeredLoad_ = false;
+};
+
+
+/**
+ * Focus on the field object.
+ * @param {goog.editor.Field} field The field to focus.
+ * @protected
+ */
+goog.editor.ClickToEditWrapper.prototype.focusOnFieldObj = function(field) {
+  field.focusAndPlaceCursorAtStart();
+};
+
+
+/**
+ * Make the field object editable.
+ * @param {goog.editor.Field} field The field to make editable.
+ * @protected
+ */
+goog.editor.ClickToEditWrapper.prototype.makeFieldEditable = function(field) {
+  field.makeEditable();
+};
+
+
+//================================================================
+// Caret-handling methods
+
+
+/**
+ * Gets a saved caret range for the given range.
+ * @param {goog.dom.AbstractRange} range A range wrapper.
+ * @return {goog.dom.SavedCaretRange} The range, saved with carets, or null
+ *    if the range wrapper was null.
+ * @private
+ */
+goog.editor.ClickToEditWrapper.createCaretRange_ = function(range) {
+  return range && goog.editor.range.saveUsingNormalizedCarets(range);
+};
+
+
+/**
+ * Inserts the carets, given the current selection.
+ *
+ * Note that for all practical purposes, a cursor position is just
+ * a selection with the start and end at the same point.
+ * @private
+ */
+goog.editor.ClickToEditWrapper.prototype.insertCarets_ = function() {
+  var fieldElement = this.fieldObj_.getOriginalElement();
+
+  this.savedCaretRange_ = null;
+  var originalWindow = this.originalDomHelper_.getWindow();
+  if (goog.dom.Range.hasSelection(originalWindow)) {
+    var range = goog.dom.Range.createFromWindow(originalWindow);
+    range = range && goog.editor.range.narrow(range, fieldElement);
+    this.savedCaretRange_ =
+        goog.editor.ClickToEditWrapper.createCaretRange_(range);
+  }
+
+  if (!this.savedCaretRange_) {
+    // We couldn't figure out where to put the carets.
+    // But in FF2/IE6+, this could mean that the user clicked on a
+    // 'special' node, (e.g., a link or an unselectable item). So the
+    // selection appears to be null or the full page, even though the user did
+    // click on something. In IE, we can determine the real selection via
+    // document.activeElement. In FF, we have to be more hacky.
+    var specialNodeClicked;
+    if (goog.editor.BrowserFeature.HAS_ACTIVE_ELEMENT) {
+      specialNodeClicked = goog.dom.getActiveElement(
+          this.originalDomHelper_.getDocument());
+    } else {
+      specialNodeClicked = this.savedAnchorClicked_;
+    }
+
+    var isFieldElement = function(node) {
+      return node == fieldElement;
+    };
+    if (specialNodeClicked &&
+        goog.dom.getAncestor(specialNodeClicked, isFieldElement, true)) {
+      // Insert the cursor at the beginning of the active element to be
+      // consistent with the behavior in FF1.5, where clicking on a
+      // link makes the current selection equal to the cursor position
+      // directly before that link.
+      //
+      // TODO(nicksantos): Is there a way to more accurately place the cursor?
+      this.savedCaretRange_ = goog.editor.ClickToEditWrapper.createCaretRange_(
+          goog.dom.Range.createFromNodes(
+              specialNodeClicked, 0, specialNodeClicked, 0));
+    }
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/command.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/command.js b/externs/GCL/externs/goog/editor/command.js
new file mode 100644
index 0000000..2996b8c
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/command.js
@@ -0,0 +1,76 @@
+// 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 Commands that the editor can execute.
+ * @see ../demos/editor/editor.html
+ */
+goog.provide('goog.editor.Command');
+
+
+/**
+ * Commands that the editor can excute via execCommand or queryCommandValue.
+ * @enum {string}
+ */
+goog.editor.Command = {
+  // Prepend all the strings of built in execCommands with a plus to ensure
+  // that there's no conflict if a client wants to use the
+  // browser's execCommand.
+  UNDO: '+undo',
+  REDO: '+redo',
+  LINK: '+link',
+  FORMAT_BLOCK: '+formatBlock',
+  INDENT: '+indent',
+  OUTDENT: '+outdent',
+  REMOVE_FORMAT: '+removeFormat',
+  STRIKE_THROUGH: '+strikeThrough',
+  HORIZONTAL_RULE: '+insertHorizontalRule',
+  SUBSCRIPT: '+subscript',
+  SUPERSCRIPT: '+superscript',
+  UNDERLINE: '+underline',
+  BOLD: '+bold',
+  ITALIC: '+italic',
+  FONT_SIZE: '+fontSize',
+  FONT_FACE: '+fontName',
+  FONT_COLOR: '+foreColor',
+  EMOTICON: '+emoticon',
+  EQUATION: '+equation',
+  BACKGROUND_COLOR: '+backColor',
+  ORDERED_LIST: '+insertOrderedList',
+  UNORDERED_LIST: '+insertUnorderedList',
+  TABLE: '+table',
+  JUSTIFY_CENTER: '+justifyCenter',
+  JUSTIFY_FULL: '+justifyFull',
+  JUSTIFY_RIGHT: '+justifyRight',
+  JUSTIFY_LEFT: '+justifyLeft',
+  BLOCKQUOTE: '+BLOCKQUOTE', // This is a nodename. Should be all caps.
+  DIR_LTR: 'ltr', // should be exactly 'ltr' as it becomes dir attribute value
+  DIR_RTL: 'rtl', // same here
+  IMAGE: 'image',
+  EDIT_HTML: 'editHtml',
+  UPDATE_LINK_BUBBLE: 'updateLinkBubble',
+
+  // queryCommandValue only: returns the default tag name used in the field.
+  // DIV should be considered the default if no plugin responds.
+  DEFAULT_TAG: '+defaultTag',
+
+  // TODO(nicksantos): Try to give clients an API so that they don't need
+  // these execCommands.
+  CLEAR_LOREM: 'clearlorem',
+  UPDATE_LOREM: 'updatelorem',
+  USING_LOREM: 'usinglorem',
+
+  // Modal editor commands (usually dialogs).
+  MODAL_LINK_EDITOR: 'link'
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/contenteditablefield.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/contenteditablefield.js b/externs/GCL/externs/goog/editor/contenteditablefield.js
new file mode 100644
index 0000000..a30d245
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/contenteditablefield.js
@@ -0,0 +1,108 @@
+// 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 Class to encapsulate an editable field that blends into the
+ * style of the page and never uses an iframe.  The field's height can be
+ * controlled by CSS styles like min-height, max-height, and overflow.  This is
+ * a goog.editor.Field, but overrides everything iframe related to use
+ * contentEditable divs.  This is essentially a much lighter alternative to
+ * goog.editor.SeamlessField, but only works in Firefox 3+, and only works
+ * *well* in Firefox 12+ due to
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=669026.
+ *
+ * @author gboyer@google.com (Garrett Boyer)
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+
+goog.provide('goog.editor.ContentEditableField');
+
+goog.require('goog.asserts');
+goog.require('goog.editor.Field');
+goog.require('goog.log');
+
+
+
+/**
+ * This class encapsulates an editable field that is just a contentEditable
+ * div.
+ *
+ * To see events fired by this object, please see the base class.
+ *
+ * @param {string} id An identifer for the field. This is used to find the
+ *     field and the element associated with this field.
+ * @param {Document=} opt_doc The document that the element with the given
+ *     id can be found in.
+ * @constructor
+ * @extends {goog.editor.Field}
+ */
+goog.editor.ContentEditableField = function(id, opt_doc) {
+  goog.editor.Field.call(this, id, opt_doc);
+};
+goog.inherits(goog.editor.ContentEditableField, goog.editor.Field);
+
+
+/**
+ * @override
+ */
+goog.editor.ContentEditableField.prototype.logger =
+    goog.log.getLogger('goog.editor.ContentEditableField');
+
+
+/** @override */
+goog.editor.ContentEditableField.prototype.usesIframe = function() {
+  // Never uses an iframe in any browser.
+  return false;
+};
+
+
+// Overridden to improve dead code elimination only.
+/** @override */
+goog.editor.ContentEditableField.prototype.turnOnDesignModeGecko =
+    goog.nullFunction;
+
+
+/** @override */
+goog.editor.ContentEditableField.prototype.installStyles = function() {
+  goog.asserts.assert(!this.cssStyles, 'ContentEditableField does not support' +
+      ' CSS styles; instead just write plain old CSS on the main page.');
+};
+
+
+/** @override */
+goog.editor.ContentEditableField.prototype.makeEditableInternal = function(
+    opt_iframeSrc) {
+  var field = this.getOriginalElement();
+  if (field) {
+    this.setupFieldObject(field);
+    // TODO(gboyer): Allow clients/plugins to override with 'plaintext-only'
+    // for WebKit.
+    field.contentEditable = true;
+
+    this.injectContents(field.innerHTML, field);
+
+    this.handleFieldLoad();
+  }
+};
+
+
+/**
+ * @override
+ *
+ * ContentEditableField does not make any changes to the DOM when it is made
+ * editable other than setting contentEditable to true.
+ */
+goog.editor.ContentEditableField.prototype.restoreDom =
+    goog.nullFunction;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/defines.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/defines.js b/externs/GCL/externs/goog/editor/defines.js
new file mode 100644
index 0000000..1bf57ba
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/defines.js
@@ -0,0 +1,34 @@
+// Copyright 2008 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 Text editor constants for compile time feature selection.
+ *
+ */
+
+goog.provide('goog.editor.defines');
+
+
+/**
+ * @define {boolean} Use contentEditable in FF.
+ * There are a number of known bugs when the only content in your field is
+ * inline (e.g. just text, no block elements):
+ * -indent is a noop and then DOMSubtreeModified events stop firing until
+ *    the structure of the DOM is changed (e.g. make something bold).
+ * -inserting lists inserts just a NBSP, no list!
+ * Once those two are fixed, we should have one client guinea pig it and put
+ * it through a QA run. If we can file the bugs with Mozilla, there's a chance
+ * they'll fix them for a dot release of Firefox 3.
+ */
+goog.define('goog.editor.defines.USE_CONTENTEDITABLE_IN_FIREFOX_3', false);


[29/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/fontsizemonitor.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/fontsizemonitor.js b/externs/GCL/externs/goog/dom/fontsizemonitor.js
new file mode 100644
index 0000000..6c7c8b4
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/fontsizemonitor.js
@@ -0,0 +1,162 @@
+// Copyright 2005 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 class that can be used to listen to font size changes.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+goog.provide('goog.dom.FontSizeMonitor');
+goog.provide('goog.dom.FontSizeMonitor.EventType');
+
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.events');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.userAgent');
+
+
+// TODO(arv): Move this to goog.events instead.
+
+
+
+/**
+ * This class can be used to monitor changes in font size.  Instances will
+ * dispatch a {@code goog.dom.FontSizeMonitor.EventType.CHANGE} event.
+ * Example usage:
+ * <pre>
+ * var fms = new goog.dom.FontSizeMonitor();
+ * goog.events.listen(fms, goog.dom.FontSizeMonitor.EventType.CHANGE,
+ *     function(e) {
+ *       alert('Font size was changed');
+ *     });
+ * </pre>
+ * @param {goog.dom.DomHelper=} opt_domHelper DOM helper object that is used to
+ *     determine where to insert the DOM nodes used to determine when the font
+ *     size changes.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @final
+ */
+goog.dom.FontSizeMonitor = function(opt_domHelper) {
+  goog.events.EventTarget.call(this);
+
+  var dom = opt_domHelper || goog.dom.getDomHelper();
+
+  /**
+   * Offscreen iframe which we use to detect resize events.
+   * @type {Element}
+   * @private
+   */
+  this.sizeElement_ = dom.createDom(
+      // The size of the iframe is expressed in em, which are font size relative
+      // which will cause the iframe to be resized when the font size changes.
+      // The actual values are not relevant as long as we can ensure that the
+      // iframe has a non zero size and is completely off screen.
+      goog.userAgent.IE ? goog.dom.TagName.DIV : goog.dom.TagName.IFRAME, {
+        'style': 'position:absolute;width:9em;height:9em;top:-99em',
+        'tabIndex': -1,
+        'aria-hidden': 'true'
+      });
+  var p = dom.getDocument().body;
+  p.insertBefore(this.sizeElement_, p.firstChild);
+
+  /**
+   * The object that we listen to resize events on.
+   * @type {Element|Window}
+   * @private
+   */
+  var resizeTarget = this.resizeTarget_ =
+      goog.userAgent.IE ? this.sizeElement_ :
+          goog.dom.getFrameContentWindow(
+              /** @type {HTMLIFrameElement} */ (this.sizeElement_));
+
+  // We need to open and close the document to get Firefox 2 to work.  We must
+  // not do this for IE in case we are using HTTPS since accessing the document
+  // on an about:blank iframe in IE using HTTPS raises a Permission Denied
+  // error.
+  if (goog.userAgent.GECKO) {
+    var doc = resizeTarget.document;
+    doc.open();
+    doc.close();
+  }
+
+  // Listen to resize event on the window inside the iframe.
+  goog.events.listen(resizeTarget, goog.events.EventType.RESIZE,
+                     this.handleResize_, false, this);
+
+  /**
+   * Last measured width of the iframe element.
+   * @type {number}
+   * @private
+   */
+  this.lastWidth_ = this.sizeElement_.offsetWidth;
+};
+goog.inherits(goog.dom.FontSizeMonitor, goog.events.EventTarget);
+
+
+/**
+ * The event types that the FontSizeMonitor fires.
+ * @enum {string}
+ */
+goog.dom.FontSizeMonitor.EventType = {
+  // TODO(arv): Change value to 'change' after updating the callers.
+  CHANGE: 'fontsizechange'
+};
+
+
+/**
+ * Constant for the change event.
+ * @type {string}
+ * @deprecated Use {@code goog.dom.FontSizeMonitor.EventType.CHANGE} instead.
+ */
+goog.dom.FontSizeMonitor.CHANGE_EVENT =
+    goog.dom.FontSizeMonitor.EventType.CHANGE;
+
+
+/** @override */
+goog.dom.FontSizeMonitor.prototype.disposeInternal = function() {
+  goog.dom.FontSizeMonitor.superClass_.disposeInternal.call(this);
+
+  goog.events.unlisten(this.resizeTarget_, goog.events.EventType.RESIZE,
+                       this.handleResize_, false, this);
+  this.resizeTarget_ = null;
+
+  // Firefox 2 crashes if the iframe is removed during the unload phase.
+  if (!goog.userAgent.GECKO ||
+      goog.userAgent.isVersionOrHigher('1.9')) {
+    goog.dom.removeNode(this.sizeElement_);
+  }
+  delete this.sizeElement_;
+};
+
+
+/**
+ * Handles the onresize event of the iframe and dispatches a change event in
+ * case its size really changed.
+ * @param {goog.events.BrowserEvent} e The event object.
+ * @private
+ */
+goog.dom.FontSizeMonitor.prototype.handleResize_ = function(e) {
+  // Only dispatch the event if the size really changed.  Some newer browsers do
+  // not really change the font-size,  instead they zoom the whole page.  This
+  // does trigger window resize events on the iframe but the logical pixel size
+  // remains the same (the device pixel size changes but that is irrelevant).
+  var currentWidth = this.sizeElement_.offsetWidth;
+  if (this.lastWidth_ != currentWidth) {
+    this.lastWidth_ = currentWidth;
+    this.dispatchEvent(goog.dom.FontSizeMonitor.EventType.CHANGE);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/forms.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/forms.js b/externs/GCL/externs/goog/dom/forms.js
new file mode 100644
index 0000000..75dc2e5
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/forms.js
@@ -0,0 +1,417 @@
+// 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 manipulating a form and elements.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+goog.provide('goog.dom.forms');
+
+goog.require('goog.dom.InputType');
+goog.require('goog.dom.TagName');
+goog.require('goog.structs.Map');
+
+
+/**
+ * Returns form data as a map of name to value arrays. This doesn't
+ * support file inputs.
+ * @param {HTMLFormElement} form The form.
+ * @return {!goog.structs.Map.<string, !Array.<string>>} A map of the form data
+ *     as field name to arrays of values.
+ */
+goog.dom.forms.getFormDataMap = function(form) {
+  var map = new goog.structs.Map();
+  goog.dom.forms.getFormDataHelper_(form, map,
+      goog.dom.forms.addFormDataToMap_);
+  return map;
+};
+
+
+/**
+ * Returns the form data as an application/x-www-url-encoded string. This
+ * doesn't support file inputs.
+ * @param {HTMLFormElement} form The form.
+ * @return {string} An application/x-www-url-encoded string.
+ */
+goog.dom.forms.getFormDataString = function(form) {
+  var sb = [];
+  goog.dom.forms.getFormDataHelper_(form, sb,
+      goog.dom.forms.addFormDataToStringBuffer_);
+  return sb.join('&');
+};
+
+
+/**
+ * Returns the form data as a map or an application/x-www-url-encoded
+ * string. This doesn't support file inputs.
+ * @param {HTMLFormElement} form The form.
+ * @param {Object} result The object form data is being put in.
+ * @param {Function} fnAppend Function that takes {@code result}, an element
+ *     name, and an element value, and adds the name/value pair to the result
+ *     object.
+ * @private
+ */
+goog.dom.forms.getFormDataHelper_ = function(form, result, fnAppend) {
+  var els = form.elements;
+  for (var el, i = 0; el = els[i]; i++) {
+    if (// Make sure we don't include elements that are not part of the form.
+        // Some browsers include non-form elements. Check for 'form' property.
+        // See http://code.google.com/p/closure-library/issues/detail?id=227
+        // and
+        // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#the-input-element
+        (el.form != form) ||
+        el.disabled ||
+        // HTMLFieldSetElement has a form property but no value.
+        el.tagName == goog.dom.TagName.FIELDSET) {
+      continue;
+    }
+
+    var name = el.name;
+    switch (el.type.toLowerCase()) {
+      case goog.dom.InputType.FILE:
+        // file inputs are not supported
+      case goog.dom.InputType.SUBMIT:
+      case goog.dom.InputType.RESET:
+      case goog.dom.InputType.BUTTON:
+        // don't submit these
+        break;
+      case goog.dom.InputType.SELECT_MULTIPLE:
+        var values = goog.dom.forms.getValue(el);
+        if (values != null) {
+          for (var value, j = 0; value = values[j]; j++) {
+            fnAppend(result, name, value);
+          }
+        }
+        break;
+      default:
+        var value = goog.dom.forms.getValue(el);
+        if (value != null) {
+          fnAppend(result, name, value);
+        }
+    }
+  }
+
+  // input[type=image] are not included in the elements collection
+  var inputs = form.getElementsByTagName(goog.dom.TagName.INPUT);
+  for (var input, i = 0; input = inputs[i]; i++) {
+    if (input.form == form &&
+        input.type.toLowerCase() == goog.dom.InputType.IMAGE) {
+      name = input.name;
+      fnAppend(result, name, input.value);
+      fnAppend(result, name + '.x', '0');
+      fnAppend(result, name + '.y', '0');
+    }
+  }
+};
+
+
+/**
+ * Adds the name/value pair to the map.
+ * @param {!goog.structs.Map.<string, !Array.<string>>} map The map to add to.
+ * @param {string} name The name.
+ * @param {string} value The value.
+ * @private
+ */
+goog.dom.forms.addFormDataToMap_ = function(map, name, value) {
+  var array = map.get(name);
+  if (!array) {
+    array = [];
+    map.set(name, array);
+  }
+  array.push(value);
+};
+
+
+/**
+ * Adds a name/value pair to an string buffer array in the form 'name=value'.
+ * @param {Array<string>} sb The string buffer array for storing data.
+ * @param {string} name The name.
+ * @param {string} value The value.
+ * @private
+ */
+goog.dom.forms.addFormDataToStringBuffer_ = function(sb, name, value) {
+  sb.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
+};
+
+
+/**
+ * Whether the form has a file input.
+ * @param {HTMLFormElement} form The form.
+ * @return {boolean} Whether the form has a file input.
+ */
+goog.dom.forms.hasFileInput = function(form) {
+  var els = form.elements;
+  for (var el, i = 0; el = els[i]; i++) {
+    if (!el.disabled && el.type &&
+        el.type.toLowerCase() == goog.dom.InputType.FILE) {
+      return true;
+    }
+  }
+  return false;
+};
+
+
+/**
+ * Enables or disables either all elements in a form or a single form element.
+ * @param {Element} el The element, either a form or an element within a form.
+ * @param {boolean} disabled Whether the element should be disabled.
+ */
+goog.dom.forms.setDisabled = function(el, disabled) {
+  // disable all elements in a form
+  if (el.tagName == goog.dom.TagName.FORM) {
+    var els = el.elements;
+    for (var i = 0; el = els[i]; i++) {
+      goog.dom.forms.setDisabled(el, disabled);
+    }
+  } else {
+    // makes sure to blur buttons, multi-selects, and any elements which
+    // maintain keyboard/accessibility focus when disabled
+    if (disabled == true) {
+      el.blur();
+    }
+    el.disabled = disabled;
+  }
+};
+
+
+/**
+ * Focuses, and optionally selects the content of, a form element.
+ * @param {Element} el The form element.
+ */
+goog.dom.forms.focusAndSelect = function(el) {
+  el.focus();
+  if (el.select) {
+    el.select();
+  }
+};
+
+
+/**
+ * Whether a form element has a value.
+ * @param {Element} el The element.
+ * @return {boolean} Whether the form has a value.
+ */
+goog.dom.forms.hasValue = function(el) {
+  var value = goog.dom.forms.getValue(el);
+  return !!value;
+};
+
+
+/**
+ * Whether a named form field has a value.
+ * @param {HTMLFormElement} form The form element.
+ * @param {string} name Name of an input to the form.
+ * @return {boolean} Whether the form has a value.
+ */
+goog.dom.forms.hasValueByName = function(form, name) {
+  var value = goog.dom.forms.getValueByName(form, name);
+  return !!value;
+};
+
+
+/**
+ * Gets the current value of any element with a type.
+ * @param {Element} el The element.
+ * @return {string|Array<string>|null} The current value of the element
+ *     (or null).
+ */
+goog.dom.forms.getValue = function(el) {
+  var type = el.type;
+  if (!goog.isDef(type)) {
+    return null;
+  }
+  switch (type.toLowerCase()) {
+    case goog.dom.InputType.CHECKBOX:
+    case goog.dom.InputType.RADIO:
+      return goog.dom.forms.getInputChecked_(el);
+    case goog.dom.InputType.SELECT_ONE:
+      return goog.dom.forms.getSelectSingle_(el);
+    case goog.dom.InputType.SELECT_MULTIPLE:
+      return goog.dom.forms.getSelectMultiple_(el);
+    default:
+      return goog.isDef(el.value) ? el.value : null;
+  }
+};
+
+
+/**
+ * Alias for goog.dom.form.element.getValue
+ * @type {Function}
+ * @deprecated Use {@link goog.dom.forms.getValue} instead.
+ * @suppress {missingProvide}
+ */
+goog.dom.$F = goog.dom.forms.getValue;
+
+
+/**
+ * Returns the value of the named form field. In the case of radio buttons,
+ * returns the value of the checked button with the given name.
+ *
+ * @param {HTMLFormElement} form The form element.
+ * @param {string} name Name of an input to the form.
+ *
+ * @return {Array<string>|string|null} The value of the form element, or
+ *     null if the form element does not exist or has no value.
+ */
+goog.dom.forms.getValueByName = function(form, name) {
+  var els = form.elements[name];
+
+  if (els) {
+    if (els.type) {
+      return goog.dom.forms.getValue(els);
+    } else {
+      for (var i = 0; i < els.length; i++) {
+        var val = goog.dom.forms.getValue(els[i]);
+        if (val) {
+          return val;
+        }
+      }
+    }
+  }
+  return null;
+};
+
+
+/**
+ * Gets the current value of a checkable input element.
+ * @param {Element} el The element.
+ * @return {?string} The value of the form element (or null).
+ * @private
+ */
+goog.dom.forms.getInputChecked_ = function(el) {
+  return el.checked ? el.value : null;
+};
+
+
+/**
+ * Gets the current value of a select-one element.
+ * @param {Element} el The element.
+ * @return {?string} The value of the form element (or null).
+ * @private
+ */
+goog.dom.forms.getSelectSingle_ = function(el) {
+  var selectedIndex = el.selectedIndex;
+  return selectedIndex >= 0 ? el.options[selectedIndex].value : null;
+};
+
+
+/**
+ * Gets the current value of a select-multiple element.
+ * @param {Element} el The element.
+ * @return {Array<string>?} The value of the form element (or null).
+ * @private
+ */
+goog.dom.forms.getSelectMultiple_ = function(el) {
+  var values = [];
+  for (var option, i = 0; option = el.options[i]; i++) {
+    if (option.selected) {
+      values.push(option.value);
+    }
+  }
+  return values.length ? values : null;
+};
+
+
+/**
+ * Sets the current value of any element with a type.
+ * @param {Element} el The element.
+ * @param {*=} opt_value The value to give to the element, which will be coerced
+ *     by the browser in the default case using toString. This value should be
+ *     an array for setting the value of select multiple elements.
+ */
+goog.dom.forms.setValue = function(el, opt_value) {
+  var type = el.type;
+  if (goog.isDef(type)) {
+    switch (type.toLowerCase()) {
+      case goog.dom.InputType.CHECKBOX:
+      case goog.dom.InputType.RADIO:
+        goog.dom.forms.setInputChecked_(el,
+            /** @type {string} */ (opt_value));
+        break;
+      case goog.dom.InputType.SELECT_ONE:
+        goog.dom.forms.setSelectSingle_(el,
+            /** @type {string} */ (opt_value));
+        break;
+      case goog.dom.InputType.SELECT_MULTIPLE:
+        goog.dom.forms.setSelectMultiple_(el,
+            /** @type {Array<string>} */ (opt_value));
+        break;
+      default:
+        el.value = goog.isDefAndNotNull(opt_value) ? opt_value : '';
+    }
+  }
+};
+
+
+/**
+ * Sets a checkable input element's checked property.
+ * #TODO(user): This seems potentially unintuitive since it doesn't set
+ * the value property but my hunch is that the primary use case is to check a
+ * checkbox, not to reset its value property.
+ * @param {Element} el The element.
+ * @param {string|boolean=} opt_value The value, sets the element checked if
+ *     val is set.
+ * @private
+ */
+goog.dom.forms.setInputChecked_ = function(el, opt_value) {
+  el.checked = opt_value;
+};
+
+
+/**
+ * Sets the value of a select-one element.
+ * @param {Element} el The element.
+ * @param {string=} opt_value The value of the selected option element.
+ * @private
+ */
+goog.dom.forms.setSelectSingle_ = function(el, opt_value) {
+  // unset any prior selections
+  el.selectedIndex = -1;
+  if (goog.isString(opt_value)) {
+    for (var option, i = 0; option = el.options[i]; i++) {
+      if (option.value == opt_value) {
+        option.selected = true;
+        break;
+      }
+    }
+  }
+};
+
+
+/**
+ * Sets the value of a select-multiple element.
+ * @param {Element} el The element.
+ * @param {Array<string>|string=} opt_value The value of the selected option
+ *     element(s).
+ * @private
+ */
+goog.dom.forms.setSelectMultiple_ = function(el, opt_value) {
+  // reset string opt_values as an array
+  if (goog.isString(opt_value)) {
+    opt_value = [opt_value];
+  }
+  for (var option, i = 0; option = el.options[i]; i++) {
+    // we have to reset the other options to false for select-multiple
+    option.selected = false;
+    if (opt_value) {
+      for (var value, j = 0; value = opt_value[j]; j++) {
+        if (option.value == value) {
+          option.selected = true;
+        }
+      }
+    }
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/fullscreen.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/fullscreen.js b/externs/GCL/externs/goog/dom/fullscreen.js
new file mode 100644
index 0000000..1954213
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/fullscreen.js
@@ -0,0 +1,144 @@
+// 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 Functions for managing full screen status of the DOM.
+ *
+ */
+
+goog.provide('goog.dom.fullscreen');
+goog.provide('goog.dom.fullscreen.EventType');
+
+goog.require('goog.dom');
+goog.require('goog.userAgent');
+
+
+/**
+ * Event types for full screen.
+ * @enum {string}
+ */
+goog.dom.fullscreen.EventType = {
+  /** Dispatched by the Document when the fullscreen status changes. */
+  CHANGE: (function() {
+    if (goog.userAgent.WEBKIT) {
+      return 'webkitfullscreenchange';
+    }
+    if (goog.userAgent.GECKO) {
+      return 'mozfullscreenchange';
+    }
+    if (goog.userAgent.IE) {
+      return 'MSFullscreenChange';
+    }
+    // Opera 12-14, and W3C standard (Draft):
+    // https://dvcs.w3.org/hg/fullscreen/raw-file/tip/Overview.html
+    return 'fullscreenchange';
+  })()
+};
+
+
+/**
+ * Determines if full screen is supported.
+ * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being
+ *     queried. If not provided, use the current DOM.
+ * @return {boolean} True iff full screen is supported.
+ */
+goog.dom.fullscreen.isSupported = function(opt_domHelper) {
+  var doc = goog.dom.fullscreen.getDocument_(opt_domHelper);
+  var body = doc.body;
+  return !!(body.webkitRequestFullscreen ||
+      (body.mozRequestFullScreen && doc.mozFullScreenEnabled) ||
+      (body.msRequestFullscreen && doc.msFullscreenEnabled) ||
+      (body.requestFullscreen && doc.fullscreenEnabled));
+};
+
+
+/**
+ * Requests putting the element in full screen.
+ * @param {!Element} element The element to put full screen.
+ */
+goog.dom.fullscreen.requestFullScreen = function(element) {
+  if (element.webkitRequestFullscreen) {
+    element.webkitRequestFullscreen();
+  } else if (element.mozRequestFullScreen) {
+    element.mozRequestFullScreen();
+  } else if (element.msRequestFullscreen) {
+    element.msRequestFullscreen();
+  } else if (element.requestFullscreen) {
+    element.requestFullscreen();
+  }
+};
+
+
+/**
+ * Requests putting the element in full screen with full keyboard access.
+ * @param {!Element} element The element to put full screen.
+ */
+goog.dom.fullscreen.requestFullScreenWithKeys = function(
+    element) {
+  if (element.mozRequestFullScreenWithKeys) {
+    element.mozRequestFullScreenWithKeys();
+  } else if (element.webkitRequestFullscreen) {
+    element.webkitRequestFullscreen();
+  } else {
+    goog.dom.fullscreen.requestFullScreen(element);
+  }
+};
+
+
+/**
+ * Exits full screen.
+ * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being
+ *     queried. If not provided, use the current DOM.
+ */
+goog.dom.fullscreen.exitFullScreen = function(opt_domHelper) {
+  var doc = goog.dom.fullscreen.getDocument_(opt_domHelper);
+  if (doc.webkitCancelFullScreen) {
+    doc.webkitCancelFullScreen();
+  } else if (doc.mozCancelFullScreen) {
+    doc.mozCancelFullScreen();
+  } else if (doc.msExitFullscreen) {
+    doc.msExitFullscreen();
+  } else if (doc.exitFullscreen) {
+    doc.exitFullscreen();
+  }
+};
+
+
+/**
+ * Determines if the document is full screen.
+ * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being
+ *     queried. If not provided, use the current DOM.
+ * @return {boolean} Whether the document is full screen.
+ */
+goog.dom.fullscreen.isFullScreen = function(opt_domHelper) {
+  var doc = goog.dom.fullscreen.getDocument_(opt_domHelper);
+  // IE 11 doesn't have similar boolean property, so check whether
+  // document.msFullscreenElement is null instead.
+  return !!(doc.webkitIsFullScreen || doc.mozFullScreen ||
+      doc.msFullscreenElement || doc.fullscreenElement);
+};
+
+
+/**
+ * Gets the document object of the dom.
+ * @param {!goog.dom.DomHelper=} opt_domHelper The DomHelper for the DOM being
+ *     queried. If not provided, use the current DOM.
+ * @return {!Document} The dom document.
+ * @private
+ */
+goog.dom.fullscreen.getDocument_ = function(opt_domHelper) {
+  return opt_domHelper ?
+      opt_domHelper.getDocument() :
+      goog.dom.getDomHelper().getDocument();
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/iframe.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/iframe.js b/externs/GCL/externs/goog/dom/iframe.js
new file mode 100644
index 0000000..a22b8b7
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/iframe.js
@@ -0,0 +1,216 @@
+// Copyright 2008 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 creating and working with iframes
+ * cross-browser.
+ * @author gboyer@google.com (Garry Boyer)
+ */
+
+
+goog.provide('goog.dom.iframe');
+
+goog.require('goog.dom');
+goog.require('goog.dom.safe');
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.SafeStyle');
+goog.require('goog.html.legacyconversions');
+goog.require('goog.userAgent');
+
+
+/**
+ * Safe source for a blank iframe.
+ *
+ * Intentionally not about:blank, which gives mixed content warnings in IE6
+ * over HTTPS.
+ *
+ * @type {string}
+ */
+goog.dom.iframe.BLANK_SOURCE = 'javascript:""';
+
+
+/**
+ * Safe source for a new blank iframe that may not cause a new load of the
+ * iframe. This is different from {@code goog.dom.iframe.BLANK_SOURCE} in that
+ * it will allow an iframe to be loaded synchronously in more browsers, notably
+ * Gecko, following the javascript protocol spec.
+ *
+ * NOTE: This should not be used to replace the source of an existing iframe.
+ * The new src value will be ignored, per the spec.
+ *
+ * Due to cross-browser differences, the load is not guaranteed  to be
+ * synchronous. If code depends on the load of the iframe,
+ * then {@code goog.net.IframeLoadMonitor} or a similar technique should be
+ * used.
+ *
+ * According to
+ * http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#javascript-protocol
+ * the 'javascript:""' URL should trigger a new load of the iframe, which may be
+ * asynchronous. A void src, such as 'javascript:undefined', does not change
+ * the browsing context document's, and thus should not trigger another load.
+ *
+ * Intentionally not about:blank, which also triggers a load.
+ *
+ * NOTE: 'javascript:' URL handling spec compliance varies per browser. IE
+ * throws an error with 'javascript:undefined'. Webkit browsers will reload the
+ * iframe when setting this source on an existing iframe.
+ *
+ * @type {string}
+ */
+goog.dom.iframe.BLANK_SOURCE_NEW_FRAME = goog.userAgent.IE ?
+    'javascript:""' :
+    'javascript:undefined';
+
+
+/**
+ * Styles to help ensure an undecorated iframe.
+ * @type {string}
+ * @private
+ */
+goog.dom.iframe.STYLES_ = 'border:0;vertical-align:bottom;';
+
+
+/**
+ * Creates a completely blank iframe element.
+ *
+ * The iframe will not caused mixed-content warnings for IE6 under HTTPS.
+ * The iframe will also have no borders or padding, so that the styled width
+ * and height will be the actual width and height of the iframe.
+ *
+ * This function currently only attempts to create a blank iframe.  There
+ * are no guarantees to the contents of the iframe or whether it is rendered
+ * in quirks mode.
+ *
+ * @param {goog.dom.DomHelper} domHelper The dom helper to use.
+ * @param {!goog.html.SafeStyle|string=} opt_styles CSS styles for the
+ *     iframe. If possible pass a SafeStyle; string is supported for
+ *     backwards-compatibility only and uses goog.html.legacyconversions.
+ * @return {!HTMLIFrameElement} A completely blank iframe.
+ */
+goog.dom.iframe.createBlank = function(domHelper, opt_styles) {
+  var styles;
+  if (goog.isString(opt_styles)) {
+    styles = goog.html.legacyconversions.safeStyleFromString(opt_styles)
+        .getTypedStringValue();
+  } else if (opt_styles instanceof goog.html.SafeStyle) {
+    // SafeStyle has to be converted back to a string for now, since there's
+    // no safe alternative to createDom().
+    styles = goog.html.SafeStyle.unwrap(opt_styles);
+  } else {  // undefined.
+    styles = '';
+  }
+  return /** @type {!HTMLIFrameElement} */ (domHelper.createDom('iframe', {
+    'frameborder': 0,
+    // Since iframes are inline elements, we must align to bottom to
+    // compensate for the line descent.
+    'style': goog.dom.iframe.STYLES_ + styles,
+    'src': goog.dom.iframe.BLANK_SOURCE
+  }));
+};
+
+
+/**
+ * Writes the contents of a blank iframe that has already been inserted
+ * into the document. If possible use {@link #writeSafeContent},
+ * this function exists for backwards-compatibility only and uses
+ * goog.html.legacyconversions.
+ * @param {!HTMLIFrameElement} iframe An iframe with no contents, such as
+ *     one created by goog.dom.iframe.createBlank, but already appended to
+ *     a parent document.
+ * @param {string} content Content to write to the iframe, from doctype to
+ *     the HTML close tag.
+ */
+goog.dom.iframe.writeContent = function(iframe, content) {
+  goog.dom.iframe.writeSafeContent(
+      iframe, goog.html.legacyconversions.safeHtmlFromString(content));
+};
+
+
+/**
+ * Writes the contents of a blank iframe that has already been inserted
+ * into the document.
+ * @param {!HTMLIFrameElement} iframe An iframe with no contents, such as
+ *     one created by {@link #createBlank}, but already appended to
+ *     a parent document.
+ * @param {!goog.html.SafeHtml} content Content to write to the iframe,
+ *     from doctype to the HTML close tag.
+ */
+goog.dom.iframe.writeSafeContent = function(iframe, content) {
+  var doc = goog.dom.getFrameContentDocument(iframe);
+  doc.open();
+  goog.dom.safe.documentWrite(doc, content);
+  doc.close();
+};
+
+
+// TODO(gboyer): Provide a higher-level API for the most common use case, so
+// that you can just provide a list of stylesheets and some content HTML.
+/**
+ * Creates a same-domain iframe containing preloaded content.
+ *
+ * This is primarily useful for DOM sandboxing.  One use case is to embed
+ * a trusted Javascript app with potentially conflicting CSS styles.  The
+ * second case is to reduce the cost of layout passes by the browser -- for
+ * example, you can perform sandbox sizing of characters in an iframe while
+ * manipulating a heavy DOM in the main window.  The iframe and parent frame
+ * can access each others' properties and functions without restriction.
+ *
+ * @param {!Element} parentElement The parent element in which to append the
+ *     iframe.
+ * @param {!goog.html.SafeHtml|string=} opt_headContents Contents to go into
+ *     the iframe's head. If possible pass a SafeHtml; string is supported for
+ *     backwards-compatibility only and uses goog.html.legacyconversions.
+ * @param {!goog.html.SafeHtml|string=} opt_bodyContents Contents to go into
+ *     the iframe's body. If possible pass a SafeHtml; string is supported for
+ *     backwards-compatibility only and uses goog.html.legacyconversions.
+ * @param {!goog.html.SafeStyle|string=} opt_styles CSS styles for the iframe
+ *     itself, before adding to the parent element. If possible pass a
+ *     SafeStyle; string is supported for backwards-compatibility only and
+ *     uses goog.html.legacyconversions.
+ * @param {boolean=} opt_quirks Whether to use quirks mode (false by default).
+ * @return {!HTMLIFrameElement} An iframe that has the specified contents.
+ */
+goog.dom.iframe.createWithContent = function(
+    parentElement, opt_headContents, opt_bodyContents, opt_styles, opt_quirks) {
+  var domHelper = goog.dom.getDomHelper(parentElement);
+
+  if (goog.isString(opt_headContents)) {
+    opt_headContents =
+        goog.html.legacyconversions.safeHtmlFromString(opt_headContents);
+  }
+  if (goog.isString(opt_bodyContents)) {
+    opt_bodyContents =
+        goog.html.legacyconversions.safeHtmlFromString(opt_bodyContents);
+  }
+  if (goog.isString(opt_styles)) {
+    opt_styles =
+        goog.html.legacyconversions.safeStyleFromString(opt_styles);
+  }
+
+  var content = goog.html.SafeHtml.create('html', {}, goog.html.SafeHtml.concat(
+      goog.html.SafeHtml.create('head', {}, opt_headContents),
+      goog.html.SafeHtml.create('body', {}, opt_bodyContents)));
+  if (!opt_quirks) {
+    content =
+        goog.html.SafeHtml.concat(goog.html.SafeHtml.DOCTYPE_HTML, content);
+  }
+
+  var iframe = goog.dom.iframe.createBlank(domHelper, opt_styles);
+
+  // Cannot manipulate iframe content until it is in a document.
+  parentElement.appendChild(iframe);
+  goog.dom.iframe.writeSafeContent(iframe, content);
+
+  return iframe;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/inputtype.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/inputtype.js b/externs/GCL/externs/goog/dom/inputtype.js
new file mode 100644
index 0000000..f5db6c8
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/inputtype.js
@@ -0,0 +1,66 @@
+// Copyright 2015 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 Defines the goog.dom.InputType enum.  This enumerates
+ * all input element types (for INPUT, BUTTON, SELECT and TEXTAREA
+ * elements) in either the the W3C HTML 4.01 index of elements or the
+ * HTML5 draft specification.
+ *
+ * References:
+ * http://www.w3.org/TR/html401/sgml/dtd.html#InputType
+ * http://www.w3.org/TR/html-markup/input.html#input
+ * https://html.spec.whatwg.org/multipage/forms.html#dom-input-type
+ * https://html.spec.whatwg.org/multipage/forms.html#dom-button-type
+ * https://html.spec.whatwg.org/multipage/forms.html#dom-select-type
+ * https://html.spec.whatwg.org/multipage/forms.html#dom-textarea-type
+ *
+ */
+goog.provide('goog.dom.InputType');
+
+
+/**
+ * Enum of all input types (for INPUT, BUTTON, SELECT and TEXTAREA elements)
+ * specified by the W3C HTML4.01 and HTML5 specifications.
+ * @enum {string}
+ */
+goog.dom.InputType = {
+  BUTTON: 'button',
+  CHECKBOX: 'checkbox',
+  COLOR: 'color',
+  DATE: 'date',
+  DATETIME: 'datetime',
+  DATETIME_LOCAL: 'datetime-local',
+  EMAIL: 'email',
+  FILE: 'file',
+  HIDDEN: 'hidden',
+  IMAGE: 'image',
+  MENU: 'menu',
+  MONTH: 'month',
+  NUMBER: 'number',
+  PASSWORD: 'password',
+  RADIO: 'radio',
+  RANGE: 'range',
+  RESET: 'reset',
+  SEARCH: 'search',
+  SELECT_MULTIPLE: 'select-multiple',
+  SELECT_ONE: 'select-one',
+  SUBMIT: 'submit',
+  TEL: 'tel',
+  TEXT: 'text',
+  TEXTAREA: 'textarea',
+  TIME: 'time',
+  URL: 'url',
+  WEEK: 'week'
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/iter.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/iter.js b/externs/GCL/externs/goog/dom/iter.js
new file mode 100644
index 0000000..7516414
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/iter.js
@@ -0,0 +1,129 @@
+// Copyright 2008 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 Iterators over DOM nodes.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.iter.AncestorIterator');
+goog.provide('goog.dom.iter.ChildIterator');
+goog.provide('goog.dom.iter.SiblingIterator');
+
+goog.require('goog.iter.Iterator');
+goog.require('goog.iter.StopIteration');
+
+
+
+/**
+ * Iterator over a Node's siblings.
+ * @param {Node} node The node to start with.
+ * @param {boolean=} opt_includeNode Whether to return the given node as the
+ *     first return value from next.
+ * @param {boolean=} opt_reverse Whether to traverse siblings in reverse
+ *     document order.
+ * @constructor
+ * @extends {goog.iter.Iterator}
+ */
+goog.dom.iter.SiblingIterator = function(node, opt_includeNode, opt_reverse) {
+  /**
+   * The current node, or null if iteration is finished.
+   * @type {Node}
+   * @private
+   */
+  this.node_ = node;
+
+  /**
+   * Whether to iterate in reverse.
+   * @type {boolean}
+   * @private
+   */
+  this.reverse_ = !!opt_reverse;
+
+  if (node && !opt_includeNode) {
+    this.next();
+  }
+};
+goog.inherits(goog.dom.iter.SiblingIterator, goog.iter.Iterator);
+
+
+/** @override */
+goog.dom.iter.SiblingIterator.prototype.next = function() {
+  var node = this.node_;
+  if (!node) {
+    throw goog.iter.StopIteration;
+  }
+  this.node_ = this.reverse_ ? node.previousSibling : node.nextSibling;
+  return node;
+};
+
+
+
+/**
+ * Iterator over an Element's children.
+ * @param {Element} element The element to iterate over.
+ * @param {boolean=} opt_reverse Optionally traverse children from last to
+ *     first.
+ * @param {number=} opt_startIndex Optional starting index.
+ * @constructor
+ * @extends {goog.dom.iter.SiblingIterator}
+ * @final
+ */
+goog.dom.iter.ChildIterator = function(element, opt_reverse, opt_startIndex) {
+  if (!goog.isDef(opt_startIndex)) {
+    opt_startIndex = opt_reverse && element.childNodes.length ?
+        element.childNodes.length - 1 : 0;
+  }
+  goog.dom.iter.SiblingIterator.call(this, element.childNodes[opt_startIndex],
+      true, opt_reverse);
+};
+goog.inherits(goog.dom.iter.ChildIterator, goog.dom.iter.SiblingIterator);
+
+
+
+/**
+ * Iterator over a Node's ancestors, stopping after the document body.
+ * @param {Node} node The node to start with.
+ * @param {boolean=} opt_includeNode Whether to return the given node as the
+ *     first return value from next.
+ * @constructor
+ * @extends {goog.iter.Iterator}
+ * @final
+ */
+goog.dom.iter.AncestorIterator = function(node, opt_includeNode) {
+  /**
+   * The current node, or null if iteration is finished.
+   * @type {Node}
+   * @private
+   */
+  this.node_ = node;
+
+  if (node && !opt_includeNode) {
+    this.next();
+  }
+};
+goog.inherits(goog.dom.iter.AncestorIterator, goog.iter.Iterator);
+
+
+/** @override */
+goog.dom.iter.AncestorIterator.prototype.next = function() {
+  var node = this.node_;
+  if (!node) {
+    throw goog.iter.StopIteration;
+  }
+  this.node_ = node.parentNode;
+  return node;
+};
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/multirange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/multirange.js b/externs/GCL/externs/goog/dom/multirange.js
new file mode 100644
index 0000000..9a57d25
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/multirange.js
@@ -0,0 +1,510 @@
+// Copyright 2008 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 working with W3C multi-part ranges.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.MultiRange');
+goog.provide('goog.dom.MultiRangeIterator');
+
+goog.require('goog.array');
+goog.require('goog.dom.AbstractMultiRange');
+goog.require('goog.dom.AbstractRange');
+goog.require('goog.dom.RangeIterator');
+goog.require('goog.dom.RangeType');
+goog.require('goog.dom.SavedRange');
+goog.require('goog.dom.TextRange');
+goog.require('goog.iter.StopIteration');
+goog.require('goog.log');
+
+
+
+/**
+ * Creates a new multi part range with no properties.  Do not use this
+ * constructor: use one of the goog.dom.Range.createFrom* methods instead.
+ * @constructor
+ * @extends {goog.dom.AbstractMultiRange}
+ * @final
+ */
+goog.dom.MultiRange = function() {
+  /**
+   * Logging object.
+   * @private {goog.log.Logger}
+   */
+  this.logger_ = goog.log.getLogger('goog.dom.MultiRange');
+
+  /**
+   * Array of browser sub-ranges comprising this multi-range.
+   * @private {Array<Range>}
+   */
+  this.browserRanges_ = [];
+
+  /**
+   * Lazily initialized array of range objects comprising this multi-range.
+   * @private {Array<goog.dom.TextRange>}
+   */
+  this.ranges_ = [];
+
+  /**
+   * Lazily computed sorted version of ranges_, sorted by start point.
+   * @private {Array<goog.dom.TextRange>?}
+   */
+  this.sortedRanges_ = null;
+
+  /**
+   * Lazily computed container node.
+   * @private {Node}
+   */
+  this.container_ = null;
+};
+goog.inherits(goog.dom.MultiRange, goog.dom.AbstractMultiRange);
+
+
+/**
+ * Creates a new range wrapper from the given browser selection object.  Do not
+ * use this method directly - please use goog.dom.Range.createFrom* instead.
+ * @param {Selection} selection The browser selection object.
+ * @return {!goog.dom.MultiRange} A range wrapper object.
+ */
+goog.dom.MultiRange.createFromBrowserSelection = function(selection) {
+  var range = new goog.dom.MultiRange();
+  for (var i = 0, len = selection.rangeCount; i < len; i++) {
+    range.browserRanges_.push(selection.getRangeAt(i));
+  }
+  return range;
+};
+
+
+/**
+ * Creates a new range wrapper from the given browser ranges.  Do not
+ * use this method directly - please use goog.dom.Range.createFrom* instead.
+ * @param {Array<Range>} browserRanges The browser ranges.
+ * @return {!goog.dom.MultiRange} A range wrapper object.
+ */
+goog.dom.MultiRange.createFromBrowserRanges = function(browserRanges) {
+  var range = new goog.dom.MultiRange();
+  range.browserRanges_ = goog.array.clone(browserRanges);
+  return range;
+};
+
+
+/**
+ * Creates a new range wrapper from the given goog.dom.TextRange objects.  Do
+ * not use this method directly - please use goog.dom.Range.createFrom* instead.
+ * @param {Array<goog.dom.TextRange>} textRanges The text range objects.
+ * @return {!goog.dom.MultiRange} A range wrapper object.
+ */
+goog.dom.MultiRange.createFromTextRanges = function(textRanges) {
+  var range = new goog.dom.MultiRange();
+  range.ranges_ = textRanges;
+  range.browserRanges_ = goog.array.map(textRanges, function(range) {
+    return range.getBrowserRangeObject();
+  });
+  return range;
+};
+
+
+// Method implementations
+
+
+/**
+ * Clears cached values.  Should be called whenever this.browserRanges_ is
+ * modified.
+ * @private
+ */
+goog.dom.MultiRange.prototype.clearCachedValues_ = function() {
+  this.ranges_ = [];
+  this.sortedRanges_ = null;
+  this.container_ = null;
+};
+
+
+/**
+ * @return {!goog.dom.MultiRange} A clone of this range.
+ * @override
+ */
+goog.dom.MultiRange.prototype.clone = function() {
+  return goog.dom.MultiRange.createFromBrowserRanges(this.browserRanges_);
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getType = function() {
+  return goog.dom.RangeType.MULTI;
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getBrowserRangeObject = function() {
+  // NOTE(robbyw): This method does not make sense for multi-ranges.
+  if (this.browserRanges_.length > 1) {
+    goog.log.warning(this.logger_,
+        'getBrowserRangeObject called on MultiRange with more than 1 range');
+  }
+  return this.browserRanges_[0];
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.setBrowserRangeObject = function(nativeRange) {
+  // TODO(robbyw): Look in to adding setBrowserSelectionObject.
+  return false;
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getTextRangeCount = function() {
+  return this.browserRanges_.length;
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getTextRange = function(i) {
+  if (!this.ranges_[i]) {
+    this.ranges_[i] = goog.dom.TextRange.createFromBrowserRange(
+        this.browserRanges_[i]);
+  }
+  return this.ranges_[i];
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getContainer = function() {
+  if (!this.container_) {
+    var nodes = [];
+    for (var i = 0, len = this.getTextRangeCount(); i < len; i++) {
+      nodes.push(this.getTextRange(i).getContainer());
+    }
+    this.container_ = goog.dom.findCommonAncestor.apply(null, nodes);
+  }
+  return this.container_;
+};
+
+
+/**
+ * @return {!Array<goog.dom.TextRange>} An array of sub-ranges, sorted by start
+ *     point.
+ */
+goog.dom.MultiRange.prototype.getSortedRanges = function() {
+  if (!this.sortedRanges_) {
+    this.sortedRanges_ = this.getTextRanges();
+    this.sortedRanges_.sort(function(a, b) {
+      var aStartNode = a.getStartNode();
+      var aStartOffset = a.getStartOffset();
+      var bStartNode = b.getStartNode();
+      var bStartOffset = b.getStartOffset();
+
+      if (aStartNode == bStartNode && aStartOffset == bStartOffset) {
+        return 0;
+      }
+
+      return goog.dom.Range.isReversed(aStartNode, aStartOffset, bStartNode,
+          bStartOffset) ? 1 : -1;
+    });
+  }
+  return this.sortedRanges_;
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getStartNode = function() {
+  return this.getSortedRanges()[0].getStartNode();
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getStartOffset = function() {
+  return this.getSortedRanges()[0].getStartOffset();
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getEndNode = function() {
+  // NOTE(robbyw): This may return the wrong node if any subranges overlap.
+  return goog.array.peek(this.getSortedRanges()).getEndNode();
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getEndOffset = function() {
+  // NOTE(robbyw): This may return the wrong value if any subranges overlap.
+  return goog.array.peek(this.getSortedRanges()).getEndOffset();
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.isRangeInDocument = function() {
+  return goog.array.every(this.getTextRanges(), function(range) {
+    return range.isRangeInDocument();
+  });
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.isCollapsed = function() {
+  return this.browserRanges_.length == 0 ||
+      this.browserRanges_.length == 1 && this.getTextRange(0).isCollapsed();
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getText = function() {
+  return goog.array.map(this.getTextRanges(), function(range) {
+    return range.getText();
+  }).join('');
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getHtmlFragment = function() {
+  return this.getValidHtml();
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getValidHtml = function() {
+  // NOTE(robbyw): This does not behave well if the sub-ranges overlap.
+  return goog.array.map(this.getTextRanges(), function(range) {
+    return range.getValidHtml();
+  }).join('');
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.getPastableHtml = function() {
+  // TODO(robbyw): This should probably do something smart like group TR and TD
+  // selections in to the same table.
+  return this.getValidHtml();
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.__iterator__ = function(opt_keys) {
+  return new goog.dom.MultiRangeIterator(this);
+};
+
+
+// RANGE ACTIONS
+
+
+/** @override */
+goog.dom.MultiRange.prototype.select = function() {
+  var selection = goog.dom.AbstractRange.getBrowserSelectionForWindow(
+      this.getWindow());
+  selection.removeAllRanges();
+  for (var i = 0, len = this.getTextRangeCount(); i < len; i++) {
+    selection.addRange(this.getTextRange(i).getBrowserRangeObject());
+  }
+};
+
+
+/** @override */
+goog.dom.MultiRange.prototype.removeContents = function() {
+  goog.array.forEach(this.getTextRanges(), function(range) {
+    range.removeContents();
+  });
+};
+
+
+// SAVE/RESTORE
+
+
+/** @override */
+goog.dom.MultiRange.prototype.saveUsingDom = function() {
+  return new goog.dom.DomSavedMultiRange_(this);
+};
+
+
+// RANGE MODIFICATION
+
+
+/**
+ * Collapses this range to a single point, either the first or last point
+ * depending on the parameter.  This will result in the number of ranges in this
+ * multi range becoming 1.
+ * @param {boolean} toAnchor Whether to collapse to the anchor.
+ * @override
+ */
+goog.dom.MultiRange.prototype.collapse = function(toAnchor) {
+  if (!this.isCollapsed()) {
+    var range = toAnchor ? this.getTextRange(0) : this.getTextRange(
+        this.getTextRangeCount() - 1);
+
+    this.clearCachedValues_();
+    range.collapse(toAnchor);
+    this.ranges_ = [range];
+    this.sortedRanges_ = [range];
+    this.browserRanges_ = [range.getBrowserRangeObject()];
+  }
+};
+
+
+// SAVED RANGE OBJECTS
+
+
+
+/**
+ * A SavedRange implementation using DOM endpoints.
+ * @param {goog.dom.MultiRange} range The range to save.
+ * @constructor
+ * @extends {goog.dom.SavedRange}
+ * @private
+ */
+goog.dom.DomSavedMultiRange_ = function(range) {
+  /**
+   * Array of saved ranges.
+   * @type {Array<goog.dom.SavedRange>}
+   * @private
+   */
+  this.savedRanges_ = goog.array.map(range.getTextRanges(), function(range) {
+    return range.saveUsingDom();
+  });
+};
+goog.inherits(goog.dom.DomSavedMultiRange_, goog.dom.SavedRange);
+
+
+/**
+ * @return {!goog.dom.MultiRange} The restored range.
+ * @override
+ */
+goog.dom.DomSavedMultiRange_.prototype.restoreInternal = function() {
+  var ranges = goog.array.map(this.savedRanges_, function(savedRange) {
+    return savedRange.restore();
+  });
+  return goog.dom.MultiRange.createFromTextRanges(ranges);
+};
+
+
+/** @override */
+goog.dom.DomSavedMultiRange_.prototype.disposeInternal = function() {
+  goog.dom.DomSavedMultiRange_.superClass_.disposeInternal.call(this);
+
+  goog.array.forEach(this.savedRanges_, function(savedRange) {
+    savedRange.dispose();
+  });
+  delete this.savedRanges_;
+};
+
+
+// RANGE ITERATION
+
+
+
+/**
+ * Subclass of goog.dom.TagIterator that iterates over a DOM range.  It
+ * adds functions to determine the portion of each text node that is selected.
+ *
+ * @param {goog.dom.MultiRange} range The range to traverse.
+ * @constructor
+ * @extends {goog.dom.RangeIterator}
+ * @final
+ */
+goog.dom.MultiRangeIterator = function(range) {
+  /**
+   * The list of range iterators left to traverse.
+   * @private {Array<goog.dom.RangeIterator>}
+   */
+  this.iterators_ = null;
+
+  /**
+   * The index of the current sub-iterator being traversed.
+   * @private {number}
+   */
+  this.currentIdx_ = 0;
+
+  if (range) {
+    this.iterators_ = goog.array.map(
+        range.getSortedRanges(),
+        function(r) {
+          return goog.iter.toIterator(r);
+        });
+  }
+
+  goog.dom.MultiRangeIterator.base(
+      this, 'constructor', range ? this.getStartNode() : null, false);
+};
+goog.inherits(goog.dom.MultiRangeIterator, goog.dom.RangeIterator);
+
+
+/** @override */
+goog.dom.MultiRangeIterator.prototype.getStartTextOffset = function() {
+  return this.iterators_[this.currentIdx_].getStartTextOffset();
+};
+
+
+/** @override */
+goog.dom.MultiRangeIterator.prototype.getEndTextOffset = function() {
+  return this.iterators_[this.currentIdx_].getEndTextOffset();
+};
+
+
+/** @override */
+goog.dom.MultiRangeIterator.prototype.getStartNode = function() {
+  return this.iterators_[0].getStartNode();
+};
+
+
+/** @override */
+goog.dom.MultiRangeIterator.prototype.getEndNode = function() {
+  return goog.array.peek(this.iterators_).getEndNode();
+};
+
+
+/** @override */
+goog.dom.MultiRangeIterator.prototype.isLast = function() {
+  return this.iterators_[this.currentIdx_].isLast();
+};
+
+
+/** @override */
+goog.dom.MultiRangeIterator.prototype.next = function() {
+  /** @preserveTry */
+  try {
+    var it = this.iterators_[this.currentIdx_];
+    var next = it.next();
+    this.setPosition(it.node, it.tagType, it.depth);
+    return next;
+  } catch (ex) {
+    if (ex !== goog.iter.StopIteration ||
+        this.iterators_.length - 1 == this.currentIdx_) {
+      throw ex;
+    } else {
+      // In case we got a StopIteration, increment counter and try again.
+      this.currentIdx_++;
+      return this.next();
+    }
+  }
+};
+
+
+/** @override */
+goog.dom.MultiRangeIterator.prototype.copyFrom = function(other) {
+  this.iterators_ = goog.array.clone(other.iterators_);
+  goog.dom.MultiRangeIterator.superClass_.copyFrom.call(this, other);
+};
+
+
+/**
+ * @return {!goog.dom.MultiRangeIterator} An identical iterator.
+ * @override
+ */
+goog.dom.MultiRangeIterator.prototype.clone = function() {
+  var copy = new goog.dom.MultiRangeIterator(null);
+  copy.copyFrom(this);
+  return copy;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/nodeiterator.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/nodeiterator.js b/externs/GCL/externs/goog/dom/nodeiterator.js
new file mode 100644
index 0000000..bca563c
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/nodeiterator.js
@@ -0,0 +1,87 @@
+// Copyright 2008 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 Iterator subclass for DOM tree traversal.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.NodeIterator');
+
+goog.require('goog.dom.TagIterator');
+
+
+
+/**
+ * A DOM tree traversal iterator.
+ *
+ * Starting with the given node, the iterator walks the DOM in order, reporting
+ * events for each node.  The iterator acts as a prefix iterator:
+ *
+ * <pre>
+ * &lt;div&gt;1&lt;span&gt;2&lt;/span&gt;3&lt;/div&gt;
+ * </pre>
+ *
+ * Will return the following nodes:
+ *
+ * <code>[div, 1, span, 2, 3]</code>
+ *
+ * With the following depths
+ *
+ * <code>[1, 1, 2, 2, 1]</code>
+ *
+ * Imagining <code>|</code> represents iterator position, the traversal stops at
+ * each of the following locations:
+ *
+ * <pre>&lt;div&gt;|1|&lt;span&gt;|2|&lt;/span&gt;3|&lt;/div&gt;</pre>
+ *
+ * The iterator can also be used in reverse mode, which will return the nodes
+ * and states in the opposite order.  The depths will be slightly different
+ * since, like in normal mode, the depth is computed *after* the last move.
+ *
+ * Lastly, it is possible to create an iterator that is unconstrained, meaning
+ * that it will continue iterating until the end of the document instead of
+ * until exiting the start node.
+ *
+ * @param {Node=} opt_node The start node.  Defaults to an empty iterator.
+ * @param {boolean=} opt_reversed Whether to traverse the tree in reverse.
+ * @param {boolean=} opt_unconstrained Whether the iterator is not constrained
+ *     to the starting node and its children.
+ * @param {number=} opt_depth The starting tree depth.
+ * @constructor
+ * @extends {goog.dom.TagIterator}
+ * @final
+ */
+goog.dom.NodeIterator = function(opt_node, opt_reversed,
+    opt_unconstrained, opt_depth) {
+  goog.dom.TagIterator.call(this, opt_node, opt_reversed, opt_unconstrained,
+      null, opt_depth);
+};
+goog.inherits(goog.dom.NodeIterator, goog.dom.TagIterator);
+
+
+/**
+ * Moves to the next position in the DOM tree.
+ * @return {Node} Returns the next node, or throws a goog.iter.StopIteration
+ *     exception if the end of the iterator's range has been reached.
+ * @override
+ */
+goog.dom.NodeIterator.prototype.next = function() {
+  do {
+    goog.dom.NodeIterator.superClass_.next.call(this);
+  } while (this.isEndTag());
+
+  return this.node;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/nodeoffset.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/nodeoffset.js b/externs/GCL/externs/goog/dom/nodeoffset.js
new file mode 100644
index 0000000..9a65dbe
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/nodeoffset.js
@@ -0,0 +1,114 @@
+// Copyright 2005 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 Object to store the offset from one node to another in a way
+ * that works on any similar DOM structure regardless of whether it is the same
+ * actual nodes.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.NodeOffset');
+
+goog.require('goog.Disposable');
+goog.require('goog.dom.TagName');
+
+
+
+/**
+ * Object to store the offset from one node to another in a way that works on
+ * any similar DOM structure regardless of whether it is the same actual nodes.
+ * @param {Node} node The node to get the offset for.
+ * @param {Node} baseNode The node to calculate the offset from.
+ * @extends {goog.Disposable}
+ * @constructor
+ * @final
+ */
+goog.dom.NodeOffset = function(node, baseNode) {
+  goog.Disposable.call(this);
+
+  /**
+   * A stack of childNode offsets.
+   * @type {Array<number>}
+   * @private
+   */
+  this.offsetStack_ = [];
+
+  /**
+   * A stack of childNode names.
+   * @type {Array<string>}
+   * @private
+   */
+  this.nameStack_ = [];
+
+  while (node && node.nodeName != goog.dom.TagName.BODY && node != baseNode) {
+    // Compute the sibling offset.
+    var siblingOffset = 0;
+    var sib = node.previousSibling;
+    while (sib) {
+      sib = sib.previousSibling;
+      ++siblingOffset;
+    }
+    this.offsetStack_.unshift(siblingOffset);
+    this.nameStack_.unshift(node.nodeName);
+
+    node = node.parentNode;
+  }
+};
+goog.inherits(goog.dom.NodeOffset, goog.Disposable);
+
+
+/**
+ * @return {string} A string representation of this object.
+ * @override
+ */
+goog.dom.NodeOffset.prototype.toString = function() {
+  var strs = [];
+  var name;
+  for (var i = 0; name = this.nameStack_[i]; i++) {
+    strs.push(this.offsetStack_[i] + ',' + name);
+  }
+  return strs.join('\n');
+};
+
+
+/**
+ * Walk the dom and find the node relative to baseNode.  Returns null on
+ * failure.
+ * @param {Node} baseNode The node to start walking from.  Should be equivalent
+ *     to the node passed in to the constructor, in that it should have the
+ *     same contents.
+ * @return {Node} The node relative to baseNode, or null on failure.
+ */
+goog.dom.NodeOffset.prototype.findTargetNode = function(baseNode) {
+  var name;
+  var curNode = baseNode;
+  for (var i = 0; name = this.nameStack_[i]; ++i) {
+    curNode = curNode.childNodes[this.offsetStack_[i]];
+
+    // Sanity check and make sure the element names match.
+    if (!curNode || curNode.nodeName != name) {
+      return null;
+    }
+  }
+  return curNode;
+};
+
+
+/** @override */
+goog.dom.NodeOffset.prototype.disposeInternal = function() {
+  delete this.offsetStack_;
+  delete this.nameStack_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/nodetype.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/nodetype.js b/externs/GCL/externs/goog/dom/nodetype.js
new file mode 100644
index 0000000..cccb470
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/nodetype.js
@@ -0,0 +1,48 @@
+// 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 Definition of goog.dom.NodeType.
+ */
+
+goog.provide('goog.dom.NodeType');
+
+
+/**
+ * Constants for the nodeType attribute in the Node interface.
+ *
+ * These constants match those specified in the Node interface. These are
+ * usually present on the Node object in recent browsers, but not in older
+ * browsers (specifically, early IEs) and thus are given here.
+ *
+ * In some browsers (early IEs), these are not defined on the Node object,
+ * so they are provided here.
+ *
+ * See http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247
+ * @enum {number}
+ */
+goog.dom.NodeType = {
+  ELEMENT: 1,
+  ATTRIBUTE: 2,
+  TEXT: 3,
+  CDATA_SECTION: 4,
+  ENTITY_REFERENCE: 5,
+  ENTITY: 6,
+  PROCESSING_INSTRUCTION: 7,
+  COMMENT: 8,
+  DOCUMENT: 9,
+  DOCUMENT_TYPE: 10,
+  DOCUMENT_FRAGMENT: 11,
+  NOTATION: 12
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/abstractpattern.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/abstractpattern.js b/externs/GCL/externs/goog/dom/pattern/abstractpattern.js
new file mode 100644
index 0000000..e785f76
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/abstractpattern.js
@@ -0,0 +1,58 @@
+// 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 DOM pattern base class.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.AbstractPattern');
+
+goog.require('goog.dom.pattern.MatchType');
+
+
+
+/**
+ * Base pattern class for DOM matching.
+ *
+ * @constructor
+ */
+goog.dom.pattern.AbstractPattern = function() {
+  /**
+   * The first node matched by this pattern.
+   * @type {Node}
+   */
+  this.matchedNode = null;
+};
+
+
+/**
+ * Reset any internal state this pattern keeps.
+ */
+goog.dom.pattern.AbstractPattern.prototype.reset = function() {
+  // The base implementation does nothing.
+};
+
+
+/**
+ * Test whether this pattern matches the given token.
+ *
+ * @param {Node} token Token to match against.
+ * @param {goog.dom.TagWalkType} type The type of token.
+ * @return {goog.dom.pattern.MatchType} {@code MATCH} if the pattern matches.
+ */
+goog.dom.pattern.AbstractPattern.prototype.matchToken = function(token, type) {
+  return goog.dom.pattern.MatchType.NO_MATCH;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/allchildren.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/allchildren.js b/externs/GCL/externs/goog/dom/pattern/allchildren.js
new file mode 100644
index 0000000..36abae4
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/allchildren.js
@@ -0,0 +1,72 @@
+// 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 DOM pattern to match any children of a tag.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.AllChildren');
+
+goog.require('goog.dom.pattern.AbstractPattern');
+goog.require('goog.dom.pattern.MatchType');
+
+
+
+/**
+ * Pattern object that matches any nodes at or below the current tree depth.
+ *
+ * @constructor
+ * @extends {goog.dom.pattern.AbstractPattern}
+ */
+goog.dom.pattern.AllChildren = function() {
+  /**
+   * Tracks the matcher's depth to detect the end of the tag.
+   *
+   * @private {number}
+   */
+  this.depth_ = 0;
+};
+goog.inherits(goog.dom.pattern.AllChildren, goog.dom.pattern.AbstractPattern);
+
+
+/**
+ * Test whether the given token is on the same level.
+ *
+ * @param {Node} token Token to match against.
+ * @param {goog.dom.TagWalkType} type The type of token.
+ * @return {goog.dom.pattern.MatchType} {@code MATCHING} if the token is on the
+ *     same level or deeper and {@code BACKTRACK_MATCH} if not.
+ * @override
+ */
+goog.dom.pattern.AllChildren.prototype.matchToken = function(token, type) {
+  this.depth_ += type;
+
+  if (this.depth_ >= 0) {
+    return goog.dom.pattern.MatchType.MATCHING;
+  } else {
+    this.depth_ = 0;
+    return goog.dom.pattern.MatchType.BACKTRACK_MATCH;
+  }
+};
+
+
+/**
+ * Reset any internal state this pattern keeps.
+ * @override
+ */
+goog.dom.pattern.AllChildren.prototype.reset = function() {
+  this.depth_ = 0;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/callback/callback.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/callback/callback.js b/externs/GCL/externs/goog/dom/pattern/callback/callback.js
new file mode 100644
index 0000000..7d7aa60
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/callback/callback.js
@@ -0,0 +1,82 @@
+// 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 Useful callback functions for the DOM matcher.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.callback');
+
+goog.require('goog.dom');
+goog.require('goog.dom.TagWalkType');
+goog.require('goog.iter');
+
+
+/**
+ * Callback function for use in {@link goog.dom.pattern.Matcher.addPattern}
+ * that removes the matched node from the tree.  Should be used in conjunciton
+ * with a {@link goog.dom.pattern.StartTag} pattern.
+ *
+ * @param {Node} node The node matched by the pattern.
+ * @param {goog.dom.TagIterator} position The position where the match
+ *     finished.
+ * @return {boolean} Returns true to indicate tree changes were made.
+ */
+goog.dom.pattern.callback.removeNode = function(node, position) {
+  // Find out which position would be next.
+  position.setPosition(node, goog.dom.TagWalkType.END_TAG);
+
+  goog.iter.nextOrValue(position, null);
+
+  // Remove the node.
+  goog.dom.removeNode(node);
+
+  // Correct for the depth change.
+  position.depth -= 1;
+
+  // Indicate that we made position/tree changes.
+  return true;
+};
+
+
+/**
+ * Callback function for use in {@link goog.dom.pattern.Matcher.addPattern}
+ * that removes the matched node from the tree and replaces it with its
+ * children.  Should be used in conjunction with a
+ * {@link goog.dom.pattern.StartTag} pattern.
+ *
+ * @param {Element} node The node matched by the pattern.
+ * @param {goog.dom.TagIterator} position The position where the match
+ *     finished.
+ * @return {boolean} Returns true to indicate tree changes were made.
+ */
+goog.dom.pattern.callback.flattenElement = function(node, position) {
+  // Find out which position would be next.
+  position.setPosition(node, node.firstChild ?
+      goog.dom.TagWalkType.START_TAG :
+      goog.dom.TagWalkType.END_TAG);
+
+  goog.iter.nextOrValue(position, null);
+
+  // Flatten the node.
+  goog.dom.flattenElement(node);
+
+  // Correct for the depth change.
+  position.depth -= 1;
+
+  // Indicate that we made position/tree changes.
+  return true;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/callback/counter.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/callback/counter.js b/externs/GCL/externs/goog/dom/pattern/callback/counter.js
new file mode 100644
index 0000000..7e9a7aa
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/callback/counter.js
@@ -0,0 +1,69 @@
+// 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 Callback object that counts matches.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.callback.Counter');
+
+
+
+/**
+ * Callback class for counting matches.
+ * @constructor
+ * @final
+ */
+goog.dom.pattern.callback.Counter = function() {
+  /**
+   * The count of objects matched so far.
+   *
+   * @type {number}
+   */
+  this.count = 0;
+
+  /**
+   * The callback function.  Suitable as a callback for
+   * {@link goog.dom.pattern.Matcher}.
+   * @private {Function}
+   */
+  this.callback_ = null;
+};
+
+
+/**
+ * Get a bound callback function that is suitable as a callback for
+ * {@link goog.dom.pattern.Matcher}.
+ *
+ * @return {!Function} A callback function.
+ */
+goog.dom.pattern.callback.Counter.prototype.getCallback = function() {
+  if (!this.callback_) {
+    this.callback_ = goog.bind(function() {
+      this.count++;
+      return false;
+    }, this);
+  }
+  return this.callback_;
+};
+
+
+/**
+ * Reset the counter.
+ */
+goog.dom.pattern.callback.Counter.prototype.reset = function() {
+  this.count = 0;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/childmatches.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/childmatches.js b/externs/GCL/externs/goog/dom/pattern/childmatches.js
new file mode 100644
index 0000000..72d6674
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/childmatches.js
@@ -0,0 +1,145 @@
+// 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 DOM pattern to match any children of a tag, and
+ * specifically collect those that match a child pattern.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.ChildMatches');
+
+goog.require('goog.dom.pattern.AllChildren');
+goog.require('goog.dom.pattern.MatchType');
+
+
+
+/**
+ * Pattern object that matches any nodes at or below the current tree depth.
+ *
+ * @param {goog.dom.pattern.AbstractPattern} childPattern Pattern to collect
+ *     child matches of.
+ * @param {number=} opt_minimumMatches Enforce a minimum nuber of matches.
+ *     Defaults to 0.
+ * @constructor
+ * @extends {goog.dom.pattern.AllChildren}
+ * @final
+ */
+goog.dom.pattern.ChildMatches = function(childPattern, opt_minimumMatches) {
+  /**
+   * The child pattern to collect matches from.
+   *
+   * @private {goog.dom.pattern.AbstractPattern}
+   */
+  this.childPattern_ = childPattern;
+
+  /**
+   * Array of matched child nodes.
+   *
+   * @type {Array<Node>}
+   */
+  this.matches = [];
+
+  /**
+   * Minimum number of matches.
+   *
+   * @private {number}
+   */
+  this.minimumMatches_ = opt_minimumMatches || 0;
+
+  /**
+   * Whether the pattern has recently matched or failed to match and will need
+   * to be reset when starting a new round of matches.
+   *
+   * @private {boolean}
+   */
+  this.needsReset_ = false;
+
+  goog.dom.pattern.ChildMatches.base(this, 'constructor');
+};
+goog.inherits(goog.dom.pattern.ChildMatches, goog.dom.pattern.AllChildren);
+
+
+/**
+ * Test whether the given token is on the same level.
+ *
+ * @param {Node} token Token to match against.
+ * @param {goog.dom.TagWalkType} type The type of token.
+ * @return {goog.dom.pattern.MatchType} {@code MATCHING} if the token is on the
+ *     same level or deeper and {@code BACKTRACK_MATCH} if not.
+ * @override
+ */
+goog.dom.pattern.ChildMatches.prototype.matchToken = function(token, type) {
+  // Defer resets so we maintain our matches array until the last possible time.
+  if (this.needsReset_) {
+    this.reset();
+  }
+
+  // Call the super-method to ensure we stay in the child tree.
+  var status =
+      goog.dom.pattern.AllChildren.prototype.matchToken.apply(this, arguments);
+
+  switch (status) {
+    case goog.dom.pattern.MatchType.MATCHING:
+      var backtrack = false;
+
+      switch (this.childPattern_.matchToken(token, type)) {
+        case goog.dom.pattern.MatchType.BACKTRACK_MATCH:
+          backtrack = true;
+        case goog.dom.pattern.MatchType.MATCH:
+          // Collect the match.
+          this.matches.push(this.childPattern_.matchedNode);
+          break;
+
+        default:
+          // Keep trying if we haven't hit a terminal state.
+          break;
+      }
+
+      if (backtrack) {
+        // The only interesting result is a MATCH, since BACKTRACK_MATCH means
+        // we are hitting an infinite loop on something like a Repeat(0).
+        if (this.childPattern_.matchToken(token, type) ==
+            goog.dom.pattern.MatchType.MATCH) {
+          this.matches.push(this.childPattern_.matchedNode);
+        }
+      }
+      return goog.dom.pattern.MatchType.MATCHING;
+
+    case goog.dom.pattern.MatchType.BACKTRACK_MATCH:
+      // TODO(robbyw): this should return something like BACKTRACK_NO_MATCH
+      // when we don't meet our minimum.
+      this.needsReset_ = true;
+      return (this.matches.length >= this.minimumMatches_) ?
+             goog.dom.pattern.MatchType.BACKTRACK_MATCH :
+             goog.dom.pattern.MatchType.NO_MATCH;
+
+    default:
+      this.needsReset_ = true;
+      return status;
+  }
+};
+
+
+/**
+ * Reset any internal state this pattern keeps.
+ * @override
+ */
+goog.dom.pattern.ChildMatches.prototype.reset = function() {
+  this.needsReset_ = false;
+  this.matches.length = 0;
+  this.childPattern_.reset();
+  goog.dom.pattern.AllChildren.prototype.reset.call(this);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/endtag.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/endtag.js b/externs/GCL/externs/goog/dom/pattern/endtag.js
new file mode 100644
index 0000000..409f952
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/endtag.js
@@ -0,0 +1,54 @@
+// 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 DOM pattern to match the end of a tag.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.EndTag');
+
+goog.require('goog.dom.TagWalkType');
+goog.require('goog.dom.pattern.Tag');
+
+
+
+/**
+ * Pattern object that matches a closing tag.
+ *
+ * @param {string|RegExp} tag Name of the tag.  Also will accept a regular
+ *     expression to match against the tag name.
+ * @param {Object=} opt_attrs Optional map of attribute names to desired values.
+ *     This pattern will only match when all attributes are present and match
+ *     the string or regular expression value provided here.
+ * @param {Object=} opt_styles Optional map of CSS style names to desired
+ *     values. This pattern will only match when all styles are present and
+ *     match the string or regular expression value provided here.
+ * @param {Function=} opt_test Optional function that takes the element as a
+ *     parameter and returns true if this pattern should match it.
+ * @constructor
+ * @extends {goog.dom.pattern.Tag}
+ * @final
+ */
+goog.dom.pattern.EndTag = function(tag, opt_attrs, opt_styles, opt_test) {
+  goog.dom.pattern.Tag.call(
+      this,
+      tag,
+      goog.dom.TagWalkType.END_TAG,
+      opt_attrs,
+      opt_styles,
+      opt_test);
+};
+goog.inherits(goog.dom.pattern.EndTag, goog.dom.pattern.Tag);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/fulltag.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/fulltag.js b/externs/GCL/externs/goog/dom/pattern/fulltag.js
new file mode 100644
index 0000000..d12ded1
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/fulltag.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 DOM pattern to match a tag and all of its children.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.FullTag');
+
+goog.require('goog.dom.pattern.MatchType');
+goog.require('goog.dom.pattern.StartTag');
+goog.require('goog.dom.pattern.Tag');
+
+
+
+/**
+ * Pattern object that matches a full tag including all its children.
+ *
+ * @param {string|RegExp} tag Name of the tag.  Also will accept a regular
+ *     expression to match against the tag name.
+ * @param {Object=} opt_attrs Optional map of attribute names to desired values.
+ *     This pattern will only match when all attributes are present and match
+ *     the string or regular expression value provided here.
+ * @param {Object=} opt_styles Optional map of CSS style names to desired
+ *     values. This pattern will only match when all styles are present and
+ *     match the string or regular expression value provided here.
+ * @param {Function=} opt_test Optional function that takes the element as a
+ *     parameter and returns true if this pattern should match it.
+ * @constructor
+ * @extends {goog.dom.pattern.StartTag}
+ * @final
+ */
+goog.dom.pattern.FullTag = function(tag, opt_attrs, opt_styles, opt_test) {
+  /**
+   * Tracks the matcher's depth to detect the end of the tag.
+   *
+   * @private {number}
+   */
+  this.depth_ = 0;
+
+  goog.dom.pattern.FullTag.base(
+      this, 'constructor', tag, opt_attrs, opt_styles, opt_test);
+};
+goog.inherits(goog.dom.pattern.FullTag, goog.dom.pattern.StartTag);
+
+
+/**
+ * Test whether the given token is a start tag token which matches the tag name,
+ * style, and attributes provided in the constructor.
+ *
+ * @param {Node} token Token to match against.
+ * @param {goog.dom.TagWalkType} type The type of token.
+ * @return {goog.dom.pattern.MatchType} <code>MATCH</code> at the end of our
+ *    tag, <code>MATCHING</code> if we are within the tag, and
+ *    <code>NO_MATCH</code> if the starting tag does not match.
+ * @override
+ */
+goog.dom.pattern.FullTag.prototype.matchToken = function(token, type) {
+  if (!this.depth_) {
+    // If we have not yet started, make sure we match as a StartTag.
+    if (goog.dom.pattern.Tag.prototype.matchToken.call(this, token, type)) {
+      this.depth_ = type;
+      return goog.dom.pattern.MatchType.MATCHING;
+
+    } else {
+      return goog.dom.pattern.MatchType.NO_MATCH;
+    }
+  } else {
+    this.depth_ += type;
+
+    return this.depth_ ?
+           goog.dom.pattern.MatchType.MATCHING :
+           goog.dom.pattern.MatchType.MATCH;
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/pattern/matcher.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/pattern/matcher.js b/externs/GCL/externs/goog/dom/pattern/matcher.js
new file mode 100644
index 0000000..ea4a1e5
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/pattern/matcher.js
@@ -0,0 +1,144 @@
+// 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 DOM pattern matcher.  Allows for simple searching of DOM
+ * using patterns descended from {@link goog.dom.pattern.AbstractPattern}.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.dom.pattern.Matcher');
+
+goog.require('goog.dom.TagIterator');
+goog.require('goog.dom.pattern.MatchType');
+goog.require('goog.iter');
+
+
+// TODO(robbyw): Allow for backtracks of size > 1.
+
+
+
+/**
+ * Given a set of patterns and a root node, this class tests the patterns in
+ * parallel.
+ *
+ * It is not (yet) a smart matcher - it doesn't do any advanced backtracking.
+ * Given the pattern <code>DIV, SPAN</code> the matcher will not match
+ * <code>DIV, DIV, SPAN</code> because it starts matching at the first
+ * <code>DIV</code>, fails to match <code>SPAN</code> at the second, and never
+ * backtracks to try again.
+ *
+ * It is also possible to have a set of complex patterns that when matched in
+ * parallel will miss some possible matches.  Running multiple times will catch
+ * all matches eventually.
+ *
+ * @constructor
+ * @final
+ */
+goog.dom.pattern.Matcher = function() {
+  /**
+   * Array of patterns to attempt to match in parallel.
+   *
+   * @private {Array<goog.dom.pattern.AbstractPattern>}
+   */
+  this.patterns_ = [];
+
+  /**
+   * Array of callbacks to call when a pattern is matched.  The indexing is the
+   * same as the {@link #patterns_} array.
+   *
+   * @private {Array<Function>}
+   */
+  this.callbacks_ = [];
+};
+
+
+/**
+ * Adds a pattern to be matched.  The callback can return an object whose keys
+ * are processing instructions.
+ *
+ * @param {goog.dom.pattern.AbstractPattern} pattern The pattern to add.
+ * @param {Function} callback Function to call when a match is found.  Uses
+ *     the above semantics.
+ */
+goog.dom.pattern.Matcher.prototype.addPattern = function(pattern, callback) {
+  this.patterns_.push(pattern);
+  this.callbacks_.push(callback);
+};
+
+
+/**
+ * Resets all the patterns.
+ *
+ * @private
+ */
+goog.dom.pattern.Matcher.prototype.reset_ = function() {
+  for (var i = 0, len = this.patterns_.length; i < len; i++) {
+    this.patterns_[i].reset();
+  }
+};
+
+
+/**
+ * Test the given node against all patterns.
+ *
+ * @param {goog.dom.TagIterator} position A position in a node walk that is
+ *     located at the token to process.
+ * @return {boolean} Whether a pattern modified the position or tree
+ *     and its callback resulted in DOM structure or position modification.
+ * @private
+ */
+goog.dom.pattern.Matcher.prototype.matchToken_ = function(position) {
+  for (var i = 0, len = this.patterns_.length; i < len; i++) {
+    var pattern = this.patterns_[i];
+    switch (pattern.matchToken(position.node, position.tagType)) {
+      case goog.dom.pattern.MatchType.MATCH:
+      case goog.dom.pattern.MatchType.BACKTRACK_MATCH:
+        var callback = this.callbacks_[i];
+
+        // Callbacks are allowed to modify the current position, but must
+        // return true if the do.
+        if (callback(pattern.matchedNode, position, pattern)) {
+          return true;
+        }
+
+      default:
+        // Do nothing.
+        break;
+    }
+  }
+
+  return false;
+};
+
+
+/**
+ * Match the set of patterns against a match tree.
+ *
+ * @param {Node} node The root node of the tree to match.
+ */
+goog.dom.pattern.Matcher.prototype.match = function(node) {
+  var position = new goog.dom.TagIterator(node);
+
+  this.reset_();
+
+  goog.iter.forEach(position, function() {
+    while (this.matchToken_(position)) {
+      // Since we've moved, our old pattern statuses don't make sense any more.
+      // Reset them.
+      this.reset_();
+    }
+  }, this);
+};


[42/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/cssom/iframe/style.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/cssom/iframe/style.js b/externs/GCL/externs/goog/cssom/iframe/style.js
new file mode 100644
index 0000000..24c8c05
--- /dev/null
+++ b/externs/GCL/externs/goog/cssom/iframe/style.js
@@ -0,0 +1,1016 @@
+// 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.
+// All Rights Reserved.
+
+/**
+ * @fileoverview Provides utility routines for copying modified
+ * {@code CSSRule} objects from the parent document into iframes so that any
+ * content in the iframe will be styled as if it was inline in the parent
+ * document.
+ *
+ * <p>
+ * For example, you might have this CSS rule:
+ *
+ * #content .highlighted { background-color: yellow; }
+ *
+ * And this DOM structure:
+ *
+ * <div id="content">
+ *   <iframe />
+ * </div>
+ *
+ * Then inside the iframe you have:
+ *
+ * <body>
+ * <div class="highlighted">
+ * </body>
+ *
+ * If you copied the CSS rule directly into the iframe, it wouldn't match the
+ * .highlighted div. So we rewrite the original stylesheets based on the
+ * context where the iframe is going to be inserted. In this case the CSS
+ * selector would be rewritten to:
+ *
+ * body .highlighted { background-color: yellow; }
+ * </p>
+ *
+ */
+
+
+goog.provide('goog.cssom.iframe.style');
+
+goog.require('goog.asserts');
+goog.require('goog.cssom');
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.classlist');
+goog.require('goog.string');
+goog.require('goog.style');
+goog.require('goog.userAgent');
+
+
+/**
+ * Regexp that matches "a", "a:link", "a:visited", etc.
+ * @type {RegExp}
+ * @private
+ */
+goog.cssom.iframe.style.selectorPartAnchorRegex_ =
+    /a(:(link|visited|active|hover))?/;
+
+
+/**
+ * Delimiter between selectors (h1, h2)
+ * @type {string}
+ * @private
+ */
+goog.cssom.iframe.style.SELECTOR_DELIMITER_ = ',';
+
+
+/**
+ * Delimiter between selector parts (.main h1)
+ * @type {string}
+ * @private
+ */
+goog.cssom.iframe.style.SELECTOR_PART_DELIMITER_ = ' ';
+
+
+/**
+ * Delimiter marking the start of a css rules section ( h1 { )
+ * @type {string}
+ * @private
+ */
+goog.cssom.iframe.style.DECLARATION_START_DELIMITER_ = '{';
+
+
+/**
+ * Delimiter marking the end of a css rules section ( } )
+ * @type {string}
+ * @private
+ */
+goog.cssom.iframe.style.DECLARATION_END_DELIMITER_ = '}\n';
+
+
+
+/**
+ * Class representing a CSS rule set. A rule set is something like this:
+ * h1, h2 { font-family: Arial; color: red; }
+ * @constructor
+ * @private
+ */
+goog.cssom.iframe.style.CssRuleSet_ = function() {
+  /**
+   * Text of the declarations inside the rule set.
+   * For example: 'font-family: Arial; color: red;'
+   * @type {string}
+   */
+  this.declarationText = '';
+
+  /**
+   * Array of CssSelector objects, one for each selector.
+   * Example: [h1, h2]
+   * @type {Array<goog.cssom.iframe.style.CssSelector_>}
+   */
+  this.selectors = [];
+};
+
+
+/**
+ * Initializes the rule set from a {@code CSSRule}.
+ *
+ * @param {CSSRule} cssRule The {@code CSSRule} to initialize from.
+ * @return {boolean} True if initialization succeeded. We only support
+ *     {@code CSSStyleRule} and {@code CSSFontFaceRule} objects.
+ */
+goog.cssom.iframe.style.CssRuleSet_.prototype.initializeFromCssRule =
+    function(cssRule) {
+  var ruleStyle = cssRule.style; // Cache object for performance.
+  if (!ruleStyle) {
+    return false;
+  }
+  var selector;
+  var declarations = '';
+  if (ruleStyle &&
+      (selector = cssRule.selectorText) &&
+      (declarations = ruleStyle.cssText)) {
+    // IE get confused about cssText context if a stylesheet uses the
+    // mid-pass hack, and it ends up with an open comment (/*) but no
+    // closing comment. This will effectively comment out large parts
+    // of generated stylesheets later. This errs on the safe side by
+    // always tacking on an empty comment to force comments to be closed
+    // We used to check for a troublesome open comment using a regular
+    // expression, but it's faster not to check and always do this.
+    if (goog.userAgent.IE) {
+      declarations += '/* */';
+    }
+  } else if (cssRule.cssText) {
+    var cssSelectorMatch = /([^\{]+)\{/;
+    var endTagMatch = /\}[^\}]*$/g;
+    // cssRule.cssText contains both selector and declarations:
+    // parse them out.
+    selector = cssSelectorMatch.exec(cssRule.cssText)[1];
+    // Remove selector, {, and trailing }.
+    declarations = cssRule.cssText.replace(cssSelectorMatch, '').replace(
+        endTagMatch, '');
+  }
+  if (selector) {
+    this.setSelectorsFromString(selector);
+    this.declarationText = declarations;
+    return true;
+  }
+  return false;
+};
+
+
+/**
+ * Parses a selectors string (which may contain multiple comma-delimited
+ * selectors) and loads the results into this.selectors.
+ * @param {string} selectorsString String containing selectors.
+ */
+goog.cssom.iframe.style.CssRuleSet_.prototype.setSelectorsFromString =
+    function(selectorsString) {
+  this.selectors = [];
+  var selectors = selectorsString.split(/,\s*/gm);
+  for (var i = 0; i < selectors.length; i++) {
+    var selector = selectors[i];
+    if (selector.length > 0) {
+      this.selectors.push(new goog.cssom.iframe.style.CssSelector_(selector));
+    }
+  }
+};
+
+
+/**
+ * Make a copy of this ruleset.
+ * @return {!goog.cssom.iframe.style.CssRuleSet_} A new CssRuleSet containing
+ *     the same data as this one.
+ */
+goog.cssom.iframe.style.CssRuleSet_.prototype.clone = function() {
+  var newRuleSet = new goog.cssom.iframe.style.CssRuleSet_();
+  newRuleSet.selectors = this.selectors.concat();
+  newRuleSet.declarationText = this.declarationText;
+  return newRuleSet;
+};
+
+
+/**
+ * Set the declaration text with properties from a given object.
+ * @param {Object} sourceObject Object whose properties and values should
+ *     be used to generate the declaration text.
+ * @param {boolean=} opt_important Whether !important should be added to each
+ *     declaration.
+ */
+goog.cssom.iframe.style.CssRuleSet_.prototype.setDeclarationTextFromObject =
+    function(sourceObject, opt_important) {
+  var stringParts = [];
+  // TODO(user): for ... in is costly in IE6 (extra garbage collection).
+  for (var prop in sourceObject) {
+    var value = sourceObject[prop];
+    if (value) {
+      stringParts.push(prop,
+                       ':',
+                       value, (opt_important ? ' !important' : ''),
+                       ';');
+    }
+  }
+  this.declarationText = stringParts.join('');
+};
+
+
+/**
+ * Serializes this CssRuleSet_ into an array as a series of strings.
+ * The array can then be join()-ed to get a string representation
+ * of this ruleset.
+ * @param {Array<string>} array The array to which to append strings.
+ */
+goog.cssom.iframe.style.CssRuleSet_.prototype.writeToArray = function(array) {
+  var selectorCount = this.selectors.length;
+  var matchesAnchorTag = false;
+  for (var i = 0; i < selectorCount; i++) {
+    var selectorParts = this.selectors[i].parts;
+    var partCount = selectorParts.length;
+    for (var j = 0; j < partCount; j++) {
+      array.push(selectorParts[j].inputString_,
+                 goog.cssom.iframe.style.SELECTOR_PART_DELIMITER_);
+    }
+    if (i < (selectorCount - 1)) {
+      array.push(goog.cssom.iframe.style.SELECTOR_DELIMITER_);
+    }
+    if (goog.userAgent.GECKO &&
+        !goog.userAgent.isVersionOrHigher('1.9a')) {
+      // In Gecko pre-1.9 (Firefox 2 and lower) we need to add !important
+      // to rulesets that match "A" tags, otherwise Gecko's built-in
+      // stylesheet will take precedence when designMode is on.
+      matchesAnchorTag = matchesAnchorTag ||
+          goog.cssom.iframe.style.selectorPartAnchorRegex_.test(
+              selectorParts[partCount - 1].inputString_);
+    }
+  }
+  var declarationText = this.declarationText;
+  if (matchesAnchorTag) {
+    declarationText = goog.cssom.iframe.style.makeColorRuleImportant_(
+        declarationText);
+  }
+  array.push(goog.cssom.iframe.style.DECLARATION_START_DELIMITER_,
+             declarationText,
+             goog.cssom.iframe.style.DECLARATION_END_DELIMITER_);
+};
+
+
+/**
+ * Regexp that matches "color: value;".
+ * @type {RegExp}
+ * @private
+ */
+goog.cssom.iframe.style.colorImportantReplaceRegex_ =
+    /(^|;|{)\s*color:([^;]+);/g;
+
+
+/**
+ * Adds !important to a css color: rule
+ * @param {string} cssText Text of the CSS rule(s) to modify.
+ * @return {string} Text with !important added to the color: rule if found.
+ * @private
+ */
+goog.cssom.iframe.style.makeColorRuleImportant_ = function(cssText) {
+  // Replace to insert a "! important" string.
+  return cssText.replace(goog.cssom.iframe.style.colorImportantReplaceRegex_,
+                         '$1 color: $2 ! important; ');
+};
+
+
+
+/**
+ * Represents a single CSS selector, as described in
+ * http://www.w3.org/TR/REC-CSS2/selector.html
+ * Currently UNSUPPORTED are the following selector features:
+ * <ul>
+ *   <li>pseudo-classes (:hover)
+ *   <li>child selectors (div > h1)
+ *   <li>adjacent sibling selectors (div + h1)
+ *   <li>attribute selectors (input[type=submit])
+ * </ul>
+ * @param {string=} opt_selectorString String containing selectors to parse.
+ * @constructor
+ * @private
+ */
+goog.cssom.iframe.style.CssSelector_ = function(opt_selectorString) {
+
+  /**
+   * Object to track ancestry matches to speed up repeatedly testing this
+   * CssSelector against the same NodeAncestry object.
+   * @type {Object}
+   * @private
+   */
+  this.ancestryMatchCache_ = {};
+  if (opt_selectorString) {
+    this.setPartsFromString_(opt_selectorString);
+  }
+};
+
+
+/**
+ * Parses a selector string into individual parts.
+ * @param {string} selectorString A string containing a CSS selector.
+ * @private
+ */
+goog.cssom.iframe.style.CssSelector_.prototype.setPartsFromString_ =
+    function(selectorString) {
+  var parts = [];
+  var selectorPartStrings = selectorString.split(/\s+/gm);
+  for (var i = 0; i < selectorPartStrings.length; i++) {
+    if (!selectorPartStrings[i]) {
+      continue; // Skip empty strings.
+    }
+    var part = new goog.cssom.iframe.style.CssSelectorPart_(
+        selectorPartStrings[i]);
+    parts.push(part);
+  }
+  this.parts = parts;
+};
+
+
+/**
+ * Tests to see what part of a DOM element hierarchy would be matched by
+ * this selector, and returns the indexes of the matching element and matching
+ * selector part.
+ * <p>
+ * For example, given this hierarchy:
+ *   document > html > body > div.content > div.sidebar > p
+ * and this CSS selector:
+ *   body div.sidebar h1
+ * This would return {elementIndex: 4, selectorPartIndex: 1},
+ * indicating that the element at index 4 matched
+ * the css selector at index 1.
+ * </p>
+ * @param {goog.cssom.iframe.style.NodeAncestry_} elementAncestry Object
+ *     representing an element and its ancestors.
+ * @return {Object} Object with the properties elementIndex and
+ *     selectorPartIndex, or null if there was no match.
+ */
+goog.cssom.iframe.style.CssSelector_.prototype.matchElementAncestry =
+    function(elementAncestry) {
+
+  var ancestryUid = elementAncestry.uid;
+  if (this.ancestryMatchCache_[ancestryUid]) {
+    return this.ancestryMatchCache_[ancestryUid];
+  }
+
+  // Walk through the selector parts and see how far down the element hierarchy
+  // we can go while matching the selector parts.
+  var elementIndex = 0;
+  var match = null;
+  var selectorPart = null;
+  var lastSelectorPart = null;
+  var ancestorNodes = elementAncestry.nodes;
+  var ancestorNodeCount = ancestorNodes.length;
+
+  for (var i = 0; i <= this.parts.length; i++) {
+    selectorPart = this.parts[i];
+    while (elementIndex < ancestorNodeCount) {
+      var currentElementInfo = ancestorNodes[elementIndex];
+      if (selectorPart &&
+          selectorPart.testElement(currentElementInfo)) {
+        match = {
+          elementIndex: elementIndex,
+          selectorPartIndex: i
+        };
+        elementIndex++;
+        break;
+      } else if (lastSelectorPart &&
+                 lastSelectorPart.testElement(currentElementInfo)) {
+        match = {
+          elementIndex: elementIndex,
+          selectorPartIndex: i - 1
+        };
+      }
+      elementIndex++;
+    }
+    lastSelectorPart = selectorPart;
+  }
+  this.ancestryMatchCache_[ancestryUid] = match;
+  return match;
+};
+
+
+
+/**
+ * Represents one part of a CSS Selector. For example in the selector
+ * 'body #foo .bar', body, #foo, and .bar would be considered selector parts.
+ * In the official CSS spec these are called "simple selectors".
+ * @param {string} selectorPartString A string containing the selector part
+ *     in css format.
+ * @constructor
+ * @private
+ */
+goog.cssom.iframe.style.CssSelectorPart_ = function(selectorPartString) {
+  // Only one CssSelectorPart instance should exist for a given string.
+  var cacheEntry = goog.cssom.iframe.style.CssSelectorPart_.instances_[
+      selectorPartString];
+  if (cacheEntry) {
+    return cacheEntry;
+  }
+
+  // Optimization to avoid the more-expensive lookahead.
+  var identifiers;
+  if (selectorPartString.match(/[#\.]/)) {
+    // Lookahead regexp, won't work on IE 5.0.
+    identifiers = selectorPartString.split(/(?=[#\.])/);
+  } else {
+    identifiers = [selectorPartString];
+  }
+  var properties = {};
+  for (var i = 0; i < identifiers.length; i++) {
+    var identifier = identifiers[i];
+    if (identifier.charAt(0) == '.') {
+      properties.className = identifier.substring(1, identifier.length);
+    } else if (identifier.charAt(0) == '#') {
+      properties.id = identifier.substring(1, identifier.length);
+    } else {
+      properties.tagName = identifier.toUpperCase();
+    }
+  }
+  this.inputString_ = selectorPartString;
+  this.matchProperties_ = properties;
+  this.testedElements_ = {};
+  goog.cssom.iframe.style.CssSelectorPart_.instances_[selectorPartString] =
+      this;
+};
+
+
+/**
+ * Cache of existing CssSelectorPart_ instances.
+ * @type {Object}
+ * @private
+ */
+goog.cssom.iframe.style.CssSelectorPart_.instances_ = {};
+
+
+/**
+ * Test whether an element matches this selector part, considered in isolation.
+ * @param {Object} elementInfo Element properties to test.
+ * @return {boolean} Whether the element matched.
+ */
+goog.cssom.iframe.style.CssSelectorPart_.prototype.testElement =
+    function(elementInfo) {
+
+  var elementUid = elementInfo.uid;
+  var cachedMatch = this.testedElements_[elementUid];
+  if (typeof cachedMatch != 'undefined') {
+    return cachedMatch;
+  }
+
+  var matchProperties = this.matchProperties_;
+  var testTag = matchProperties.tagName;
+  var testClass = matchProperties.className;
+  var testId = matchProperties.id;
+
+  var matched = true;
+  if (testTag && testTag != '*' && testTag != elementInfo.nodeName) {
+    matched = false;
+  } else if (testId && testId != elementInfo.id) {
+    matched = false;
+  } else if (testClass &&
+             !elementInfo.classNames[testClass]) {
+    matched = false;
+  }
+
+  this.testedElements_[elementUid] = matched;
+  return matched;
+};
+
+
+
+/**
+ * Represents an element and all its parent/ancestor nodes.
+ * This class exists as an optimization so we run tests on an element
+ * hierarchy multiple times without walking the dom each time.
+ * @param {Element} el The DOM element whose ancestry should be stored.
+ * @constructor
+ * @private
+ */
+goog.cssom.iframe.style.NodeAncestry_ = function(el) {
+  var node = el;
+  var nodeUid = goog.getUid(node);
+
+  // Return an existing object from the cache if one exits for this node.
+  var ancestry = goog.cssom.iframe.style.NodeAncestry_.instances_[nodeUid];
+  if (ancestry) {
+    return ancestry;
+  }
+
+  var nodes = [];
+  do {
+    var nodeInfo = {
+      id: node.id,
+      nodeName: node.nodeName
+    };
+    nodeInfo.uid = goog.getUid(nodeInfo);
+    var className = node.className;
+    var classNamesLookup = {};
+    if (className) {
+      var classNames = goog.dom.classlist.get(goog.asserts.assertElement(node));
+      for (var i = 0; i < classNames.length; i++) {
+        classNamesLookup[classNames[i]] = 1;
+      }
+    }
+    nodeInfo.classNames = classNamesLookup;
+    nodes.unshift(nodeInfo);
+  } while (node = node.parentNode);
+
+  /**
+   * Array of nodes in order of hierarchy from the top of the document
+   * to the node passed to the constructor
+   * @type {Array<Node>}
+   */
+  this.nodes = nodes;
+
+  this.uid = goog.getUid(this);
+  goog.cssom.iframe.style.NodeAncestry_.instances_[nodeUid] = this;
+};
+
+
+/**
+ * Object for caching existing NodeAncestry instances.
+ * @private
+ */
+goog.cssom.iframe.style.NodeAncestry_.instances_ = {};
+
+
+/**
+ * Throw away all cached dom information. Call this if you've modified
+ * the structure or class/id attributes of your document and you want
+ * to recalculate the currently applied CSS rules.
+ */
+goog.cssom.iframe.style.resetDomCache = function() {
+  goog.cssom.iframe.style.NodeAncestry_.instances_ = {};
+};
+
+
+/**
+ * Inspects a document and returns all active rule sets
+ * @param {Document} doc The document from which to read CSS rules.
+ * @return {!Array<goog.cssom.iframe.style.CssRuleSet_>} An array of CssRuleSet
+ *     objects representing all the active rule sets in the document.
+ * @private
+ */
+goog.cssom.iframe.style.getRuleSetsFromDocument_ = function(doc) {
+  var ruleSets = [];
+  var styleSheets = goog.cssom.getAllCssStyleSheets(doc.styleSheets);
+  for (var i = 0, styleSheet; styleSheet = styleSheets[i]; i++) {
+    var domRuleSets = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
+    if (domRuleSets && domRuleSets.length) {
+      for (var j = 0, n = domRuleSets.length; j < n; j++) {
+        var ruleSet = new goog.cssom.iframe.style.CssRuleSet_();
+        if (ruleSet.initializeFromCssRule(domRuleSets[j])) {
+          ruleSets.push(ruleSet);
+        }
+      }
+    }
+  }
+  return ruleSets;
+};
+
+
+/**
+ * Static object to cache rulesets read from documents. Inspecting all
+ * active css rules is an expensive operation, so its best to only do
+ * it once and then cache the results.
+ * @type {Object}
+ * @private
+ */
+goog.cssom.iframe.style.ruleSetCache_ = {};
+
+
+/**
+ * Cache of ruleset objects keyed by document unique ID.
+ * @type {Object}
+ * @private
+ */
+goog.cssom.iframe.style.ruleSetCache_.ruleSetCache_ = {};
+
+
+/**
+ * Loads ruleset definitions from a document. If the cache already
+ * has rulesets for this document the cached version will be replaced.
+ * @param {Document} doc The document from which to load rulesets.
+ */
+goog.cssom.iframe.style.ruleSetCache_.loadRuleSetsForDocument = function(doc) {
+  var docUid = goog.getUid(doc);
+  goog.cssom.iframe.style.ruleSetCache_.ruleSetCache_[docUid] =
+      goog.cssom.iframe.style.getRuleSetsFromDocument_(doc);
+};
+
+
+/**
+ * Retrieves the array of css rulesets for this document. A cached
+ * version will be used when possible.
+ * @param {Document} doc The document for which to get rulesets.
+ * @return {!Array<goog.cssom.iframe.style.CssRuleSet_>} An array of CssRuleSet
+ *     objects representing the css rule sets in the supplied document.
+ */
+goog.cssom.iframe.style.ruleSetCache_.getRuleSetsForDocument = function(doc) {
+  var docUid = goog.getUid(doc);
+  var cache = goog.cssom.iframe.style.ruleSetCache_.ruleSetCache_;
+  if (!cache[docUid]) {
+    goog.cssom.iframe.style.ruleSetCache_.loadRuleSetsForDocument(doc);
+  }
+  // Build a cloned copy of rulesets array, so if object in the returned array
+  // get modified future calls will still return the original unmodified
+  // versions.
+  var ruleSets = cache[docUid];
+  var ruleSetsCopy = [];
+  for (var i = 0; i < ruleSets.length; i++) {
+    ruleSetsCopy.push(ruleSets[i].clone());
+  }
+  return ruleSetsCopy;
+};
+
+
+/**
+ * Array of CSS properties that are inherited by child nodes, according to
+ * the CSS 2.1 spec. Properties that may be set to relative values, such
+ * as font-size, and line-height, are omitted.
+ * @type {Array<string>}
+ * @private
+ */
+goog.cssom.iframe.style.inheritedProperties_ = [
+  'color',
+  'visibility',
+  'quotes',
+  'list-style-type',
+  'list-style-image',
+  'list-style-position',
+  'list-style',
+  'page-break-inside',
+  'orphans',
+  'widows',
+  'font-family',
+  'font-style',
+  'font-variant',
+  'font-weight',
+  'text-indent',
+  'text-align',
+  'text-transform',
+  'white-space',
+  'caption-side',
+  'border-collapse',
+  'border-spacing',
+  'empty-cells',
+  'cursor'
+];
+
+
+/**
+ * Array of CSS 2.1 properties that directly effect text nodes.
+ * @type {Array<string>}
+ * @private
+ */
+goog.cssom.iframe.style.textProperties_ = [
+  'font-family',
+  'font-size',
+  'font-weight',
+  'font-variant',
+  'font-style',
+  'color',
+  'text-align',
+  'text-decoration',
+  'text-indent',
+  'text-transform',
+  'letter-spacing',
+  'white-space',
+  'word-spacing'
+];
+
+
+/**
+ * Reads the current css rules from element's document, and returns them
+ * rewriting selectors so that any rules that formerly applied to element will
+ * be applied to doc.body. This makes it possible to replace a block in a page
+ * with an iframe and preserve the css styling of the contents.
+ *
+ * @param {Element} element The element for which context should be calculated.
+ * @param {boolean=} opt_forceRuleSetCacheUpdate Flag to force the internal
+ *     cache of rulesets to refresh itself before we read the same.
+ * @param {boolean=} opt_copyBackgroundContext Flag indicating that if the
+ *     {@code element} has a transparent background, background rules
+ *     from the nearest ancestor element(s) that have background-color
+ *     and/or background-image set should be copied.
+ * @return {string} String containing all CSS rules present in the original
+ *     document, with modified selectors.
+ * @see goog.cssom.iframe.style.getBackgroundContext.
+ */
+goog.cssom.iframe.style.getElementContext = function(
+    element,
+    opt_forceRuleSetCacheUpdate,
+    opt_copyBackgroundContext) {
+  var sourceDocument = element.ownerDocument;
+  if (opt_forceRuleSetCacheUpdate) {
+    goog.cssom.iframe.style.ruleSetCache_.loadRuleSetsForDocument(
+        sourceDocument);
+  }
+  var ruleSets = goog.cssom.iframe.style.ruleSetCache_.
+      getRuleSetsForDocument(sourceDocument);
+
+  var elementAncestry = new goog.cssom.iframe.style.NodeAncestry_(element);
+  var bodySelectorPart = new goog.cssom.iframe.style.CssSelectorPart_('body');
+
+  for (var i = 0; i < ruleSets.length; i++) {
+    var ruleSet = ruleSets[i];
+    var selectors = ruleSet.selectors;
+    // Cache selectors.length since we may be adding rules in the loop.
+    var ruleCount = selectors.length;
+    for (var j = 0; j < ruleCount; j++) {
+      var selector = selectors[j];
+      // Test whether all or part of this selector would match
+      // this element or one of its ancestors
+      var match = selector.matchElementAncestry(elementAncestry);
+      if (match) {
+        var ruleIndex = match.selectorPartIndex;
+        var selectorParts = selector.parts;
+        var lastSelectorPartIndex = selectorParts.length - 1;
+        var selectorCopy;
+        if (match.elementIndex == elementAncestry.nodes.length - 1 ||
+            ruleIndex < lastSelectorPartIndex) {
+          // Either the first part(s) of the selector matched this element,
+          // or the first part(s) of the selector matched a parent element
+          // and there are more parts of the selector that could target
+          // children of this element.
+          // So we inject a new selector, replacing the part that matched this
+          // element with 'body' so it will continue to match.
+          var selectorPartsCopy = selectorParts.concat();
+          selectorPartsCopy.splice(0,
+                                   ruleIndex + 1,
+                                   bodySelectorPart);
+          selectorCopy = new goog.cssom.iframe.style.CssSelector_();
+          selectorCopy.parts = selectorPartsCopy;
+          selectors.push(selectorCopy);
+        } else if (ruleIndex > 0 && ruleIndex == lastSelectorPartIndex) {
+          // The rule didn't match this element, but the entire rule did
+          // match an ancestor element. In this case we want to copy
+          // just the last part of the rule, to give it a chance to be applied
+          // to additional matching elements inside this element.
+          // Example DOM structure: body > div.funky > ul > li#editme
+          // Example CSS selector: .funky ul
+          // New CSS selector: body ul
+          selectorCopy = new goog.cssom.iframe.style.CssSelector_();
+          selectorCopy.parts = [
+            bodySelectorPart,
+            selectorParts[lastSelectorPartIndex]
+          ];
+          selectors.push(selectorCopy);
+        }
+      }
+    }
+  }
+
+  // Insert a new ruleset, setting the current inheritable styles of this
+  // element as the defaults for everything under in the frame.
+  var defaultPropertiesRuleSet = new goog.cssom.iframe.style.CssRuleSet_();
+  var computedStyle = goog.cssom.iframe.style.getComputedStyleObject_(element);
+
+  // Copy inheritable styles so they are applied to everything under HTML.
+  var htmlSelector = new goog.cssom.iframe.style.CssSelector_();
+  htmlSelector.parts = [new goog.cssom.iframe.style.CssSelectorPart_('html')];
+  defaultPropertiesRuleSet.selectors = [htmlSelector];
+  var defaultProperties = {};
+  for (var i = 0, prop;
+       prop = goog.cssom.iframe.style.inheritedProperties_[i];
+       i++) {
+    defaultProperties[prop] = computedStyle[goog.string.toCamelCase(prop)];
+  }
+  defaultPropertiesRuleSet.setDeclarationTextFromObject(defaultProperties);
+  ruleSets.push(defaultPropertiesRuleSet);
+
+  var bodyRuleSet = new goog.cssom.iframe.style.CssRuleSet_();
+  var bodySelector = new goog.cssom.iframe.style.CssSelector_();
+  bodySelector.parts = [new goog.cssom.iframe.style.CssSelectorPart_('body')];
+  // Core set of sane property values for BODY, to prevent copied
+  // styles from completely breaking the display.
+  var bodyProperties = {
+    position: 'relative',
+    top: '0',
+    left: '0',
+    right: 'auto', // Override any existing right value so 'left' works.
+    display: 'block',
+    visibility: 'visible'
+  };
+  // Text formatting property values, to keep text nodes directly under BODY
+  // looking right.
+  for (i = 0; prop = goog.cssom.iframe.style.textProperties_[i]; i++) {
+    bodyProperties[prop] = computedStyle[goog.string.toCamelCase(prop)];
+  }
+  if (opt_copyBackgroundContext &&
+      goog.cssom.iframe.style.isTransparentValue_(
+          computedStyle['backgroundColor'])) {
+    // opt_useAncestorBackgroundRules means that, if the original element
+    // has a transparent backgorund, background properties rules should be
+    // added to explicitly make the body have the same background appearance
+    // as in the original element, even if its positioned somewhere else
+    // in the DOM.
+    var bgProperties =
+        goog.cssom.iframe.style.getBackgroundContext(element);
+    bodyProperties['background-color'] = bgProperties['backgroundColor'];
+    var elementBgImage = computedStyle['backgroundImage'];
+    if (!elementBgImage || elementBgImage == 'none') {
+      bodyProperties['background-image'] = bgProperties['backgroundImage'];
+      bodyProperties['background-repeat'] = bgProperties['backgroundRepeat'];
+      bodyProperties['background-position'] =
+          bgProperties['backgroundPosition'];
+    }
+  }
+
+  bodyRuleSet.setDeclarationTextFromObject(bodyProperties, true);
+  bodyRuleSet.selectors = [bodySelector];
+  ruleSets.push(bodyRuleSet);
+
+  // Write outputTextParts to doc.
+  var ruleSetStrings = [];
+  ruleCount = ruleSets.length;
+  for (i = 0; i < ruleCount; i++) {
+    ruleSets[i].writeToArray(ruleSetStrings);
+  }
+  return ruleSetStrings.join('');
+};
+
+
+/**
+ * Tests whether a value is equivalent to 'transparent'.
+ * @param {string} colorValue The value to test.
+ * @return {boolean} Whether the value is transparent.
+ * @private
+ */
+goog.cssom.iframe.style.isTransparentValue_ = function(colorValue) {
+  return colorValue == 'transparent' || colorValue == 'rgba(0, 0, 0, 0)';
+};
+
+
+/**
+ * Returns an object containing the set of computedStyle/currentStyle
+ * values for the given element. Note that this should be used with
+ * caution as it ignores the fact that currentStyle and computedStyle
+ * are not the same for certain properties.
+ *
+ * @param {Element} element The element whose computed style to return.
+ * @return {Object} Object containing style properties and values.
+ * @private
+ */
+goog.cssom.iframe.style.getComputedStyleObject_ = function(element) {
+  // Return an object containing the element's computedStyle/currentStyle.
+  // The resulting object can be re-used to read multiple properties, which
+  // is faster than calling goog.style.getComputedStyle every time.
+  return element.currentStyle ||
+      goog.dom.getOwnerDocument(element).defaultView.getComputedStyle(
+          element, '') || {};
+};
+
+
+/**
+ * RegExp that splits a value like "10px" or "-1em" into parts.
+ * @private
+ * @type {RegExp}
+ */
+goog.cssom.iframe.style.valueWithUnitsRegEx_ = /^(-?)([0-9]+)([a-z]*|%)/;
+
+
+/**
+ * Given an object containing a set of styles, returns a two-element array
+ * containing the values of background-position-x and background-position-y.
+ * @param {Object} styleObject Object from which to read style properties.
+ * @return {Array<string>} The background-position values in the order [x, y].
+ * @private
+ */
+goog.cssom.iframe.style.getBackgroundXYValues_ = function(styleObject) {
+  // Gecko only has backgroundPosition, containing both values.
+  // IE has only backgroundPositionX/backgroundPositionY.
+  // WebKit has both.
+  if (styleObject['backgroundPositionY']) {
+    return [styleObject['backgroundPositionX'],
+            styleObject['backgroundPositionY']];
+  } else {
+    return (styleObject['backgroundPosition'] || '0 0').split(' ');
+  }
+};
+
+
+/**
+ * Generates a set of CSS properties that can be used to make another
+ * element's background look like the background of a given element.
+ * This is useful when you want to copy the CSS context of an element,
+ * but the element's background is transparent. In the original context
+ * you would see the ancestor's backround color/image showing through,
+ * but in the new context there might be a something different underneath.
+ * Note that this assumes the element you're copying context from has a
+ * fairly standard positioning/layout - it assumes that when the element
+ * has a transparent background what you're going to see through it is its
+ * ancestors.
+ * @param {Element} element The element from which to copy background styles.
+ * @return {!Object} Object containing background* properties.
+ */
+goog.cssom.iframe.style.getBackgroundContext = function(element) {
+  var propertyValues = {
+    'backgroundImage': 'none'
+  };
+  var ancestor = element;
+  var currentIframeWindow;
+  // Walk up the DOM tree to find the ancestor nodes whose backgrounds
+  // may be visible underneath this element. Background-image and
+  // background-color don't have to come from the same node, but as soon
+  // an element with background-color is found there's no need to continue
+  // because backgrounds farther up the chain won't be visible.
+  // (This implementation is not sophisticated enough to handle opacity,
+  // or multple layered partially-transparent background images.)
+  while ((ancestor = ancestor.parentNode) &&
+         ancestor.nodeType == goog.dom.NodeType.ELEMENT) {
+    var computedStyle = goog.cssom.iframe.style.getComputedStyleObject_(
+        /** @type {!Element} */ (ancestor));
+    // Copy background color if a non-transparent value is found.
+    var backgroundColorValue = computedStyle['backgroundColor'];
+    if (!goog.cssom.iframe.style.isTransparentValue_(backgroundColorValue)) {
+      propertyValues['backgroundColor'] = backgroundColorValue;
+    }
+    // If a background image value is found, copy background-image,
+    // background-repeat, and background-position.
+    if (computedStyle['backgroundImage'] &&
+        computedStyle['backgroundImage'] != 'none') {
+      propertyValues['backgroundImage'] = computedStyle['backgroundImage'];
+      propertyValues['backgroundRepeat'] = computedStyle['backgroundRepeat'];
+      // Calculate the offset between the original element and the element
+      // providing the background image, so the background position can be
+      // adjusted.
+      var relativePosition;
+      if (currentIframeWindow) {
+        relativePosition = goog.style.getFramedPageOffset(
+            element, currentIframeWindow);
+        var frameElement = currentIframeWindow.frameElement;
+        var iframeRelativePosition = goog.style.getRelativePosition(
+            /** @type {!Element} */ (frameElement),
+            /** @type {!Element} */ (ancestor));
+        var iframeBorders = goog.style.getBorderBox(frameElement);
+        relativePosition.x += iframeRelativePosition.x + iframeBorders.left;
+        relativePosition.y += iframeRelativePosition.y + iframeBorders.top;
+      } else {
+        relativePosition = goog.style.getRelativePosition(
+            element, /** @type {Element} */ (ancestor));
+      }
+      var backgroundXYValues = goog.cssom.iframe.style.getBackgroundXYValues_(
+          computedStyle);
+      // Parse background-repeat-* values in the form "10px", and adjust them.
+      for (var i = 0; i < 2; i++) {
+        var positionValue = backgroundXYValues[i];
+        var coordinate = i == 0 ? 'X' : 'Y';
+        var positionProperty = 'backgroundPosition' + coordinate;
+        // relative position to its ancestor.
+        var positionValueParts =
+            goog.cssom.iframe.style.valueWithUnitsRegEx_.exec(positionValue);
+        if (positionValueParts) {
+          var value = parseInt(
+              positionValueParts[1] + positionValueParts[2], 10);
+          var units = positionValueParts[3];
+          // This only attempts to handle pixel values for now (plus
+          // '0anything', which is equivalent to 0px).
+          // TODO(user) Convert non-pixel values to pixels when possible.
+          if (value == 0 || units == 'px') {
+            value -= (coordinate == 'X' ?
+                      relativePosition.x : relativePosition.y);
+          }
+          positionValue = value + units;
+        }
+        propertyValues[positionProperty] = positionValue;
+      }
+      propertyValues['backgroundPosition'] =
+          propertyValues['backgroundPositionX'] + ' ' +
+          propertyValues['backgroundPositionY'];
+    }
+    if (propertyValues['backgroundColor']) {
+      break;
+    }
+    if (ancestor.tagName == goog.dom.TagName.HTML) {
+      try {
+        currentIframeWindow = goog.dom.getWindow(
+            /** @type {Document} */ (ancestor.parentNode));
+        // This could theoretically throw a security exception if the parent
+        // iframe is in a different domain.
+        ancestor = currentIframeWindow.frameElement;
+        if (!ancestor) {
+          // Loop has reached the top level window.
+          break;
+        }
+      } catch (e) {
+        // We don't have permission to go up to the parent window, stop here.
+        break;
+      }
+    }
+  }
+  return propertyValues;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/cssom/iframe/style_test_import.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/cssom/iframe/style_test_import.css b/externs/GCL/externs/goog/cssom/iframe/style_test_import.css
new file mode 100644
index 0000000..d2c603f
--- /dev/null
+++ b/externs/GCL/externs/goog/cssom/iframe/style_test_import.css
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2010 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+div div strong {
+  font-style: italic;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/datasource/datamanager.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/datasource/datamanager.js b/externs/GCL/externs/goog/datasource/datamanager.js
new file mode 100644
index 0000000..5eccd20
--- /dev/null
+++ b/externs/GCL/externs/goog/datasource/datamanager.js
@@ -0,0 +1,561 @@
+// 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
+ * Central class for registering and accessing data sources
+ * Also handles processing of data events.
+ *
+ * There is a shared global instance that most client code should access via
+ * goog.ds.DataManager.getInstance(). However you can also create your own
+ * DataManager using new
+ *
+ * Implements DataNode to provide the top element in a data registry
+ * Prepends '$' to top level data names in path to denote they are root object
+ *
+ */
+goog.provide('goog.ds.DataManager');
+
+goog.require('goog.ds.BasicNodeList');
+goog.require('goog.ds.DataNode');
+goog.require('goog.ds.Expr');
+goog.require('goog.object');
+goog.require('goog.string');
+goog.require('goog.structs');
+goog.require('goog.structs.Map');
+
+
+
+/**
+ * Create a DataManger
+ * @extends {goog.ds.DataNode}
+ * @constructor
+ * @final
+ */
+goog.ds.DataManager = function() {
+  this.dataSources_ = new goog.ds.BasicNodeList();
+  this.autoloads_ = new goog.structs.Map();
+  this.listenerMap_ = {};
+  this.listenersByFunction_ = {};
+  this.aliases_ = {};
+  this.eventCount_ = 0;
+  this.indexedListenersByFunction_ = {};
+};
+
+
+/**
+ * Global instance
+ * @private
+ */
+goog.ds.DataManager.instance_ = null;
+goog.inherits(goog.ds.DataManager, goog.ds.DataNode);
+
+
+/**
+ * Get the global instance
+ * @return {!goog.ds.DataManager} The data manager singleton.
+ */
+goog.ds.DataManager.getInstance = function() {
+  if (!goog.ds.DataManager.instance_) {
+    goog.ds.DataManager.instance_ = new goog.ds.DataManager();
+  }
+  return goog.ds.DataManager.instance_;
+};
+
+
+/**
+ * Clears the global instance (for unit tests to reset state).
+ */
+goog.ds.DataManager.clearInstance = function() {
+  goog.ds.DataManager.instance_ = null;
+};
+
+
+/**
+ * Add a data source
+ * @param {goog.ds.DataNode} ds The data source.
+ * @param {boolean=} opt_autoload Whether to automatically load the data,
+ *   defaults to false.
+ * @param {string=} opt_name Optional name, can also get name
+ *   from the datasource.
+ */
+goog.ds.DataManager.prototype.addDataSource = function(ds, opt_autoload,
+    opt_name) {
+  var autoload = !!opt_autoload;
+  var name = opt_name || ds.getDataName();
+  if (!goog.string.startsWith(name, '$')) {
+    name = '$' + name;
+  }
+  ds.setDataName(name);
+  this.dataSources_.add(ds);
+  this.autoloads_.set(name, autoload);
+};
+
+
+/**
+ * Create an alias for a data path, very similar to assigning a variable.
+ * For example, you can set $CurrentContact -> $Request/Contacts[5], and all
+ * references to $CurrentContact will be procesed on $Request/Contacts[5].
+ *
+ * Aliases will hide datasources of the same name.
+ *
+ * @param {string} name Alias name, must be a top level path ($Foo).
+ * @param {string} dataPath Data path being aliased.
+ */
+goog.ds.DataManager.prototype.aliasDataSource = function(name, dataPath) {
+  if (!this.aliasListener_) {
+    this.aliasListener_ = goog.bind(this.listenForAlias_, this);
+  }
+  if (this.aliases_[name]) {
+    var oldPath = this.aliases_[name].getSource();
+    this.removeListeners(this.aliasListener_, oldPath + '/...', name);
+  }
+  this.aliases_[name] = goog.ds.Expr.create(dataPath);
+  this.addListener(this.aliasListener_, dataPath + '/...', name);
+  this.fireDataChange(name);
+};
+
+
+/**
+ * Listener function for matches of paths that have been aliased.
+ * Fires a data change on the alias as well.
+ *
+ * @param {string} dataPath Path of data event fired.
+ * @param {string} name Name of the alias.
+ * @private
+ */
+goog.ds.DataManager.prototype.listenForAlias_ = function(dataPath, name) {
+  var aliasedExpr = this.aliases_[name];
+
+  if (aliasedExpr) {
+    // If it's a subpath, appends the subpath to the alias name
+    // otherwise just fires on the top level alias
+    var aliasedPath = aliasedExpr.getSource();
+    if (dataPath.indexOf(aliasedPath) == 0) {
+      this.fireDataChange(name + dataPath.substring(aliasedPath.length));
+    } else {
+      this.fireDataChange(name);
+    }
+  }
+};
+
+
+/**
+ * Gets a named child node of the current node.
+ *
+ * @param {string} name The node name.
+ * @return {goog.ds.DataNode} The child node,
+ *   or null if no node of this name exists.
+ */
+goog.ds.DataManager.prototype.getDataSource = function(name) {
+  if (this.aliases_[name]) {
+    return this.aliases_[name].getNode();
+  } else {
+    return this.dataSources_.get(name);
+  }
+};
+
+
+/**
+ * Get the value of the node
+ * @return {!Object} The value of the node.
+ * @override
+ */
+goog.ds.DataManager.prototype.get = function() {
+  return this.dataSources_;
+};
+
+
+/** @override */
+goog.ds.DataManager.prototype.set = function(value) {
+  throw Error('Can\'t set on DataManager');
+};
+
+
+/** @override */
+goog.ds.DataManager.prototype.getChildNodes = function(opt_selector) {
+  if (opt_selector) {
+    return new goog.ds.BasicNodeList(
+        [this.getChildNode(/** @type {string} */(opt_selector))]);
+  } else {
+    return this.dataSources_;
+  }
+};
+
+
+/**
+ * Gets a named child node of the current node
+ * @param {string} name The node name.
+ * @return {goog.ds.DataNode} The child node,
+ *     or null if no node of this name exists.
+ * @override
+ */
+goog.ds.DataManager.prototype.getChildNode = function(name) {
+  return this.getDataSource(name);
+};
+
+
+/** @override */
+goog.ds.DataManager.prototype.getChildNodeValue = function(name) {
+  var ds = this.getDataSource(name);
+  return ds ? ds.get() : null;
+};
+
+
+/**
+ * Get the name of the node relative to the parent node
+ * @return {string} The name of the node.
+ * @override
+ */
+goog.ds.DataManager.prototype.getDataName = function() {
+  return '';
+};
+
+
+/**
+ * Gets the a qualified data path to this node
+ * @return {string} The data path.
+ * @override
+ */
+goog.ds.DataManager.prototype.getDataPath = function() {
+  return '';
+};
+
+
+/**
+ * Load or reload the backing data for this node
+ * only loads datasources flagged with autoload
+ * @override
+ */
+goog.ds.DataManager.prototype.load = function() {
+  var len = this.dataSources_.getCount();
+  for (var i = 0; i < len; i++) {
+    var ds = this.dataSources_.getByIndex(i);
+    var autoload = this.autoloads_.get(ds.getDataName());
+    if (autoload) {
+      ds.load();
+    }
+  }
+};
+
+
+/**
+ * Gets the state of the backing data for this node
+ * @return {goog.ds.LoadState} The state.
+ * @override
+ */
+goog.ds.DataManager.prototype.getLoadState = goog.abstractMethod;
+
+
+/**
+ * Whether the value of this node is a homogeneous list of data
+ * @return {boolean} True if a list.
+ * @override
+ */
+goog.ds.DataManager.prototype.isList = function() {
+  return false;
+};
+
+
+/**
+ * Get the total count of events fired (mostly for debugging)
+ * @return {number} Count of events.
+ */
+goog.ds.DataManager.prototype.getEventCount = function() {
+  return this.eventCount_;
+};
+
+
+/**
+ * Adds a listener
+ * Listeners should fire when any data with path that has dataPath as substring
+ * is changed.
+ * TODO(user) Look into better listener handling
+ *
+ * @param {Function} fn Callback function, signature function(dataPath, id).
+ * @param {string} dataPath Fully qualified data path.
+ * @param {string=} opt_id A value passed back to the listener when the dataPath
+ *   is matched.
+ */
+goog.ds.DataManager.prototype.addListener = function(fn, dataPath, opt_id) {
+  // maxAncestor sets how distant an ancestor you can be of the fired event
+  // and still fire (you always fire if you are a descendant).
+  // 0 means you don't fire if you are an ancestor
+  // 1 means you only fire if you are parent
+  // 1000 means you will fire if you are ancestor (effectively infinite)
+  var maxAncestors = 0;
+  if (goog.string.endsWith(dataPath, '/...')) {
+    maxAncestors = 1000;
+    dataPath = dataPath.substring(0, dataPath.length - 4);
+  } else if (goog.string.endsWith(dataPath, '/*')) {
+    maxAncestors = 1;
+    dataPath = dataPath.substring(0, dataPath.length - 2);
+  }
+
+  opt_id = opt_id || '';
+  var key = dataPath + ':' + opt_id + ':' + goog.getUid(fn);
+  var listener = {dataPath: dataPath, id: opt_id, fn: fn};
+  var expr = goog.ds.Expr.create(dataPath);
+
+  var fnUid = goog.getUid(fn);
+  if (!this.listenersByFunction_[fnUid]) {
+    this.listenersByFunction_[fnUid] = {};
+  }
+  this.listenersByFunction_[fnUid][key] = {listener: listener, items: []};
+
+  while (expr) {
+    var listenerSpec = {listener: listener, maxAncestors: maxAncestors};
+    var matchingListeners = this.listenerMap_[expr.getSource()];
+    if (matchingListeners == null) {
+      matchingListeners = {};
+      this.listenerMap_[expr.getSource()] = matchingListeners;
+    }
+    matchingListeners[key] = listenerSpec;
+    maxAncestors = 0;
+    expr = expr.getParent();
+    this.listenersByFunction_[fnUid][key].items.push(
+        {key: key, obj: matchingListeners});
+  }
+};
+
+
+/**
+ * Adds an indexed listener.
+ *
+ * Indexed listeners allow for '*' in data paths. If a * exists, will match
+ * all values and return the matched values in an array to the callback.
+ *
+ * Currently uses a promiscuous match algorithm: Matches everything before the
+ * first '*', and then does a regex match for all of the returned events.
+ * Although this isn't optimized, it is still an improvement as you can collapse
+ * 100's of listeners into a single regex match
+ *
+ * @param {Function} fn Callback function, signature (dataPath, id, indexes).
+ * @param {string} dataPath Fully qualified data path.
+ * @param {string=} opt_id A value passed back to the listener when the dataPath
+ *   is matched.
+ */
+goog.ds.DataManager.prototype.addIndexedListener = function(fn, dataPath,
+    opt_id) {
+  var firstStarPos = dataPath.indexOf('*');
+  // Just need a regular listener
+  if (firstStarPos == -1) {
+    this.addListener(fn, dataPath, opt_id);
+    return;
+  }
+
+  var listenPath = dataPath.substring(0, firstStarPos) + '...';
+
+  // Create regex that matches * to any non '\' character
+  var ext = '$';
+  if (goog.string.endsWith(dataPath, '/...')) {
+    dataPath = dataPath.substring(0, dataPath.length - 4);
+    ext = '';
+  }
+  var regExpPath = goog.string.regExpEscape(dataPath);
+  var matchRegExp = regExpPath.replace(/\\\*/g, '([^\\\/]+)') + ext;
+
+  // Matcher function applies the regex and calls back the original function
+  // if the regex matches, passing in an array of the matched values
+  var matchRegExpRe = new RegExp(matchRegExp);
+  var matcher = function(path, id) {
+    var match = matchRegExpRe.exec(path);
+    if (match) {
+      match.shift();
+      fn(path, opt_id, match);
+    }
+  };
+  this.addListener(matcher, listenPath, opt_id);
+
+  // Add the indexed listener to the map so that we can remove it later.
+  var fnUid = goog.getUid(fn);
+  if (!this.indexedListenersByFunction_[fnUid]) {
+    this.indexedListenersByFunction_[fnUid] = {};
+  }
+  var key = dataPath + ':' + opt_id;
+  this.indexedListenersByFunction_[fnUid][key] = {
+    listener: {dataPath: listenPath, fn: matcher, id: opt_id}
+  };
+};
+
+
+/**
+ * Removes indexed listeners with a given callback function, and optional
+ * matching datapath and matching id.
+ *
+ * @param {Function} fn Callback function, signature function(dataPath, id).
+ * @param {string=} opt_dataPath Fully qualified data path.
+ * @param {string=} opt_id A value passed back to the listener when the dataPath
+ *   is matched.
+ */
+goog.ds.DataManager.prototype.removeIndexedListeners = function(
+    fn, opt_dataPath, opt_id) {
+  this.removeListenersByFunction_(
+      this.indexedListenersByFunction_, true, fn, opt_dataPath, opt_id);
+};
+
+
+/**
+ * Removes listeners with a given callback function, and optional
+ * matching dataPath and matching id
+ *
+ * @param {Function} fn Callback function, signature function(dataPath, id).
+ * @param {string=} opt_dataPath Fully qualified data path.
+ * @param {string=} opt_id A value passed back to the listener when the dataPath
+ *   is matched.
+ */
+goog.ds.DataManager.prototype.removeListeners = function(fn, opt_dataPath,
+    opt_id) {
+
+  // Normalize data path root
+  if (opt_dataPath && goog.string.endsWith(opt_dataPath, '/...')) {
+    opt_dataPath = opt_dataPath.substring(0, opt_dataPath.length - 4);
+  } else if (opt_dataPath && goog.string.endsWith(opt_dataPath, '/*')) {
+    opt_dataPath = opt_dataPath.substring(0, opt_dataPath.length - 2);
+  }
+
+  this.removeListenersByFunction_(
+      this.listenersByFunction_, false, fn, opt_dataPath, opt_id);
+};
+
+
+/**
+ * Removes listeners with a given callback function, and optional
+ * matching dataPath and matching id from the given listenersByFunction
+ * data structure.
+ *
+ * @param {Object} listenersByFunction The listeners by function.
+ * @param {boolean} indexed Indicates whether the listenersByFunction are
+ *     indexed or not.
+ * @param {Function} fn Callback function, signature function(dataPath, id).
+ * @param {string=} opt_dataPath Fully qualified data path.
+ * @param {string=} opt_id A value passed back to the listener when the dataPath
+ *   is matched.
+ * @private
+ */
+goog.ds.DataManager.prototype.removeListenersByFunction_ = function(
+    listenersByFunction, indexed, fn, opt_dataPath, opt_id) {
+  var fnUid = goog.getUid(fn);
+  var functionMatches = listenersByFunction[fnUid];
+  if (functionMatches != null) {
+    for (var key in functionMatches) {
+      var functionMatch = functionMatches[key];
+      var listener = functionMatch.listener;
+      if ((!opt_dataPath || opt_dataPath == listener.dataPath) &&
+          (!opt_id || opt_id == listener.id)) {
+        if (indexed) {
+          this.removeListeners(
+              listener.fn, listener.dataPath, listener.id);
+        }
+        if (functionMatch.items) {
+          for (var i = 0; i < functionMatch.items.length; i++) {
+            var item = functionMatch.items[i];
+            delete item.obj[item.key];
+          }
+        }
+        delete functionMatches[key];
+      }
+    }
+  }
+};
+
+
+/**
+ * Get the total number of listeners (per expression listened to, so may be
+ * more than number of times addListener() has been called
+ * @return {number} Number of listeners.
+ */
+goog.ds.DataManager.prototype.getListenerCount = function() {
+  var count = 0;
+  goog.object.forEach(this.listenerMap_, function(matchingListeners) {
+    count += goog.structs.getCount(matchingListeners);
+  });
+  return count;
+};
+
+
+/**
+ * Disables the sending of all data events during the execution of the given
+ * callback. This provides a way to avoid useless notifications of small changes
+ * when you will eventually send a data event manually that encompasses them
+ * all.
+ *
+ * Note that this function can not be called reentrantly.
+ *
+ * @param {Function} callback Zero-arg function to execute.
+ */
+goog.ds.DataManager.prototype.runWithoutFiringDataChanges = function(callback) {
+  if (this.disableFiring_) {
+    throw Error('Can not nest calls to runWithoutFiringDataChanges');
+  }
+
+  this.disableFiring_ = true;
+  try {
+    callback();
+  } finally {
+    this.disableFiring_ = false;
+  }
+};
+
+
+/**
+ * Fire a data change event to all listeners
+ *
+ * If the path matches the path of a listener, the listener will fire
+ *
+ * If your path is the parent of a listener, the listener will fire. I.e.
+ * if $Contacts/bob@bob.com changes, then we will fire listener for
+ * $Contacts/bob@bob.com/Name as well, as the assumption is that when
+ * a parent changes, all children are invalidated.
+ *
+ * If your path is the child of a listener, the listener may fire, depending
+ * on the ancestor depth.
+ *
+ * A listener for $Contacts might only be interested if the contact name changes
+ * (i.e. $Contacts doesn't fire on $Contacts/bob@bob.com/Name),
+ * while a listener for a specific contact might
+ * (i.e. $Contacts/bob@bob.com would fire on $Contacts/bob@bob.com/Name).
+ * Adding "/..." to a lisetener path listens to all children, and adding "/*" to
+ * a listener path listens only to direct children
+ *
+ * @param {string} dataPath Fully qualified data path.
+ */
+goog.ds.DataManager.prototype.fireDataChange = function(dataPath) {
+  if (this.disableFiring_) {
+    return;
+  }
+
+  var expr = goog.ds.Expr.create(dataPath);
+  var ancestorDepth = 0;
+
+  // Look for listeners for expression and all its parents.
+  // Parents of listener expressions are all added to the listenerMap as well,
+  // so this will evaluate inner loop every time the dataPath is a child or
+  // an ancestor of the original listener path
+  while (expr) {
+    var matchingListeners = this.listenerMap_[expr.getSource()];
+    if (matchingListeners) {
+      for (var id in matchingListeners) {
+        var match = matchingListeners[id];
+        var listener = match.listener;
+        if (ancestorDepth <= match.maxAncestors) {
+          listener.fn(dataPath, listener.id);
+        }
+      }
+    }
+    ancestorDepth++;
+    expr = expr.getParent();
+  }
+  this.eventCount_++;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/datasource/datasource.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/datasource/datasource.js b/externs/GCL/externs/goog/datasource/datasource.js
new file mode 100644
index 0000000..4cb0db6
--- /dev/null
+++ b/externs/GCL/externs/goog/datasource/datasource.js
@@ -0,0 +1,658 @@
+// 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 Generic rich data access API.
+ *
+ * Abstraction for data sources that allows listening for changes at different
+ * levels of the data tree and updating the data via XHR requests
+ *
+ */
+
+
+goog.provide('goog.ds.BaseDataNode');
+goog.provide('goog.ds.BasicNodeList');
+goog.provide('goog.ds.DataNode');
+goog.provide('goog.ds.DataNodeList');
+goog.provide('goog.ds.EmptyNodeList');
+goog.provide('goog.ds.LoadState');
+goog.provide('goog.ds.SortedNodeList');
+goog.provide('goog.ds.Util');
+goog.provide('goog.ds.logger');
+
+goog.require('goog.array');
+goog.require('goog.log');
+
+
+
+/**
+ * Interface for node in rich data tree.
+ *
+ * Names that are reserved for system use and shouldn't be used for data node
+ * names: eval, toSource, toString, unwatch, valueOf, watch. Behavior is
+ * undefined if these names are used.
+ *
+ * @constructor
+ */
+goog.ds.DataNode = function() {};
+
+
+/**
+ * Get the value of the node
+ * @param {...?} var_args Do not check arity of arguments, because
+ *     some subclasses require args.
+ * @return {*} The value of the node, or null if no value.
+ */
+goog.ds.DataNode.prototype.get = goog.abstractMethod;
+
+
+/**
+ * Set the value of the node
+ * @param {*} value The new value of the node.
+ */
+goog.ds.DataNode.prototype.set = goog.abstractMethod;
+
+
+/**
+ * Gets all of the child nodes of the current node.
+ * Should return an empty DataNode list if no child nodes.
+ * @param {string=} opt_selector String selector to choose child nodes.
+ * @return {!goog.ds.DataNodeList} The child nodes.
+ */
+goog.ds.DataNode.prototype.getChildNodes = goog.abstractMethod;
+
+
+/**
+ * Gets a named child node of the current node
+ * @param {string} name The node name.
+ * @param {boolean=} opt_canCreate Whether to create a child node if it does not
+ *     exist.
+ * @return {goog.ds.DataNode} The child node, or null
+ * if no node of this name exists.
+ */
+goog.ds.DataNode.prototype.getChildNode = goog.abstractMethod;
+
+
+/**
+ * Gets the value of a child node
+ * @param {string} name The node name.
+ * @return {*} The value of the node, or null if no value or the child node
+ *     doesn't exist.
+ */
+goog.ds.DataNode.prototype.getChildNodeValue = goog.abstractMethod;
+
+
+/**
+ * Sets a named child node of the current node.
+ *
+ * @param {string} name The node name.
+ * @param {Object} value The value to set, can be DataNode, object, property,
+ *     or null. If value is null, removes the child node.
+ * @return {Object} The child node, if the node was set.
+ */
+goog.ds.DataNode.prototype.setChildNode = goog.abstractMethod;
+
+
+/**
+ * Get the name of the node relative to the parent node
+ * @return {string} The name of the node.
+ */
+goog.ds.DataNode.prototype.getDataName = goog.abstractMethod;
+
+
+/**
+ * Set the name of the node relative to the parent node
+ * @param {string} name The name of the node.
+ */
+goog.ds.DataNode.prototype.setDataName = goog.abstractMethod;
+
+
+/**
+ * Gets the a qualified data path to this node
+ * @return {string} The data path.
+ */
+goog.ds.DataNode.prototype.getDataPath = goog.abstractMethod;
+
+
+/**
+ * Load or reload the backing data for this node
+ */
+goog.ds.DataNode.prototype.load = goog.abstractMethod;
+
+
+/**
+ * Gets the state of the backing data for this node
+ * @return {goog.ds.LoadState} The state.
+ */
+goog.ds.DataNode.prototype.getLoadState = goog.abstractMethod;
+
+
+/**
+ * Whether the value of this node is a homogeneous list of data
+ * @return {boolean} True if a list.
+ */
+goog.ds.DataNode.prototype.isList = goog.abstractMethod;
+
+
+/**
+ * Enum for load state of a DataNode.
+ * @enum {string}
+ */
+goog.ds.LoadState = {
+  LOADED: 'LOADED',
+  LOADING: 'LOADING',
+  FAILED: 'FAILED',
+  NOT_LOADED: 'NOT_LOADED'
+};
+
+
+
+/**
+ * Base class for data node functionality, has default implementations for
+ * many of the functions.
+ *
+ * implements {goog.ds.DataNode}
+ * @constructor
+ */
+goog.ds.BaseDataNode = function() {};
+
+
+/**
+ * Set the value of the node
+ * @param {Object} value The new value of the node.
+ */
+goog.ds.BaseDataNode.prototype.set = goog.abstractMethod;
+
+
+/**
+ * Gets all of the child nodes of the current node.
+ * Should return an empty DataNode list if no child nodes.
+ * @param {string=} opt_selector String selector to choose child nodes.
+ * @return {!goog.ds.DataNodeList} The child nodes.
+ */
+goog.ds.BaseDataNode.prototype.getChildNodes = function(opt_selector) {
+  return new goog.ds.EmptyNodeList();
+};
+
+
+/**
+ * Gets a named child node of the current node
+ * @param {string} name The node name.
+ * @param {boolean=} opt_canCreate Whether you can create the child node if
+ *     it doesn't exist already.
+ * @return {goog.ds.DataNode} The child node, or null if no node of
+ *     this name exists and opt_create is false.
+ */
+goog.ds.BaseDataNode.prototype.getChildNode = function(name, opt_canCreate) {
+  return null;
+};
+
+
+/**
+ * Gets the value of a child node
+ * @param {string} name The node name.
+ * @return {Object} The value of the node, or null if no value or the
+ *     child node doesn't exist.
+ */
+goog.ds.BaseDataNode.prototype.getChildNodeValue = function(name) {
+  return null;
+};
+
+
+/**
+ * Get the name of the node relative to the parent node
+ * @return {string} The name of the node.
+ */
+goog.ds.BaseDataNode.prototype.getDataName = goog.abstractMethod;
+
+
+/**
+ * Gets the a qualified data path to this node
+ * @return {string} The data path.
+ */
+goog.ds.BaseDataNode.prototype.getDataPath = function() {
+  var parentPath = '';
+  var myName = this.getDataName();
+  if (this.getParent && this.getParent()) {
+    parentPath = this.getParent().getDataPath() +
+        (myName.indexOf(goog.ds.STR_ARRAY_START) != -1 ? '' :
+        goog.ds.STR_PATH_SEPARATOR);
+  }
+
+  return parentPath + myName;
+};
+
+
+/**
+ * Load or reload the backing data for this node
+ */
+goog.ds.BaseDataNode.prototype.load = goog.nullFunction;
+
+
+/**
+ * Gets the state of the backing data for this node
+ * @return {goog.ds.LoadState} The state.
+ */
+goog.ds.BaseDataNode.prototype.getLoadState = function() {
+  return goog.ds.LoadState.LOADED;
+};
+
+
+/**
+ * Gets the parent node. Subclasses implement this function
+ * @type {Function}
+ * @protected
+ */
+goog.ds.BaseDataNode.prototype.getParent = null;
+
+
+/**
+ * Interface for node list in rich data tree.
+ *
+ * Has both map and list-style accessors
+ *
+ * @constructor
+ * @extends {goog.ds.DataNode}
+ */
+// TODO(arv): Use interfaces when available.
+goog.ds.DataNodeList = function() {};
+
+
+/**
+ * Add a node to the node list.
+ * If the node has a dataName, uses this for the key in the map.
+ *
+ * @param {goog.ds.DataNode} node The node to add.
+ */
+goog.ds.DataNodeList.prototype.add = goog.abstractMethod;
+
+
+/**
+ * Get a node by string key.
+ * Returns null if node doesn't exist.
+ *
+ * @param {string} key String lookup key.
+ * @return {*} The node, or null if doesn't exist.
+ * @override
+ */
+goog.ds.DataNodeList.prototype.get = goog.abstractMethod;
+
+
+/**
+ * Get a node by index
+ * Returns null if the index is out of range
+ *
+ * @param {number} index The index of the node.
+ * @return {goog.ds.DataNode} The node, or null if doesn't exist.
+ */
+goog.ds.DataNodeList.prototype.getByIndex = goog.abstractMethod;
+
+
+/**
+ * Gets the size of the node list
+ *
+ * @return {number} The size of the list.
+ */
+goog.ds.DataNodeList.prototype.getCount = goog.abstractMethod;
+
+
+/**
+ * Sets a node in the list of a given name
+ * @param {string} name Name of the node.
+ * @param {goog.ds.DataNode} node The node.
+ */
+goog.ds.DataNodeList.prototype.setNode = goog.abstractMethod;
+
+
+/**
+ * Removes a node in the list of a given name
+ * @param {string} name Name of the node.
+ * @return {boolean} True if node existed and was deleted.
+ */
+goog.ds.DataNodeList.prototype.removeNode = goog.abstractMethod;
+
+
+/**
+ * Simple node list implementation with underlying array and map
+ * implements goog.ds.DataNodeList.
+ *
+ * Names that are reserved for system use and shouldn't be used for data node
+ * names: eval, toSource, toString, unwatch, valueOf, watch. Behavior is
+ * undefined if these names are used.
+ *
+ * @param {Array<goog.ds.DataNode>=} opt_nodes optional nodes to add to list.
+ * @constructor
+ * @extends {goog.ds.DataNodeList}
+ */
+// TODO(arv): Use interfaces when available.
+goog.ds.BasicNodeList = function(opt_nodes) {
+  this.map_ = {};
+  this.list_ = [];
+  this.indexMap_ = {};
+  if (opt_nodes) {
+    for (var i = 0, node; node = opt_nodes[i]; i++) {
+      this.add(node);
+    }
+  }
+};
+
+
+/**
+ * Add a node to the node list.
+ * If the node has a dataName, uses this for the key in the map.
+ * TODO(user) Remove function as well
+ *
+ * @param {goog.ds.DataNode} node The node to add.
+ * @override
+ */
+goog.ds.BasicNodeList.prototype.add = function(node) {
+  this.list_.push(node);
+  var dataName = node.getDataName();
+  if (dataName) {
+    this.map_[dataName] = node;
+    this.indexMap_[dataName] = this.list_.length - 1;
+  }
+};
+
+
+/**
+ * Get a node by string key.
+ * Returns null if node doesn't exist.
+ *
+ * @param {string} key String lookup key.
+ * @return {goog.ds.DataNode} The node, or null if doesn't exist.
+ * @override
+ */
+goog.ds.BasicNodeList.prototype.get = function(key) {
+  return this.map_[key] || null;
+};
+
+
+/**
+ * Get a node by index
+ * Returns null if the index is out of range
+ *
+ * @param {number} index The index of the node.
+ * @return {goog.ds.DataNode} The node, or null if doesn't exist.
+ * @override
+ */
+goog.ds.BasicNodeList.prototype.getByIndex = function(index) {
+  return this.list_[index] || null;
+};
+
+
+/**
+ * Gets the size of the node list
+ *
+ * @return {number} The size of the list.
+ * @override
+ */
+goog.ds.BasicNodeList.prototype.getCount = function() {
+  return this.list_.length;
+};
+
+
+/**
+ * Sets a node in the list of a given name
+ * @param {string} name Name of the node.
+ * @param {goog.ds.DataNode} node The node.
+ * @override
+ */
+goog.ds.BasicNodeList.prototype.setNode = function(name, node) {
+  if (node == null) {
+    this.removeNode(name);
+  } else {
+    var existingNode = this.indexMap_[name];
+    if (existingNode != null) {
+      this.map_[name] = node;
+      this.list_[existingNode] = node;
+    } else {
+      this.add(node);
+    }
+  }
+};
+
+
+/**
+ * Removes a node in the list of a given name
+ * @param {string} name Name of the node.
+ * @return {boolean} True if node existed and was deleted.
+ * @override
+ */
+goog.ds.BasicNodeList.prototype.removeNode = function(name) {
+  var existingNode = this.indexMap_[name];
+  if (existingNode != null) {
+    this.list_.splice(existingNode, 1);
+    delete this.map_[name];
+    delete this.indexMap_[name];
+    for (var index in this.indexMap_) {
+      if (this.indexMap_[index] > existingNode) {
+        this.indexMap_[index]--;
+      }
+    }
+  }
+  return existingNode != null;
+};
+
+
+/**
+ * Get the index of a named node
+ * @param {string} name The name of the node to get the index of.
+ * @return {number|undefined} The index.
+ */
+goog.ds.BasicNodeList.prototype.indexOf = function(name) {
+  return this.indexMap_[name];
+};
+
+
+/**
+ * Immulatable empty node list
+ * @extends {goog.ds.BasicNodeList}
+ * @constructor
+ * @final
+ */
+
+goog.ds.EmptyNodeList = function() {
+  goog.ds.BasicNodeList.call(this);
+};
+goog.inherits(goog.ds.EmptyNodeList, goog.ds.BasicNodeList);
+
+
+/**
+ * Add a node to the node list.
+ * If the node has a dataName, uses this for the key in the map.
+ *
+ * @param {goog.ds.DataNode} node The node to add.
+ * @override
+ */
+goog.ds.EmptyNodeList.prototype.add = function(node) {
+  throw Error('Can\'t add to EmptyNodeList');
+};
+
+
+
+/**
+ * Node list implementation which maintains sort order during insertion and
+ * modification operations based on a comparison function.
+ *
+ * The SortedNodeList does not guarantee sort order will be maintained if
+ * the underlying data nodes are modified externally.
+ *
+ * Names that are reserved for system use and shouldn't be used for data node
+ * names: eval, toSource, toString, unwatch, valueOf, watch. Behavior is
+ * undefined if these names are used.
+ *
+ * @param {Function} compareFn Comparison function by which the
+ *     node list is sorted. Should take 2 arguments to compare, and return a
+ *     negative integer, zero, or a positive integer depending on whether the
+ *     first argument is less than, equal to, or greater than the second.
+ * @param {Array<goog.ds.DataNode>=} opt_nodes optional nodes to add to list;
+ *    these are assumed to be in sorted order.
+ * @extends {goog.ds.BasicNodeList}
+ * @constructor
+ */
+goog.ds.SortedNodeList = function(compareFn, opt_nodes) {
+  this.compareFn_ = compareFn;
+  goog.ds.BasicNodeList.call(this, opt_nodes);
+};
+goog.inherits(goog.ds.SortedNodeList, goog.ds.BasicNodeList);
+
+
+/**
+ * Add a node to the node list, maintaining sort order.
+ * If the node has a dataName, uses this for the key in the map.
+ *
+ * @param {goog.ds.DataNode} node The node to add.
+ * @override
+ */
+goog.ds.SortedNodeList.prototype.add = function(node) {
+  if (!this.compareFn_) {
+    this.append(node);
+    return;
+  }
+
+  var searchLoc = goog.array.binarySearch(this.list_, node, this.compareFn_);
+
+  // if there is another node that is "equal" according to the comparison
+  // function, insert before that one; otherwise insert at the location
+  // goog.array.binarySearch indicated
+  if (searchLoc < 0) {
+    searchLoc = -(searchLoc + 1);
+  }
+
+  // update any indexes that are after the insertion point
+  for (var index in this.indexMap_) {
+    if (this.indexMap_[index] >= searchLoc) {
+      this.indexMap_[index]++;
+    }
+  }
+
+  goog.array.insertAt(this.list_, node, searchLoc);
+  var dataName = node.getDataName();
+  if (dataName) {
+    this.map_[dataName] = node;
+    this.indexMap_[dataName] = searchLoc;
+  }
+};
+
+
+/**
+ * Adds the given node to the end of the SortedNodeList. This should
+ * only be used when the caller can guarantee that the sort order will
+ * be maintained according to this SortedNodeList's compareFn (e.g.
+ * when initializing a new SortedNodeList from a list of nodes that has
+ * already been sorted).
+ * @param {goog.ds.DataNode} node The node to append.
+ */
+goog.ds.SortedNodeList.prototype.append = function(node) {
+  goog.ds.SortedNodeList.superClass_.add.call(this, node);
+};
+
+
+/**
+ * Sets a node in the list of a given name, maintaining sort order.
+ * @param {string} name Name of the node.
+ * @param {goog.ds.DataNode} node The node.
+ * @override
+ */
+goog.ds.SortedNodeList.prototype.setNode = function(name, node) {
+  if (node == null) {
+    this.removeNode(name);
+  } else {
+    var existingNode = this.indexMap_[name];
+    if (existingNode != null) {
+      if (this.compareFn_) {
+        var compareResult = this.compareFn_(this.list_[existingNode], node);
+        if (compareResult == 0) {
+          // the new node can just replace the old one
+          this.map_[name] = node;
+          this.list_[existingNode] = node;
+        } else {
+          // remove the old node, then add the new one
+          this.removeNode(name);
+          this.add(node);
+        }
+      }
+    } else {
+      this.add(node);
+    }
+  }
+};
+
+
+/**
+ * The character denoting an attribute.
+ * @type {string}
+ */
+goog.ds.STR_ATTRIBUTE_START = '@';
+
+
+/**
+ * The character denoting all children.
+ * @type {string}
+ */
+goog.ds.STR_ALL_CHILDREN_SELECTOR = '*';
+
+
+/**
+ * The wildcard character.
+ * @type {string}
+ */
+goog.ds.STR_WILDCARD = '*';
+
+
+/**
+ * The character denoting path separation.
+ * @type {string}
+ */
+goog.ds.STR_PATH_SEPARATOR = '/';
+
+
+/**
+ * The character denoting the start of an array.
+ * @type {string}
+ */
+goog.ds.STR_ARRAY_START = '[';
+
+
+/**
+ * Shared logger instance for data package
+ * @type {goog.log.Logger}
+ */
+goog.ds.logger = goog.log.getLogger('goog.ds');
+
+
+/**
+ * Create a data node that references another data node,
+ * useful for pointer-like functionality.
+ * All functions will return same values as the original node except for
+ * getDataName()
+ * @param {!goog.ds.DataNode} node The original node.
+ * @param {string} name The new name.
+ * @return {!goog.ds.DataNode} The new data node.
+ */
+goog.ds.Util.makeReferenceNode = function(node, name) {
+  /**
+   * @constructor
+   * @extends {goog.ds.DataNode}
+   * @final
+   */
+  var nodeCreator = function() {};
+  nodeCreator.prototype = node;
+  var newNode = new nodeCreator();
+  newNode.getDataName = function() {
+    return name;
+  };
+  return newNode;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/datasource/expr.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/datasource/expr.js b/externs/GCL/externs/goog/datasource/expr.js
new file mode 100644
index 0000000..c384fd1
--- /dev/null
+++ b/externs/GCL/externs/goog/datasource/expr.js
@@ -0,0 +1,545 @@
+// 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
+ * Expression evaluation utilities. Expression format is very similar to XPath.
+ *
+ * Expression details:
+ * - Of format A/B/C, which will evaluate getChildNode('A').getChildNode('B').
+ *    getChildNodes('C')|getChildNodeValue('C')|getChildNode('C') depending on
+ *    call
+ * - If expression ends with '/name()', will get the name() of the node
+ *    referenced by the preceding path.
+ * - If expression ends with '/count()', will get the count() of the nodes that
+ *    match the expression referenced by the preceding path.
+ * - If expression ends with '?', the value is OK to evaluate to null. This is
+ *    not enforced by the expression evaluation functions, instead it is
+ *    provided as a flag for client code which may ignore depending on usage
+ * - If expression has [INDEX], will use getChildNodes().getByIndex(INDEX)
+ *
+ */
+
+
+goog.provide('goog.ds.Expr');
+
+goog.require('goog.ds.BasicNodeList');
+goog.require('goog.ds.EmptyNodeList');
+goog.require('goog.string');
+
+
+
+/**
+ * Create a new expression. An expression uses a string expression language, and
+ * from this string and a passed in DataNode can evaluate to a value, DataNode,
+ * or a DataNodeList.
+ *
+ * @param {string=} opt_expr The string expression.
+ * @constructor
+ * @final
+ */
+goog.ds.Expr = function(opt_expr) {
+  if (opt_expr) {
+    this.setSource_(opt_expr);
+  }
+};
+
+
+/**
+ * Set the source expression text & parse
+ *
+ * @param {string} expr The string expression source.
+ * @param {Array=} opt_parts Array of the parts of an expression.
+ * @param {goog.ds.Expr=} opt_childExpr Optional child of this expression,
+ *   passed in as a hint for processing.
+ * @param {goog.ds.Expr=} opt_prevExpr Optional preceding expression
+ *   (i.e. $A/B/C is previous expression to B/C) passed in as a hint for
+ *   processing.
+ * @private
+ */
+goog.ds.Expr.prototype.setSource_ = function(expr, opt_parts,
+    opt_childExpr, opt_prevExpr) {
+  this.src_ = expr;
+
+  if (!opt_childExpr && !opt_prevExpr) {
+    // Check whether it can be empty
+    if (goog.string.endsWith(expr, goog.ds.Expr.String_.CAN_BE_EMPTY)) {
+      this.canBeEmpty_ = true;
+      expr = expr.substring(0, expr.length - 1);
+    }
+
+    // Check whether this is an node function
+    if (goog.string.endsWith(expr, '()')) {
+      if (goog.string.endsWith(expr, goog.ds.Expr.String_.NAME_EXPR) ||
+          goog.string.endsWith(expr, goog.ds.Expr.String_.COUNT_EXPR) ||
+          goog.string.endsWith(expr, goog.ds.Expr.String_.POSITION_EXPR)) {
+        var lastPos = expr.lastIndexOf(goog.ds.Expr.String_.SEPARATOR);
+        if (lastPos != -1) {
+          this.exprFn_ = expr.substring(lastPos + 1);
+          expr = expr.substring(0, lastPos);
+        } else {
+          this.exprFn_ = expr;
+          expr = goog.ds.Expr.String_.CURRENT_NODE_EXPR;
+        }
+        if (this.exprFn_ == goog.ds.Expr.String_.COUNT_EXPR) {
+          this.isCount_ = true;
+        }
+      }
+    }
+  }
+
+  // Split into component parts
+  this.parts_ = opt_parts || expr.split('/');
+  this.size_ = this.parts_.length;
+  this.last_ = this.parts_[this.size_ - 1];
+  this.root_ = this.parts_[0];
+
+  if (this.size_ == 1) {
+    this.rootExpr_ = this;
+    this.isAbsolute_ = goog.string.startsWith(expr, '$');
+  } else {
+    this.rootExpr_ = goog.ds.Expr.createInternal_(this.root_, null,
+        this, null);
+    this.isAbsolute_ = this.rootExpr_.isAbsolute_;
+    this.root_ = this.rootExpr_.root_;
+  }
+
+  if (this.size_ == 1 && !this.isAbsolute_) {
+    // Check whether expression maps to current node, for convenience
+    this.isCurrent_ = (expr == goog.ds.Expr.String_.CURRENT_NODE_EXPR ||
+        expr == goog.ds.Expr.String_.EMPTY_EXPR);
+
+    // Whether this expression is just an attribute (i.e. '@foo')
+    this.isJustAttribute_ =
+        goog.string.startsWith(expr, goog.ds.Expr.String_.ATTRIBUTE_START);
+
+    // Check whether this is a common node expression
+    this.isAllChildNodes_ = expr == goog.ds.Expr.String_.ALL_CHILD_NODES_EXPR;
+    this.isAllAttributes_ = expr == goog.ds.Expr.String_.ALL_ATTRIBUTES_EXPR;
+    this.isAllElements_ = expr == goog.ds.Expr.String_.ALL_ELEMENTS_EXPR;
+  }
+};
+
+
+/**
+ * Get the source data path for the expression
+ * @return {string} The path.
+ */
+goog.ds.Expr.prototype.getSource = function() {
+  return this.src_;
+};
+
+
+/**
+ * Gets the last part of the expression.
+ * @return {?string} Last part of the expression.
+ */
+goog.ds.Expr.prototype.getLast = function() {
+  return this.last_;
+};
+
+
+/**
+ * Gets the parent expression of this expression, or null if this is top level
+ * @return {goog.ds.Expr} The parent.
+ */
+goog.ds.Expr.prototype.getParent = function() {
+  if (!this.parentExprSet_) {
+    if (this.size_ > 1) {
+      this.parentExpr_ = goog.ds.Expr.createInternal_(null,
+          this.parts_.slice(0, this.parts_.length - 1), this, null);
+    }
+    this.parentExprSet_ = true;
+  }
+  return this.parentExpr_;
+};
+
+
+/**
+ * Gets the parent expression of this expression, or null if this is top level
+ * @return {goog.ds.Expr} The parent.
+ */
+goog.ds.Expr.prototype.getNext = function() {
+  if (!this.nextExprSet_) {
+    if (this.size_ > 1) {
+      this.nextExpr_ = goog.ds.Expr.createInternal_(null, this.parts_.slice(1),
+          null, this);
+    }
+    this.nextExprSet_ = true;
+  }
+  return this.nextExpr_;
+};
+
+
+/**
+ * Evaluate an expression on a data node, and return a value
+ * Recursively walks through child nodes to evaluate
+ * TODO(user) Support other expression functions
+ *
+ * @param {goog.ds.DataNode=} opt_ds Optional datasource to evaluate against.
+ *     If not provided, evaluates against DataManager global root.
+ * @return {*} Value of the node, or null if doesn't exist.
+ */
+goog.ds.Expr.prototype.getValue = function(opt_ds) {
+  if (opt_ds == null) {
+    opt_ds = goog.ds.DataManager.getInstance();
+  } else if (this.isAbsolute_) {
+    opt_ds = opt_ds.getDataRoot ? opt_ds.getDataRoot() :
+        goog.ds.DataManager.getInstance();
+  }
+
+  if (this.isCount_) {
+    var nodes = this.getNodes(opt_ds);
+    return nodes.getCount();
+  }
+
+  if (this.size_ == 1) {
+    return opt_ds.getChildNodeValue(this.root_);
+  } else if (this.size_ == 0) {
+    return opt_ds.get();
+  }
+
+  var nextDs = opt_ds.getChildNode(this.root_);
+
+  if (nextDs == null) {
+    return null;
+  } else {
+    return this.getNext().getValue(nextDs);
+  }
+};
+
+
+/**
+ * Evaluate an expression on a data node, and return matching nodes
+ * Recursively walks through child nodes to evaluate
+ *
+ * @param {goog.ds.DataNode=} opt_ds Optional datasource to evaluate against.
+ *     If not provided, evaluates against data root.
+ * @param {boolean=} opt_canCreate If true, will try to create new nodes.
+ * @return {goog.ds.DataNodeList} Matching nodes.
+ */
+goog.ds.Expr.prototype.getNodes = function(opt_ds, opt_canCreate) {
+  return /** @type {goog.ds.DataNodeList} */(this.getNodes_(opt_ds,
+      false, opt_canCreate));
+};
+
+
+/**
+ * Evaluate an expression on a data node, and return the first matching node
+ * Recursively walks through child nodes to evaluate
+ *
+ * @param {goog.ds.DataNode=} opt_ds Optional datasource to evaluate against.
+ *     If not provided, evaluates against DataManager global root.
+ * @param {boolean=} opt_canCreate If true, will try to create new nodes.
+ * @return {goog.ds.DataNode} Matching nodes, or null if doesn't exist.
+ */
+goog.ds.Expr.prototype.getNode = function(opt_ds, opt_canCreate) {
+  return /** @type {goog.ds.DataNode} */(this.getNodes_(opt_ds,
+      true, opt_canCreate));
+};
+
+
+/**
+ * Evaluate an expression on a data node, and return the first matching node
+ * Recursively walks through child nodes to evaluate
+ *
+ * @param {goog.ds.DataNode=} opt_ds Optional datasource to evaluate against.
+ *     If not provided, evaluates against DataManager global root.
+ * @param {boolean=} opt_selectOne Whether to return single matching DataNode
+ *     or matching nodes in DataNodeList.
+ * @param {boolean=} opt_canCreate If true, will try to create new nodes.
+ * @return {goog.ds.DataNode|goog.ds.DataNodeList} Matching node or nodes,
+ *     depending on value of opt_selectOne.
+ * @private
+ */
+goog.ds.Expr.prototype.getNodes_ = function(opt_ds, opt_selectOne,
+    opt_canCreate) {
+  if (opt_ds == null) {
+    opt_ds = goog.ds.DataManager.getInstance();
+  } else if (this.isAbsolute_) {
+    opt_ds = opt_ds.getDataRoot ? opt_ds.getDataRoot() :
+        goog.ds.DataManager.getInstance();
+  }
+
+  if (this.size_ == 0 && opt_selectOne) {
+      return opt_ds;
+  } else if (this.size_ == 0 && !opt_selectOne) {
+    return new goog.ds.BasicNodeList([opt_ds]);
+  } else if (this.size_ == 1) {
+    if (opt_selectOne) {
+      return opt_ds.getChildNode(this.root_, opt_canCreate);
+    }
+    else {
+      var possibleListChild = opt_ds.getChildNode(this.root_);
+      if (possibleListChild && possibleListChild.isList()) {
+        return possibleListChild.getChildNodes();
+      } else {
+        return opt_ds.getChildNodes(this.root_);
+      }
+    }
+  } else {
+    var nextDs = opt_ds.getChildNode(this.root_, opt_canCreate);
+    if (nextDs == null && opt_selectOne) {
+      return null;
+    } else if (nextDs == null && !opt_selectOne) {
+      return new goog.ds.EmptyNodeList();
+    }
+    return this.getNext().getNodes_(nextDs, opt_selectOne, opt_canCreate);
+  }
+};
+
+
+/**
+ * Whether the expression can be null.
+ *
+ * @type {boolean}
+ * @private
+ */
+goog.ds.Expr.prototype.canBeEmpty_ = false;
+
+
+/**
+ * The parsed paths in the expression
+ *
+ * @type {Array<string>}
+ * @private
+ */
+goog.ds.Expr.prototype.parts_ = [];
+
+
+/**
+ * Number of paths in the expression
+ *
+ * @type {?number}
+ * @private
+ */
+goog.ds.Expr.prototype.size_ = null;
+
+
+/**
+ * The root node path in the expression
+ *
+ * @type {string}
+ * @private
+ */
+goog.ds.Expr.prototype.root_;
+
+
+/**
+ * The last path in the expression
+ *
+ * @type {?string}
+ * @private
+ */
+goog.ds.Expr.prototype.last_ = null;
+
+
+/**
+ * Whether the expression evaluates to current node
+ *
+ * @type {boolean}
+ * @private
+ */
+goog.ds.Expr.prototype.isCurrent_ = false;
+
+
+/**
+ * Whether the expression is just an attribute
+ *
+ * @type {boolean}
+ * @private
+ */
+goog.ds.Expr.prototype.isJustAttribute_ = false;
+
+
+/**
+ * Does this expression select all DOM-style child nodes (element and text)
+ *
+ * @type {boolean}
+ * @private
+ */
+goog.ds.Expr.prototype.isAllChildNodes_ = false;
+
+
+/**
+ * Does this expression select all DOM-style attribute nodes (starts with '@')
+ *
+ * @type {boolean}
+ * @private
+ */
+goog.ds.Expr.prototype.isAllAttributes_ = false;
+
+
+/**
+ * Does this expression select all DOM-style element child nodes
+ *
+ * @type {boolean}
+ * @private
+ */
+goog.ds.Expr.prototype.isAllElements_ = false;
+
+
+/**
+ * The function used by this expression
+ *
+ * @type {?string}
+ * @private
+ */
+goog.ds.Expr.prototype.exprFn_ = null;
+
+
+/**
+ * Cached value for the parent expression.
+ * @type {goog.ds.Expr?}
+ * @private
+ */
+goog.ds.Expr.prototype.parentExpr_ = null;
+
+
+/**
+ * Cached value for the next expression.
+ * @type {goog.ds.Expr?}
+ * @private
+ */
+goog.ds.Expr.prototype.nextExpr_ = null;
+
+
+/**
+ * Create an expression from a string, can use cached values
+ *
+ * @param {string} expr The expression string.
+ * @return {goog.ds.Expr} The expression object.
+ */
+goog.ds.Expr.create = function(expr) {
+  var result = goog.ds.Expr.cache_[expr];
+
+  if (result == null) {
+    result = new goog.ds.Expr(expr);
+    goog.ds.Expr.cache_[expr] = result;
+  }
+  return result;
+};
+
+
+/**
+ * Create an expression from a string, can use cached values
+ * Uses hints from related expressions to help in creation
+ *
+ * @param {?string=} opt_expr The string expression source.
+ * @param {Array=} opt_parts Array of the parts of an expression.
+ * @param {goog.ds.Expr=} opt_childExpr Optional child of this expression,
+ *   passed in as a hint for processing.
+ * @param {goog.ds.Expr=} opt_prevExpr Optional preceding expression
+ *   (i.e. $A/B/C is previous expression to B/C) passed in as a hint for
+ *   processing.
+ * @return {goog.ds.Expr} The expression object.
+ * @private
+ */
+goog.ds.Expr.createInternal_ = function(opt_expr, opt_parts, opt_childExpr,
+    opt_prevExpr) {
+  var expr = opt_expr || opt_parts.join('/');
+  var result = goog.ds.Expr.cache_[expr];
+
+  if (result == null) {
+    result = new goog.ds.Expr();
+    result.setSource_(expr, opt_parts, opt_childExpr, opt_prevExpr);
+    goog.ds.Expr.cache_[expr] = result;
+  }
+  return result;
+};
+
+
+/**
+ * Cache of pre-parsed expressions
+ * @private
+ */
+goog.ds.Expr.cache_ = {};
+
+
+/**
+ * Commonly used strings in expressions.
+ * @enum {string}
+ * @private
+ */
+goog.ds.Expr.String_ = {
+  SEPARATOR: '/',
+  CURRENT_NODE_EXPR: '.',
+  EMPTY_EXPR: '',
+  ATTRIBUTE_START: '@',
+  ALL_CHILD_NODES_EXPR: '*|text()',
+  ALL_ATTRIBUTES_EXPR: '@*',
+  ALL_ELEMENTS_EXPR: '*',
+  NAME_EXPR: 'name()',
+  COUNT_EXPR: 'count()',
+  POSITION_EXPR: 'position()',
+  INDEX_START: '[',
+  INDEX_END: ']',
+  CAN_BE_EMPTY: '?'
+};
+
+
+/**
+ * Standard expressions
+ */
+
+
+/**
+ * The current node
+ */
+goog.ds.Expr.CURRENT = goog.ds.Expr.create(
+    goog.ds.Expr.String_.CURRENT_NODE_EXPR);
+
+
+/**
+ * For DOM interop - all DOM child nodes (text + element).
+ * Text nodes have dataName #text
+ */
+goog.ds.Expr.ALL_CHILD_NODES =
+    goog.ds.Expr.create(goog.ds.Expr.String_.ALL_CHILD_NODES_EXPR);
+
+
+/**
+ * For DOM interop - all DOM element child nodes
+ */
+goog.ds.Expr.ALL_ELEMENTS =
+    goog.ds.Expr.create(goog.ds.Expr.String_.ALL_ELEMENTS_EXPR);
+
+
+/**
+ * For DOM interop - all DOM attribute nodes
+ * Attribute nodes have dataName starting with "@"
+ */
+goog.ds.Expr.ALL_ATTRIBUTES =
+    goog.ds.Expr.create(goog.ds.Expr.String_.ALL_ATTRIBUTES_EXPR);
+
+
+/**
+ * Get the dataName of a node
+ */
+goog.ds.Expr.NAME = goog.ds.Expr.create(goog.ds.Expr.String_.NAME_EXPR);
+
+
+/**
+ * Get the count of nodes matching an expression
+ */
+goog.ds.Expr.COUNT = goog.ds.Expr.create(goog.ds.Expr.String_.COUNT_EXPR);
+
+
+/**
+ * Get the position of the "current" node in the current node list
+ * This will only apply for datasources that support the concept of a current
+ * node (none exist yet). This is similar to XPath position() and concept of
+ * current node
+ */
+goog.ds.Expr.POSITION = goog.ds.Expr.create(goog.ds.Expr.String_.POSITION_EXPR);


[05/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/i18n/charpickerdata.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/i18n/charpickerdata.js b/externs/GCL/externs/goog/i18n/charpickerdata.js
new file mode 100644
index 0000000..edb6b26
--- /dev/null
+++ b/externs/GCL/externs/goog/i18n/charpickerdata.js
@@ -0,0 +1,3666 @@
+// Copyright 2010 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 Character lists and their classifications used by character
+ * picker widget. Autogenerated from Unicode data:
+ * https://sites/cibu/character-picker.
+ */
+
+goog.provide('goog.i18n.CharPickerData');
+
+
+
+/**
+ * Object holding two level character organization and character listing.
+ * @constructor
+ */
+goog.i18n.CharPickerData = function() {};
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SYMBOL = goog.getMsg('Symbol');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_ARROWS = goog.getMsg('Arrows');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_BRAILLE = goog.getMsg('Braille');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_CONTROL_PICTURES =
+    goog.getMsg('Control Pictures');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_CURRENCY = goog.getMsg('Currency');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_EMOTICONS = goog.getMsg('Emoticons');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_GAME_PIECES = goog.getMsg('Game Pieces');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_GENDER_AND_GENEALOGICAL =
+    goog.getMsg('Gender and Genealogical');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_GEOMETRIC_SHAPES =
+    goog.getMsg('Geometric Shapes');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_KEYBOARD_AND_UI =
+    goog.getMsg('Keyboard and UI');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_LATIN_1_SUPPLEMENT =
+    goog.getMsg('Latin 1 Supplement');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MATH = goog.getMsg('Math');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MATH_ALPHANUMERIC =
+    goog.getMsg('Math Alphanumeric');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MISCELLANEOUS = goog.getMsg('Miscellaneous');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MUSICAL = goog.getMsg('Musical');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_STARS_ASTERISKS =
+    goog.getMsg('Stars/Asterisks');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SUBSCRIPT = goog.getMsg('Subscript');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SUPERSCRIPT = goog.getMsg('Superscript');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TECHNICAL = goog.getMsg('Technical');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TRANSPORT_AND_MAP =
+    goog.getMsg('Transport And Map');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_WEATHER_AND_ASTROLOGICAL =
+    goog.getMsg('Weather and Astrological');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_YIJING_TAI_XUAN_JING =
+    goog.getMsg('Yijing / Tai Xuan Jing');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HISTORIC = goog.getMsg('Historic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_COMPATIBILITY = goog.getMsg('Compatibility');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_EMOJI = goog.getMsg('Emoji');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_PEOPLE_AND_EMOTIONS =
+    goog.getMsg('People and Emotions');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_ANIMALS_PLANTS_AND_FOOD =
+    goog.getMsg('Animals, Plants and Food');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_OBJECTS = goog.getMsg('Objects');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SPORTS_CELEBRATIONS_AND_ACTIVITIES =
+    goog.getMsg('Sports, Celebrations and Activities');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TRANSPORT_MAPS_AND_SIGNAGE =
+    goog.getMsg('Transport, Maps and Signage');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_WEATHER_SCENES_AND_ZODIAC_SIGNS =
+    goog.getMsg('Weather, Scenes and Zodiac signs');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_ENCLOSED = goog.getMsg('Enclosed');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MARKS = goog.getMsg('Marks');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SYMBOLS = goog.getMsg('Symbols');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_PUNCTUATION = goog.getMsg('Punctuation');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_ASCII_BASED = goog.getMsg('ASCII Based');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_DASH_CONNECTOR = goog.getMsg('Dash/Connector');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_OTHER = goog.getMsg('Other');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_PAIRED = goog.getMsg('Paired');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_NUMBER = goog.getMsg('Number');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_DECIMAL = goog.getMsg('Decimal');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_ENCLOSED_DOTTED =
+    goog.getMsg('Enclosed/Dotted');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_FRACTIONS_RELATED =
+    goog.getMsg('Fractions/Related');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_FORMAT_WHITESPACE =
+    goog.getMsg('Format & Whitespace');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_FORMAT = goog.getMsg('Format');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_VARIATION_SELECTOR =
+    goog.getMsg('Variation Selector');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_WHITESPACE = goog.getMsg('Whitespace');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MODIFIER = goog.getMsg('Modifier');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_ENCLOSING = goog.getMsg('Enclosing');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_NONSPACING = goog.getMsg('Nonspacing');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SPACING = goog.getMsg('Spacing');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_LATIN = goog.getMsg('Latin');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_COMMON = goog.getMsg('Common');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_FLIPPED_MIRRORED =
+    goog.getMsg('Flipped/Mirrored');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_PHONETICS_IPA = goog.getMsg('Phonetics (IPA)');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_PHONETICS_X_IPA =
+    goog.getMsg('Phonetics (X-IPA)');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_OTHER_EUROPEAN_SCRIPTS =
+    goog.getMsg('Other European Scripts');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_ARMENIAN = goog.getMsg('Armenian');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_CYRILLIC = goog.getMsg('Cyrillic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_GEORGIAN = goog.getMsg('Georgian');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_GREEK = goog.getMsg('Greek');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_CYPRIOT = goog.getMsg('Cypriot');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_GLAGOLITIC = goog.getMsg('Glagolitic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_GOTHIC = goog.getMsg('Gothic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_LINEAR_B = goog.getMsg('Linear B');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_OGHAM = goog.getMsg('Ogham');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_OLD_ITALIC = goog.getMsg('Old Italic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_RUNIC = goog.getMsg('Runic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SHAVIAN = goog.getMsg('Shavian');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_AMERICAN_SCRIPTS =
+    goog.getMsg('American Scripts');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_CANADIAN_ABORIGINAL =
+    goog.getMsg('Canadian Aboriginal');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_CHEROKEE = goog.getMsg('Cherokee');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_DESERET = goog.getMsg('Deseret');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_AFRICAN_SCRIPTS =
+    goog.getMsg('African Scripts');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_EGYPTIAN_HIEROGLYPHS =
+    goog.getMsg('Egyptian Hieroglyphs');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_ETHIOPIC = goog.getMsg('Ethiopic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MEROITIC_CURSIVE =
+    goog.getMsg('Meroitic Cursive');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MEROITIC_HIEROGLYPHS =
+    goog.getMsg('Meroitic Hieroglyphs');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_NKO = goog.getMsg('Nko');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TIFINAGH = goog.getMsg('Tifinagh');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_VAI = goog.getMsg('Vai');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_BAMUM = goog.getMsg('Bamum');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_COPTIC = goog.getMsg('Coptic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_OSMANYA = goog.getMsg('Osmanya');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MIDDLE_EASTERN_SCRIPTS =
+    goog.getMsg('Middle Eastern Scripts');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_ARABIC = goog.getMsg('Arabic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HEBREW = goog.getMsg('Hebrew');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_IMPERIAL_ARAMAIC =
+    goog.getMsg('Imperial Aramaic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_INSCRIPTIONAL_PAHLAVI =
+    goog.getMsg('Inscriptional Pahlavi');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_INSCRIPTIONAL_PARTHIAN =
+    goog.getMsg('Inscriptional Parthian');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MANDAIC = goog.getMsg('Mandaic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_OLD_SOUTH_ARABIAN =
+    goog.getMsg('Old South Arabian');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SAMARITAN = goog.getMsg('Samaritan');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SYRIAC = goog.getMsg('Syriac');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_AVESTAN = goog.getMsg('Avestan');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_CARIAN = goog.getMsg('Carian');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_CUNEIFORM = goog.getMsg('Cuneiform');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_LYCIAN = goog.getMsg('Lycian');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_LYDIAN = goog.getMsg('Lydian');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_OLD_PERSIAN = goog.getMsg('Old Persian');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_PHOENICIAN = goog.getMsg('Phoenician');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_UGARITIC = goog.getMsg('Ugaritic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SOUTH_ASIAN_SCRIPTS =
+    goog.getMsg('South Asian Scripts');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_BENGALI = goog.getMsg('Bengali');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_CHAKMA = goog.getMsg('Chakma');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_DEVANAGARI = goog.getMsg('Devanagari');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_GUJARATI = goog.getMsg('Gujarati');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_GURMUKHI = goog.getMsg('Gurmukhi');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_KANNADA = goog.getMsg('Kannada');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_LEPCHA = goog.getMsg('Lepcha');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_LIMBU = goog.getMsg('Limbu');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MALAYALAM = goog.getMsg('Malayalam');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MEETEI_MAYEK = goog.getMsg('Meetei Mayek');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_OL_CHIKI = goog.getMsg('Ol Chiki');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_ORIYA = goog.getMsg('Oriya');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SAURASHTRA = goog.getMsg('Saurashtra');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SINHALA = goog.getMsg('Sinhala');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SORA_SOMPENG = goog.getMsg('Sora Sompeng');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TAMIL = goog.getMsg('Tamil');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TELUGU = goog.getMsg('Telugu');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_THAANA = goog.getMsg('Thaana');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TIBETAN = goog.getMsg('Tibetan');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_BRAHMI = goog.getMsg('Brahmi');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_KAITHI = goog.getMsg('Kaithi');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_KHAROSHTHI = goog.getMsg('Kharoshthi');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SHARADA = goog.getMsg('Sharada');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SYLOTI_NAGRI = goog.getMsg('Syloti Nagri');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TAKRI = goog.getMsg('Takri');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SOUTHEAST_ASIAN_SCRIPTS =
+    goog.getMsg('Southeast Asian Scripts');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_BALINESE = goog.getMsg('Balinese');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_BATAK = goog.getMsg('Batak');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_CHAM = goog.getMsg('Cham');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_JAVANESE = goog.getMsg('Javanese');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_KAYAH_LI = goog.getMsg('Kayah Li');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_KHMER = goog.getMsg('Khmer');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_LAO = goog.getMsg('Lao');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MYANMAR = goog.getMsg('Myanmar');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_NEW_TAI_LUE = goog.getMsg('New Tai Lue');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TAI_LE = goog.getMsg('Tai Le');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TAI_THAM = goog.getMsg('Tai Tham');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TAI_VIET = goog.getMsg('Tai Viet');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_THAI = goog.getMsg('Thai');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_BUGINESE = goog.getMsg('Buginese');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_BUHID = goog.getMsg('Buhid');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HANUNOO = goog.getMsg('Hanunoo');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_REJANG = goog.getMsg('Rejang');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_SUNDANESE = goog.getMsg('Sundanese');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TAGALOG = goog.getMsg('Tagalog');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_TAGBANWA = goog.getMsg('Tagbanwa');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HANGUL = goog.getMsg('Hangul');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_OTHER_EAST_ASIAN_SCRIPTS =
+    goog.getMsg('Other East Asian Scripts');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_BOPOMOFO = goog.getMsg('Bopomofo');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HIRAGANA = goog.getMsg('Hiragana');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_KATAKANA = goog.getMsg('Katakana');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_LISU = goog.getMsg('Lisu');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MIAO = goog.getMsg('Miao');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_MONGOLIAN = goog.getMsg('Mongolian');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_OLD_TURKIC = goog.getMsg('Old Turkic');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_PHAGS_PA = goog.getMsg('Phags Pa');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_YI = goog.getMsg('Yi');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HAN_1_STROKE_RADICALS =
+    goog.getMsg('Han 1-Stroke Radicals');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_LESS_COMMON = goog.getMsg('Less Common');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HAN_2_STROKE_RADICALS =
+    goog.getMsg('Han 2-Stroke Radicals');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HAN_3_STROKE_RADICALS =
+    goog.getMsg('Han 3-Stroke Radicals');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HAN_4_STROKE_RADICALS =
+    goog.getMsg('Han 4-Stroke Radicals');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HAN_5_STROKE_RADICALS =
+    goog.getMsg('Han 5-Stroke Radicals');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HAN_6_STROKE_RADICALS =
+    goog.getMsg('Han 6-Stroke Radicals');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HAN_7_STROKE_RADICALS =
+    goog.getMsg('Han 7-Stroke Radicals');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HAN_8_STROKE_RADICALS =
+    goog.getMsg('Han 8-Stroke Radicals');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HAN_9_STROKE_RADICALS =
+    goog.getMsg('Han 9-Stroke Radicals');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HAN_10_STROKE_RADICALS =
+    goog.getMsg('Han 10-Stroke Radicals');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HAN_11_17_STROKE_RADICALS =
+    goog.getMsg('Han 11..17-Stroke Radicals');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_HAN_OTHER = goog.getMsg('Han - Other');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_CJK_STROKES = goog.getMsg('CJK Strokes');
+
+
+/**
+ * @desc Name for a symbol or character category. Used in a pull-down list
+ *   shown to a  document editing user trying to insert a special character.
+ *   Newlines are not allowed; translation should be a noun and as consise as
+ *   possible. More details:
+ *   docs/fileview?id=0B8NbxddKsFtwYjExMGJjNzgtYjkzOS00NjdiLTlmOGQtOGVhZDkyZDU5YjM4.
+ * @type {string}
+ */
+goog.i18n.CharPickerData.MSG_CP_IDEOGRAPHIC_DESCRIPTION =
+    goog.getMsg('Ideographic Description');
+
+
+/**
+ * Top catagory names of character organization.
+ * @type {!Array<string>}
+ */
+goog.i18n.CharPickerData.prototype.categories = [
+  goog.i18n.CharPickerData.MSG_CP_SYMBOL,
+  goog.i18n.CharPickerData.MSG_CP_EMOJI,
+  goog.i18n.CharPickerData.MSG_CP_PUNCTUATION,
+  goog.i18n.CharPickerData.MSG_CP_NUMBER,
+  goog.i18n.CharPickerData.MSG_CP_FORMAT_WHITESPACE,
+  goog.i18n.CharPickerData.MSG_CP_MODIFIER,
+  goog.i18n.CharPickerData.MSG_CP_LATIN,
+  goog.i18n.CharPickerData.MSG_CP_OTHER_EUROPEAN_SCRIPTS,
+  goog.i18n.CharPickerData.MSG_CP_AMERICAN_SCRIPTS,
+  goog.i18n.CharPickerData.MSG_CP_AFRICAN_SCRIPTS,
+  goog.i18n.CharPickerData.MSG_CP_MIDDLE_EASTERN_SCRIPTS,
+  goog.i18n.CharPickerData.MSG_CP_SOUTH_ASIAN_SCRIPTS,
+  goog.i18n.CharPickerData.MSG_CP_SOUTHEAST_ASIAN_SCRIPTS,
+  goog.i18n.CharPickerData.MSG_CP_HANGUL,
+  goog.i18n.CharPickerData.MSG_CP_OTHER_EAST_ASIAN_SCRIPTS,
+  goog.i18n.CharPickerData.MSG_CP_HAN_1_STROKE_RADICALS,
+  goog.i18n.CharPickerData.MSG_CP_HAN_2_STROKE_RADICALS,
+  goog.i18n.CharPickerData.MSG_CP_HAN_3_STROKE_RADICALS,
+  goog.i18n.CharPickerData.MSG_CP_HAN_4_STROKE_RADICALS,
+  goog.i18n.CharPickerData.MSG_CP_HAN_5_STROKE_RADICALS,
+  goog.i18n.CharPickerData.MSG_CP_HAN_6_STROKE_RADICALS,
+  goog.i18n.CharPickerData.MSG_CP_HAN_7_STROKE_RADICALS,
+  goog.i18n.CharPickerData.MSG_CP_HAN_8_STROKE_RADICALS,
+  goog.i18n.CharPickerData.MSG_CP_HAN_9_STROKE_RADICALS,
+  goog.i18n.CharPickerData.MSG_CP_HAN_10_STROKE_RADICALS,
+  goog.i18n.CharPickerData.MSG_CP_HAN_11_17_STROKE_RADICALS,
+  goog.i18n.CharPickerData.MSG_CP_HAN_OTHER
+];
+
+
+/**
+ * Names of subcategories. Each message this array is the
+ * name for the corresponding subcategory specified in
+ * {@code goog.i18n.CharPickerData.subcategories}.
+ * @type {!Array<string>}
+ */
+goog.i18n.CharPickerData.SUBCATEGORY_NAMES_OF_SYMBOL = [
+  goog.i18n.CharPickerData.MSG_CP_ARROWS,
+  goog.i18n.CharPickerData.MSG_CP_BRAILLE,
+  goog.i18n.CharPickerData.MSG_CP_CONTROL_PICTURES,
+  goog.i18n.CharPickerData.MSG_CP_CURRENCY,
+  goog.i18n.CharPickerData.MSG_CP_EMOTICONS,
+  goog.i18n.CharPickerData.MSG_CP_GAME_PIECES,
+  goog.i18n.CharPickerData.MSG_CP_GENDER_AND_GENEALOGICAL,
+  goog.i18n.CharPickerData.MSG_CP_GEOMETRIC_SHAPES,
+  goog.i18n.CharPickerData.MSG_CP_KEYBOARD_AND_UI,
+  goog.i18n.CharPickerData.MSG_CP_LATIN_1_SUPPLEMENT,
+  goog.i18n.CharPickerData.MSG_CP_MATH,
+  goog.i18n.CharPickerData.MSG_CP_MATH_ALPHANUMERIC,
+  goog.i18n.CharPickerData.MSG_CP_MISCELLANEOUS,
+  goog.i18n.CharPickerData.MSG_CP_MUSICAL,
+  goog.i18n.CharPickerData.MSG_CP_STARS_ASTERISKS,
+  goog.i18n.CharPickerData.MSG_CP_SUBSCRIPT,
+  goog.i18n.CharPickerData.MSG_CP_SUPERSCRIPT,
+  goog.i18n.CharPickerData.MSG_CP_TECHNICAL,
+  goog.i18n.CharPickerData.MSG_CP_TRANSPORT_AND_MAP,
+  goog.i18n.CharPickerData.MSG_CP_WEATHER_AND_ASTROLOGICAL,
+  goog.i18n.CharPickerData.MSG_CP_YIJING_TAI_XUAN_JING,
+  goog.i18n.CharPickerData.MSG_CP_HISTORIC,
+  goog.i18n.CharPickerData.MSG_CP_COMPATIBILITY
+];
+
+
+/**
+ * List of characters in base88 encoding scheme. Each base88 encoded
+ * charater string represents corresponding subcategory specified in
+ * {@code goog.i18n.CharPickerData.subcategories}. Encoding
+ * scheme is described in {@code goog.i18n.CharListDecompressor}.
+ * @type {!Array<string>}
+ */
+goog.i18n.CharPickerData.CHARLIST_OF_SYMBOL = [
+  '2>807AnTMm6e6HDk%`O728F1f4V1PNF2WF1G}58?]514M]Ol1%2l2^3X1U:1Un2Mb>$0MD-(068k11I3706:%MwiZ06',
+  ';oA0FN',
+  '(j90d3',
+  'H3XBMQQ10HB(2106uPM]N:qol202S20t2^.Z0^xM0:91E]J6O6',
+  ';(i1-5W?',
+  'Q6A06f5#1H2,]4MeEY[W1@3W}891N1GF1GN18N1P%k',
+  '2JA0sOc',
+  'oG90nMcPTFNfFEQE10t2H3kQ7X1sj>$0OW6*F%E',
+  '(P90UGv771.Uv46%7Y^Y1F2mc]1M+<Z1',
+  '9FP1',
+  ':3f1En5894WX3:2v+]lEQ?60f2E11OH1P1M]1U11UfCf111MuUmH6Ue6WGGu:26G8:2NO$M:16H8%2V28H211cvg.]4s9AnU#5PNdkX4-1Gc24P1P2:2P2:2P2:2P2:2P2g>50M8V2868G8,8M88mW888E868G8888868GM8k8M8M88,8d1eE8U8d1%46bf$0:;c8%Ef1Ev2:28]BmMbp)02p8071WO6WUw+w0',
+  '9G6e:-EGX26G6(k70Ocm,]AWG,8OUmOO68E86uMeU^`Q1t78V686GG6GM8|88k8-58MGs8k8d28M8U8Ok8-UGF28F28#28F28#28F28#28F28#28F28sGd4rLS1H1',
+  '1FGW8I(90EHB686WU8l1$Uv4?8En1E8|:29168U8718k8kG8M868688686e686888,148MO8|8E]7wV10k2tN1cYf806813692W]3%68X2f2|O6G86%1P5m6%5$6%468e[E8c11126v1MH2|%F9DuM8E86m8UTN%065j#0M',
+  ';DA0k2mO1NM[d3GV5eEms$6ut2WN493@5OA;80sD790UOc$sGk%2MfDE',
+  ';OA0v5-3g510E^jW1WV1:l',
+  'Qq80N1871QC30',
+  'XFu6e6^X80O?vE82+Y16T+g1Ug2709+H12F30QjW0PC6',
+  'gM90sW#1G6$l7H1!%2N2O?ml1]6?',
+  'g?i1N6',
+  'Q4A0F1mv3}1v8,uUe^zX171',
+  'w8A0sf7c2WA0#5A>E1-7',
+  'I{)0%4!P7|%4}3A,$0dA',
+  '(PD0M(ZU16H1-3e!u6'
+];
+
+
+/**
+ * Names of subcategories. Each message this array is the
+ * name for the corresponding subcategory specified in
+ * {@code goog.i18n.CharPickerData.subcategories}.
+ * @type {!Array<string>}
+ */
+goog.i18n.CharPickerData.SUBCATEGORY_NAMES_OF_EMOJI = [
+  goog.i18n.CharPickerData.MSG_CP_PEOPLE_AND_EMOTIONS,
+  goog.i18n.CharPickerData.MSG_CP_ANIMALS_PLANTS_AND_FOOD,
+  goog.i18n.CharPickerData.MSG_CP_OBJECTS,
+  goog.i18n.CharPickerData.MSG_CP_SPORTS_CELEBRATIONS_AND_ACTIVITIES,
+  goog.i18n.CharPickerData.MSG_CP_TRANSPORT_MAPS_AND_SIGNAGE,
+  goog.i18n.CharPickerData.MSG_CP_WEATHER_SCENES_AND_ZODIAC_SIGNS,
+  goog.i18n.CharPickerData.MSG_CP_ENCLOSED,
+  goog.i18n.CharPickerData.MSG_CP_MARKS,
+  goog.i18n.CharPickerData.MSG_CP_SYMBOLS
+];
+
+
+/**
+ * List of characters in base88 encoding scheme. Each base88 encoded
+ * charater string represents corresponding subcategory specified in
+ * {@code goog.i18n.CharPickerData.subcategories}. Encoding
+ * scheme is described in {@code goog.i18n.CharListDecompressor}.
+ * @type {!Array<string>}
+ */
+goog.i18n.CharPickerData.CHARLIST_OF_EMOJI = [
+  '^6A0n2:IE]7Y>X18N1%1-28EOO8871G|%U-5W?',
+  'I6A0A_X1c8N6eXBt5',
+  ';O906PJG]m1C1Amew)X16:It1]2W68E8X168[8d68MP171P1!1372',
+  '2DA0s%76o]W1@3nAN1GF1GN18N1Xzd191N38U9I',
+  '(DA0v1O]2694t1m72$2>X1d1%DvXUvBN6',
+  'Q4A0F1mv4|HAUe98(rX1@2]k',
+  'Y#90;v308ICU1d2W-3H9EH1-3e!u6',
+  ';5A09M9188:48WE8n5EH2',
+  'Y%C0(wV1P7N3[EP1M'
+];
+
+
+/**
+ * Names of subcategories. Each message this array is the
+ * name for the corresponding subcategory specified in
+ * {@code goog.i18n.CharPickerData.subcategories}.
+ * @type {!Array<string>}
+ */
+goog.i18n.CharPickerData.SUBCATEGORY_NAMES_OF_PUNCTUATION = [
+  goog.i18n.CharPickerData.MSG_CP_ASCII_BASED,
+  goog.i18n.CharPickerData.MSG_CP_DASH_CONNECTOR,
+  goog.i18n.CharPickerData.MSG_CP_OTHER,
+  goog.i18n.CharPickerData.MSG_CP_PAIRED,
+  goog.i18n.CharPickerData.MSG_CP_HISTORIC,
+  goog.i18n.CharPickerData.MSG_CP_COMPATIBILITY
+];
+
+
+/**
+ * List of characters in base88 encoding scheme. Each base88 encoded
+ * charater string represents corresponding subcategory specified in
+ * {@code goog.i18n.CharPickerData.subcategories}. Encoding
+ * scheme is described in {@code goog.i18n.CharListDecompressor}.
+ * @type {!Array<string>}
+ */
+goog.i18n.CharPickerData.CHARLIST_OF_PUNCTUATION = [
+  ':2M8EG886[6O6f2H6eP16u',
+  '14f4gX80c%36%1gu30:26Q3t0XG',
+  '(s70:<.MOEmEGGG8OEms88Iu3068G6n1!',
+  'n36f48v2894X1;P80sP26[6]46P16nvMPF6f3c1^F1H76:2,va@1%5M]26;7106G,fh,Gs2Ms06nPcXF6f48v288686',
+  'gm808kQT30MnN72v1U8U(%t0Eb(t0',
+  'Ig80e91E91686W8$EH1X36P162pw0,12-1G|8F18W86nDE8c8M[6O6X2E8f2886'
+];
+
+
+/**
+ * Names of subcategories. Each message this array is the
+ * name for the corresponding subcategory specified in
+ * {@code goog.i18n.CharPickerData.subcategories}.
+ * @type {!Array<string>}
+ */
+goog.i18n.CharPickerData.SUBCATEGORY_NAMES_OF_NUMBER = [
+  goog.i18n.CharPickerData.MSG_CP_DECIMAL,
+  goog.i18n.CharPickerData.MSG_CP_ENCLOSED_DOTTED,
+  goog.i18n.CharPickerData.MSG_CP_FRACTIONS_RELATED,
+  goog.i18n.CharPickerData.MSG_CP_OTHER,
+  goog.i18n.CharPickerData.MSG_CP_HISTORIC,
+  goog.i18n.CharPickerData.MSG_CP_COMPATIBILITY
+];
+
+
+/**
+ * 

<TRUNCATED>

[19/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/browserevent.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/browserevent.js b/externs/GCL/externs/goog/events/browserevent.js
new file mode 100644
index 0000000..f0773ce
--- /dev/null
+++ b/externs/GCL/externs/goog/events/browserevent.js
@@ -0,0 +1,386 @@
+// Copyright 2005 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 patched, standardized event object for browser events.
+ *
+ * <pre>
+ * The patched event object contains the following members:
+ * - type           {string}    Event type, e.g. 'click'
+ * - target         {Object}    The element that actually triggered the event
+ * - currentTarget  {Object}    The element the listener is attached to
+ * - relatedTarget  {Object}    For mouseover and mouseout, the previous object
+ * - offsetX        {number}    X-coordinate relative to target
+ * - offsetY        {number}    Y-coordinate relative to target
+ * - clientX        {number}    X-coordinate relative to viewport
+ * - clientY        {number}    Y-coordinate relative to viewport
+ * - screenX        {number}    X-coordinate relative to the edge of the screen
+ * - screenY        {number}    Y-coordinate relative to the edge of the screen
+ * - button         {number}    Mouse button. Use isButton() to test.
+ * - keyCode        {number}    Key-code
+ * - ctrlKey        {boolean}   Was ctrl key depressed
+ * - altKey         {boolean}   Was alt key depressed
+ * - shiftKey       {boolean}   Was shift key depressed
+ * - metaKey        {boolean}   Was meta key depressed
+ * - defaultPrevented {boolean} Whether the default action has been prevented
+ * - state          {Object}    History state object
+ *
+ * NOTE: The keyCode member contains the raw browser keyCode. For normalized
+ * key and character code use {@link goog.events.KeyHandler}.
+ * </pre>
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+goog.provide('goog.events.BrowserEvent');
+goog.provide('goog.events.BrowserEvent.MouseButton');
+
+goog.require('goog.events.BrowserFeature');
+goog.require('goog.events.Event');
+goog.require('goog.events.EventType');
+goog.require('goog.reflect');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Accepts a browser event object and creates a patched, cross browser event
+ * object.
+ * The content of this object will not be initialized if no event object is
+ * provided. If this is the case, init() needs to be invoked separately.
+ * @param {Event=} opt_e Browser event object.
+ * @param {EventTarget=} opt_currentTarget Current target for event.
+ * @constructor
+ * @extends {goog.events.Event}
+ */
+goog.events.BrowserEvent = function(opt_e, opt_currentTarget) {
+  goog.events.BrowserEvent.base(this, 'constructor', opt_e ? opt_e.type : '');
+
+  /**
+   * Target that fired the event.
+   * @override
+   * @type {Node}
+   */
+  this.target = null;
+
+  /**
+   * Node that had the listener attached.
+   * @override
+   * @type {Node|undefined}
+   */
+  this.currentTarget = null;
+
+  /**
+   * For mouseover and mouseout events, the related object for the event.
+   * @type {Node}
+   */
+  this.relatedTarget = null;
+
+  /**
+   * X-coordinate relative to target.
+   * @type {number}
+   */
+  this.offsetX = 0;
+
+  /**
+   * Y-coordinate relative to target.
+   * @type {number}
+   */
+  this.offsetY = 0;
+
+  /**
+   * X-coordinate relative to the window.
+   * @type {number}
+   */
+  this.clientX = 0;
+
+  /**
+   * Y-coordinate relative to the window.
+   * @type {number}
+   */
+  this.clientY = 0;
+
+  /**
+   * X-coordinate relative to the monitor.
+   * @type {number}
+   */
+  this.screenX = 0;
+
+  /**
+   * Y-coordinate relative to the monitor.
+   * @type {number}
+   */
+  this.screenY = 0;
+
+  /**
+   * Which mouse button was pressed.
+   * @type {number}
+   */
+  this.button = 0;
+
+  /**
+   * Keycode of key press.
+   * @type {number}
+   */
+  this.keyCode = 0;
+
+  /**
+   * Keycode of key press.
+   * @type {number}
+   */
+  this.charCode = 0;
+
+  /**
+   * Whether control was pressed at time of event.
+   * @type {boolean}
+   */
+  this.ctrlKey = false;
+
+  /**
+   * Whether alt was pressed at time of event.
+   * @type {boolean}
+   */
+  this.altKey = false;
+
+  /**
+   * Whether shift was pressed at time of event.
+   * @type {boolean}
+   */
+  this.shiftKey = false;
+
+  /**
+   * Whether the meta key was pressed at time of event.
+   * @type {boolean}
+   */
+  this.metaKey = false;
+
+  /**
+   * History state object, only set for PopState events where it's a copy of the
+   * state object provided to pushState or replaceState.
+   * @type {Object}
+   */
+  this.state = null;
+
+  /**
+   * Whether the default platform modifier key was pressed at time of event.
+   * (This is control for all platforms except Mac, where it's Meta.)
+   * @type {boolean}
+   */
+  this.platformModifierKey = false;
+
+  /**
+   * The browser event object.
+   * @private {Event}
+   */
+  this.event_ = null;
+
+  if (opt_e) {
+    this.init(opt_e, opt_currentTarget);
+  }
+};
+goog.inherits(goog.events.BrowserEvent, goog.events.Event);
+
+
+/**
+ * Normalized button constants for the mouse.
+ * @enum {number}
+ */
+goog.events.BrowserEvent.MouseButton = {
+  LEFT: 0,
+  MIDDLE: 1,
+  RIGHT: 2
+};
+
+
+/**
+ * Static data for mapping mouse buttons.
+ * @type {!Array<number>}
+ */
+goog.events.BrowserEvent.IEButtonMap = [
+  1, // LEFT
+  4, // MIDDLE
+  2  // RIGHT
+];
+
+
+/**
+ * Accepts a browser event object and creates a patched, cross browser event
+ * object.
+ * @param {Event} e Browser event object.
+ * @param {EventTarget=} opt_currentTarget Current target for event.
+ */
+goog.events.BrowserEvent.prototype.init = function(e, opt_currentTarget) {
+  var type = this.type = e.type;
+
+  // TODO(nicksantos): Change this.target to type EventTarget.
+  this.target = /** @type {Node} */ (e.target) || e.srcElement;
+
+  // TODO(nicksantos): Change this.currentTarget to type EventTarget.
+  this.currentTarget = /** @type {Node} */ (opt_currentTarget);
+
+  var relatedTarget = /** @type {Node} */ (e.relatedTarget);
+  if (relatedTarget) {
+    // There's a bug in FireFox where sometimes, relatedTarget will be a
+    // chrome element, and accessing any property of it will get a permission
+    // denied exception. See:
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=497780
+    if (goog.userAgent.GECKO) {
+      if (!goog.reflect.canAccessProperty(relatedTarget, 'nodeName')) {
+        relatedTarget = null;
+      }
+    }
+    // TODO(arv): Use goog.events.EventType when it has been refactored into its
+    // own file.
+  } else if (type == goog.events.EventType.MOUSEOVER) {
+    relatedTarget = e.fromElement;
+  } else if (type == goog.events.EventType.MOUSEOUT) {
+    relatedTarget = e.toElement;
+  }
+
+  this.relatedTarget = relatedTarget;
+
+  // Webkit emits a lame warning whenever layerX/layerY is accessed.
+  // http://code.google.com/p/chromium/issues/detail?id=101733
+  this.offsetX = (goog.userAgent.WEBKIT || e.offsetX !== undefined) ?
+      e.offsetX : e.layerX;
+  this.offsetY = (goog.userAgent.WEBKIT || e.offsetY !== undefined) ?
+      e.offsetY : e.layerY;
+
+  this.clientX = e.clientX !== undefined ? e.clientX : e.pageX;
+  this.clientY = e.clientY !== undefined ? e.clientY : e.pageY;
+  this.screenX = e.screenX || 0;
+  this.screenY = e.screenY || 0;
+
+  this.button = e.button;
+
+  this.keyCode = e.keyCode || 0;
+  this.charCode = e.charCode || (type == 'keypress' ? e.keyCode : 0);
+  this.ctrlKey = e.ctrlKey;
+  this.altKey = e.altKey;
+  this.shiftKey = e.shiftKey;
+  this.metaKey = e.metaKey;
+  this.platformModifierKey = goog.userAgent.MAC ? e.metaKey : e.ctrlKey;
+  this.state = e.state;
+  this.event_ = e;
+  if (e.defaultPrevented) {
+    this.preventDefault();
+  }
+};
+
+
+/**
+ * Tests to see which button was pressed during the event. This is really only
+ * useful in IE and Gecko browsers. And in IE, it's only useful for
+ * mousedown/mouseup events, because click only fires for the left mouse button.
+ *
+ * Safari 2 only reports the left button being clicked, and uses the value '1'
+ * instead of 0. Opera only reports a mousedown event for the middle button, and
+ * no mouse events for the right button. Opera has default behavior for left and
+ * middle click that can only be overridden via a configuration setting.
+ *
+ * There's a nice table of this mess at http://www.unixpapa.com/js/mouse.html.
+ *
+ * @param {goog.events.BrowserEvent.MouseButton} button The button
+ *     to test for.
+ * @return {boolean} True if button was pressed.
+ */
+goog.events.BrowserEvent.prototype.isButton = function(button) {
+  if (!goog.events.BrowserFeature.HAS_W3C_BUTTON) {
+    if (this.type == 'click') {
+      return button == goog.events.BrowserEvent.MouseButton.LEFT;
+    } else {
+      return !!(this.event_.button &
+          goog.events.BrowserEvent.IEButtonMap[button]);
+    }
+  } else {
+    return this.event_.button == button;
+  }
+};
+
+
+/**
+ * Whether this has an "action"-producing mouse button.
+ *
+ * By definition, this includes left-click on windows/linux, and left-click
+ * without the ctrl key on Macs.
+ *
+ * @return {boolean} The result.
+ */
+goog.events.BrowserEvent.prototype.isMouseActionButton = function() {
+  // Webkit does not ctrl+click to be a right-click, so we
+  // normalize it to behave like Gecko and Opera.
+  return this.isButton(goog.events.BrowserEvent.MouseButton.LEFT) &&
+      !(goog.userAgent.WEBKIT && goog.userAgent.MAC && this.ctrlKey);
+};
+
+
+/**
+ * @override
+ */
+goog.events.BrowserEvent.prototype.stopPropagation = function() {
+  goog.events.BrowserEvent.superClass_.stopPropagation.call(this);
+  if (this.event_.stopPropagation) {
+    this.event_.stopPropagation();
+  } else {
+    this.event_.cancelBubble = true;
+  }
+};
+
+
+/**
+ * @override
+ */
+goog.events.BrowserEvent.prototype.preventDefault = function() {
+  goog.events.BrowserEvent.superClass_.preventDefault.call(this);
+  var be = this.event_;
+  if (!be.preventDefault) {
+    be.returnValue = false;
+    if (goog.events.BrowserFeature.SET_KEY_CODE_TO_PREVENT_DEFAULT) {
+      /** @preserveTry */
+      try {
+        // Most keys can be prevented using returnValue. Some special keys
+        // require setting the keyCode to -1 as well:
+        //
+        // In IE7:
+        // F3, F5, F10, F11, Ctrl+P, Crtl+O, Ctrl+F (these are taken from IE6)
+        //
+        // In IE8:
+        // Ctrl+P, Crtl+O, Ctrl+F (F1-F12 cannot be stopped through the event)
+        //
+        // We therefore do this for all function keys as well as when Ctrl key
+        // is pressed.
+        var VK_F1 = 112;
+        var VK_F12 = 123;
+        if (be.ctrlKey || be.keyCode >= VK_F1 && be.keyCode <= VK_F12) {
+          be.keyCode = -1;
+        }
+      } catch (ex) {
+        // IE throws an 'access denied' exception when trying to change
+        // keyCode in some situations (e.g. srcElement is input[type=file],
+        // or srcElement is an anchor tag rewritten by parent's innerHTML).
+        // Do nothing in this case.
+      }
+    }
+  } else {
+    be.preventDefault();
+  }
+};
+
+
+/**
+ * @return {Event} The underlying browser event object.
+ */
+goog.events.BrowserEvent.prototype.getBrowserEvent = function() {
+  return this.event_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/browserfeature3.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/browserfeature3.js b/externs/GCL/externs/goog/events/browserfeature3.js
new file mode 100644
index 0000000..61b9d60
--- /dev/null
+++ b/externs/GCL/externs/goog/events/browserfeature3.js
@@ -0,0 +1,85 @@
+// Copyright 2010 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 Browser capability checks for the events package.
+ *
+ */
+
+
+goog.provide('goog.events.BrowserFeature');
+
+goog.require('goog.userAgent');
+
+
+/**
+ * Enum of browser capabilities.
+ * @enum {boolean}
+ */
+goog.events.BrowserFeature = {
+  /**
+   * Whether the button attribute of the event is W3C compliant.  False in
+   * Internet Explorer prior to version 9; document-version dependent.
+   */
+  HAS_W3C_BUTTON: !goog.userAgent.IE ||
+      goog.userAgent.isDocumentModeOrHigher(9),
+
+  /**
+   * Whether the browser supports full W3C event model.
+   */
+  HAS_W3C_EVENT_SUPPORT: !goog.userAgent.IE ||
+      goog.userAgent.isDocumentModeOrHigher(9),
+
+  /**
+   * To prevent default in IE7-8 for certain keydown events we need set the
+   * keyCode to -1.
+   */
+  SET_KEY_CODE_TO_PREVENT_DEFAULT: goog.userAgent.IE &&
+      !goog.userAgent.isVersionOrHigher('9'),
+
+  /**
+   * Whether the {@code navigator.onLine} property is supported.
+   */
+  HAS_NAVIGATOR_ONLINE_PROPERTY: !goog.userAgent.WEBKIT ||
+      goog.userAgent.isVersionOrHigher('528'),
+
+  /**
+   * Whether HTML5 network online/offline events are supported.
+   */
+  HAS_HTML5_NETWORK_EVENT_SUPPORT:
+      goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9b') ||
+      goog.userAgent.IE && goog.userAgent.isVersionOrHigher('8') ||
+      goog.userAgent.OPERA && goog.userAgent.isVersionOrHigher('9.5') ||
+      goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('528'),
+
+  /**
+   * Whether HTML5 network events fire on document.body, or otherwise the
+   * window.
+   */
+  HTML5_NETWORK_EVENTS_FIRE_ON_BODY:
+      goog.userAgent.GECKO && !goog.userAgent.isVersionOrHigher('8') ||
+      goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9'),
+
+  /**
+   * Whether touch is enabled in the browser.
+   */
+  TOUCH_ENABLED:
+      ('ontouchstart' in goog.global ||
+          !!(goog.global['document'] &&
+             document.documentElement &&
+             'ontouchstart' in document.documentElement) ||
+          // IE10 uses non-standard touch events, so it has a different check.
+          !!(goog.global['navigator'] &&
+              goog.global['navigator']['msMaxTouchPoints']))
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/event.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/event.js b/externs/GCL/externs/goog/events/event.js
new file mode 100644
index 0000000..b671289
--- /dev/null
+++ b/externs/GCL/externs/goog/events/event.js
@@ -0,0 +1,143 @@
+// Copyright 2005 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 base class for event objects.
+ *
+ */
+
+
+goog.provide('goog.events.Event');
+goog.provide('goog.events.EventLike');
+
+/**
+ * goog.events.Event no longer depends on goog.Disposable. Keep requiring
+ * goog.Disposable here to not break projects which assume this dependency.
+ * @suppress {extraRequire}
+ */
+goog.require('goog.Disposable');
+goog.require('goog.events.EventId');
+
+
+/**
+ * A typedef for event like objects that are dispatchable via the
+ * goog.events.dispatchEvent function. strings are treated as the type for a
+ * goog.events.Event. Objects are treated as an extension of a new
+ * goog.events.Event with the type property of the object being used as the type
+ * of the Event.
+ * @typedef {string|Object|goog.events.Event|goog.events.EventId}
+ */
+goog.events.EventLike;
+
+
+
+/**
+ * A base class for event objects, so that they can support preventDefault and
+ * stopPropagation.
+ *
+ * @param {string|!goog.events.EventId} type Event Type.
+ * @param {Object=} opt_target Reference to the object that is the target of
+ *     this event. It has to implement the {@code EventTarget} interface
+ *     declared at {@link http://developer.mozilla.org/en/DOM/EventTarget}.
+ * @constructor
+ */
+goog.events.Event = function(type, opt_target) {
+  /**
+   * Event type.
+   * @type {string}
+   */
+  this.type = type instanceof goog.events.EventId ? String(type) : type;
+
+  /**
+   * TODO(tbreisacher): The type should probably be
+   * EventTarget|goog.events.EventTarget.
+   *
+   * Target of the event.
+   * @type {Object|undefined}
+   */
+  this.target = opt_target;
+
+  /**
+   * Object that had the listener attached.
+   * @type {Object|undefined}
+   */
+  this.currentTarget = this.target;
+
+  /**
+   * Whether to cancel the event in internal capture/bubble processing for IE.
+   * @type {boolean}
+   * @public
+   * @suppress {underscore|visibility} Technically public, but referencing this
+   *     outside this package is strongly discouraged.
+   */
+  this.propagationStopped_ = false;
+
+  /**
+   * Whether the default action has been prevented.
+   * This is a property to match the W3C specification at
+   * {@link http://www.w3.org/TR/DOM-Level-3-Events/
+   * #events-event-type-defaultPrevented}.
+   * Must be treated as read-only outside the class.
+   * @type {boolean}
+   */
+  this.defaultPrevented = false;
+
+  /**
+   * Return value for in internal capture/bubble processing for IE.
+   * @type {boolean}
+   * @public
+   * @suppress {underscore|visibility} Technically public, but referencing this
+   *     outside this package is strongly discouraged.
+   */
+  this.returnValue_ = true;
+};
+
+
+/**
+ * Stops event propagation.
+ */
+goog.events.Event.prototype.stopPropagation = function() {
+  this.propagationStopped_ = true;
+};
+
+
+/**
+ * Prevents the default action, for example a link redirecting to a url.
+ */
+goog.events.Event.prototype.preventDefault = function() {
+  this.defaultPrevented = true;
+  this.returnValue_ = false;
+};
+
+
+/**
+ * Stops the propagation of the event. It is equivalent to
+ * {@code e.stopPropagation()}, but can be used as the callback argument of
+ * {@link goog.events.listen} without declaring another function.
+ * @param {!goog.events.Event} e An event.
+ */
+goog.events.Event.stopPropagation = function(e) {
+  e.stopPropagation();
+};
+
+
+/**
+ * Prevents the default action. It is equivalent to
+ * {@code e.preventDefault()}, but can be used as the callback argument of
+ * {@link goog.events.listen} without declaring another function.
+ * @param {!goog.events.Event} e An event.
+ */
+goog.events.Event.preventDefault = function(e) {
+  e.preventDefault();
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/eventhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/eventhandler.js b/externs/GCL/externs/goog/events/eventhandler.js
new file mode 100644
index 0000000..16b1ad0
--- /dev/null
+++ b/externs/GCL/externs/goog/events/eventhandler.js
@@ -0,0 +1,459 @@
+// Copyright 2005 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 Class to create objects which want to handle multiple events
+ * and have their listeners easily cleaned up via a dispose method.
+ *
+ * Example:
+ * <pre>
+ * function Something() {
+ *   Something.base(this);
+ *
+ *   ... set up object ...
+ *
+ *   // Add event listeners
+ *   this.listen(this.starEl, goog.events.EventType.CLICK, this.handleStar);
+ *   this.listen(this.headerEl, goog.events.EventType.CLICK, this.expand);
+ *   this.listen(this.collapseEl, goog.events.EventType.CLICK, this.collapse);
+ *   this.listen(this.infoEl, goog.events.EventType.MOUSEOVER, this.showHover);
+ *   this.listen(this.infoEl, goog.events.EventType.MOUSEOUT, this.hideHover);
+ * }
+ * goog.inherits(Something, goog.events.EventHandler);
+ *
+ * Something.prototype.disposeInternal = function() {
+ *   Something.base(this, 'disposeInternal');
+ *   goog.dom.removeNode(this.container);
+ * };
+ *
+ *
+ * // Then elsewhere:
+ *
+ * var activeSomething = null;
+ * function openSomething() {
+ *   activeSomething = new Something();
+ * }
+ *
+ * function closeSomething() {
+ *   if (activeSomething) {
+ *     activeSomething.dispose();  // Remove event listeners
+ *     activeSomething = null;
+ *   }
+ * }
+ * </pre>
+ *
+ */
+
+goog.provide('goog.events.EventHandler');
+
+goog.require('goog.Disposable');
+goog.require('goog.events');
+goog.require('goog.object');
+
+goog.forwardDeclare('goog.events.EventWrapper');
+
+
+
+/**
+ * Super class for objects that want to easily manage a number of event
+ * listeners.  It allows a short cut to listen and also provides a quick way
+ * to remove all events listeners belonging to this object.
+ * @param {SCOPE=} opt_scope Object in whose scope to call the listeners.
+ * @constructor
+ * @extends {goog.Disposable}
+ * @template SCOPE
+ */
+goog.events.EventHandler = function(opt_scope) {
+  goog.Disposable.call(this);
+  // TODO(mknichel): Rename this to this.scope_ and fix the classes in google3
+  // that access this private variable. :(
+  this.handler_ = opt_scope;
+
+  /**
+   * Keys for events that are being listened to.
+   * @type {!Object<!goog.events.Key>}
+   * @private
+   */
+  this.keys_ = {};
+};
+goog.inherits(goog.events.EventHandler, goog.Disposable);
+
+
+/**
+ * Utility array used to unify the cases of listening for an array of types
+ * and listening for a single event, without using recursion or allocating
+ * an array each time.
+ * @type {!Array<string>}
+ * @const
+ * @private
+ */
+goog.events.EventHandler.typeArray_ = [];
+
+
+/**
+ * Listen to an event on a Listenable.  If the function is omitted then the
+ * EventHandler's handleEvent method will be used.
+ * @param {goog.events.ListenableType} src Event source.
+ * @param {string|Array<string>|
+ *     !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
+ *     type Event type to listen for or array of event types.
+ * @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=}
+ *     opt_fn Optional callback function to be used as the listener or an object
+ *     with handleEvent function.
+ * @param {boolean=} opt_capture Optional whether to use capture phase.
+ * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for
+ *     chaining of calls.
+ * @template EVENTOBJ
+ */
+goog.events.EventHandler.prototype.listen = function(
+    src, type, opt_fn, opt_capture) {
+  return this.listen_(src, type, opt_fn, opt_capture);
+};
+
+
+/**
+ * Listen to an event on a Listenable.  If the function is omitted then the
+ * EventHandler's handleEvent method will be used.
+ * @param {goog.events.ListenableType} src Event source.
+ * @param {string|Array<string>|
+ *     !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
+ *     type Event type to listen for or array of event types.
+ * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}|
+ *     null|undefined} fn Optional callback function to be used as the
+ *     listener or an object with handleEvent function.
+ * @param {boolean|undefined} capture Optional whether to use capture phase.
+ * @param {T} scope Object in whose scope to call the listener.
+ * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for
+ *     chaining of calls.
+ * @template T,EVENTOBJ
+ */
+goog.events.EventHandler.prototype.listenWithScope = function(
+    src, type, fn, capture, scope) {
+  // TODO(mknichel): Deprecate this function.
+  return this.listen_(src, type, fn, capture, scope);
+};
+
+
+/**
+ * Listen to an event on a Listenable.  If the function is omitted then the
+ * EventHandler's handleEvent method will be used.
+ * @param {goog.events.ListenableType} src Event source.
+ * @param {string|Array<string>|
+ *     !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
+ *     type Event type to listen for or array of event types.
+ * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn
+ *     Optional callback function to be used as the listener or an object with
+ *     handleEvent function.
+ * @param {boolean=} opt_capture Optional whether to use capture phase.
+ * @param {Object=} opt_scope Object in whose scope to call the listener.
+ * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for
+ *     chaining of calls.
+ * @template EVENTOBJ
+ * @private
+ */
+goog.events.EventHandler.prototype.listen_ = function(src, type, opt_fn,
+                                                      opt_capture,
+                                                      opt_scope) {
+  if (!goog.isArray(type)) {
+    if (type) {
+      goog.events.EventHandler.typeArray_[0] = type.toString();
+    }
+    type = goog.events.EventHandler.typeArray_;
+  }
+  for (var i = 0; i < type.length; i++) {
+    var listenerObj = goog.events.listen(
+        src, type[i], opt_fn || this.handleEvent,
+        opt_capture || false,
+        opt_scope || this.handler_ || this);
+
+    if (!listenerObj) {
+      // When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT
+      // (goog.events.CaptureSimulationMode) in IE8-, it will return null
+      // value.
+      return this;
+    }
+
+    var key = listenerObj.key;
+    this.keys_[key] = listenerObj;
+  }
+
+  return this;
+};
+
+
+/**
+ * Listen to an event on a Listenable.  If the function is omitted, then the
+ * EventHandler's handleEvent method will be used. After the event has fired the
+ * event listener is removed from the target. If an array of event types is
+ * provided, each event type will be listened to once.
+ * @param {goog.events.ListenableType} src Event source.
+ * @param {string|Array<string>|
+ *     !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
+ *     type Event type to listen for or array of event types.
+ * @param {function(this:SCOPE, EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn
+ *    Optional callback function to be used as the listener or an object with
+ *    handleEvent function.
+ * @param {boolean=} opt_capture Optional whether to use capture phase.
+ * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for
+ *     chaining of calls.
+ * @template EVENTOBJ
+ */
+goog.events.EventHandler.prototype.listenOnce = function(
+    src, type, opt_fn, opt_capture) {
+  return this.listenOnce_(src, type, opt_fn, opt_capture);
+};
+
+
+/**
+ * Listen to an event on a Listenable.  If the function is omitted, then the
+ * EventHandler's handleEvent method will be used. After the event has fired the
+ * event listener is removed from the target. If an array of event types is
+ * provided, each event type will be listened to once.
+ * @param {goog.events.ListenableType} src Event source.
+ * @param {string|Array<string>|
+ *     !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
+ *     type Event type to listen for or array of event types.
+ * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(this:T, ?):?}|
+ *     null|undefined} fn Optional callback function to be used as the
+ *     listener or an object with handleEvent function.
+ * @param {boolean|undefined} capture Optional whether to use capture phase.
+ * @param {T} scope Object in whose scope to call the listener.
+ * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for
+ *     chaining of calls.
+ * @template T,EVENTOBJ
+ */
+goog.events.EventHandler.prototype.listenOnceWithScope = function(
+    src, type, fn, capture, scope) {
+  // TODO(mknichel): Deprecate this function.
+  return this.listenOnce_(src, type, fn, capture, scope);
+};
+
+
+/**
+ * Listen to an event on a Listenable.  If the function is omitted, then the
+ * EventHandler's handleEvent method will be used. After the event has fired
+ * the event listener is removed from the target. If an array of event types is
+ * provided, each event type will be listened to once.
+ * @param {goog.events.ListenableType} src Event source.
+ * @param {string|Array<string>|
+ *     !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
+ *     type Event type to listen for or array of event types.
+ * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn
+ *    Optional callback function to be used as the listener or an object with
+ *    handleEvent function.
+ * @param {boolean=} opt_capture Optional whether to use capture phase.
+ * @param {Object=} opt_scope Object in whose scope to call the listener.
+ * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for
+ *     chaining of calls.
+ * @template EVENTOBJ
+ * @private
+ */
+goog.events.EventHandler.prototype.listenOnce_ = function(
+    src, type, opt_fn, opt_capture, opt_scope) {
+  if (goog.isArray(type)) {
+    for (var i = 0; i < type.length; i++) {
+      this.listenOnce_(src, type[i], opt_fn, opt_capture, opt_scope);
+    }
+  } else {
+    var listenerObj = goog.events.listenOnce(
+        src, type, opt_fn || this.handleEvent, opt_capture,
+        opt_scope || this.handler_ || this);
+    if (!listenerObj) {
+      // When goog.events.listen run on OFF_AND_FAIL or OFF_AND_SILENT
+      // (goog.events.CaptureSimulationMode) in IE8-, it will return null
+      // value.
+      return this;
+    }
+
+    var key = listenerObj.key;
+    this.keys_[key] = listenerObj;
+  }
+
+  return this;
+};
+
+
+/**
+ * Adds an event listener with a specific event wrapper on a DOM Node or an
+ * object that has implemented {@link goog.events.EventTarget}. A listener can
+ * only be added once to an object.
+ *
+ * @param {EventTarget|goog.events.EventTarget} src The node to listen to
+ *     events on.
+ * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
+ * @param {function(this:SCOPE, ?):?|{handleEvent:function(?):?}|null} listener
+ *     Callback method, or an object with a handleEvent function.
+ * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
+ *     false).
+ * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for
+ *     chaining of calls.
+ */
+goog.events.EventHandler.prototype.listenWithWrapper = function(
+    src, wrapper, listener, opt_capt) {
+  // TODO(mknichel): Remove the opt_scope from this function and then
+  // templatize it.
+  return this.listenWithWrapper_(src, wrapper, listener, opt_capt);
+};
+
+
+/**
+ * Adds an event listener with a specific event wrapper on a DOM Node or an
+ * object that has implemented {@link goog.events.EventTarget}. A listener can
+ * only be added once to an object.
+ *
+ * @param {EventTarget|goog.events.EventTarget} src The node to listen to
+ *     events on.
+ * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
+ * @param {function(this:T, ?):?|{handleEvent:function(this:T, ?):?}|null}
+ *     listener Optional callback function to be used as the
+ *     listener or an object with handleEvent function.
+ * @param {boolean|undefined} capture Optional whether to use capture phase.
+ * @param {T} scope Object in whose scope to call the listener.
+ * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for
+ *     chaining of calls.
+ * @template T
+ */
+goog.events.EventHandler.prototype.listenWithWrapperAndScope = function(
+    src, wrapper, listener, capture, scope) {
+  // TODO(mknichel): Deprecate this function.
+  return this.listenWithWrapper_(src, wrapper, listener, capture, scope);
+};
+
+
+/**
+ * Adds an event listener with a specific event wrapper on a DOM Node or an
+ * object that has implemented {@link goog.events.EventTarget}. A listener can
+ * only be added once to an object.
+ *
+ * @param {EventTarget|goog.events.EventTarget} src The node to listen to
+ *     events on.
+ * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
+ * @param {function(?):?|{handleEvent:function(?):?}|null} listener Callback
+ *     method, or an object with a handleEvent function.
+ * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
+ *     false).
+ * @param {Object=} opt_scope Element in whose scope to call the listener.
+ * @return {!goog.events.EventHandler<SCOPE>} This object, allowing for
+ *     chaining of calls.
+ * @private
+ */
+goog.events.EventHandler.prototype.listenWithWrapper_ = function(
+    src, wrapper, listener, opt_capt, opt_scope) {
+  wrapper.listen(src, listener, opt_capt, opt_scope || this.handler_ || this,
+                 this);
+  return this;
+};
+
+
+/**
+ * @return {number} Number of listeners registered by this handler.
+ */
+goog.events.EventHandler.prototype.getListenerCount = function() {
+  var count = 0;
+  for (var key in this.keys_) {
+    if (Object.prototype.hasOwnProperty.call(this.keys_, key)) {
+      count++;
+    }
+  }
+  return count;
+};
+
+
+/**
+ * Unlistens on an event.
+ * @param {goog.events.ListenableType} src Event source.
+ * @param {string|Array<string>|
+ *     !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
+ *     type Event type or array of event types to unlisten to.
+ * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null=} opt_fn
+ *     Optional callback function to be used as the listener or an object with
+ *     handleEvent function.
+ * @param {boolean=} opt_capture Optional whether to use capture phase.
+ * @param {Object=} opt_scope Object in whose scope to call the listener.
+ * @return {!goog.events.EventHandler} This object, allowing for chaining of
+ *     calls.
+ * @template EVENTOBJ
+ */
+goog.events.EventHandler.prototype.unlisten = function(src, type, opt_fn,
+                                                       opt_capture,
+                                                       opt_scope) {
+  if (goog.isArray(type)) {
+    for (var i = 0; i < type.length; i++) {
+      this.unlisten(src, type[i], opt_fn, opt_capture, opt_scope);
+    }
+  } else {
+    var listener = goog.events.getListener(src, type,
+        opt_fn || this.handleEvent,
+        opt_capture, opt_scope || this.handler_ || this);
+
+    if (listener) {
+      goog.events.unlistenByKey(listener);
+      delete this.keys_[listener.key];
+    }
+  }
+
+  return this;
+};
+
+
+/**
+ * Removes an event listener which was added with listenWithWrapper().
+ *
+ * @param {EventTarget|goog.events.EventTarget} src The target to stop
+ *     listening to events on.
+ * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
+ * @param {function(?):?|{handleEvent:function(?):?}|null} listener The
+ *     listener function to remove.
+ * @param {boolean=} opt_capt In DOM-compliant browsers, this determines
+ *     whether the listener is fired during the capture or bubble phase of the
+ *     event.
+ * @param {Object=} opt_scope Element in whose scope to call the listener.
+ * @return {!goog.events.EventHandler} This object, allowing for chaining of
+ *     calls.
+ */
+goog.events.EventHandler.prototype.unlistenWithWrapper = function(src, wrapper,
+    listener, opt_capt, opt_scope) {
+  wrapper.unlisten(src, listener, opt_capt,
+                   opt_scope || this.handler_ || this, this);
+  return this;
+};
+
+
+/**
+ * Unlistens to all events.
+ */
+goog.events.EventHandler.prototype.removeAll = function() {
+  goog.object.forEach(this.keys_, goog.events.unlistenByKey);
+  this.keys_ = {};
+};
+
+
+/**
+ * Disposes of this EventHandler and removes all listeners that it registered.
+ * @override
+ * @protected
+ */
+goog.events.EventHandler.prototype.disposeInternal = function() {
+  goog.events.EventHandler.superClass_.disposeInternal.call(this);
+  this.removeAll();
+};
+
+
+/**
+ * Default event handler
+ * @param {goog.events.Event} e Event object.
+ */
+goog.events.EventHandler.prototype.handleEvent = function(e) {
+  throw Error('EventHandler.handleEvent not implemented');
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/eventid.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/eventid.js b/externs/GCL/externs/goog/events/eventid.js
new file mode 100644
index 0000000..9a4822e
--- /dev/null
+++ b/externs/GCL/externs/goog/events/eventid.js
@@ -0,0 +1,47 @@
+// Copyright 2013 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.
+
+goog.provide('goog.events.EventId');
+
+
+
+/**
+ * A templated class that is used when registering for events. Typical usage:
+ * <code>
+ *   /** @type {goog.events.EventId<MyEventObj>}
+ *   var myEventId = new goog.events.EventId(
+ *       goog.events.getUniqueId(('someEvent'));
+ *
+ *   // No need to cast or declare here since the compiler knows the correct
+ *   // type of 'evt' (MyEventObj).
+ *   something.listen(myEventId, function(evt) {});
+ * </code>
+ *
+ * @param {string} eventId
+ * @template T
+ * @constructor
+ * @struct
+ * @final
+ */
+goog.events.EventId = function(eventId) {
+  /** @const */ this.id = eventId;
+};
+
+
+/**
+ * @override
+ */
+goog.events.EventId.prototype.toString = function() {
+  return this.id;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/events.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/events.js b/externs/GCL/externs/goog/events/events.js
new file mode 100644
index 0000000..39cc405
--- /dev/null
+++ b/externs/GCL/externs/goog/events/events.js
@@ -0,0 +1,983 @@
+// Copyright 2005 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 An event manager for both native browser event
+ * targets and custom JavaScript event targets
+ * ({@code goog.events.Listenable}). This provides an abstraction
+ * over browsers' event systems.
+ *
+ * It also provides a simulation of W3C event model's capture phase in
+ * Internet Explorer (IE 8 and below). Caveat: the simulation does not
+ * interact well with listeners registered directly on the elements
+ * (bypassing goog.events) or even with listeners registered via
+ * goog.events in a separate JS binary. In these cases, we provide
+ * no ordering guarantees.
+ *
+ * The listeners will receive a "patched" event object. Such event object
+ * contains normalized values for certain event properties that differs in
+ * different browsers.
+ *
+ * Example usage:
+ * <pre>
+ * goog.events.listen(myNode, 'click', function(e) { alert('woo') });
+ * goog.events.listen(myNode, 'mouseover', mouseHandler, true);
+ * goog.events.unlisten(myNode, 'mouseover', mouseHandler, true);
+ * goog.events.removeAll(myNode);
+ * </pre>
+ *
+ *                                            in IE and event object patching]
+ * @author arv@google.com (Erik Arvidsson)
+ *
+ * @see ../demos/events.html
+ * @see ../demos/event-propagation.html
+ * @see ../demos/stopevent.html
+ */
+
+// IMPLEMENTATION NOTES:
+// goog.events stores an auxiliary data structure on each EventTarget
+// source being listened on. This allows us to take advantage of GC,
+// having the data structure GC'd when the EventTarget is GC'd. This
+// GC behavior is equivalent to using W3C DOM Events directly.
+
+goog.provide('goog.events');
+goog.provide('goog.events.CaptureSimulationMode');
+goog.provide('goog.events.Key');
+goog.provide('goog.events.ListenableType');
+
+goog.require('goog.asserts');
+goog.require('goog.debug.entryPointRegistry');
+goog.require('goog.events.BrowserEvent');
+goog.require('goog.events.BrowserFeature');
+goog.require('goog.events.Listenable');
+goog.require('goog.events.ListenerMap');
+
+goog.forwardDeclare('goog.debug.ErrorHandler');
+goog.forwardDeclare('goog.events.EventWrapper');
+
+
+/**
+ * @typedef {number|goog.events.ListenableKey}
+ */
+goog.events.Key;
+
+
+/**
+ * @typedef {EventTarget|goog.events.Listenable}
+ */
+goog.events.ListenableType;
+
+
+/**
+ * Property name on a native event target for the listener map
+ * associated with the event target.
+ * @private @const {string}
+ */
+goog.events.LISTENER_MAP_PROP_ = 'closure_lm_' + ((Math.random() * 1e6) | 0);
+
+
+/**
+ * String used to prepend to IE event types.
+ * @const
+ * @private
+ */
+goog.events.onString_ = 'on';
+
+
+/**
+ * Map of computed "on<eventname>" strings for IE event types. Caching
+ * this removes an extra object allocation in goog.events.listen which
+ * improves IE6 performance.
+ * @const
+ * @dict
+ * @private
+ */
+goog.events.onStringMap_ = {};
+
+
+/**
+ * @enum {number} Different capture simulation mode for IE8-.
+ */
+goog.events.CaptureSimulationMode = {
+  /**
+   * Does not perform capture simulation. Will asserts in IE8- when you
+   * add capture listeners.
+   */
+  OFF_AND_FAIL: 0,
+
+  /**
+   * Does not perform capture simulation, silently ignore capture
+   * listeners.
+   */
+  OFF_AND_SILENT: 1,
+
+  /**
+   * Performs capture simulation.
+   */
+  ON: 2
+};
+
+
+/**
+ * @define {number} The capture simulation mode for IE8-. By default,
+ *     this is ON.
+ */
+goog.define('goog.events.CAPTURE_SIMULATION_MODE', 2);
+
+
+/**
+ * Estimated count of total native listeners.
+ * @private {number}
+ */
+goog.events.listenerCountEstimate_ = 0;
+
+
+/**
+ * Adds an event listener for a specific event on a native event
+ * target (such as a DOM element) or an object that has implemented
+ * {@link goog.events.Listenable}. A listener can only be added once
+ * to an object and if it is added again the key for the listener is
+ * returned. Note that if the existing listener is a one-off listener
+ * (registered via listenOnce), it will no longer be a one-off
+ * listener after a call to listen().
+ *
+ * @param {EventTarget|goog.events.Listenable} src The node to listen
+ *     to events on.
+ * @param {string|Array<string>|
+ *     !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
+ *     type Event type or array of event types.
+ * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null}
+ *     listener Callback method, or an object with a handleEvent function.
+ *     WARNING: passing an Object is now softly deprecated.
+ * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
+ *     false).
+ * @param {T=} opt_handler Element in whose scope to call the listener.
+ * @return {goog.events.Key} Unique key for the listener.
+ * @template T,EVENTOBJ
+ */
+goog.events.listen = function(src, type, listener, opt_capt, opt_handler) {
+  if (goog.isArray(type)) {
+    for (var i = 0; i < type.length; i++) {
+      goog.events.listen(src, type[i], listener, opt_capt, opt_handler);
+    }
+    return null;
+  }
+
+  listener = goog.events.wrapListener(listener);
+  if (goog.events.Listenable.isImplementedBy(src)) {
+    return src.listen(
+        /** @type {string|!goog.events.EventId} */ (type),
+        listener, opt_capt, opt_handler);
+  } else {
+    return goog.events.listen_(
+        /** @type {!EventTarget} */ (src),
+        /** @type {string|!goog.events.EventId} */ (type),
+        listener, /* callOnce */ false, opt_capt, opt_handler);
+  }
+};
+
+
+/**
+ * Adds an event listener for a specific event on a native event
+ * target. A listener can only be added once to an object and if it
+ * is added again the key for the listener is returned.
+ *
+ * Note that a one-off listener will not change an existing listener,
+ * if any. On the other hand a normal listener will change existing
+ * one-off listener to become a normal listener.
+ *
+ * @param {EventTarget} src The node to listen to events on.
+ * @param {string|!goog.events.EventId} type Event type.
+ * @param {!Function} listener Callback function.
+ * @param {boolean} callOnce Whether the listener is a one-off
+ *     listener or otherwise.
+ * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
+ *     false).
+ * @param {Object=} opt_handler Element in whose scope to call the listener.
+ * @return {goog.events.ListenableKey} Unique key for the listener.
+ * @private
+ */
+goog.events.listen_ = function(
+    src, type, listener, callOnce, opt_capt, opt_handler) {
+  if (!type) {
+    throw Error('Invalid event type');
+  }
+
+  var capture = !!opt_capt;
+  if (capture && !goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT) {
+    if (goog.events.CAPTURE_SIMULATION_MODE ==
+        goog.events.CaptureSimulationMode.OFF_AND_FAIL) {
+      goog.asserts.fail('Can not register capture listener in IE8-.');
+      return null;
+    } else if (goog.events.CAPTURE_SIMULATION_MODE ==
+        goog.events.CaptureSimulationMode.OFF_AND_SILENT) {
+      return null;
+    }
+  }
+
+  var listenerMap = goog.events.getListenerMap_(src);
+  if (!listenerMap) {
+    src[goog.events.LISTENER_MAP_PROP_] = listenerMap =
+        new goog.events.ListenerMap(src);
+  }
+
+  var listenerObj = listenerMap.add(
+      type, listener, callOnce, opt_capt, opt_handler);
+
+  // If the listenerObj already has a proxy, it has been set up
+  // previously. We simply return.
+  if (listenerObj.proxy) {
+    return listenerObj;
+  }
+
+  var proxy = goog.events.getProxy();
+  listenerObj.proxy = proxy;
+
+  proxy.src = src;
+  proxy.listener = listenerObj;
+
+  // Attach the proxy through the browser's API
+  if (src.addEventListener) {
+    src.addEventListener(type.toString(), proxy, capture);
+  } else {
+    // The else above used to be else if (src.attachEvent) and then there was
+    // another else statement that threw an exception warning the developer
+    // they made a mistake. This resulted in an extra object allocation in IE6
+    // due to a wrapper object that had to be implemented around the element
+    // and so was removed.
+    src.attachEvent(goog.events.getOnString_(type.toString()), proxy);
+  }
+
+  goog.events.listenerCountEstimate_++;
+  return listenerObj;
+};
+
+
+/**
+ * Helper function for returning a proxy function.
+ * @return {!Function} A new or reused function object.
+ */
+goog.events.getProxy = function() {
+  var proxyCallbackFunction = goog.events.handleBrowserEvent_;
+  // Use a local var f to prevent one allocation.
+  var f = goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT ?
+      function(eventObject) {
+        return proxyCallbackFunction.call(f.src, f.listener, eventObject);
+      } :
+      function(eventObject) {
+        var v = proxyCallbackFunction.call(f.src, f.listener, eventObject);
+        // NOTE(chrishenry): In IE, we hack in a capture phase. However, if
+        // there is inline event handler which tries to prevent default (for
+        // example <a href="..." onclick="return false">...</a>) in a
+        // descendant element, the prevent default will be overridden
+        // by this listener if this listener were to return true. Hence, we
+        // return undefined.
+        if (!v) return v;
+      };
+  return f;
+};
+
+
+/**
+ * Adds an event listener for a specific event on a native event
+ * target (such as a DOM element) or an object that has implemented
+ * {@link goog.events.Listenable}. After the event has fired the event
+ * listener is removed from the target.
+ *
+ * If an existing listener already exists, listenOnce will do
+ * nothing. In particular, if the listener was previously registered
+ * via listen(), listenOnce() will not turn the listener into a
+ * one-off listener. Similarly, if there is already an existing
+ * one-off listener, listenOnce does not modify the listeners (it is
+ * still a once listener).
+ *
+ * @param {EventTarget|goog.events.Listenable} src The node to listen
+ *     to events on.
+ * @param {string|Array<string>|
+ *     !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
+ *     type Event type or array of event types.
+ * @param {function(this:T, EVENTOBJ):?|{handleEvent:function(?):?}|null}
+ *     listener Callback method.
+ * @param {boolean=} opt_capt Fire in capture phase?.
+ * @param {T=} opt_handler Element in whose scope to call the listener.
+ * @return {goog.events.Key} Unique key for the listener.
+ * @template T,EVENTOBJ
+ */
+goog.events.listenOnce = function(src, type, listener, opt_capt, opt_handler) {
+  if (goog.isArray(type)) {
+    for (var i = 0; i < type.length; i++) {
+      goog.events.listenOnce(src, type[i], listener, opt_capt, opt_handler);
+    }
+    return null;
+  }
+
+  listener = goog.events.wrapListener(listener);
+  if (goog.events.Listenable.isImplementedBy(src)) {
+    return src.listenOnce(
+        /** @type {string|!goog.events.EventId} */ (type),
+        listener, opt_capt, opt_handler);
+  } else {
+    return goog.events.listen_(
+        /** @type {!EventTarget} */ (src),
+        /** @type {string|!goog.events.EventId} */ (type),
+        listener, /* callOnce */ true, opt_capt, opt_handler);
+  }
+};
+
+
+/**
+ * Adds an event listener with a specific event wrapper on a DOM Node or an
+ * object that has implemented {@link goog.events.Listenable}. A listener can
+ * only be added once to an object.
+ *
+ * @param {EventTarget|goog.events.Listenable} src The target to
+ *     listen to events on.
+ * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
+ * @param {function(this:T, ?):?|{handleEvent:function(?):?}|null} listener
+ *     Callback method, or an object with a handleEvent function.
+ * @param {boolean=} opt_capt Whether to fire in capture phase (defaults to
+ *     false).
+ * @param {T=} opt_handler Element in whose scope to call the listener.
+ * @template T
+ */
+goog.events.listenWithWrapper = function(src, wrapper, listener, opt_capt,
+    opt_handler) {
+  wrapper.listen(src, listener, opt_capt, opt_handler);
+};
+
+
+/**
+ * Removes an event listener which was added with listen().
+ *
+ * @param {EventTarget|goog.events.Listenable} src The target to stop
+ *     listening to events on.
+ * @param {string|Array<string>|
+ *     !goog.events.EventId<EVENTOBJ>|!Array<!goog.events.EventId<EVENTOBJ>>}
+ *     type Event type or array of event types to unlisten to.
+ * @param {function(?):?|{handleEvent:function(?):?}|null} listener The
+ *     listener function to remove.
+ * @param {boolean=} opt_capt In DOM-compliant browsers, this determines
+ *     whether the listener is fired during the capture or bubble phase of the
+ *     event.
+ * @param {Object=} opt_handler Element in whose scope to call the listener.
+ * @return {?boolean} indicating whether the listener was there to remove.
+ * @template EVENTOBJ
+ */
+goog.events.unlisten = function(src, type, listener, opt_capt, opt_handler) {
+  if (goog.isArray(type)) {
+    for (var i = 0; i < type.length; i++) {
+      goog.events.unlisten(src, type[i], listener, opt_capt, opt_handler);
+    }
+    return null;
+  }
+
+  listener = goog.events.wrapListener(listener);
+  if (goog.events.Listenable.isImplementedBy(src)) {
+    return src.unlisten(
+        /** @type {string|!goog.events.EventId} */ (type),
+        listener, opt_capt, opt_handler);
+  }
+
+  if (!src) {
+    // TODO(chrishenry): We should tighten the API to only accept
+    // non-null objects, or add an assertion here.
+    return false;
+  }
+
+  var capture = !!opt_capt;
+  var listenerMap = goog.events.getListenerMap_(
+      /** @type {!EventTarget} */ (src));
+  if (listenerMap) {
+    var listenerObj = listenerMap.getListener(
+        /** @type {string|!goog.events.EventId} */ (type),
+        listener, capture, opt_handler);
+    if (listenerObj) {
+      return goog.events.unlistenByKey(listenerObj);
+    }
+  }
+
+  return false;
+};
+
+
+/**
+ * Removes an event listener which was added with listen() by the key
+ * returned by listen().
+ *
+ * @param {goog.events.Key} key The key returned by listen() for this
+ *     event listener.
+ * @return {boolean} indicating whether the listener was there to remove.
+ */
+goog.events.unlistenByKey = function(key) {
+  // TODO(chrishenry): Remove this check when tests that rely on this
+  // are fixed.
+  if (goog.isNumber(key)) {
+    return false;
+  }
+
+  var listener = /** @type {goog.events.ListenableKey} */ (key);
+  if (!listener || listener.removed) {
+    return false;
+  }
+
+  var src = listener.src;
+  if (goog.events.Listenable.isImplementedBy(src)) {
+    return src.unlistenByKey(listener);
+  }
+
+  var type = listener.type;
+  var proxy = listener.proxy;
+  if (src.removeEventListener) {
+    src.removeEventListener(type, proxy, listener.capture);
+  } else if (src.detachEvent) {
+    src.detachEvent(goog.events.getOnString_(type), proxy);
+  }
+  goog.events.listenerCountEstimate_--;
+
+  var listenerMap = goog.events.getListenerMap_(
+      /** @type {!EventTarget} */ (src));
+  // TODO(chrishenry): Try to remove this conditional and execute the
+  // first branch always. This should be safe.
+  if (listenerMap) {
+    listenerMap.removeByKey(listener);
+    if (listenerMap.getTypeCount() == 0) {
+      // Null the src, just because this is simple to do (and useful
+      // for IE <= 7).
+      listenerMap.src = null;
+      // We don't use delete here because IE does not allow delete
+      // on a window object.
+      src[goog.events.LISTENER_MAP_PROP_] = null;
+    }
+  } else {
+    listener.markAsRemoved();
+  }
+
+  return true;
+};
+
+
+/**
+ * Removes an event listener which was added with listenWithWrapper().
+ *
+ * @param {EventTarget|goog.events.Listenable} src The target to stop
+ *     listening to events on.
+ * @param {goog.events.EventWrapper} wrapper Event wrapper to use.
+ * @param {function(?):?|{handleEvent:function(?):?}|null} listener The
+ *     listener function to remove.
+ * @param {boolean=} opt_capt In DOM-compliant browsers, this determines
+ *     whether the listener is fired during the capture or bubble phase of the
+ *     event.
+ * @param {Object=} opt_handler Element in whose scope to call the listener.
+ */
+goog.events.unlistenWithWrapper = function(src, wrapper, listener, opt_capt,
+    opt_handler) {
+  wrapper.unlisten(src, listener, opt_capt, opt_handler);
+};
+
+
+/**
+ * Removes all listeners from an object. You can also optionally
+ * remove listeners of a particular type.
+ *
+ * @param {Object|undefined} obj Object to remove listeners from. Must be an
+ *     EventTarget or a goog.events.Listenable.
+ * @param {string|!goog.events.EventId=} opt_type Type of event to remove.
+ *     Default is all types.
+ * @return {number} Number of listeners removed.
+ */
+goog.events.removeAll = function(obj, opt_type) {
+  // TODO(chrishenry): Change the type of obj to
+  // (!EventTarget|!goog.events.Listenable).
+
+  if (!obj) {
+    return 0;
+  }
+
+  if (goog.events.Listenable.isImplementedBy(obj)) {
+    return obj.removeAllListeners(opt_type);
+  }
+
+  var listenerMap = goog.events.getListenerMap_(
+      /** @type {!EventTarget} */ (obj));
+  if (!listenerMap) {
+    return 0;
+  }
+
+  var count = 0;
+  var typeStr = opt_type && opt_type.toString();
+  for (var type in listenerMap.listeners) {
+    if (!typeStr || type == typeStr) {
+      // Clone so that we don't need to worry about unlistenByKey
+      // changing the content of the ListenerMap.
+      var listeners = listenerMap.listeners[type].concat();
+      for (var i = 0; i < listeners.length; ++i) {
+        if (goog.events.unlistenByKey(listeners[i])) {
+          ++count;
+        }
+      }
+    }
+  }
+  return count;
+};
+
+
+/**
+ * Gets the listeners for a given object, type and capture phase.
+ *
+ * @param {Object} obj Object to get listeners for.
+ * @param {string|!goog.events.EventId} type Event type.
+ * @param {boolean} capture Capture phase?.
+ * @return {Array<goog.events.Listener>} Array of listener objects.
+ */
+goog.events.getListeners = function(obj, type, capture) {
+  if (goog.events.Listenable.isImplementedBy(obj)) {
+    return obj.getListeners(type, capture);
+  } else {
+    if (!obj) {
+      // TODO(chrishenry): We should tighten the API to accept
+      // !EventTarget|goog.events.Listenable, and add an assertion here.
+      return [];
+    }
+
+    var listenerMap = goog.events.getListenerMap_(
+        /** @type {!EventTarget} */ (obj));
+    return listenerMap ? listenerMap.getListeners(type, capture) : [];
+  }
+};
+
+
+/**
+ * Gets the goog.events.Listener for the event or null if no such listener is
+ * in use.
+ *
+ * @param {EventTarget|goog.events.Listenable} src The target from
+ *     which to get listeners.
+ * @param {?string|!goog.events.EventId<EVENTOBJ>} type The type of the event.
+ * @param {function(EVENTOBJ):?|{handleEvent:function(?):?}|null} listener The
+ *     listener function to get.
+ * @param {boolean=} opt_capt In DOM-compliant browsers, this determines
+ *                            whether the listener is fired during the
+ *                            capture or bubble phase of the event.
+ * @param {Object=} opt_handler Element in whose scope to call the listener.
+ * @return {goog.events.ListenableKey} the found listener or null if not found.
+ * @template EVENTOBJ
+ */
+goog.events.getListener = function(src, type, listener, opt_capt, opt_handler) {
+  // TODO(chrishenry): Change type from ?string to string, or add assertion.
+  type = /** @type {string} */ (type);
+  listener = goog.events.wrapListener(listener);
+  var capture = !!opt_capt;
+  if (goog.events.Listenable.isImplementedBy(src)) {
+    return src.getListener(type, listener, capture, opt_handler);
+  }
+
+  if (!src) {
+    // TODO(chrishenry): We should tighten the API to only accept
+    // non-null objects, or add an assertion here.
+    return null;
+  }
+
+  var listenerMap = goog.events.getListenerMap_(
+      /** @type {!EventTarget} */ (src));
+  if (listenerMap) {
+    return listenerMap.getListener(type, listener, capture, opt_handler);
+  }
+  return null;
+};
+
+
+/**
+ * Returns whether an event target has any active listeners matching the
+ * specified signature. If either the type or capture parameters are
+ * unspecified, the function will match on the remaining criteria.
+ *
+ * @param {EventTarget|goog.events.Listenable} obj Target to get
+ *     listeners for.
+ * @param {string|!goog.events.EventId=} opt_type Event type.
+ * @param {boolean=} opt_capture Whether to check for capture or bubble-phase
+ *     listeners.
+ * @return {boolean} Whether an event target has one or more listeners matching
+ *     the requested type and/or capture phase.
+ */
+goog.events.hasListener = function(obj, opt_type, opt_capture) {
+  if (goog.events.Listenable.isImplementedBy(obj)) {
+    return obj.hasListener(opt_type, opt_capture);
+  }
+
+  var listenerMap = goog.events.getListenerMap_(
+      /** @type {!EventTarget} */ (obj));
+  return !!listenerMap && listenerMap.hasListener(opt_type, opt_capture);
+};
+
+
+/**
+ * Provides a nice string showing the normalized event objects public members
+ * @param {Object} e Event Object.
+ * @return {string} String of the public members of the normalized event object.
+ */
+goog.events.expose = function(e) {
+  var str = [];
+  for (var key in e) {
+    if (e[key] && e[key].id) {
+      str.push(key + ' = ' + e[key] + ' (' + e[key].id + ')');
+    } else {
+      str.push(key + ' = ' + e[key]);
+    }
+  }
+  return str.join('\n');
+};
+
+
+/**
+ * Returns a string with on prepended to the specified type. This is used for IE
+ * which expects "on" to be prepended. This function caches the string in order
+ * to avoid extra allocations in steady state.
+ * @param {string} type Event type.
+ * @return {string} The type string with 'on' prepended.
+ * @private
+ */
+goog.events.getOnString_ = function(type) {
+  if (type in goog.events.onStringMap_) {
+    return goog.events.onStringMap_[type];
+  }
+  return goog.events.onStringMap_[type] = goog.events.onString_ + type;
+};
+
+
+/**
+ * Fires an object's listeners of a particular type and phase
+ *
+ * @param {Object} obj Object whose listeners to call.
+ * @param {string|!goog.events.EventId} type Event type.
+ * @param {boolean} capture Which event phase.
+ * @param {Object} eventObject Event object to be passed to listener.
+ * @return {boolean} True if all listeners returned true else false.
+ */
+goog.events.fireListeners = function(obj, type, capture, eventObject) {
+  if (goog.events.Listenable.isImplementedBy(obj)) {
+    return obj.fireListeners(type, capture, eventObject);
+  }
+
+  return goog.events.fireListeners_(obj, type, capture, eventObject);
+};
+
+
+/**
+ * Fires an object's listeners of a particular type and phase.
+ * @param {Object} obj Object whose listeners to call.
+ * @param {string|!goog.events.EventId} type Event type.
+ * @param {boolean} capture Which event phase.
+ * @param {Object} eventObject Event object to be passed to listener.
+ * @return {boolean} True if all listeners returned true else false.
+ * @private
+ */
+goog.events.fireListeners_ = function(obj, type, capture, eventObject) {
+  /** @type {boolean} */
+  var retval = true;
+
+  var listenerMap = goog.events.getListenerMap_(
+      /** @type {EventTarget} */ (obj));
+  if (listenerMap) {
+    // TODO(chrishenry): Original code avoids array creation when there
+    // is no listener, so we do the same. If this optimization turns
+    // out to be not required, we can replace this with
+    // listenerMap.getListeners(type, capture) instead, which is simpler.
+    var listenerArray = listenerMap.listeners[type.toString()];
+    if (listenerArray) {
+      listenerArray = listenerArray.concat();
+      for (var i = 0; i < listenerArray.length; i++) {
+        var listener = listenerArray[i];
+        // We might not have a listener if the listener was removed.
+        if (listener && listener.capture == capture && !listener.removed) {
+          var result = goog.events.fireListener(listener, eventObject);
+          retval = retval && (result !== false);
+        }
+      }
+    }
+  }
+  return retval;
+};
+
+
+/**
+ * Fires a listener with a set of arguments
+ *
+ * @param {goog.events.Listener} listener The listener object to call.
+ * @param {Object} eventObject The event object to pass to the listener.
+ * @return {boolean} Result of listener.
+ */
+goog.events.fireListener = function(listener, eventObject) {
+  var listenerFn = listener.listener;
+  var listenerHandler = listener.handler || listener.src;
+
+  if (listener.callOnce) {
+    goog.events.unlistenByKey(listener);
+  }
+  return listenerFn.call(listenerHandler, eventObject);
+};
+
+
+/**
+ * Gets the total number of listeners currently in the system.
+ * @return {number} Number of listeners.
+ * @deprecated This returns estimated count, now that Closure no longer
+ * stores a central listener registry. We still return an estimation
+ * to keep existing listener-related tests passing. In the near future,
+ * this function will be removed.
+ */
+goog.events.getTotalListenerCount = function() {
+  return goog.events.listenerCountEstimate_;
+};
+
+
+/**
+ * Dispatches an event (or event like object) and calls all listeners
+ * listening for events of this type. The type of the event is decided by the
+ * type property on the event object.
+ *
+ * If any of the listeners returns false OR calls preventDefault then this
+ * function will return false.  If one of the capture listeners calls
+ * stopPropagation, then the bubble listeners won't fire.
+ *
+ * @param {goog.events.Listenable} src The event target.
+ * @param {goog.events.EventLike} e Event object.
+ * @return {boolean} If anyone called preventDefault on the event object (or
+ *     if any of the handlers returns false) this will also return false.
+ *     If there are no handlers, or if all handlers return true, this returns
+ *     true.
+ */
+goog.events.dispatchEvent = function(src, e) {
+  goog.asserts.assert(
+      goog.events.Listenable.isImplementedBy(src),
+      'Can not use goog.events.dispatchEvent with ' +
+      'non-goog.events.Listenable instance.');
+  return src.dispatchEvent(e);
+};
+
+
+/**
+ * Installs exception protection for the browser event entry point using the
+ * given error handler.
+ *
+ * @param {goog.debug.ErrorHandler} errorHandler Error handler with which to
+ *     protect the entry point.
+ */
+goog.events.protectBrowserEventEntryPoint = function(errorHandler) {
+  goog.events.handleBrowserEvent_ = errorHandler.protectEntryPoint(
+      goog.events.handleBrowserEvent_);
+};
+
+
+/**
+ * Handles an event and dispatches it to the correct listeners. This
+ * function is a proxy for the real listener the user specified.
+ *
+ * @param {goog.events.Listener} listener The listener object.
+ * @param {Event=} opt_evt Optional event object that gets passed in via the
+ *     native event handlers.
+ * @return {boolean} Result of the event handler.
+ * @this {EventTarget} The object or Element that fired the event.
+ * @private
+ */
+goog.events.handleBrowserEvent_ = function(listener, opt_evt) {
+  if (listener.removed) {
+    return true;
+  }
+
+  // Synthesize event propagation if the browser does not support W3C
+  // event model.
+  if (!goog.events.BrowserFeature.HAS_W3C_EVENT_SUPPORT) {
+    var ieEvent = opt_evt ||
+        /** @type {Event} */ (goog.getObjectByName('window.event'));
+    var evt = new goog.events.BrowserEvent(ieEvent, this);
+    /** @type {boolean} */
+    var retval = true;
+
+    if (goog.events.CAPTURE_SIMULATION_MODE ==
+            goog.events.CaptureSimulationMode.ON) {
+      // If we have not marked this event yet, we should perform capture
+      // simulation.
+      if (!goog.events.isMarkedIeEvent_(ieEvent)) {
+        goog.events.markIeEvent_(ieEvent);
+
+        var ancestors = [];
+        for (var parent = evt.currentTarget; parent;
+             parent = parent.parentNode) {
+          ancestors.push(parent);
+        }
+
+        // Fire capture listeners.
+        var type = listener.type;
+        for (var i = ancestors.length - 1; !evt.propagationStopped_ && i >= 0;
+             i--) {
+          evt.currentTarget = ancestors[i];
+          var result = goog.events.fireListeners_(ancestors[i], type, true, evt);
+          retval = retval && result;
+        }
+
+        // Fire bubble listeners.
+        //
+        // We can technically rely on IE to perform bubble event
+        // propagation. However, it turns out that IE fires events in
+        // opposite order of attachEvent registration, which broke
+        // some code and tests that rely on the order. (While W3C DOM
+        // Level 2 Events TR leaves the event ordering unspecified,
+        // modern browsers and W3C DOM Level 3 Events Working Draft
+        // actually specify the order as the registration order.)
+        for (var i = 0; !evt.propagationStopped_ && i < ancestors.length; i++) {
+          evt.currentTarget = ancestors[i];
+          var result = goog.events.fireListeners_(ancestors[i], type, false, evt);
+          retval = retval && result;
+        }
+      }
+    } else {
+      retval = goog.events.fireListener(listener, evt);
+    }
+    return retval;
+  }
+
+  // Otherwise, simply fire the listener.
+  return goog.events.fireListener(
+      listener, new goog.events.BrowserEvent(opt_evt, this));
+};
+
+
+/**
+ * This is used to mark the IE event object so we do not do the Closure pass
+ * twice for a bubbling event.
+ * @param {Event} e The IE browser event.
+ * @private
+ */
+goog.events.markIeEvent_ = function(e) {
+  // Only the keyCode and the returnValue can be changed. We use keyCode for
+  // non keyboard events.
+  // event.returnValue is a bit more tricky. It is undefined by default. A
+  // boolean false prevents the default action. In a window.onbeforeunload and
+  // the returnValue is non undefined it will be alerted. However, we will only
+  // modify the returnValue for keyboard events. We can get a problem if non
+  // closure events sets the keyCode or the returnValue
+
+  var useReturnValue = false;
+
+  if (e.keyCode == 0) {
+    // We cannot change the keyCode in case that srcElement is input[type=file].
+    // We could test that that is the case but that would allocate 3 objects.
+    // If we use try/catch we will only allocate extra objects in the case of a
+    // failure.
+    /** @preserveTry */
+    try {
+      e.keyCode = -1;
+      return;
+    } catch (ex) {
+      useReturnValue = true;
+    }
+  }
+
+  if (useReturnValue ||
+      /** @type {boolean|undefined} */ (e.returnValue) == undefined) {
+    e.returnValue = true;
+  }
+};
+
+
+/**
+ * This is used to check if an IE event has already been handled by the Closure
+ * system so we do not do the Closure pass twice for a bubbling event.
+ * @param {Event} e  The IE browser event.
+ * @return {boolean} True if the event object has been marked.
+ * @private
+ */
+goog.events.isMarkedIeEvent_ = function(e) {
+  return e.keyCode < 0 || e.returnValue != undefined;
+};
+
+
+/**
+ * Counter to create unique event ids.
+ * @private {number}
+ */
+goog.events.uniqueIdCounter_ = 0;
+
+
+/**
+ * Creates a unique event id.
+ *
+ * @param {string} identifier The identifier.
+ * @return {string} A unique identifier.
+ * @idGenerator
+ */
+goog.events.getUniqueId = function(identifier) {
+  return identifier + '_' + goog.events.uniqueIdCounter_++;
+};
+
+
+/**
+ * @param {EventTarget} src The source object.
+ * @return {goog.events.ListenerMap} A listener map for the given
+ *     source object, or null if none exists.
+ * @private
+ */
+goog.events.getListenerMap_ = function(src) {
+  var listenerMap = src[goog.events.LISTENER_MAP_PROP_];
+  // IE serializes the property as well (e.g. when serializing outer
+  // HTML). So we must check that the value is of the correct type.
+  return listenerMap instanceof goog.events.ListenerMap ? listenerMap : null;
+};
+
+
+/**
+ * Expando property for listener function wrapper for Object with
+ * handleEvent.
+ * @private @const {string}
+ */
+goog.events.LISTENER_WRAPPER_PROP_ = '__closure_events_fn_' +
+    ((Math.random() * 1e9) >>> 0);
+
+
+/**
+ * @param {Object|Function} listener The listener function or an
+ *     object that contains handleEvent method.
+ * @return {!Function} Either the original function or a function that
+ *     calls obj.handleEvent. If the same listener is passed to this
+ *     function more than once, the same function is guaranteed to be
+ *     returned.
+ */
+goog.events.wrapListener = function(listener) {
+  goog.asserts.assert(listener, 'Listener can not be null.');
+
+  if (goog.isFunction(listener)) {
+    return listener;
+  }
+
+  goog.asserts.assert(
+      listener.handleEvent, 'An object listener must have handleEvent method.');
+  if (!listener[goog.events.LISTENER_WRAPPER_PROP_]) {
+    listener[goog.events.LISTENER_WRAPPER_PROP_] =
+        function(e) { return listener.handleEvent(e); };
+  }
+  return listener[goog.events.LISTENER_WRAPPER_PROP_];
+};
+
+
+// Register the browser event handler as an entry point, so that
+// it can be monitored for exception handling, etc.
+goog.debug.entryPointRegistry.register(
+    /**
+     * @param {function(!Function): !Function} transformer The transforming
+     *     function.
+     */
+    function(transformer) {
+      goog.events.handleBrowserEvent_ = transformer(
+          goog.events.handleBrowserEvent_);
+    });

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/events/eventtarget.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/events/eventtarget.js b/externs/GCL/externs/goog/events/eventtarget.js
new file mode 100644
index 0000000..7408c7e
--- /dev/null
+++ b/externs/GCL/externs/goog/events/eventtarget.js
@@ -0,0 +1,394 @@
+// Copyright 2005 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 disposable implementation of a custom
+ * listenable/event target. See also: documentation for
+ * {@code goog.events.Listenable}.
+ *
+ * @author arv@google.com (Erik Arvidsson) [Original implementation]
+ * @see ../demos/eventtarget.html
+ * @see goog.events.Listenable
+ */
+
+goog.provide('goog.events.EventTarget');
+
+goog.require('goog.Disposable');
+goog.require('goog.asserts');
+goog.require('goog.events');
+goog.require('goog.events.Event');
+goog.require('goog.events.Listenable');
+goog.require('goog.events.ListenerMap');
+goog.require('goog.object');
+
+
+
+/**
+ * An implementation of {@code goog.events.Listenable} with full W3C
+ * EventTarget-like support (capture/bubble mechanism, stopping event
+ * propagation, preventing default actions).
+ *
+ * You may subclass this class to turn your class into a Listenable.
+ *
+ * Unless propagation is stopped, an event dispatched by an
+ * EventTarget will bubble to the parent returned by
+ * {@code getParentEventTarget}. To set the parent, call
+ * {@code setParentEventTarget}. Subclasses that don't support
+ * changing the parent can override the setter to throw an error.
+ *
+ * Example usage:
+ * <pre>
+ *   var source = new goog.events.EventTarget();
+ *   function handleEvent(e) {
+ *     alert('Type: ' + e.type + '; Target: ' + e.target);
+ *   }
+ *   source.listen('foo', handleEvent);
+ *   // Or: goog.events.listen(source, 'foo', handleEvent);
+ *   ...
+ *   source.dispatchEvent('foo');  // will call handleEvent
+ *   ...
+ *   source.unlisten('foo', handleEvent);
+ *   // Or: goog.events.unlisten(source, 'foo', handleEvent);
+ * </pre>
+ *
+ * @constructor
+ * @extends {goog.Disposable}
+ * @implements {goog.events.Listenable}
+ */
+goog.events.EventTarget = function() {
+  goog.Disposable.call(this);
+
+  /**
+   * Maps of event type to an array of listeners.
+   * @private {!goog.events.ListenerMap}
+   */
+  this.eventTargetListeners_ = new goog.events.ListenerMap(this);
+
+  /**
+   * The object to use for event.target. Useful when mixing in an
+   * EventTarget to another object.
+   * @private {!Object}
+   */
+  this.actualEventTarget_ = this;
+
+  /**
+   * Parent event target, used during event bubbling.
+   *
+   * TODO(chrishenry): Change this to goog.events.Listenable. This
+   * currently breaks people who expect getParentEventTarget to return
+   * goog.events.EventTarget.
+   *
+   * @private {goog.events.EventTarget}
+   */
+  this.parentEventTarget_ = null;
+};
+goog.inherits(goog.events.EventTarget, goog.Disposable);
+goog.events.Listenable.addImplementation(goog.events.EventTarget);
+
+
+/**
+ * An artificial cap on the number of ancestors you can have. This is mainly
+ * for loop detection.
+ * @const {number}
+ * @private
+ */
+goog.events.EventTarget.MAX_ANCESTORS_ = 1000;
+
+
+/**
+ * Returns the parent of this event target to use for bubbling.
+ *
+ * @return {goog.events.EventTarget} The parent EventTarget or null if
+ *     there is no parent.
+ * @override
+ */
+goog.events.EventTarget.prototype.getParentEventTarget = function() {
+  return this.parentEventTarget_;
+};
+
+
+/**
+ * Sets the parent of this event target to use for capture/bubble
+ * mechanism.
+ * @param {goog.events.EventTarget} parent Parent listenable (null if none).
+ */
+goog.events.EventTarget.prototype.setParentEventTarget = function(parent) {
+  this.parentEventTarget_ = parent;
+};
+
+
+/**
+ * Adds an event listener to the event target. The same handler can only be
+ * added once per the type. Even if you add the same handler multiple times
+ * using the same type then it will only be called once when the event is
+ * dispatched.
+ *
+ * @param {string} type The type of the event to listen for.
+ * @param {function(?):?|{handleEvent:function(?):?}|null} handler The function
+ *     to handle the event. The handler can also be an object that implements
+ *     the handleEvent method which takes the event object as argument.
+ * @param {boolean=} opt_capture In DOM-compliant browsers, this determines
+ *     whether the listener is fired during the capture or bubble phase
+ *     of the event.
+ * @param {Object=} opt_handlerScope Object in whose scope to call
+ *     the listener.
+ * @deprecated Use {@code #listen} instead, when possible. Otherwise, use
+ *     {@code goog.events.listen} if you are passing Object
+ *     (instead of Function) as handler.
+ */
+goog.events.EventTarget.prototype.addEventListener = function(
+    type, handler, opt_capture, opt_handlerScope) {
+  goog.events.listen(this, type, handler, opt_capture, opt_handlerScope);
+};
+
+
+/**
+ * Removes an event listener from the event target. The handler must be the
+ * same object as the one added. If the handler has not been added then
+ * nothing is done.
+ *
+ * @param {string} type The type of the event to listen for.
+ * @param {function(?):?|{handleEvent:function(?):?}|null} handler The function
+ *     to handle the event. The handler can also be an object that implements
+ *     the handleEvent method which takes the event object as argument.
+ * @param {boolean=} opt_capture In DOM-compliant browsers, this determines
+ *     whether the listener is fired during the capture or bubble phase
+ *     of the event.
+ * @param {Object=} opt_handlerScope Object in whose scope to call
+ *     the listener.
+ * @deprecated Use {@code #unlisten} instead, when possible. Otherwise, use
+ *     {@code goog.events.unlisten} if you are passing Object
+ *     (instead of Function) as handler.
+ */
+goog.events.EventTarget.prototype.removeEventListener = function(
+    type, handler, opt_capture, opt_handlerScope) {
+  goog.events.unlisten(this, type, handler, opt_capture, opt_handlerScope);
+};
+
+
+/** @override */
+goog.events.EventTarget.prototype.dispatchEvent = function(e) {
+  this.assertInitialized_();
+
+  var ancestorsTree, ancestor = this.getParentEventTarget();
+  if (ancestor) {
+    ancestorsTree = [];
+    var ancestorCount = 1;
+    for (; ancestor; ancestor = ancestor.getParentEventTarget()) {
+      ancestorsTree.push(ancestor);
+      goog.asserts.assert(
+          (++ancestorCount < goog.events.EventTarget.MAX_ANCESTORS_),
+          'infinite loop');
+    }
+  }
+
+  return goog.events.EventTarget.dispatchEventInternal_(
+      this.actualEventTarget_, e, ancestorsTree);
+};
+
+
+/**
+ * Removes listeners from this object.  Classes that extend EventTarget may
+ * need to override this method in order to remove references to DOM Elements
+ * and additional listeners.
+ * @override
+ */
+goog.events.EventTarget.prototype.disposeInternal = function() {
+  goog.events.EventTarget.superClass_.disposeInternal.call(this);
+
+  this.removeAllListeners();
+  this.parentEventTarget_ = null;
+};
+
+
+/** @override */
+goog.events.EventTarget.prototype.listen = function(
+    type, listener, opt_useCapture, opt_listenerScope) {
+  this.assertInitialized_();
+  return this.eventTargetListeners_.add(
+      String(type), listener, false /* callOnce */, opt_useCapture,
+      opt_listenerScope);
+};
+
+
+/** @override */
+goog.events.EventTarget.prototype.listenOnce = function(
+    type, listener, opt_useCapture, opt_listenerScope) {
+  return this.eventTargetListeners_.add(
+      String(type), listener, true /* callOnce */, opt_useCapture,
+      opt_listenerScope);
+};
+
+
+/** @override */
+goog.events.EventTarget.prototype.unlisten = function(
+    type, listener, opt_useCapture, opt_listenerScope) {
+  return this.eventTargetListeners_.remove(
+      String(type), listener, opt_useCapture, opt_listenerScope);
+};
+
+
+/** @override */
+goog.events.EventTarget.prototype.unlistenByKey = function(key) {
+  return this.eventTargetListeners_.removeByKey(key);
+};
+
+
+/** @override */
+goog.events.EventTarget.prototype.removeAllListeners = function(opt_type) {
+  // TODO(chrishenry): Previously, removeAllListeners can be called on
+  // uninitialized EventTarget, so we preserve that behavior. We
+  // should remove this when usages that rely on that fact are purged.
+  if (!this.eventTargetListeners_) {
+    return 0;
+  }
+  return this.eventTargetListeners_.removeAll(opt_type);
+};
+
+
+/** @override */
+goog.events.EventTarget.prototype.fireListeners = function(
+    type, capture, eventObject) {
+  // TODO(chrishenry): Original code avoids array creation when there
+  // is no listener, so we do the same. If this optimization turns
+  // out to be not required, we can replace this with
+  // getListeners(type, capture) instead, which is simpler.
+  var listenerArray = this.eventTargetListeners_.listeners[String(type)];
+  if (!listenerArray) {
+    return true;
+  }
+  listenerArray = listenerArray.concat();
+
+  var rv = true;
+  for (var i = 0; i < listenerArray.length; ++i) {
+    var listener = listenerArray[i];
+    // We might not have a listener if the listener was removed.
+    if (listener && !listener.removed && listener.capture == capture) {
+      var listenerFn = listener.listener;
+      var listenerHandler = listener.handler || listener.src;
+
+      if (listener.callOnce) {
+        this.unlistenByKey(listener);
+      }
+      rv = listenerFn.call(listenerHandler, eventObject) !== false && rv;
+    }
+  }
+
+  return rv && eventObject.returnValue_ != false;
+};
+
+
+/** @override */
+goog.events.EventTarget.prototype.getListeners = function(type, capture) {
+  return this.eventTargetListeners_.getListeners(String(type), capture);
+};
+
+
+/** @override */
+goog.events.EventTarget.prototype.getListener = function(
+    type, listener, capture, opt_listenerScope) {
+  return this.eventTargetListeners_.getListener(
+      String(type), listener, capture, opt_listenerScope);
+};
+
+
+/** @override */
+goog.events.EventTarget.prototype.hasListener = function(
+    opt_type, opt_capture) {
+  var id = goog.isDef(opt_type) ? String(opt_type) : undefined;
+  return this.eventTargetListeners_.hasListener(id, opt_capture);
+};
+
+
+/**
+ * Sets the target to be used for {@code event.target} when firing
+ * event. Mainly used for testing. For example, see
+ * {@code goog.testing.events.mixinListenable}.
+ * @param {!Object} target The target.
+ */
+goog.events.EventTarget.prototype.setTargetForTesting = function(target) {
+  this.actualEventTarget_ = target;
+};
+
+
+/**
+ * Asserts that the event target instance is initialized properly.
+ * @private
+ */
+goog.events.EventTarget.prototype.assertInitialized_ = function() {
+  goog.asserts.assert(
+      this.eventTargetListeners_,
+      'Event target is not initialized. Did you call the superclass ' +
+      '(goog.events.EventTarget) constructor?');
+};
+
+
+/**
+ * Dispatches the given event on the ancestorsTree.
+ *
+ * @param {!Object} target The target to dispatch on.
+ * @param {goog.events.Event|Object|string} e The event object.
+ * @param {Array<goog.events.Listenable>=} opt_ancestorsTree The ancestors
+ *     tree of the target, in reverse order from the closest ancestor
+ *     to the root event target. May be null if the target has no ancestor.
+ * @return {boolean} If anyone called preventDefault on the event object (or
+ *     if any of the listeners returns false) this will also return false.
+ * @private
+ */
+goog.events.EventTarget.dispatchEventInternal_ = function(
+    target, e, opt_ancestorsTree) {
+  var type = e.type || /** @type {string} */ (e);
+
+  // If accepting a string or object, create a custom event object so that
+  // preventDefault and stopPropagation work with the event.
+  if (goog.isString(e)) {
+    e = new goog.events.Event(e, target);
+  } else if (!(e instanceof goog.events.Event)) {
+    var oldEvent = e;
+    e = new goog.events.Event(type, target);
+    goog.object.extend(e, oldEvent);
+  } else {
+    e.target = e.target || target;
+  }
+
+  var rv = true, currentTarget;
+
+  // Executes all capture listeners on the ancestors, if any.
+  if (opt_ancestorsTree) {
+    for (var i = opt_ancestorsTree.length - 1; !e.propagationStopped_ && i >= 0;
+         i--) {
+      currentTarget = e.currentTarget = opt_ancestorsTree[i];
+      rv = currentTarget.fireListeners(type, true, e) && rv;
+    }
+  }
+
+  // Executes capture and bubble listeners on the target.
+  if (!e.propagationStopped_) {
+    currentTarget = e.currentTarget = target;
+    rv = currentTarget.fireListeners(type, true, e) && rv;
+    if (!e.propagationStopped_) {
+      rv = currentTarget.fireListeners(type, false, e) && rv;
+    }
+  }
+
+  // Executes all bubble listeners on the ancestors, if any.
+  if (opt_ancestorsTree) {
+    for (i = 0; !e.propagationStopped_ && i < opt_ancestorsTree.length; i++) {
+      currentTarget = e.currentTarget = opt_ancestorsTree[i];
+      rv = currentTarget.fireListeners(type, false, e) && rv;
+    }
+  }
+
+  return rv;
+};


[40/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/date/date.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/date/date.js b/externs/GCL/externs/goog/date/date.js
new file mode 100644
index 0000000..1f17b36
--- /dev/null
+++ b/externs/GCL/externs/goog/date/date.js
@@ -0,0 +1,1761 @@
+// 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 Functions and objects for date representation and manipulation.
+ *
+ * @author eae@google.com (Emil A Eklund)
+ */
+
+goog.provide('goog.date');
+goog.provide('goog.date.Date');
+goog.provide('goog.date.DateTime');
+goog.provide('goog.date.Interval');
+goog.provide('goog.date.month');
+goog.provide('goog.date.weekDay');
+
+goog.require('goog.asserts');
+/** @suppress {extraRequire} */
+goog.require('goog.date.DateLike');
+goog.require('goog.i18n.DateTimeSymbols');
+goog.require('goog.string');
+
+
+/**
+ * Constants for weekdays.
+ * @enum {number}
+ */
+goog.date.weekDay = {
+  MON: 0,
+  TUE: 1,
+  WED: 2,
+  THU: 3,
+  FRI: 4,
+  SAT: 5,
+  SUN: 6
+};
+
+
+/**
+ * Constants for months.
+ * @enum {number}
+ */
+goog.date.month = {
+  JAN: 0,
+  FEB: 1,
+  MAR: 2,
+  APR: 3,
+  MAY: 4,
+  JUN: 5,
+  JUL: 6,
+  AUG: 7,
+  SEP: 8,
+  OCT: 9,
+  NOV: 10,
+  DEC: 11
+};
+
+
+/**
+ * Formats a month/year string.
+ * Example: "January 2008"
+ *
+ * @param {string} monthName The month name to use in the result.
+ * @param {number} yearNum The numeric year to use in the result.
+ * @return {string} A formatted month/year string.
+ */
+goog.date.formatMonthAndYear = function(monthName, yearNum) {
+  /** @desc Month/year format given the month name and the numeric year. */
+  var MSG_MONTH_AND_YEAR = goog.getMsg(
+      '{$monthName} {$yearNum}',
+      { 'monthName' : monthName, 'yearNum' : yearNum });
+  return MSG_MONTH_AND_YEAR;
+};
+
+
+/**
+ * Regular expression for splitting date parts from ISO 8601 styled string.
+ * Examples: '20060210' or '2005-02-22' or '20050222' or '2005-08'
+ * or '2005-W22' or '2005W22' or '2005-W22-4', etc.
+ * For explanation and more examples, see:
+ * {@link http://en.wikipedia.org/wiki/ISO_8601}
+ *
+ * @type {RegExp}
+ * @private
+ */
+goog.date.splitDateStringRegex_ = new RegExp(
+    '^(\\d{4})(?:(?:-?(\\d{2})(?:-?(\\d{2}))?)|' +
+    '(?:-?(\\d{3}))|(?:-?W(\\d{2})(?:-?([1-7]))?))?$');
+
+
+/**
+ * Regular expression for splitting time parts from ISO 8601 styled string.
+ * Examples: '18:46:39.994' or '184639.994'
+ *
+ * @type {RegExp}
+ * @private
+ */
+goog.date.splitTimeStringRegex_ =
+    /^(\d{2})(?::?(\d{2})(?::?(\d{2})(\.\d+)?)?)?$/;
+
+
+/**
+ * Regular expression for splitting timezone parts from ISO 8601 styled string.
+ * Example: The part after the '+' in '18:46:39+07:00'.  Or '09:30Z' (UTC).
+ *
+ * @type {RegExp}
+ * @private
+ */
+goog.date.splitTimezoneStringRegex_ = /Z|(?:([-+])(\d{2})(?::?(\d{2}))?)$/;
+
+
+/**
+ * Regular expression for splitting duration parts from ISO 8601 styled string.
+ * Example: '-P1Y2M3DT4H5M6.7S'
+ *
+ * @type {RegExp}
+ * @private
+ */
+goog.date.splitDurationRegex_ = new RegExp(
+    '^(-)?P(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)D)?' +
+    '(T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+(?:\\.\\d+)?)S)?)?$');
+
+
+/**
+ * Number of milliseconds in a day.
+ * @type {number}
+ */
+goog.date.MS_PER_DAY = 24 * 60 * 60 * 1000;
+
+
+/**
+ * Returns whether the given year is a leap year.
+ *
+ * @param {number} year Year part of date.
+ * @return {boolean} Whether the given year is a leap year.
+ */
+goog.date.isLeapYear = function(year) {
+  // Leap year logic; the 4-100-400 rule
+  return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
+};
+
+
+/**
+ * Returns whether the given year is a long ISO year.
+ * See {@link http://www.phys.uu.nl/~vgent/calendar/isocalendar_text3.htm}.
+ *
+ * @param {number} year Full year part of date.
+ * @return {boolean} Whether the given year is a long ISO year.
+ */
+goog.date.isLongIsoYear = function(year) {
+  var n = 5 * year + 12 - 4 * (Math.floor(year / 100) - Math.floor(year / 400));
+  n += Math.floor((year - 100) / 400) - Math.floor((year - 102) / 400);
+  n += Math.floor((year - 200) / 400) - Math.floor((year - 199) / 400);
+
+  return n % 28 < 5;
+};
+
+
+/**
+ * Returns the number of days for a given month.
+ *
+ * @param {number} year Year part of date.
+ * @param {number} month Month part of date.
+ * @return {number} The number of days for the given month.
+ */
+goog.date.getNumberOfDaysInMonth = function(year, month) {
+  switch (month) {
+    case goog.date.month.FEB:
+      return goog.date.isLeapYear(year) ? 29 : 28;
+    case goog.date.month.JUN:
+    case goog.date.month.SEP:
+    case goog.date.month.NOV:
+    case goog.date.month.APR:
+      return 30;
+  }
+  return 31;
+};
+
+
+/**
+ * Returns true if the 2 dates are in the same day.
+ * @param {goog.date.DateLike} date The time to check.
+ * @param {goog.date.DateLike=} opt_now The current time.
+ * @return {boolean} Whether the dates are on the same day.
+ */
+goog.date.isSameDay = function(date, opt_now) {
+  var now = opt_now || new Date(goog.now());
+  return date.getDate() == now.getDate() &&
+      goog.date.isSameMonth(date, now);
+};
+
+
+/**
+ * Returns true if the 2 dates are in the same month.
+ * @param {goog.date.DateLike} date The time to check.
+ * @param {goog.date.DateLike=} opt_now The current time.
+ * @return {boolean} Whether the dates are in the same calendar month.
+ */
+goog.date.isSameMonth = function(date, opt_now) {
+  var now = opt_now || new Date(goog.now());
+  return date.getMonth() == now.getMonth() &&
+      goog.date.isSameYear(date, now);
+};
+
+
+/**
+ * Returns true if the 2 dates are in the same year.
+ * @param {goog.date.DateLike} date The time to check.
+ * @param {goog.date.DateLike=} opt_now The current time.
+ * @return {boolean} Whether the dates are in the same calendar year.
+ */
+goog.date.isSameYear = function(date, opt_now) {
+  var now = opt_now || new Date(goog.now());
+  return date.getFullYear() == now.getFullYear();
+};
+
+
+/**
+ * Static function for week number calculation. ISO 8601 implementation.
+ *
+ * @param {number} year Year part of date.
+ * @param {number} month Month part of date (0-11).
+ * @param {number} date Day part of date (1-31).
+ * @param {number=} opt_weekDay Cut off weekday, defaults to Thursday.
+ * @param {number=} opt_firstDayOfWeek First day of the week, defaults to
+ *     Monday.
+ *     Monday=0, Sunday=6.
+ * @return {number} The week number (1-53).
+ */
+goog.date.getWeekNumber = function(year, month, date, opt_weekDay,
+    opt_firstDayOfWeek) {
+  var d = new Date(year, month, date);
+
+  // Default to Thursday for cut off as per ISO 8601.
+  var cutoff = opt_weekDay || goog.date.weekDay.THU;
+
+  // Default to Monday for first day of the week as per ISO 8601.
+  var firstday = opt_firstDayOfWeek || goog.date.weekDay.MON;
+
+  // The d.getDay() has to be converted first to ISO weekday (Monday=0).
+  var isoday = (d.getDay() + 6) % 7;
+
+  // Position of given day in the picker grid w.r.t. first day of week
+  var daypos = (isoday - firstday + 7) % 7;
+
+  // Position of cut off day in the picker grid w.r.t. first day of week
+  var cutoffpos = (cutoff - firstday + 7) % 7;
+
+  // Unix timestamp of the midnight of the cutoff day in the week of 'd'.
+  // There might be +-1 hour shift in the result due to the daylight saving,
+  // but it doesn't affect the year.
+  var cutoffSameWeek = d.valueOf() +
+      (cutoffpos - daypos) * goog.date.MS_PER_DAY;
+
+  // Unix timestamp of January 1 in the year of 'cutoffSameWeek'.
+  var jan1 = new Date(new Date(cutoffSameWeek).getFullYear(), 0, 1).valueOf();
+
+  // Number of week. The round() eliminates the effect of daylight saving.
+  return Math.floor(Math.round(
+      (cutoffSameWeek - jan1) / goog.date.MS_PER_DAY) / 7) + 1;
+};
+
+
+/**
+ * @param {T} date1 A datelike object.
+ * @param {S} date2 Another datelike object.
+ * @return {T|S} The earlier of them in time.
+ * @template T,S
+ */
+goog.date.min = function(date1, date2) {
+  return date1 < date2 ? date1 : date2;
+};
+
+
+/**
+ * @param {T} date1 A datelike object.
+ * @param {S} date2 Another datelike object.
+ * @return {T|S} The later of them in time.
+ * @template T,S
+ */
+goog.date.max = function(date1, date2) {
+  return date1 > date2 ? date1 : date2;
+};
+
+
+/**
+ * Creates a DateTime from a datetime string expressed in ISO 8601 format.
+ *
+ * @param {string} formatted A date or datetime expressed in ISO 8601 format.
+ * @return {goog.date.DateTime} Parsed date or null if parse fails.
+ */
+goog.date.fromIsoString = function(formatted) {
+  var ret = new goog.date.DateTime(2000);
+  return goog.date.setIso8601DateTime(ret, formatted) ? ret : null;
+};
+
+
+/**
+ * Parses a datetime string expressed in ISO 8601 format. Overwrites the date
+ * and optionally the time part of the given object with the parsed values.
+ *
+ * @param {!goog.date.DateTime} dateTime Object whose fields will be set.
+ * @param {string} formatted A date or datetime expressed in ISO 8601 format.
+ * @return {boolean} Whether the parsing succeeded.
+ */
+goog.date.setIso8601DateTime = function(dateTime, formatted) {
+  formatted = goog.string.trim(formatted);
+  var delim = formatted.indexOf('T') == -1 ? ' ' : 'T';
+  var parts = formatted.split(delim);
+  return goog.date.setIso8601DateOnly_(dateTime, parts[0]) &&
+      (parts.length < 2 || goog.date.setIso8601TimeOnly_(dateTime, parts[1]));
+};
+
+
+/**
+ * Sets date fields based on an ISO 8601 format string.
+ *
+ * @param {!goog.date.DateTime} d Object whose fields will be set.
+ * @param {string} formatted A date expressed in ISO 8601 format.
+ * @return {boolean} Whether the parsing succeeded.
+ * @private
+ */
+goog.date.setIso8601DateOnly_ = function(d, formatted) {
+  // split the formatted ISO date string into its date fields
+  var parts = formatted.match(goog.date.splitDateStringRegex_);
+  if (!parts) {
+    return false;
+  }
+
+  var year = Number(parts[1]);
+  var month = Number(parts[2]);
+  var date = Number(parts[3]);
+  var dayOfYear = Number(parts[4]);
+  var week = Number(parts[5]);
+  // ISO weekdays start with 1, native getDay() values start with 0
+  var dayOfWeek = Number(parts[6]) || 1;
+
+  d.setFullYear(year);
+
+  if (dayOfYear) {
+    d.setDate(1);
+    d.setMonth(0);
+    var offset = dayOfYear - 1; // offset, so 1-indexed, i.e., skip day 1
+    d.add(new goog.date.Interval(goog.date.Interval.DAYS, offset));
+  } else if (week) {
+    goog.date.setDateFromIso8601Week_(d, week, dayOfWeek);
+  } else {
+    if (month) {
+      d.setDate(1);
+      d.setMonth(month - 1);
+    }
+    if (date) {
+      d.setDate(date);
+    }
+  }
+
+  return true;
+};
+
+
+/**
+ * Sets date fields based on an ISO 8601 week string.
+ * See {@link http://en.wikipedia.org/wiki/ISO_week_date}, "Relation with the
+ * Gregorian Calendar".  The first week of a new ISO year is the week with the
+ * majority of its days in the new Gregorian year.  I.e., ISO Week 1's Thursday
+ * is in that year.  ISO weeks always start on Monday. So ISO Week 1 can
+ * contain a few days from the previous Gregorian year.  And ISO weeks always
+ * end on Sunday, so the last ISO week (Week 52 or 53) can have a few days from
+ * the following Gregorian year.
+ * Example: '1997-W01' lasts from 1996-12-30 to 1997-01-05.  January 1, 1997 is
+ * a Wednesday. So W01's Monday is Dec.30, 1996, and Sunday is January 5, 1997.
+ *
+ * @param {goog.date.DateTime} d Object whose fields will be set.
+ * @param {number} week ISO week number.
+ * @param {number} dayOfWeek ISO day of week.
+ * @private
+ */
+goog.date.setDateFromIso8601Week_ = function(d, week, dayOfWeek) {
+  // calculate offset for first week
+  d.setMonth(0);
+  d.setDate(1);
+  var jsDay = d.getDay();
+  // switch Sunday (0) to index 7; ISO days are 1-indexed
+  var jan1WeekDay = jsDay || 7;
+
+  var THURSDAY = 4;
+  if (jan1WeekDay <= THURSDAY) {
+    // was extended back to Monday
+    var startDelta = 1 - jan1WeekDay; // e.g., Thu(4) ==> -3
+  } else {
+    // was extended forward to Monday
+    startDelta = 8 - jan1WeekDay; // e.g., Fri(5) ==> +3
+  }
+
+  // find the absolute number of days to offset from the start of year
+  // to arrive close to the Gregorian equivalent (pending adjustments above)
+  // Note: decrement week multiplier by one because 1st week is
+  // represented by dayOfWeek value
+  var absoluteDays = Number(dayOfWeek) + (7 * (Number(week) - 1));
+
+  // convert from ISO weekday format to Gregorian calendar date
+  // note: subtract 1 because 1-indexed; offset should not include 1st of month
+  var delta = startDelta + absoluteDays - 1;
+  var interval = new goog.date.Interval(goog.date.Interval.DAYS, delta);
+  d.add(interval);
+};
+
+
+/**
+ * Sets time fields based on an ISO 8601 format string.
+ * Note: only time fields, not date fields.
+ *
+ * @param {!goog.date.DateTime} d Object whose fields will be set.
+ * @param {string} formatted A time expressed in ISO 8601 format.
+ * @return {boolean} Whether the parsing succeeded.
+ * @private
+ */
+goog.date.setIso8601TimeOnly_ = function(d, formatted) {
+  // first strip timezone info from the end
+  var parts = formatted.match(goog.date.splitTimezoneStringRegex_);
+
+  var offset = 0; // local time if no timezone info
+  if (parts) {
+    if (parts[0] != 'Z') {
+      offset = parts[2] * 60 + Number(parts[3]);
+      offset *= parts[1] == '-' ? 1 : -1;
+    }
+    offset -= d.getTimezoneOffset();
+    formatted = formatted.substr(0, formatted.length - parts[0].length);
+  }
+
+  // then work out the time
+  parts = formatted.match(goog.date.splitTimeStringRegex_);
+  if (!parts) {
+    return false;
+  }
+
+  d.setHours(Number(parts[1]));
+  d.setMinutes(Number(parts[2]) || 0);
+  d.setSeconds(Number(parts[3]) || 0);
+  d.setMilliseconds(parts[4] ? parts[4] * 1000 : 0);
+
+  if (offset != 0) {
+    // adjust the date and time according to the specified timezone
+    d.setTime(d.getTime() + offset * 60000);
+  }
+
+  return true;
+};
+
+
+
+/**
+ * Class representing a date/time interval. Used for date calculations.
+ * <pre>
+ * new goog.date.Interval(0, 1) // One month
+ * new goog.date.Interval(0, 0, 3, 1) // Three days and one hour
+ * new goog.date.Interval(goog.date.Interval.DAYS, 1) // One day
+ * </pre>
+ *
+ * @param {number|string=} opt_years Years or string representing date part.
+ * @param {number=} opt_months Months or number of whatever date part specified
+ *     by first parameter.
+ * @param {number=} opt_days Days.
+ * @param {number=} opt_hours Hours.
+ * @param {number=} opt_minutes Minutes.
+ * @param {number=} opt_seconds Seconds.
+ * @constructor
+ * @struct
+ * @final
+ */
+goog.date.Interval = function(opt_years, opt_months, opt_days, opt_hours,
+                              opt_minutes, opt_seconds) {
+  if (goog.isString(opt_years)) {
+    var type = opt_years;
+    var interval = /** @type {number} */ (opt_months);
+    this.years = type == goog.date.Interval.YEARS ? interval : 0;
+    this.months = type == goog.date.Interval.MONTHS ? interval : 0;
+    this.days = type == goog.date.Interval.DAYS ? interval : 0;
+    this.hours = type == goog.date.Interval.HOURS ? interval : 0;
+    this.minutes = type == goog.date.Interval.MINUTES ? interval : 0;
+    this.seconds = type == goog.date.Interval.SECONDS ? interval : 0;
+  } else {
+    this.years = /** @type {number} */ (opt_years) || 0;
+    this.months = opt_months || 0;
+    this.days = opt_days || 0;
+    this.hours = opt_hours || 0;
+    this.minutes = opt_minutes || 0;
+    this.seconds = opt_seconds || 0;
+  }
+};
+
+
+/**
+ * Parses an XML Schema duration (ISO 8601 extended).
+ * @see http://www.w3.org/TR/xmlschema-2/#duration
+ *
+ * @param  {string} duration An XML schema duration in textual format.
+ *     Recurring durations and weeks are not supported.
+ * @return {goog.date.Interval} The duration as a goog.date.Interval or null
+ *     if the parse fails.
+ */
+goog.date.Interval.fromIsoString = function(duration) {
+  var parts = duration.match(goog.date.splitDurationRegex_);
+  if (!parts) {
+    return null;
+  }
+
+  var timeEmpty = !(parts[6] || parts[7] || parts[8]);
+  var dateTimeEmpty = timeEmpty && !(parts[2] || parts[3] || parts[4]);
+  if (dateTimeEmpty || timeEmpty && parts[5]) {
+    return null;
+  }
+
+  var negative = parts[1];
+  var years = parseInt(parts[2], 10) || 0;
+  var months = parseInt(parts[3], 10) || 0;
+  var days = parseInt(parts[4], 10) || 0;
+  var hours = parseInt(parts[6], 10) || 0;
+  var minutes = parseInt(parts[7], 10) || 0;
+  var seconds = parseFloat(parts[8]) || 0;
+  return negative ? new goog.date.Interval(-years, -months, -days,
+                                           -hours, -minutes, -seconds) :
+                    new goog.date.Interval(years, months, days,
+                                           hours, minutes, seconds);
+};
+
+
+/**
+ * Serializes goog.date.Interval into XML Schema duration (ISO 8601 extended).
+ * @see http://www.w3.org/TR/xmlschema-2/#duration
+ *
+ * @param {boolean=} opt_verbose Include zero fields in the duration string.
+ * @return {?string} An XML schema duration in ISO 8601 extended format,
+ *     or null if the interval contains both positive and negative fields.
+ */
+goog.date.Interval.prototype.toIsoString = function(opt_verbose) {
+  var minField = Math.min(this.years, this.months, this.days,
+                          this.hours, this.minutes, this.seconds);
+  var maxField = Math.max(this.years, this.months, this.days,
+                          this.hours, this.minutes, this.seconds);
+  if (minField < 0 && maxField > 0) {
+    return null;
+  }
+
+  // Return 0 seconds if all fields are zero.
+  if (!opt_verbose && minField == 0 && maxField == 0) {
+    return 'PT0S';
+  }
+
+  var res = [];
+
+  // Add sign and 'P' prefix.
+  if (minField < 0) {
+    res.push('-');
+  }
+  res.push('P');
+
+  // Add date.
+  if (this.years || opt_verbose) {
+    res.push(Math.abs(this.years) + 'Y');
+  }
+  if (this.months || opt_verbose) {
+    res.push(Math.abs(this.months) + 'M');
+  }
+  if (this.days || opt_verbose) {
+    res.push(Math.abs(this.days) + 'D');
+  }
+
+  // Add time.
+  if (this.hours || this.minutes || this.seconds || opt_verbose) {
+    res.push('T');
+    if (this.hours || opt_verbose) {
+      res.push(Math.abs(this.hours) + 'H');
+    }
+    if (this.minutes || opt_verbose) {
+      res.push(Math.abs(this.minutes) + 'M');
+    }
+    if (this.seconds || opt_verbose) {
+      res.push(Math.abs(this.seconds) + 'S');
+    }
+  }
+
+  return res.join('');
+};
+
+
+/**
+ * Tests whether the given interval is equal to this interval.
+ * Note, this is a simple field-by-field comparison, it doesn't
+ * account for comparisons like "12 months == 1 year".
+ *
+ * @param {goog.date.Interval} other The interval to test.
+ * @return {boolean} Whether the intervals are equal.
+ */
+goog.date.Interval.prototype.equals = function(other) {
+  return other.years == this.years &&
+         other.months == this.months &&
+         other.days == this.days &&
+         other.hours == this.hours &&
+         other.minutes == this.minutes &&
+         other.seconds == this.seconds;
+};
+
+
+/**
+ * @return {!goog.date.Interval} A clone of the interval object.
+ */
+goog.date.Interval.prototype.clone = function() {
+  return new goog.date.Interval(
+      this.years, this.months, this.days,
+      this.hours, this.minutes, this.seconds);
+};
+
+
+/**
+ * Years constant for the date parts.
+ * @type {string}
+ */
+goog.date.Interval.YEARS = 'y';
+
+
+/**
+ * Months constant for the date parts.
+ * @type {string}
+ */
+goog.date.Interval.MONTHS = 'm';
+
+
+/**
+ * Days constant for the date parts.
+ * @type {string}
+ */
+goog.date.Interval.DAYS = 'd';
+
+
+/**
+ * Hours constant for the date parts.
+ * @type {string}
+ */
+goog.date.Interval.HOURS = 'h';
+
+
+/**
+ * Minutes constant for the date parts.
+ * @type {string}
+ */
+goog.date.Interval.MINUTES = 'n';
+
+
+/**
+ * Seconds constant for the date parts.
+ * @type {string}
+ */
+goog.date.Interval.SECONDS = 's';
+
+
+/**
+ * @return {boolean} Whether all fields of the interval are zero.
+ */
+goog.date.Interval.prototype.isZero = function() {
+  return this.years == 0 &&
+         this.months == 0 &&
+         this.days == 0 &&
+         this.hours == 0 &&
+         this.minutes == 0 &&
+         this.seconds == 0;
+};
+
+
+/**
+ * @return {!goog.date.Interval} Negative of this interval.
+ */
+goog.date.Interval.prototype.getInverse = function() {
+  return this.times(-1);
+};
+
+
+/**
+ * Calculates n * (this interval) by memberwise multiplication.
+ * @param {number} n An integer.
+ * @return {!goog.date.Interval} n * this.
+ */
+goog.date.Interval.prototype.times = function(n) {
+  return new goog.date.Interval(this.years * n,
+                                this.months * n,
+                                this.days * n,
+                                this.hours * n,
+                                this.minutes * n,
+                                this.seconds * n);
+};
+
+
+/**
+ * Gets the total number of seconds in the time interval. Assumes that months
+ * and years are empty.
+ * @return {number} Total number of seconds in the interval.
+ */
+goog.date.Interval.prototype.getTotalSeconds = function() {
+  goog.asserts.assert(this.years == 0 && this.months == 0);
+  return ((this.days * 24 + this.hours) * 60 + this.minutes) * 60 +
+      this.seconds;
+};
+
+
+/**
+ * Adds the Interval in the argument to this Interval field by field.
+ *
+ * @param {goog.date.Interval} interval The Interval to add.
+ */
+goog.date.Interval.prototype.add = function(interval) {
+  this.years += interval.years;
+  this.months += interval.months;
+  this.days += interval.days;
+  this.hours += interval.hours;
+  this.minutes += interval.minutes;
+  this.seconds += interval.seconds;
+};
+
+
+
+/**
+ * Class representing a date. Defaults to current date if none is specified.
+ *
+ * Implements most methods of the native js Date object (except the time related
+ * ones, {@see goog.date.DateTime}) and can be used interchangeably with it just
+ * as if goog.date.Date was a synonym of Date. To make this more transparent,
+ * Closure APIs should accept goog.date.DateLike instead of the real Date
+ * object.
+ *
+ * To allow goog.date.Date objects to be passed as arguments to methods
+ * expecting Date objects this class is marked as extending the built in Date
+ * object even though that's not strictly true.
+ *
+ * @param {number|goog.date.DateLike=} opt_year Four digit year or a date-like
+ *     object. If not set, the created object will contain the date
+ *     determined by goog.now().
+ * @param {number=} opt_month Month, 0 = Jan, 11 = Dec.
+ * @param {number=} opt_date Date of month, 1 - 31.
+ * @constructor
+ * @struct
+ * @see goog.date.DateTime
+ */
+goog.date.Date = function(opt_year, opt_month, opt_date) {
+  /** @protected {!Date} The wrapped date or datetime. */
+  this.date;
+  // goog.date.DateTime assumes that only this.date is added in this ctor.
+  if (goog.isNumber(opt_year)) {
+    this.date = this.buildDate_(opt_year, opt_month || 0, opt_date || 1);
+    this.maybeFixDst_(opt_date || 1);
+  } else if (goog.isObject(opt_year)) {
+    this.date = this.buildDate_(opt_year.getFullYear(), opt_year.getMonth(),
+        opt_year.getDate());
+    this.maybeFixDst_(opt_year.getDate());
+  } else {
+    this.date = new Date(goog.now());
+    this.date.setHours(0);
+    this.date.setMinutes(0);
+    this.date.setSeconds(0);
+    this.date.setMilliseconds(0);
+  }
+};
+
+
+/**
+ * new Date(y, m, d) treats years in the interval [0, 100) as two digit years,
+ * adding 1900 to them. This method ensures that calling the date constructor
+ * as a copy constructor returns a value that is equal to the passed in
+ * date value by explicitly setting the full year.
+ * @private
+ * @param {number} fullYear The full year (including century).
+ * @param {number} month The month, from 0-11.
+ * @param {number} date The day of the month.
+ * @return {!Date} The constructed Date object.
+ */
+goog.date.Date.prototype.buildDate_ = function(fullYear, month, date) {
+  var d = new Date(fullYear, month, date);
+  if (fullYear >= 0 && fullYear < 100) {
+    // Can't just setFullYear as new Date() can flip over for e.g. month = 13.
+    d.setFullYear(d.getFullYear() - 1900);
+  }
+  return d;
+};
+
+
+/**
+ * First day of week. 0 = Mon, 6 = Sun.
+ * @type {number}
+ * @private
+ */
+goog.date.Date.prototype.firstDayOfWeek_ =
+    goog.i18n.DateTimeSymbols.FIRSTDAYOFWEEK;
+
+
+/**
+ * The cut off weekday used for week number calculations. 0 = Mon, 6 = Sun.
+ * @type {number}
+ * @private
+ */
+goog.date.Date.prototype.firstWeekCutOffDay_ =
+    goog.i18n.DateTimeSymbols.FIRSTWEEKCUTOFFDAY;
+
+
+/**
+ * @return {!goog.date.Date} A clone of the date object.
+ */
+goog.date.Date.prototype.clone = function() {
+  var date = new goog.date.Date(this.date);
+  date.firstDayOfWeek_ = this.firstDayOfWeek_;
+  date.firstWeekCutOffDay_ = this.firstWeekCutOffDay_;
+
+  return date;
+};
+
+
+/**
+ * @return {number} The four digit year of date.
+ */
+goog.date.Date.prototype.getFullYear = function() {
+  return this.date.getFullYear();
+};
+
+
+/**
+ * Alias for getFullYear.
+ *
+ * @return {number} The four digit year of date.
+ * @see #getFullyear
+ */
+goog.date.Date.prototype.getYear = function() {
+  return this.getFullYear();
+};
+
+
+/**
+ * @return {goog.date.month} The month of date, 0 = Jan, 11 = Dec.
+ */
+goog.date.Date.prototype.getMonth = function() {
+  return /** @type {goog.date.month} */ (this.date.getMonth());
+};
+
+
+/**
+ * @return {number} The date of month.
+ */
+goog.date.Date.prototype.getDate = function() {
+  return this.date.getDate();
+};
+
+
+/**
+ * Returns the number of milliseconds since 1 January 1970 00:00:00.
+ *
+ * @return {number} The number of milliseconds since 1 January 1970 00:00:00.
+ */
+goog.date.Date.prototype.getTime = function() {
+  return this.date.getTime();
+};
+
+
+/**
+ * @return {number} The day of week, US style. 0 = Sun, 6 = Sat.
+ */
+goog.date.Date.prototype.getDay = function() {
+  return this.date.getDay();
+};
+
+
+/**
+ * @return {goog.date.weekDay} The day of week, ISO style. 0 = Mon, 6 = Sun.
+ */
+goog.date.Date.prototype.getIsoWeekday = function() {
+  return /** @type {goog.date.weekDay} */ ((this.getDay() + 6) % 7);
+};
+
+
+/**
+ * @return {number} The day of week according to firstDayOfWeek setting.
+ */
+goog.date.Date.prototype.getWeekday = function() {
+  return (this.getIsoWeekday() - this.firstDayOfWeek_ + 7) % 7;
+};
+
+
+/**
+ * @return {number} The four digit year of date according to universal time.
+ */
+goog.date.Date.prototype.getUTCFullYear = function() {
+  return this.date.getUTCFullYear();
+};
+
+
+/**
+ * @return {goog.date.month} The month of date according to universal time,
+ *     0 = Jan, 11 = Dec.
+ */
+goog.date.Date.prototype.getUTCMonth = function() {
+  return /** @type {goog.date.month} */ (this.date.getUTCMonth());
+};
+
+
+/**
+ * @return {number} The date of month according to universal time.
+ */
+goog.date.Date.prototype.getUTCDate = function() {
+  return this.date.getUTCDate();
+};
+
+
+/**
+ * @return {number} The day of week according to universal time, US style.
+ *     0 = Sun, 1 = Mon, 6 = Sat.
+ */
+goog.date.Date.prototype.getUTCDay = function() {
+  return this.date.getDay();
+};
+
+
+/**
+ * @return {number} The hours value according to universal time.
+ */
+goog.date.Date.prototype.getUTCHours = function() {
+  return this.date.getUTCHours();
+};
+
+
+/**
+ * @return {number} The hours value according to universal time.
+ */
+goog.date.Date.prototype.getUTCMinutes = function() {
+  return this.date.getUTCMinutes();
+};
+
+
+/**
+ * @return {goog.date.weekDay} The day of week according to universal time, ISO
+ *     style. 0 = Mon, 6 = Sun.
+ */
+goog.date.Date.prototype.getUTCIsoWeekday = function() {
+  return /** @type {goog.date.weekDay} */ ((this.date.getUTCDay() + 6) % 7);
+};
+
+
+/**
+ * @return {number} The day of week according to universal time and
+ *     firstDayOfWeek setting.
+ */
+goog.date.Date.prototype.getUTCWeekday = function() {
+  return (this.getUTCIsoWeekday() - this.firstDayOfWeek_ + 7) % 7;
+};
+
+
+/**
+ * @return {number} The first day of the week. 0 = Mon, 6 = Sun.
+ */
+goog.date.Date.prototype.getFirstDayOfWeek = function() {
+  return this.firstDayOfWeek_;
+};
+
+
+/**
+ * @return {number} The cut off weekday used for week number calculations.
+ *     0 = Mon, 6 = Sun.
+ */
+goog.date.Date.prototype.getFirstWeekCutOffDay = function() {
+  return this.firstWeekCutOffDay_;
+};
+
+
+/**
+ * @return {number} The number of days for the selected month.
+ */
+goog.date.Date.prototype.getNumberOfDaysInMonth = function() {
+  return goog.date.getNumberOfDaysInMonth(this.getFullYear(), this.getMonth());
+};
+
+
+/**
+ * @return {number} The week number.
+ */
+goog.date.Date.prototype.getWeekNumber = function() {
+  return goog.date.getWeekNumber(
+      this.getFullYear(), this.getMonth(), this.getDate(),
+      this.firstWeekCutOffDay_, this.firstDayOfWeek_);
+};
+
+
+/**
+ * @return {number} The day of year.
+ */
+goog.date.Date.prototype.getDayOfYear = function() {
+  var dayOfYear = this.getDate();
+  var year = this.getFullYear();
+  for (var m = this.getMonth() - 1; m >= 0; m--) {
+    dayOfYear += goog.date.getNumberOfDaysInMonth(year, m);
+  }
+
+  return dayOfYear;
+};
+
+
+/**
+ * Returns timezone offset. The timezone offset is the delta in minutes between
+ * UTC and your local time. E.g., UTC+10 returns -600. Daylight savings time
+ * prevents this value from being constant.
+ *
+ * @return {number} The timezone offset.
+ */
+goog.date.Date.prototype.getTimezoneOffset = function() {
+  return this.date.getTimezoneOffset();
+};
+
+
+/**
+ * Returns timezone offset as a string. Returns offset in [+-]HH:mm format or Z
+ * for UTC.
+ *
+ * @return {string} The timezone offset as a string.
+ */
+goog.date.Date.prototype.getTimezoneOffsetString = function() {
+  var tz;
+  var offset = this.getTimezoneOffset();
+
+  if (offset == 0) {
+    tz = 'Z';
+  } else {
+    var n = Math.abs(offset) / 60;
+    var h = Math.floor(n);
+    var m = (n - h) * 60;
+    tz = (offset > 0 ? '-' : '+') +
+        goog.string.padNumber(h, 2) + ':' +
+        goog.string.padNumber(m, 2);
+  }
+
+  return tz;
+};
+
+
+/**
+ * Sets the date.
+ *
+ * @param {goog.date.Date} date Date object to set date from.
+ */
+goog.date.Date.prototype.set = function(date) {
+  this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
+};
+
+
+/**
+ * Sets the year part of the date.
+ *
+ * @param {number} year Four digit year.
+ */
+goog.date.Date.prototype.setFullYear = function(year) {
+  this.date.setFullYear(year);
+};
+
+
+/**
+ * Alias for setFullYear.
+ *
+ * @param {number} year Four digit year.
+ * @see #setFullYear
+ */
+goog.date.Date.prototype.setYear = function(year) {
+  this.setFullYear(year);
+};
+
+
+/**
+ * Sets the month part of the date.
+ *
+ * TODO(nnaze): Update type to goog.date.month.
+ *
+ * @param {number} month The month, where 0 = Jan, 11 = Dec.
+ */
+goog.date.Date.prototype.setMonth = function(month) {
+  this.date.setMonth(month);
+};
+
+
+/**
+ * Sets the day part of the date.
+ *
+ * @param {number} date The day part.
+ */
+goog.date.Date.prototype.setDate = function(date) {
+  this.date.setDate(date);
+};
+
+
+/**
+ * Sets the value of the date object as expressed in the number of milliseconds
+ * since 1 January 1970 00:00:00.
+ *
+ * @param {number} ms Number of milliseconds since 1 Jan 1970.
+ */
+goog.date.Date.prototype.setTime = function(ms) {
+  this.date.setTime(ms);
+};
+
+
+/**
+ * Sets the year part of the date according to universal time.
+ *
+ * @param {number} year Four digit year.
+ */
+goog.date.Date.prototype.setUTCFullYear = function(year) {
+  this.date.setUTCFullYear(year);
+};
+
+
+/**
+ * Sets the month part of the date according to universal time.
+ *
+ * @param {number} month The month, where 0 = Jan, 11 = Dec.
+ */
+goog.date.Date.prototype.setUTCMonth = function(month) {
+  this.date.setUTCMonth(month);
+};
+
+
+/**
+ * Sets the day part of the date according to universal time.
+ *
+ * @param {number} date The UTC date.
+ */
+goog.date.Date.prototype.setUTCDate = function(date) {
+  this.date.setUTCDate(date);
+};
+
+
+/**
+ * Sets the first day of week.
+ *
+ * @param {number} day 0 = Mon, 6 = Sun.
+ */
+goog.date.Date.prototype.setFirstDayOfWeek = function(day) {
+  this.firstDayOfWeek_ = day;
+};
+
+
+/**
+ * Sets cut off weekday used for week number calculations. 0 = Mon, 6 = Sun.
+ *
+ * @param {number} day The cut off weekday.
+ */
+goog.date.Date.prototype.setFirstWeekCutOffDay = function(day) {
+  this.firstWeekCutOffDay_ = day;
+};
+
+
+/**
+ * Performs date calculation by adding the supplied interval to the date.
+ *
+ * @param {goog.date.Interval} interval Date interval to add.
+ */
+goog.date.Date.prototype.add = function(interval) {
+  if (interval.years || interval.months) {
+    // As months have different number of days adding a month to Jan 31 by just
+    // setting the month would result in a date in early March rather than Feb
+    // 28 or 29. Doing it this way overcomes that problem.
+
+    // adjust year and month, accounting for both directions
+    var month = this.getMonth() + interval.months + interval.years * 12;
+    var year = this.getYear() + Math.floor(month / 12);
+    month %= 12;
+    if (month < 0) {
+      month += 12;
+    }
+
+    var daysInTargetMonth = goog.date.getNumberOfDaysInMonth(year, month);
+    var date = Math.min(daysInTargetMonth, this.getDate());
+
+    // avoid inadvertently causing rollovers to adjacent months
+    this.setDate(1);
+
+    this.setFullYear(year);
+    this.setMonth(month);
+    this.setDate(date);
+  }
+
+  if (interval.days) {
+    // Convert the days to milliseconds and add it to the UNIX timestamp.
+    // Taking noon helps to avoid 1 day error due to the daylight saving.
+    var noon = new Date(this.getYear(), this.getMonth(), this.getDate(), 12);
+    var result = new Date(noon.getTime() + interval.days * 86400000);
+
+    // Set date to 1 to prevent rollover caused by setting the year or month.
+    this.setDate(1);
+    this.setFullYear(result.getFullYear());
+    this.setMonth(result.getMonth());
+    this.setDate(result.getDate());
+
+    this.maybeFixDst_(result.getDate());
+  }
+};
+
+
+/**
+ * Returns ISO 8601 string representation of date.
+ *
+ * @param {boolean=} opt_verbose Whether the verbose format should be used
+ *     instead of the default compact one.
+ * @param {boolean=} opt_tz Whether the timezone offset should be included
+ *     in the string.
+ * @return {string} ISO 8601 string representation of date.
+ */
+goog.date.Date.prototype.toIsoString = function(opt_verbose, opt_tz) {
+  var str = [
+    this.getFullYear(),
+    goog.string.padNumber(this.getMonth() + 1, 2),
+    goog.string.padNumber(this.getDate(), 2)
+  ];
+
+  return str.join((opt_verbose) ? '-' : '') +
+         (opt_tz ? this.getTimezoneOffsetString() : '');
+};
+
+
+/**
+ * Returns ISO 8601 string representation of date according to universal time.
+ *
+ * @param {boolean=} opt_verbose Whether the verbose format should be used
+ *     instead of the default compact one.
+ * @param {boolean=} opt_tz Whether the timezone offset should be included in
+ *     the string.
+ * @return {string} ISO 8601 string representation of date according to
+ *     universal time.
+ */
+goog.date.Date.prototype.toUTCIsoString = function(opt_verbose, opt_tz) {
+  var str = [
+    this.getUTCFullYear(),
+    goog.string.padNumber(this.getUTCMonth() + 1, 2),
+    goog.string.padNumber(this.getUTCDate(), 2)
+  ];
+
+  return str.join((opt_verbose) ? '-' : '') + (opt_tz ? 'Z' : '');
+};
+
+
+/**
+ * Tests whether given date is equal to this Date.
+ * Note: This ignores units more precise than days (hours and below)
+ * and also ignores timezone considerations.
+ *
+ * @param {goog.date.Date} other The date to compare.
+ * @return {boolean} Whether the given date is equal to this one.
+ */
+goog.date.Date.prototype.equals = function(other) {
+  return !!(other &&
+            this.getYear() == other.getYear() &&
+            this.getMonth() == other.getMonth() &&
+            this.getDate() == other.getDate());
+};
+
+
+/**
+ * Overloaded toString method for object.
+ * @return {string} ISO 8601 string representation of date.
+ * @override
+ */
+goog.date.Date.prototype.toString = function() {
+  return this.toIsoString();
+};
+
+
+/**
+ * Fixes date to account for daylight savings time in browsers that fail to do
+ * so automatically.
+ * @param {number} expected Expected date.
+ * @private
+ */
+goog.date.Date.prototype.maybeFixDst_ = function(expected) {
+  if (this.getDate() != expected) {
+    var dir = this.getDate() < expected ? 1 : -1;
+    this.date.setUTCHours(this.date.getUTCHours() + dir);
+  }
+};
+
+
+/**
+ * @return {number} Value of wrapped date.
+ * @override
+ */
+goog.date.Date.prototype.valueOf = function() {
+  return this.date.valueOf();
+};
+
+
+/**
+ * Compares two dates.  May be used as a sorting function.
+ * @see goog.array.sort
+ * @param {!goog.date.DateLike} date1 Date to compare.
+ * @param {!goog.date.DateLike} date2 Date to compare.
+ * @return {number} Comparison result. 0 if dates are the same, less than 0 if
+ *     date1 is earlier than date2, greater than 0 if date1 is later than date2.
+ */
+goog.date.Date.compare = function(date1, date2) {
+  return date1.getTime() - date2.getTime();
+};
+
+
+
+/**
+ * Class representing a date and time. Defaults to current date and time if none
+ * is specified.
+ *
+ * Implements most methods of the native js Date object and can be used
+ * interchangeably with it just as if goog.date.DateTime was a subclass of Date.
+ *
+ * @param {number|Object=} opt_year Four digit year or a date-like object. If
+ *     not set, the created object will contain the date determined by
+ *     goog.now().
+ * @param {number=} opt_month Month, 0 = Jan, 11 = Dec.
+ * @param {number=} opt_date Date of month, 1 - 31.
+ * @param {number=} opt_hours Hours, 0 - 23.
+ * @param {number=} opt_minutes Minutes, 0 - 59.
+ * @param {number=} opt_seconds Seconds, 0 - 61.
+ * @param {number=} opt_milliseconds Milliseconds, 0 - 999.
+ * @constructor
+ * @struct
+ * @extends {goog.date.Date}
+ */
+goog.date.DateTime = function(opt_year, opt_month, opt_date, opt_hours,
+                              opt_minutes, opt_seconds, opt_milliseconds) {
+  if (goog.isNumber(opt_year)) {
+    this.date = new Date(opt_year, opt_month || 0, opt_date || 1,
+        opt_hours || 0, opt_minutes || 0, opt_seconds || 0,
+        opt_milliseconds || 0);
+  } else {
+    this.date = new Date(opt_year ? opt_year.getTime() : goog.now());
+  }
+};
+goog.inherits(goog.date.DateTime, goog.date.Date);
+
+
+/**
+ * @param {number} timestamp Number of milliseconds since Epoch.
+ * @return {!goog.date.DateTime}
+ */
+goog.date.DateTime.fromTimestamp = function(timestamp) {
+  var date = new goog.date.DateTime();
+  date.setTime(timestamp);
+  return date;
+};
+
+
+/**
+ * Creates a DateTime from a datetime string expressed in RFC 822 format.
+ *
+ * @param {string} formatted A date or datetime expressed in RFC 822 format.
+ * @return {goog.date.DateTime} Parsed date or null if parse fails.
+ */
+goog.date.DateTime.fromRfc822String = function(formatted) {
+  var date = new Date(formatted);
+  return !isNaN(date.getTime()) ? new goog.date.DateTime(date) : null;
+};
+
+
+/**
+ * Returns the hours part of the datetime.
+ *
+ * @return {number} An integer between 0 and 23, representing the hour.
+ */
+goog.date.DateTime.prototype.getHours = function() {
+  return this.date.getHours();
+};
+
+
+/**
+ * Returns the minutes part of the datetime.
+ *
+ * @return {number} An integer between 0 and 59, representing the minutes.
+ */
+goog.date.DateTime.prototype.getMinutes = function() {
+  return this.date.getMinutes();
+};
+
+
+/**
+ * Returns the seconds part of the datetime.
+ *
+ * @return {number} An integer between 0 and 59, representing the seconds.
+ */
+goog.date.DateTime.prototype.getSeconds = function() {
+  return this.date.getSeconds();
+};
+
+
+/**
+ * Returns the milliseconds part of the datetime.
+ *
+ * @return {number} An integer between 0 and 999, representing the milliseconds.
+ */
+goog.date.DateTime.prototype.getMilliseconds = function() {
+  return this.date.getMilliseconds();
+};
+
+
+/**
+ * Returns the day of week according to universal time, US style.
+ *
+ * @return {goog.date.weekDay} Day of week, 0 = Sun, 1 = Mon, 6 = Sat.
+ * @override
+ */
+goog.date.DateTime.prototype.getUTCDay = function() {
+  return /** @type {goog.date.weekDay} */ (this.date.getUTCDay());
+};
+
+
+/**
+ * Returns the hours part of the datetime according to universal time.
+ *
+ * @return {number} An integer between 0 and 23, representing the hour.
+ * @override
+ */
+goog.date.DateTime.prototype.getUTCHours = function() {
+  return this.date.getUTCHours();
+};
+
+
+/**
+ * Returns the minutes part of the datetime according to universal time.
+ *
+ * @return {number} An integer between 0 and 59, representing the minutes.
+ * @override
+ */
+goog.date.DateTime.prototype.getUTCMinutes = function() {
+  return this.date.getUTCMinutes();
+};
+
+
+/**
+ * Returns the seconds part of the datetime according to universal time.
+ *
+ * @return {number} An integer between 0 and 59, representing the seconds.
+ */
+goog.date.DateTime.prototype.getUTCSeconds = function() {
+  return this.date.getUTCSeconds();
+};
+
+
+/**
+ * Returns the milliseconds part of the datetime according to universal time.
+ *
+ * @return {number} An integer between 0 and 999, representing the milliseconds.
+ */
+goog.date.DateTime.prototype.getUTCMilliseconds = function() {
+  return this.date.getUTCMilliseconds();
+};
+
+
+/**
+ * Sets the hours part of the datetime.
+ *
+ * @param {number} hours An integer between 0 and 23, representing the hour.
+ */
+goog.date.DateTime.prototype.setHours = function(hours) {
+  this.date.setHours(hours);
+};
+
+
+/**
+ * Sets the minutes part of the datetime.
+ *
+ * @param {number} minutes Integer between 0 and 59, representing the minutes.
+ */
+goog.date.DateTime.prototype.setMinutes = function(minutes) {
+  this.date.setMinutes(minutes);
+};
+
+
+/**
+ * Sets the seconds part of the datetime.
+ *
+ * @param {number} seconds Integer between 0 and 59, representing the seconds.
+ */
+goog.date.DateTime.prototype.setSeconds = function(seconds) {
+  this.date.setSeconds(seconds);
+};
+
+
+/**
+ * Sets the seconds part of the datetime.
+ *
+ * @param {number} ms Integer between 0 and 999, representing the milliseconds.
+ */
+goog.date.DateTime.prototype.setMilliseconds = function(ms) {
+  this.date.setMilliseconds(ms);
+};
+
+
+/**
+ * Sets the hours part of the datetime according to universal time.
+ *
+ * @param {number} hours An integer between 0 and 23, representing the hour.
+ */
+goog.date.DateTime.prototype.setUTCHours = function(hours) {
+  this.date.setUTCHours(hours);
+};
+
+
+/**
+ * Sets the minutes part of the datetime according to universal time.
+ *
+ * @param {number} minutes Integer between 0 and 59, representing the minutes.
+ */
+goog.date.DateTime.prototype.setUTCMinutes = function(minutes) {
+  this.date.setUTCMinutes(minutes);
+};
+
+
+/**
+ * Sets the seconds part of the datetime according to universal time.
+ *
+ * @param {number} seconds Integer between 0 and 59, representing the seconds.
+ */
+goog.date.DateTime.prototype.setUTCSeconds = function(seconds) {
+  this.date.setUTCSeconds(seconds);
+};
+
+
+/**
+ * Sets the seconds part of the datetime according to universal time.
+ *
+ * @param {number} ms Integer between 0 and 999, representing the milliseconds.
+ */
+goog.date.DateTime.prototype.setUTCMilliseconds = function(ms) {
+  this.date.setUTCMilliseconds(ms);
+};
+
+
+/**
+ * @return {boolean} Whether the datetime is aligned to midnight.
+ */
+goog.date.DateTime.prototype.isMidnight = function() {
+  return this.getHours() == 0 && this.getMinutes() == 0 &&
+      this.getSeconds() == 0 && this.getMilliseconds() == 0;
+};
+
+
+/**
+ * Performs date calculation by adding the supplied interval to the date.
+ *
+ * @param {goog.date.Interval} interval Date interval to add.
+ * @override
+ */
+goog.date.DateTime.prototype.add = function(interval) {
+  goog.date.Date.prototype.add.call(this, interval);
+
+  if (interval.hours) {
+    this.setHours(this.date.getHours() + interval.hours);
+  }
+  if (interval.minutes) {
+    this.setMinutes(this.date.getMinutes() + interval.minutes);
+  }
+  if (interval.seconds) {
+    this.setSeconds(this.date.getSeconds() + interval.seconds);
+  }
+};
+
+
+/**
+ * Returns ISO 8601 string representation of date/time.
+ *
+ * @param {boolean=} opt_verbose Whether the verbose format should be used
+ *     instead of the default compact one.
+ * @param {boolean=} opt_tz Whether the timezone offset should be included
+ *     in the string.
+ * @return {string} ISO 8601 string representation of date/time.
+ * @override
+ */
+goog.date.DateTime.prototype.toIsoString = function(opt_verbose, opt_tz) {
+  var dateString = goog.date.Date.prototype.toIsoString.call(this, opt_verbose);
+
+  if (opt_verbose) {
+    return dateString + ' ' +
+        goog.string.padNumber(this.getHours(), 2) + ':' +
+        goog.string.padNumber(this.getMinutes(), 2) + ':' +
+        goog.string.padNumber(this.getSeconds(), 2) +
+        (opt_tz ? this.getTimezoneOffsetString() : '');
+  }
+
+  return dateString + 'T' +
+      goog.string.padNumber(this.getHours(), 2) +
+      goog.string.padNumber(this.getMinutes(), 2) +
+      goog.string.padNumber(this.getSeconds(), 2) +
+      (opt_tz ? this.getTimezoneOffsetString() : '');
+};
+
+
+/**
+ * Returns XML Schema 2 string representation of date/time.
+ * The return value is also ISO 8601 compliant.
+ *
+ * @param {boolean=} opt_timezone Should the timezone offset be included in the
+ *     string?.
+ * @return {string} XML Schema 2 string representation of date/time.
+ */
+goog.date.DateTime.prototype.toXmlDateTime = function(opt_timezone) {
+  return goog.date.Date.prototype.toIsoString.call(this, true) + 'T' +
+      goog.string.padNumber(this.getHours(), 2) + ':' +
+      goog.string.padNumber(this.getMinutes(), 2) + ':' +
+      goog.string.padNumber(this.getSeconds(), 2) +
+      (opt_timezone ? this.getTimezoneOffsetString() : '');
+};
+
+
+/**
+ * Returns ISO 8601 string representation of date/time according to universal
+ * time.
+ *
+ * @param {boolean=} opt_verbose Whether the opt_verbose format should be
+ *     returned instead of the default compact one.
+ * @param {boolean=} opt_tz Whether the the timezone offset should be included
+ *     in the string.
+ * @return {string} ISO 8601 string representation of date/time according to
+ *     universal time.
+ * @override
+ */
+goog.date.DateTime.prototype.toUTCIsoString = function(opt_verbose, opt_tz) {
+  var dateStr = goog.date.Date.prototype.toUTCIsoString.call(this, opt_verbose);
+
+  if (opt_verbose) {
+    return dateStr + ' ' +
+        goog.string.padNumber(this.getUTCHours(), 2) + ':' +
+        goog.string.padNumber(this.getUTCMinutes(), 2) + ':' +
+        goog.string.padNumber(this.getUTCSeconds(), 2) +
+        (opt_tz ? 'Z' : '');
+  }
+
+  return dateStr + 'T' +
+      goog.string.padNumber(this.getUTCHours(), 2) +
+      goog.string.padNumber(this.getUTCMinutes(), 2) +
+      goog.string.padNumber(this.getUTCSeconds(), 2) +
+      (opt_tz ? 'Z' : '');
+};
+
+
+/**
+ * Tests whether given datetime is exactly equal to this DateTime.
+ *
+ * @param {goog.date.Date} other The datetime to compare.
+ * @return {boolean} Whether the given datetime is exactly equal to this one.
+ * @override
+ */
+goog.date.DateTime.prototype.equals = function(other) {
+  return this.getTime() == other.getTime();
+};
+
+
+/**
+ * Overloaded toString method for object.
+ * @return {string} ISO 8601 string representation of date/time.
+ * @override
+ */
+goog.date.DateTime.prototype.toString = function() {
+  return this.toIsoString();
+};
+
+
+/**
+ * Generates time label for the datetime, e.g., '5:30am'.
+ * By default this does not pad hours (e.g., to '05:30') and it does add
+ * an am/pm suffix.
+ * TODO(user): i18n -- hardcoding time format like this is bad.  E.g., in CJK
+ *               locales, need Chinese characters for hour and minute units.
+ * @param {boolean=} opt_padHours Whether to pad hours, e.g., '05:30' vs '5:30'.
+ * @param {boolean=} opt_showAmPm Whether to show the 'am' and 'pm' suffix.
+ * @param {boolean=} opt_omitZeroMinutes E.g., '5:00pm' becomes '5pm',
+ *                                      but '5:01pm' remains '5:01pm'.
+ * @return {string} The time label.
+ */
+goog.date.DateTime.prototype.toUsTimeString = function(opt_padHours,
+                                                       opt_showAmPm,
+                                                       opt_omitZeroMinutes) {
+  var hours = this.getHours();
+
+  // show am/pm marker by default
+  if (!goog.isDef(opt_showAmPm)) {
+    opt_showAmPm = true;
+  }
+
+  // 12pm
+  var isPM = hours == 12;
+
+  // change from 1-24 to 1-12 basis
+  if (hours > 12) {
+    hours -= 12;
+    isPM = true;
+  }
+
+  // midnight is expressed as "12am", but if am/pm marker omitted, keep as '0'
+  if (hours == 0 && opt_showAmPm) {
+    hours = 12;
+  }
+
+  var label = opt_padHours ? goog.string.padNumber(hours, 2) : String(hours);
+  var minutes = this.getMinutes();
+  if (!opt_omitZeroMinutes || minutes > 0) {
+    label += ':' + goog.string.padNumber(minutes, 2);
+  }
+
+  // by default, show am/pm suffix
+  if (opt_showAmPm) {
+    /**
+     * @desc Suffix for morning times.
+     */
+    var MSG_TIME_AM = goog.getMsg('am');
+
+    /**
+     * @desc Suffix for afternoon times.
+     */
+    var MSG_TIME_PM = goog.getMsg('pm');
+
+    label += isPM ? MSG_TIME_PM : MSG_TIME_AM;
+  }
+  return label;
+};
+
+
+/**
+ * Generates time label for the datetime in standard ISO 24-hour time format.
+ * E.g., '06:00:00' or '23:30:15'.
+ * @param {boolean=} opt_showSeconds Whether to shows seconds. Defaults to TRUE.
+ * @return {string} The time label.
+ */
+goog.date.DateTime.prototype.toIsoTimeString = function(opt_showSeconds) {
+  var hours = this.getHours();
+  var label = goog.string.padNumber(hours, 2) +
+              ':' +
+              goog.string.padNumber(this.getMinutes(), 2);
+  if (!goog.isDef(opt_showSeconds) || opt_showSeconds) {
+    label += ':' + goog.string.padNumber(this.getSeconds(), 2);
+  }
+  return label;
+};
+
+
+/**
+ * @return {!goog.date.DateTime} A clone of the datetime object.
+ * @override
+ */
+goog.date.DateTime.prototype.clone = function() {
+  var date = new goog.date.DateTime(this.date);
+  date.setFirstDayOfWeek(this.getFirstDayOfWeek());
+  date.setFirstWeekCutOffDay(this.getFirstWeekCutOffDay());
+  return date;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/date/datelike.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/date/datelike.js b/externs/GCL/externs/goog/date/datelike.js
new file mode 100644
index 0000000..ed18576
--- /dev/null
+++ b/externs/GCL/externs/goog/date/datelike.js
@@ -0,0 +1,27 @@
+// Copyright 2010 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 Typedefs for working with dates.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.date.DateLike');
+
+
+/**
+ * @typedef {(Date|goog.date.Date)}
+ */
+goog.date.DateLike;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/date/daterange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/date/daterange.js b/externs/GCL/externs/goog/date/daterange.js
new file mode 100644
index 0000000..262001e
--- /dev/null
+++ b/externs/GCL/externs/goog/date/daterange.js
@@ -0,0 +1,430 @@
+// Copyright 2008 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 Date range data structure. Based loosely on
+ * com.google.common.util.DateRange.
+ *
+ */
+
+goog.provide('goog.date.DateRange');
+goog.provide('goog.date.DateRange.Iterator');
+goog.provide('goog.date.DateRange.StandardDateRangeKeys');
+
+goog.require('goog.date.Date');
+goog.require('goog.date.Interval');
+goog.require('goog.iter.Iterator');
+goog.require('goog.iter.StopIteration');
+
+
+
+/**
+ * Constructs a date range.
+ * @constructor
+ * @struct
+ * @param {goog.date.Date} startDate The first date in the range.
+ * @param {goog.date.Date} endDate The last date in the range.
+ * @final
+ */
+goog.date.DateRange = function(startDate, endDate) {
+  /**
+   * The first date in the range.
+   * @type {goog.date.Date}
+   * @private
+   */
+  this.startDate_ = startDate;
+
+  /**
+   * The last date in the range.
+   * @type {goog.date.Date}
+   * @private
+   */
+  this.endDate_ = endDate;
+};
+
+
+/**
+ * The first possible day, as far as this class is concerned.
+ * @type {goog.date.Date}
+ */
+goog.date.DateRange.MINIMUM_DATE = new goog.date.Date(0, 0, 1);
+
+
+/**
+ * The last possible day, as far as this class is concerned.
+ * @type {goog.date.Date}
+ */
+goog.date.DateRange.MAXIMUM_DATE = new goog.date.Date(9999, 11, 31);
+
+
+/**
+ * @return {goog.date.Date} The first date in the range.
+ */
+goog.date.DateRange.prototype.getStartDate = function() {
+  return this.startDate_;
+};
+
+
+/**
+ * @return {goog.date.Date} The last date in the range.
+ */
+goog.date.DateRange.prototype.getEndDate = function() {
+  return this.endDate_;
+};
+
+
+/**
+ * Tests if a date falls within this range.
+ *
+ * @param {goog.date.Date} date The date to test.
+ * @return {boolean} Whether the date is in the range.
+ */
+goog.date.DateRange.prototype.contains = function(date) {
+  return date.valueOf() >= this.startDate_.valueOf() &&
+      date.valueOf() <= this.endDate_.valueOf();
+};
+
+
+/**
+ * @return {!goog.iter.Iterator} An iterator over the date range.
+ */
+goog.date.DateRange.prototype.iterator = function() {
+  return new goog.date.DateRange.Iterator(this);
+};
+
+
+/**
+ * Tests two {@link goog.date.DateRange} objects for equality.
+ * @param {goog.date.DateRange} a A date range.
+ * @param {goog.date.DateRange} b A date range.
+ * @return {boolean} Whether |a| is the same range as |b|.
+ */
+goog.date.DateRange.equals = function(a, b) {
+  // Test for same object reference; type conversion is irrelevant.
+  if (a === b) {
+    return true;
+  }
+
+  if (a == null || b == null) {
+    return false;
+  }
+
+  return a.startDate_.equals(b.startDate_) && a.endDate_.equals(b.endDate_);
+};
+
+
+/**
+ * Calculates a date that is a number of days after a date. Does not modify its
+ * input.
+ * @param {goog.date.Date} date The input date.
+ * @param {number} offset Number of days.
+ * @return {!goog.date.Date} The date that is |offset| days after |date|.
+ * @private
+ */
+goog.date.DateRange.offsetInDays_ = function(date, offset) {
+  var newDate = date.clone();
+  newDate.add(new goog.date.Interval(goog.date.Interval.DAYS, offset));
+  return newDate;
+};
+
+
+/**
+ * Calculates the Monday before a date. If the input is a Monday, returns the
+ * input. Does not modify its input.
+ * @param {goog.date.Date} date The input date.
+ * @return {!goog.date.Date} If |date| is a Monday, return |date|; otherwise
+ *     return the Monday before |date|.
+ * @private
+ */
+goog.date.DateRange.currentOrLastMonday_ = function(date) {
+  var newDate = date.clone();
+  newDate.add(new goog.date.Interval(goog.date.Interval.DAYS,
+      -newDate.getIsoWeekday()));
+  return newDate;
+};
+
+
+/**
+ * Calculates a date that is a number of months after the first day in the
+ * month that contains its input. Does not modify its input.
+ * @param {goog.date.Date} date The input date.
+ * @param {number} offset Number of months.
+ * @return {!goog.date.Date} The date that is |offset| months after the first
+ *     day in the month that contains |date|.
+ * @private
+ */
+goog.date.DateRange.offsetInMonths_ = function(date, offset) {
+  var newDate = date.clone();
+  newDate.setDate(1);
+  newDate.add(new goog.date.Interval(goog.date.Interval.MONTHS, offset));
+  return newDate;
+};
+
+
+/**
+ * Returns the range from yesterday to yesterday.
+ * @param {goog.date.Date=} opt_today The date to consider today.
+ *     Defaults to today.
+ * @return {!goog.date.DateRange} The range that includes only yesterday.
+ */
+goog.date.DateRange.yesterday = function(opt_today) {
+  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
+  var yesterday = goog.date.DateRange.offsetInDays_(today, -1);
+  return new goog.date.DateRange(yesterday, yesterday);
+};
+
+
+/**
+ * Returns the range from today to today.
+ * @param {goog.date.Date=} opt_today The date to consider today.
+ *     Defaults to today.
+ * @return {!goog.date.DateRange} The range that includes only today.
+ */
+goog.date.DateRange.today = function(opt_today) {
+  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
+  return new goog.date.DateRange(today, today);
+};
+
+
+/**
+ * Returns the range that includes the seven days that end yesterday.
+ * @param {goog.date.Date=} opt_today The date to consider today.
+ *     Defaults to today.
+ * @return {!goog.date.DateRange} The range that includes the seven days that
+ *     end yesterday.
+ */
+goog.date.DateRange.last7Days = function(opt_today) {
+  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
+  var yesterday = goog.date.DateRange.offsetInDays_(today, -1);
+  return new goog.date.DateRange(goog.date.DateRange.offsetInDays_(today, -7),
+      yesterday);
+};
+
+
+/**
+ * Returns the range that starts the first of this month and ends the last day
+ * of this month.
+ * @param {goog.date.Date=} opt_today The date to consider today.
+ *     Defaults to today.
+ * @return {!goog.date.DateRange} The range that starts the first of this month
+ *     and ends the last day of this month.
+ */
+goog.date.DateRange.thisMonth = function(opt_today) {
+  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
+  return new goog.date.DateRange(
+      goog.date.DateRange.offsetInMonths_(today, 0),
+      goog.date.DateRange.offsetInDays_(
+          goog.date.DateRange.offsetInMonths_(today, 1),
+          -1));
+};
+
+
+/**
+ * Returns the range that starts the first of last month and ends the last day
+ * of last month.
+ * @param {goog.date.Date=} opt_today The date to consider today.
+ *     Defaults to today.
+ * @return {!goog.date.DateRange} The range that starts the first of last month
+ *     and ends the last day of last month.
+ */
+goog.date.DateRange.lastMonth = function(opt_today) {
+  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
+  return new goog.date.DateRange(
+      goog.date.DateRange.offsetInMonths_(today, -1),
+      goog.date.DateRange.offsetInDays_(
+          goog.date.DateRange.offsetInMonths_(today, 0),
+          -1));
+};
+
+
+/**
+ * Returns the seven-day range that starts on the first day of the week
+ * (see {@link goog.i18n.DateTimeSymbols.FIRSTDAYOFWEEK}) on or before today.
+ * @param {goog.date.Date=} opt_today The date to consider today.
+ *     Defaults to today.
+ * @return {!goog.date.DateRange} The range that starts the Monday on or before
+ *     today and ends the Sunday on or after today.
+ */
+goog.date.DateRange.thisWeek = function(opt_today) {
+  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
+  var iso = today.getIsoWeekday();
+  var firstDay = today.getFirstDayOfWeek();
+  var i18nFirstDay = (iso >= firstDay) ? iso - firstDay : iso + (7 - firstDay);
+  var start = goog.date.DateRange.offsetInDays_(today, -i18nFirstDay);
+  var end = goog.date.DateRange.offsetInDays_(start, 6);
+  return new goog.date.DateRange(start, end);
+};
+
+
+/**
+ * Returns the seven-day range that ends the day before the first day of
+ * the week (see {@link goog.i18n.DateTimeSymbols.FIRSTDAYOFWEEK}) that
+ * contains today.
+ * @param {goog.date.Date=} opt_today The date to consider today.
+ *     Defaults to today.
+ * @return {!goog.date.DateRange} The range that starts seven days before the
+ *     Monday on or before today and ends the Sunday on or before yesterday.
+ */
+goog.date.DateRange.lastWeek = function(opt_today) {
+  var thisWeek = goog.date.DateRange.thisWeek(opt_today);
+  var start = goog.date.DateRange.offsetInDays_(thisWeek.getStartDate(), -7);
+  var end = goog.date.DateRange.offsetInDays_(thisWeek.getEndDate(), -7);
+  return new goog.date.DateRange(start, end);
+};
+
+
+/**
+ * Returns the range that starts seven days before the Monday on or before
+ * today and ends the Friday before today.
+ * @param {goog.date.Date=} opt_today The date to consider today.
+ *     Defaults to today.
+ * @return {!goog.date.DateRange} The range that starts seven days before the
+ *     Monday on or before today and ends the Friday before today.
+ */
+goog.date.DateRange.lastBusinessWeek = function(opt_today) {
+  // TODO(user): should be i18nized.
+  var today = goog.date.DateRange.cloneOrCreate_(opt_today);
+  var start = goog.date.DateRange.offsetInDays_(today,
+      - 7 - today.getIsoWeekday());
+  var end = goog.date.DateRange.offsetInDays_(start, 4);
+  return new goog.date.DateRange(start, end);
+};
+
+
+/**
+ * Returns the range that includes all days between January 1, 1900 and
+ * December 31, 9999.
+ * @param {goog.date.Date=} opt_today The date to consider today.
+ *     Defaults to today.
+ * @return {!goog.date.DateRange} The range that includes all days between
+ *     January 1, 1900 and December 31, 9999.
+ */
+goog.date.DateRange.allTime = function(opt_today) {
+  return new goog.date.DateRange(
+      goog.date.DateRange.MINIMUM_DATE,
+      goog.date.DateRange.MAXIMUM_DATE);
+};
+
+
+/**
+ * Standard date range keys. Equivalent to the enum IDs in
+ * DateRange.java http://go/datarange.java
+ *
+ * @enum {string}
+ */
+goog.date.DateRange.StandardDateRangeKeys = {
+  YESTERDAY: 'yesterday',
+  TODAY: 'today',
+  LAST_7_DAYS: 'last7days',
+  THIS_MONTH: 'thismonth',
+  LAST_MONTH: 'lastmonth',
+  THIS_WEEK: 'thisweek',
+  LAST_WEEK: 'lastweek',
+  LAST_BUSINESS_WEEK: 'lastbusinessweek',
+  ALL_TIME: 'alltime'
+};
+
+
+/**
+ * @param {string} dateRangeKey A standard date range key.
+ * @param {goog.date.Date=} opt_today The date to consider today.
+ *     Defaults to today.
+ * @return {!goog.date.DateRange} The date range that corresponds to that key.
+ * @throws {Error} If no standard date range with that key exists.
+ */
+goog.date.DateRange.standardDateRange = function(dateRangeKey, opt_today) {
+  switch (dateRangeKey) {
+    case goog.date.DateRange.StandardDateRangeKeys.YESTERDAY:
+      return goog.date.DateRange.yesterday(opt_today);
+
+    case goog.date.DateRange.StandardDateRangeKeys.TODAY:
+      return goog.date.DateRange.today(opt_today);
+
+    case goog.date.DateRange.StandardDateRangeKeys.LAST_7_DAYS:
+      return goog.date.DateRange.last7Days(opt_today);
+
+    case goog.date.DateRange.StandardDateRangeKeys.THIS_MONTH:
+      return goog.date.DateRange.thisMonth(opt_today);
+
+    case goog.date.DateRange.StandardDateRangeKeys.LAST_MONTH:
+      return goog.date.DateRange.lastMonth(opt_today);
+
+    case goog.date.DateRange.StandardDateRangeKeys.THIS_WEEK:
+      return goog.date.DateRange.thisWeek(opt_today);
+
+    case goog.date.DateRange.StandardDateRangeKeys.LAST_WEEK:
+      return goog.date.DateRange.lastWeek(opt_today);
+
+    case goog.date.DateRange.StandardDateRangeKeys.LAST_BUSINESS_WEEK:
+      return goog.date.DateRange.lastBusinessWeek(opt_today);
+
+    case goog.date.DateRange.StandardDateRangeKeys.ALL_TIME:
+      return goog.date.DateRange.allTime(opt_today);
+
+    default:
+      throw Error('no such date range key: ' + dateRangeKey);
+  }
+};
+
+
+/**
+ * Clones or creates new.
+ * @param {goog.date.Date=} opt_today The date to consider today.
+ *     Defaults to today.
+ * @return {!goog.date.Date} cloned or new.
+ * @private
+ */
+goog.date.DateRange.cloneOrCreate_ = function(opt_today) {
+  return opt_today ? opt_today.clone() : new goog.date.Date();
+};
+
+
+
+/**
+ * Creates an iterator over the dates in a {@link goog.date.DateRange}.
+ * @constructor
+ * @struct
+ * @suppress {checkStructDictInheritance}
+ * @extends {goog.iter.Iterator}
+ * @param {goog.date.DateRange} dateRange The date range to iterate.
+ * @final
+ */
+goog.date.DateRange.Iterator = function(dateRange) {
+  /**
+   * The next date.
+   * @type {goog.date.Date}
+   * @private
+   */
+  this.nextDate_ = dateRange.getStartDate().clone();
+
+  /**
+   * The end date, expressed as an integer: YYYYMMDD.
+   * @type {number}
+   * @private
+   */
+  this.endDate_ = Number(dateRange.getEndDate().toIsoString());
+};
+goog.inherits(goog.date.DateRange.Iterator, goog.iter.Iterator);
+
+
+/** @override */
+goog.date.DateRange.Iterator.prototype.next = function() {
+  if (Number(this.nextDate_.toIsoString()) > this.endDate_) {
+    throw goog.iter.StopIteration;
+  }
+
+  var rv = this.nextDate_.clone();
+  this.nextDate_.add(new goog.date.Interval(goog.date.Interval.DAYS, 1));
+  return rv;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/date/duration.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/date/duration.js b/externs/GCL/externs/goog/date/duration.js
new file mode 100644
index 0000000..62ad584
--- /dev/null
+++ b/externs/GCL/externs/goog/date/duration.js
@@ -0,0 +1,153 @@
+// Copyright 2013 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 Functions for formatting duration values.  Such as "3 days"
+ * "3 hours", "14 minutes", "2 hours 45 minutes".
+ *
+ */
+
+goog.provide('goog.date.duration');
+
+goog.require('goog.i18n.DateTimeFormat');
+goog.require('goog.i18n.MessageFormat');
+
+
+/**
+ * Number of milliseconds in a minute.
+ * @type {number}
+ * @private
+ */
+goog.date.duration.MINUTE_MS_ = 60000;
+
+
+/**
+ * Number of milliseconds in an hour.
+ * @type {number}
+ * @private
+ */
+goog.date.duration.HOUR_MS_ = 3600000;
+
+
+/**
+ * Number of milliseconds in a day.
+ * @type {number}
+ * @private
+ */
+goog.date.duration.DAY_MS_ = 86400000;
+
+
+/**
+ * Accepts a duration in milliseconds and outputs an absolute duration time in
+ * form of "1 day", "2 hours", "20 minutes", "2 days 1 hour 15 minutes" etc.
+ * @param {number} durationMs Duration in milliseconds.
+ * @return {string} The formatted duration.
+ */
+goog.date.duration.format = function(durationMs) {
+  var ms = Math.abs(durationMs);
+
+  // Handle durations shorter than 1 minute.
+  if (ms < goog.date.duration.MINUTE_MS_) {
+    /**
+     * @desc Duration time of zero minutes.
+     */
+    var MSG_ZERO_MINUTES = goog.getMsg('0 minutes');
+    return MSG_ZERO_MINUTES;
+  }
+
+  var days = Math.floor(ms / goog.date.duration.DAY_MS_);
+  ms %= goog.date.duration.DAY_MS_;
+
+  var hours = Math.floor(ms / goog.date.duration.HOUR_MS_);
+  ms %= goog.date.duration.HOUR_MS_;
+
+  var minutes = Math.floor(ms / goog.date.duration.MINUTE_MS_);
+
+  // Localized number representations.
+  var daysText = goog.i18n.DateTimeFormat.localizeNumbers(days);
+  var hoursText = goog.i18n.DateTimeFormat.localizeNumbers(hours);
+  var minutesText = goog.i18n.DateTimeFormat.localizeNumbers(minutes);
+
+  // We need a space after the days if there are hours or minutes to come.
+  var daysSeparator = days * (hours + minutes) ? ' ' : '';
+  // We need a space after the hours if there are minutes to come.
+  var hoursSeparator = hours * minutes ? ' ' : '';
+
+  /**
+   * @desc The days part of the duration message: 1 day, 5 days.
+   */
+  var MSG_DURATION_DAYS = goog.getMsg(
+      '{COUNT, plural, ' +
+      '=0 {}' +
+      '=1 {{TEXT} day}' +
+      'other {{TEXT} days}}');
+  /**
+   * @desc The hours part of the duration message: 1 hour, 5 hours.
+   */
+  var MSG_DURATION_HOURS = goog.getMsg(
+      '{COUNT, plural, ' +
+      '=0 {}' +
+      '=1 {{TEXT} hour}' +
+      'other {{TEXT} hours}}');
+  /**
+   * @desc The minutes part of the duration message: 1 minute, 5 minutes.
+   */
+  var MSG_DURATION_MINUTES = goog.getMsg(
+      '{COUNT, plural, ' +
+      '=0 {}' +
+      '=1 {{TEXT} minute}' +
+      'other {{TEXT} minutes}}');
+
+  var daysPart = goog.date.duration.getDurationMessagePart_(
+      MSG_DURATION_DAYS, days, daysText);
+  var hoursPart = goog.date.duration.getDurationMessagePart_(
+      MSG_DURATION_HOURS, hours, hoursText);
+  var minutesPart = goog.date.duration.getDurationMessagePart_(
+      MSG_DURATION_MINUTES, minutes, minutesText);
+
+  /**
+   * @desc Duration time text concatenated from the individual time unit message
+   * parts. The separator will be a space (e.g. '1 day 2 hours 24 minutes') or
+   * nothing in case one/two of the duration parts is empty (
+   * e.g. '1 hour 30 minutes', '3 days 15 minutes', '2 hours').
+   */
+  var MSG_CONCATENATED_DURATION_TEXT = goog.getMsg(
+      '{$daysPart}{$daysSeparator}{$hoursPart}{$hoursSeparator}{$minutesPart}',
+      {
+        'daysPart': daysPart,
+        'daysSeparator': daysSeparator,
+        'hoursPart': hoursPart,
+        'hoursSeparator': hoursSeparator,
+        'minutesPart': minutesPart
+      });
+
+  return MSG_CONCATENATED_DURATION_TEXT;
+};
+
+
+/**
+ * Gets a duration message part for a time unit.
+ * @param {string} pattern The pattern to apply.
+ * @param {number} count The number of units.
+ * @param {string} text The string to use for amount of units in the message.
+ * @return {string} The formatted message part.
+ * @private
+ */
+goog.date.duration.getDurationMessagePart_ = function(pattern, count, text) {
+  var formatter = new goog.i18n.MessageFormat(pattern);
+  return formatter.format({
+    'COUNT': count,
+    'TEXT': text
+  });
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/date/relative.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/date/relative.js b/externs/GCL/externs/goog/date/relative.js
new file mode 100644
index 0000000..890dcc1
--- /dev/null
+++ b/externs/GCL/externs/goog/date/relative.js
@@ -0,0 +1,490 @@
+// 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 Functions for formatting relative dates.  Such as "3 days ago"
+ * "3 hours ago", "14 minutes ago", "12 days ago", "Today", "Yesterday".
+ *
+ * For better quality localization of plurals ("hours"/"minutes"/"days") and
+ * to use local digits, goog.date.relativeWithPlurals can be loaded in addition
+ * to this namespace.
+ *
+ */
+
+goog.provide('goog.date.relative');
+goog.provide('goog.date.relative.TimeDeltaFormatter');
+goog.provide('goog.date.relative.Unit');
+
+goog.require('goog.i18n.DateTimeFormat');
+goog.require('goog.i18n.DateTimePatterns');
+
+
+/**
+ * Number of milliseconds in a minute.
+ * @type {number}
+ * @private
+ */
+goog.date.relative.MINUTE_MS_ = 60000;
+
+
+/**
+ * Number of milliseconds in a day.
+ * @type {number}
+ * @private
+ */
+goog.date.relative.DAY_MS_ = 86400000;
+
+
+/**
+ * Enumeration used to identify time units internally.
+ * @enum {number}
+ */
+goog.date.relative.Unit = {
+  MINUTES: 0,
+  HOURS: 1,
+  DAYS: 2
+};
+
+
+/**
+ * Full date formatter.
+ * @type {goog.i18n.DateTimeFormat}
+ * @private
+ */
+goog.date.relative.fullDateFormatter_;
+
+
+/**
+ * Short time formatter.
+ * @type {goog.i18n.DateTimeFormat}
+ * @private
+ */
+goog.date.relative.shortTimeFormatter_;
+
+
+/**
+ * Month-date formatter.
+ * @type {goog.i18n.DateTimeFormat}
+ * @private
+ */
+goog.date.relative.monthDateFormatter_;
+
+
+/**
+ * @typedef {function(number, boolean, goog.date.relative.Unit): string}
+ */
+goog.date.relative.TimeDeltaFormatter;
+
+
+/**
+ * Handles formatting of time deltas.
+ * @private {goog.date.relative.TimeDeltaFormatter}
+ */
+goog.date.relative.formatTimeDelta_;
+
+
+/**
+ * Sets a different formatting function for time deltas ("3 days ago").
+ * While its visibility is public, this function is Closure-internal and should
+ * not be used in application code.
+ * @param {goog.date.relative.TimeDeltaFormatter} formatter The function to use
+ *     for formatting time deltas (i.e. relative times).
+ */
+goog.date.relative.setTimeDeltaFormatter = function(formatter) {
+  goog.date.relative.formatTimeDelta_ = formatter;
+};
+
+
+/**
+ * Returns a date in month format, e.g. Mar 15.
+ * @param {Date} date The date object.
+ * @return {string} The formatted string.
+ * @private
+ */
+goog.date.relative.formatMonth_ = function(date) {
+  if (!goog.date.relative.monthDateFormatter_) {
+    goog.date.relative.monthDateFormatter_ = new goog.i18n.DateTimeFormat(
+        goog.i18n.DateTimePatterns.MONTH_DAY_ABBR);
+  }
+  return goog.date.relative.monthDateFormatter_.format(date);
+};
+
+
+/**
+ * Returns a date in short-time format, e.g. 2:50 PM.
+ * @param {Date|goog.date.DateTime} date The date object.
+ * @return {string} The formatted string.
+ * @private
+ */
+goog.date.relative.formatShortTime_ = function(date) {
+  if (!goog.date.relative.shortTimeFormatter_) {
+    goog.date.relative.shortTimeFormatter_ = new goog.i18n.DateTimeFormat(
+        goog.i18n.DateTimeFormat.Format.SHORT_TIME);
+  }
+  return goog.date.relative.shortTimeFormatter_.format(date);
+};
+
+
+/**
+ * Returns a date in full date format, e.g. Tuesday, March 24, 2009.
+ * @param {Date|goog.date.DateTime} date The date object.
+ * @return {string} The formatted string.
+ * @private
+ */
+goog.date.relative.formatFullDate_ = function(date) {
+  if (!goog.date.relative.fullDateFormatter_) {
+    goog.date.relative.fullDateFormatter_ = new goog.i18n.DateTimeFormat(
+        goog.i18n.DateTimeFormat.Format.FULL_DATE);
+  }
+  return goog.date.relative.fullDateFormatter_.format(date);
+};
+
+
+/**
+ * Accepts a timestamp in milliseconds and outputs a relative time in the form
+ * of "1 hour ago", "1 day ago", "in 1 hour", "in 2 days" etc.  If the date
+ * delta is over 2 weeks, then the output string will be empty.
+ * @param {number} dateMs Date in milliseconds.
+ * @return {string} The formatted date.
+ */
+goog.date.relative.format = function(dateMs) {
+  var now = goog.now();
+  var delta = Math.floor((now - dateMs) / goog.date.relative.MINUTE_MS_);
+
+  var future = false;
+
+  if (delta < 0) {
+    future = true;
+    delta *= -1;
+  }
+
+  if (delta < 60) { // Minutes.
+    return goog.date.relative.formatTimeDelta_(
+        delta, future, goog.date.relative.Unit.MINUTES);
+
+  } else {
+    delta = Math.floor(delta / 60);
+    if (delta < 24) { // Hours.
+      return goog.date.relative.formatTimeDelta_(
+          delta, future, goog.date.relative.Unit.HOURS);
+
+    } else {
+      // We can be more than 24 hours apart but still only 1 day apart, so we
+      // compare the closest time from today against the target time to find
+      // the number of days in the delta.
+      var midnight = new Date(goog.now());
+      midnight.setHours(0);
+      midnight.setMinutes(0);
+      midnight.setSeconds(0);
+      midnight.setMilliseconds(0);
+
+      // Convert to days ago.
+      delta = Math.ceil(
+          (midnight.getTime() - dateMs) / goog.date.relative.DAY_MS_);
+
+      if (future) {
+        delta *= -1;
+      }
+
+      // Uses days for less than 2-weeks.
+      if (delta < 14) {
+        return goog.date.relative.formatTimeDelta_(
+            delta, future, goog.date.relative.Unit.DAYS);
+
+      } else {
+        // For messages older than 2 weeks do not show anything.  The client
+        // should decide the date format to show.
+        return '';
+      }
+    }
+  }
+};
+
+
+/**
+ * Accepts a timestamp in milliseconds and outputs a relative time in the form
+ * of "1 hour ago", "1 day ago".  All future times will be returned as 0 minutes
+ * ago.
+ *
+ * This is provided for compatibility with users of the previous incarnation of
+ * the above {@see #format} method who relied on it protecting against
+ * future dates.
+ *
+ * @param {number} dateMs Date in milliseconds.
+ * @return {string} The formatted date.
+ */
+goog.date.relative.formatPast = function(dateMs) {
+  var now = goog.now();
+  if (now < dateMs) {
+    dateMs = now;
+  }
+  return goog.date.relative.format(dateMs);
+};
+
+
+/**
+ * Accepts a timestamp in milliseconds and outputs a relative day. i.e. "Today",
+ * "Yesterday", "Tomorrow", or "Sept 15".
+ *
+ * @param {number} dateMs Date in milliseconds.
+ * @param {function(!Date):string=} opt_formatter Formatter for the date.
+ *     Defaults to form 'MMM dd'.
+ * @return {string} The formatted date.
+ */
+goog.date.relative.formatDay = function(dateMs, opt_formatter) {
+  var today = new Date(goog.now());
+
+  today.setHours(0);
+  today.setMinutes(0);
+  today.setSeconds(0);
+  today.setMilliseconds(0);
+
+  var yesterday = new Date(today.getTime() - goog.date.relative.DAY_MS_);
+  var tomorrow = new Date(today.getTime() + goog.date.relative.DAY_MS_);
+  var dayAfterTomorrow = new Date(today.getTime() +
+      2 * goog.date.relative.DAY_MS_);
+
+  var message;
+  if (dateMs >= tomorrow.getTime() && dateMs < dayAfterTomorrow.getTime()) {
+    /** @desc Tomorrow. */
+    var MSG_TOMORROW = goog.getMsg('Tomorrow');
+    message = MSG_TOMORROW;
+  } else if (dateMs >= today.getTime() && dateMs < tomorrow.getTime()) {
+    /** @desc Today. */
+    var MSG_TODAY = goog.getMsg('Today');
+    message = MSG_TODAY;
+  } else if (dateMs >= yesterday.getTime() && dateMs < today.getTime()) {
+    /** @desc Yesterday. */
+    var MSG_YESTERDAY = goog.getMsg('Yesterday');
+    message = MSG_YESTERDAY;
+  } else {
+    // If we don't have a special relative term for this date, then return the
+    // short date format (or a custom-formatted date).
+    var formatFunction = opt_formatter || goog.date.relative.formatMonth_;
+    message = formatFunction(new Date(dateMs));
+  }
+  return message;
+};
+
+
+/**
+ * Formats a date, adding the relative date in parenthesis.  If the date is less
+ * than 24 hours then the time will be printed, otherwise the full-date will be
+ * used.  Examples:
+ *   2:20 PM (1 minute ago)
+ *   Monday, February 27, 2009 (4 days ago)
+ *   Tuesday, March 20, 2005    // Too long ago for a relative date.
+ *
+ * @param {Date|goog.date.DateTime} date A date object.
+ * @param {string=} opt_shortTimeMsg An optional short time message can be
+ *     provided if available, so that it's not recalculated in this function.
+ * @param {string=} opt_fullDateMsg An optional date message can be
+ *     provided if available, so that it's not recalculated in this function.
+ * @return {string} The date string in the above form.
+ */
+goog.date.relative.getDateString = function(
+    date, opt_shortTimeMsg, opt_fullDateMsg) {
+  return goog.date.relative.getDateString_(
+      date, goog.date.relative.format, opt_shortTimeMsg, opt_fullDateMsg);
+};
+
+
+/**
+ * Formats a date, adding the relative date in parenthesis.   Functions the same
+ * as #getDateString but ensures that the date is always seen to be in the past.
+ * If the date is in the future, it will be shown as 0 minutes ago.
+ *
+ * This is provided for compatibility with users of the previous incarnation of
+ * the above {@see #getDateString} method who relied on it protecting against
+ * future dates.
+ *
+ * @param {Date|goog.date.DateTime} date A date object.
+ * @param {string=} opt_shortTimeMsg An optional short time message can be
+ *     provided if available, so that it's not recalculated in this function.
+ * @param {string=} opt_fullDateMsg An optional date message can be
+ *     provided if available, so that it's not recalculated in this function.
+ * @return {string} The date string in the above form.
+ */
+goog.date.relative.getPastDateString = function(
+    date, opt_shortTimeMsg, opt_fullDateMsg) {
+  return goog.date.relative.getDateString_(
+      date, goog.date.relative.formatPast, opt_shortTimeMsg, opt_fullDateMsg);
+};
+
+
+/**
+ * Formats a date, adding the relative date in parenthesis.  If the date is less
+ * than 24 hours then the time will be printed, otherwise the full-date will be
+ * used.  Examples:
+ *   2:20 PM (1 minute ago)
+ *   Monday, February 27, 2009 (4 days ago)
+ *   Tuesday, March 20, 2005    // Too long ago for a relative date.
+ *
+ * @param {Date|goog.date.DateTime} date A date object.
+ * @param {function(number) : string} relativeFormatter Function to use when
+ *     formatting the relative date.
+ * @param {string=} opt_shortTimeMsg An optional short time message can be
+ *     provided if available, so that it's not recalculated in this function.
+ * @param {string=} opt_fullDateMsg An optional date message can be
+ *     provided if available, so that it's not recalculated in this function.
+ * @return {string} The date string in the above form.
+ * @private
+ */
+goog.date.relative.getDateString_ = function(
+    date, relativeFormatter, opt_shortTimeMsg, opt_fullDateMsg) {
+  var dateMs = date.getTime();
+
+  var relativeDate = relativeFormatter(dateMs);
+
+  if (relativeDate) {
+    relativeDate = ' (' + relativeDate + ')';
+  }
+
+  var delta = Math.floor((goog.now() - dateMs) / goog.date.relative.MINUTE_MS_);
+  if (delta < 60 * 24) {
+    // TODO(user): this call raises an exception if date is a goog.date.Date.
+    return (opt_shortTimeMsg || goog.date.relative.formatShortTime_(date)) +
+        relativeDate;
+  } else {
+    return (opt_fullDateMsg || goog.date.relative.formatFullDate_(date)) +
+        relativeDate;
+  }
+};
+
+
+/*
+ * TODO(user):
+ *
+ * I think that this whole relative formatting should move to DateTimeFormat.
+ * But we would have to wait for the next version of CLDR, which is cleaning
+ * the data for relative dates (even ICU has incomplete support for this).
+ */
+/**
+ * Gets a localized relative date string for a given delta and unit.
+ * @param {number} delta Number of minutes/hours/days.
+ * @param {boolean} future Whether the delta is in the future.
+ * @param {goog.date.relative.Unit} unit The units the delta is in.
+ * @return {string} The message.
+ * @private
+ */
+goog.date.relative.getMessage_ = function(delta, future, unit) {
+  var deltaFormatted = goog.i18n.DateTimeFormat.localizeNumbers(delta);
+  if (!future && unit == goog.date.relative.Unit.MINUTES) {
+    /**
+     * @desc Relative date indicating how many minutes ago something happened
+     * (singular).
+     */
+    var MSG_MINUTES_AGO_SINGULAR =
+        goog.getMsg('{$num} minute ago', {'num' : deltaFormatted});
+
+    /**
+     * @desc Relative date indicating how many minutes ago something happened
+     * (plural).
+     */
+    var MSG_MINUTES_AGO_PLURAL =
+        goog.getMsg('{$num} minutes ago', {'num' : deltaFormatted});
+
+    return delta == 1 ? MSG_MINUTES_AGO_SINGULAR : MSG_MINUTES_AGO_PLURAL;
+
+  } else if (future && unit == goog.date.relative.Unit.MINUTES) {
+    /**
+     * @desc Relative date indicating in how many minutes something happens
+     * (singular).
+     */
+    var MSG_IN_MINUTES_SINGULAR =
+        goog.getMsg('in {$num} minute', {'num' : deltaFormatted});
+
+    /**
+     * @desc Relative date indicating in how many minutes something happens
+     * (plural).
+     */
+    var MSG_IN_MINUTES_PLURAL =
+        goog.getMsg('in {$num} minutes', {'num' : deltaFormatted});
+
+    return delta == 1 ? MSG_IN_MINUTES_SINGULAR : MSG_IN_MINUTES_PLURAL;
+
+  } else if (!future && unit == goog.date.relative.Unit.HOURS) {
+    /**
+     * @desc Relative date indicating how many hours ago something happened
+     * (singular).
+     */
+    var MSG_HOURS_AGO_SINGULAR =
+        goog.getMsg('{$num} hour ago', {'num' : deltaFormatted});
+
+    /**
+     * @desc Relative date indicating how many hours ago something happened
+     * (plural).
+     */
+    var MSG_HOURS_AGO_PLURAL =
+        goog.getMsg('{$num} hours ago', {'num' : deltaFormatted});
+
+    return delta == 1 ? MSG_HOURS_AGO_SINGULAR : MSG_HOURS_AGO_PLURAL;
+
+  } else if (future && unit == goog.date.relative.Unit.HOURS) {
+    /**
+     * @desc Relative date indicating in how many hours something happens
+     * (singular).
+     */
+    var MSG_IN_HOURS_SINGULAR =
+        goog.getMsg('in {$num} hour', {'num' : deltaFormatted});
+
+    /**
+     * @desc Relative date indicating in how many hours something happens
+     * (plural).
+     */
+    var MSG_IN_HOURS_PLURAL =
+        goog.getMsg('in {$num} hours', {'num' : deltaFormatted});
+
+    return delta == 1 ? MSG_IN_HOURS_SINGULAR : MSG_IN_HOURS_PLURAL;
+
+  } else if (!future && unit == goog.date.relative.Unit.DAYS) {
+    /**
+     * @desc Relative date indicating how many days ago something happened
+     * (singular).
+     */
+    var MSG_DAYS_AGO_SINGULAR =
+        goog.getMsg('{$num} day ago', {'num' : deltaFormatted});
+
+    /**
+     * @desc Relative date indicating how many days ago something happened
+     * (plural).
+     */
+    var MSG_DAYS_AGO_PLURAL =
+        goog.getMsg('{$num} days ago', {'num' : deltaFormatted});
+
+    return delta == 1 ? MSG_DAYS_AGO_SINGULAR : MSG_DAYS_AGO_PLURAL;
+
+  } else if (future && unit == goog.date.relative.Unit.DAYS) {
+    /**
+     * @desc Relative date indicating in how many days something happens
+     * (singular).
+     */
+    var MSG_IN_DAYS_SINGULAR =
+        goog.getMsg('in {$num} day', {'num' : deltaFormatted});
+
+    /**
+     * @desc Relative date indicating in how many days something happens
+     * (plural).
+     */
+    var MSG_IN_DAYS_PLURAL =
+        goog.getMsg('in {$num} days', {'num' : deltaFormatted});
+
+    return delta == 1 ? MSG_IN_DAYS_SINGULAR : MSG_IN_DAYS_PLURAL;
+
+  } else {
+    return '';
+  }
+};
+
+goog.date.relative.setTimeDeltaFormatter(goog.date.relative.getMessage_);


[08/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/history/html5history.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/history/html5history.js b/externs/GCL/externs/goog/history/html5history.js
new file mode 100644
index 0000000..038d711
--- /dev/null
+++ b/externs/GCL/externs/goog/history/html5history.js
@@ -0,0 +1,303 @@
+// Copyright 2010 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 HTML5 based history implementation, compatible with
+ * goog.History.
+ *
+ * TODO(user): There should really be a history interface and multiple
+ * implementations.
+ *
+ */
+
+
+goog.provide('goog.history.Html5History');
+goog.provide('goog.history.Html5History.TokenTransformer');
+
+goog.require('goog.asserts');
+goog.require('goog.events');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.history.Event');
+
+
+
+/**
+ * An implementation compatible with goog.History that uses the HTML5
+ * history APIs.
+ *
+ * @param {Window=} opt_win The window to listen/dispatch history events on.
+ * @param {goog.history.Html5History.TokenTransformer=} opt_transformer
+ *     The token transformer that is used to create URL from the token
+ *     when storing token without using hash fragment.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @final
+ */
+goog.history.Html5History = function(opt_win, opt_transformer) {
+  goog.events.EventTarget.call(this);
+  goog.asserts.assert(goog.history.Html5History.isSupported(opt_win),
+      'HTML5 history is not supported.');
+
+  /**
+   * The window object to use for history tokens.  Typically the top window.
+   * @type {Window}
+   * @private
+   */
+  this.window_ = opt_win || window;
+
+  /**
+   * The token transformer that is used to create URL from the token
+   * when storing token without using hash fragment.
+   * @type {goog.history.Html5History.TokenTransformer}
+   * @private
+   */
+  this.transformer_ = opt_transformer || null;
+
+  goog.events.listen(this.window_, goog.events.EventType.POPSTATE,
+      this.onHistoryEvent_, false, this);
+  goog.events.listen(this.window_, goog.events.EventType.HASHCHANGE,
+      this.onHistoryEvent_, false, this);
+};
+goog.inherits(goog.history.Html5History, goog.events.EventTarget);
+
+
+/**
+ * Returns whether Html5History is supported.
+ * @param {Window=} opt_win Optional window to check.
+ * @return {boolean} Whether html5 history is supported.
+ */
+goog.history.Html5History.isSupported = function(opt_win) {
+  var win = opt_win || window;
+  return !!(win.history && win.history.pushState);
+};
+
+
+/**
+ * Status of when the object is active and dispatching events.
+ * @type {boolean}
+ * @private
+ */
+goog.history.Html5History.prototype.enabled_ = false;
+
+
+/**
+ * Whether to use the fragment to store the token, defaults to true.
+ * @type {boolean}
+ * @private
+ */
+goog.history.Html5History.prototype.useFragment_ = true;
+
+
+/**
+ * If useFragment is false the path will be used, the path prefix will be
+ * prepended to all tokens. Defaults to '/'.
+ * @type {string}
+ * @private
+ */
+goog.history.Html5History.prototype.pathPrefix_ = '/';
+
+
+/**
+ * Starts or stops the History.  When enabled, the History object
+ * will immediately fire an event for the current location. The caller can set
+ * up event listeners between the call to the constructor and the call to
+ * setEnabled.
+ *
+ * @param {boolean} enable Whether to enable history.
+ */
+goog.history.Html5History.prototype.setEnabled = function(enable) {
+  if (enable == this.enabled_) {
+    return;
+  }
+
+  this.enabled_ = enable;
+
+  if (enable) {
+    this.dispatchEvent(new goog.history.Event(this.getToken(), false));
+  }
+};
+
+
+/**
+ * Returns the current token.
+ * @return {string} The current token.
+ */
+goog.history.Html5History.prototype.getToken = function() {
+  if (this.useFragment_) {
+    var loc = this.window_.location.href;
+    var index = loc.indexOf('#');
+    return index < 0 ? '' : loc.substring(index + 1);
+  } else {
+    return this.transformer_ ?
+        this.transformer_.retrieveToken(
+            this.pathPrefix_, this.window_.location) :
+        this.window_.location.pathname.substr(this.pathPrefix_.length);
+  }
+};
+
+
+/**
+ * Sets the history state.
+ * @param {string} token The history state identifier.
+ * @param {string=} opt_title Optional title to associate with history entry.
+ */
+goog.history.Html5History.prototype.setToken = function(token, opt_title) {
+  if (token == this.getToken()) {
+    return;
+  }
+
+  // Per externs/gecko_dom.js document.title can be null.
+  this.window_.history.pushState(null,
+      opt_title || this.window_.document.title || '', this.getUrl_(token));
+  this.dispatchEvent(new goog.history.Event(token, false));
+};
+
+
+/**
+ * Replaces the current history state without affecting the rest of the history
+ * stack.
+ * @param {string} token The history state identifier.
+ * @param {string=} opt_title Optional title to associate with history entry.
+ */
+goog.history.Html5History.prototype.replaceToken = function(token, opt_title) {
+  // Per externs/gecko_dom.js document.title can be null.
+  this.window_.history.replaceState(null,
+      opt_title || this.window_.document.title || '', this.getUrl_(token));
+  this.dispatchEvent(new goog.history.Event(token, false));
+};
+
+
+/** @override */
+goog.history.Html5History.prototype.disposeInternal = function() {
+  goog.events.unlisten(this.window_, goog.events.EventType.POPSTATE,
+      this.onHistoryEvent_, false, this);
+  if (this.useFragment_) {
+    goog.events.unlisten(this.window_, goog.events.EventType.HASHCHANGE,
+        this.onHistoryEvent_, false, this);
+  }
+};
+
+
+/**
+ * Sets whether to use the fragment to store tokens.
+ * @param {boolean} useFragment Whether to use the fragment.
+ */
+goog.history.Html5History.prototype.setUseFragment = function(useFragment) {
+  if (this.useFragment_ != useFragment) {
+    if (useFragment) {
+      goog.events.listen(this.window_, goog.events.EventType.HASHCHANGE,
+          this.onHistoryEvent_, false, this);
+    } else {
+      goog.events.unlisten(this.window_, goog.events.EventType.HASHCHANGE,
+          this.onHistoryEvent_, false, this);
+    }
+    this.useFragment_ = useFragment;
+  }
+};
+
+
+/**
+ * Sets the path prefix to use if storing tokens in the path. The path
+ * prefix should start and end with slash.
+ * @param {string} pathPrefix Sets the path prefix.
+ */
+goog.history.Html5History.prototype.setPathPrefix = function(pathPrefix) {
+  this.pathPrefix_ = pathPrefix;
+};
+
+
+/**
+ * Gets the path prefix.
+ * @return {string} The path prefix.
+ */
+goog.history.Html5History.prototype.getPathPrefix = function() {
+  return this.pathPrefix_;
+};
+
+
+/**
+ * Gets the URL to set when calling history.pushState
+ * @param {string} token The history token.
+ * @return {string} The URL.
+ * @private
+ */
+goog.history.Html5History.prototype.getUrl_ = function(token) {
+  if (this.useFragment_) {
+    return '#' + token;
+  } else {
+    return this.transformer_ ?
+        this.transformer_.createUrl(
+            token, this.pathPrefix_, this.window_.location) :
+        this.pathPrefix_ + token + this.window_.location.search;
+  }
+};
+
+
+/**
+ * Handles history events dispatched by the browser.
+ * @param {goog.events.BrowserEvent} e The browser event object.
+ * @private
+ */
+goog.history.Html5History.prototype.onHistoryEvent_ = function(e) {
+  if (this.enabled_) {
+    this.dispatchEvent(new goog.history.Event(this.getToken(), true));
+  }
+};
+
+
+
+/**
+ * A token transformer that can create a URL from a history
+ * token. This is used by {@code goog.history.Html5History} to create
+ * URL when storing token without the hash fragment.
+ *
+ * Given a {@code window.location} object containing the location
+ * created by {@code createUrl}, the token transformer allows
+ * retrieval of the token back via {@code retrieveToken}.
+ *
+ * @interface
+ */
+goog.history.Html5History.TokenTransformer = function() {};
+
+
+/**
+ * Retrieves a history token given the path prefix and
+ * {@code window.location} object.
+ *
+ * @param {string} pathPrefix The path prefix to use when storing token
+ *     in a path; always begin with a slash.
+ * @param {Location} location The {@code window.location} object.
+ *     Treat this object as read-only.
+ * @return {string} token The history token.
+ */
+goog.history.Html5History.TokenTransformer.prototype.retrieveToken = function(
+    pathPrefix, location) {};
+
+
+/**
+ * Creates a URL to be pushed into HTML5 history stack when storing
+ * token without using hash fragment.
+ *
+ * @param {string} token The history token.
+ * @param {string} pathPrefix The path prefix to use when storing token
+ *     in a path; always begin with a slash.
+ * @param {Location} location The {@code window.location} object.
+ *     Treat this object as read-only.
+ * @return {string} url The complete URL string from path onwards
+ *     (without {@code protocol://host:port} part); must begin with a
+ *     slash.
+ */
+goog.history.Html5History.TokenTransformer.prototype.createUrl = function(
+    token, pathPrefix, location) {};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/html/flash.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/html/flash.js b/externs/GCL/externs/goog/html/flash.js
new file mode 100644
index 0000000..9f72665
--- /dev/null
+++ b/externs/GCL/externs/goog/html/flash.js
@@ -0,0 +1,177 @@
+// Copyright 2014 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 SafeHtml factory methods for creating object and embed tags
+ * for loading Flash files.
+ */
+
+goog.provide('goog.html.flash');
+
+goog.require('goog.asserts');
+goog.require('goog.html.SafeHtml');
+
+
+/**
+ * Attributes and param tag name attributes not allowed to be overriden
+ * when calling createObject() and createObjectForOldIe().
+ *
+ * While values that should be specified as params are probably not
+ * recognized as attributes, we block them anyway just to be sure.
+ * @const {!Array<string>}
+ * @private
+ */
+goog.html.flash.FORBIDDEN_ATTRS_AND_PARAMS_ON_FLASH_ = [
+  'classid',  // Used on old IE.
+  'data',  // Used in <object> to specify a URL.
+  'movie',  // Used on old IE.
+  'type',  // Used in <object> on for non-IE/modern IE.
+  'typemustmatch'  // Always set to a fixed value.
+];
+
+
+goog.html.flash.createEmbed = function(src, opt_attributes) {
+  var fixedAttributes = {
+    'src': src,
+    'type': 'application/x-shockwave-flash',
+    'pluginspage': 'https://www.macromedia.com/go/getflashplayer'
+  };
+  var defaultAttributes = {
+    'allownetworking': 'none',
+    'allowscriptaccess': 'never'
+  };
+  var attributes = goog.html.SafeHtml.combineAttributes(
+      fixedAttributes, defaultAttributes, opt_attributes);
+  return goog.html.SafeHtml.
+      createSafeHtmlTagSecurityPrivateDoNotAccessOrElse('embed', attributes);
+};
+
+
+goog.html.flash.createObject = function(
+    data, opt_params, opt_attributes) {
+  goog.html.flash.verifyKeysNotInMaps(
+      goog.html.flash.FORBIDDEN_ATTRS_AND_PARAMS_ON_FLASH_,
+      opt_attributes,
+      opt_params);
+
+  var paramTags = goog.html.flash.combineParams(
+      {
+        'allownetworking': 'none',
+        'allowscriptaccess': 'never'
+      },
+      opt_params);
+  var fixedAttributes = {
+    'data': data,
+    'type': 'application/x-shockwave-flash',
+    'typemustmatch': ''
+  };
+  var attributes = goog.html.SafeHtml.combineAttributes(
+      fixedAttributes, {}, opt_attributes);
+
+  return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
+      'object', attributes, paramTags);
+};
+
+
+goog.html.flash.createObjectForOldIe = function(
+    movie, opt_params, opt_attributes) {
+  goog.html.flash.verifyKeysNotInMaps(
+      goog.html.flash.FORBIDDEN_ATTRS_AND_PARAMS_ON_FLASH_,
+      opt_attributes,
+      opt_params);
+
+  var paramTags = goog.html.flash.combineParams(
+      {
+        'allownetworking': 'none',
+        'allowscriptaccess': 'never',
+        'movie': movie
+      },
+      opt_params);
+  var fixedAttributes =
+      {'classid': 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000'};
+  var attributes = goog.html.SafeHtml.combineAttributes(
+      fixedAttributes, {}, opt_attributes);
+
+  return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
+      'object', attributes, paramTags);
+};
+
+
+/**
+ * @param {!Object<string, string|!goog.string.TypedString>} defaultParams
+ * @param {!Object<string, string>=}
+ *     opt_params Optional params passed to create*().
+ * @return {!Array<!goog.html.SafeHtml>} Combined params.
+ * @throws {Error} If opt_attributes contains an attribute with the same name
+ *     as an attribute in fixedAttributes.
+ * @package
+ */
+goog.html.flash.combineParams = function(defaultParams, opt_params) {
+  var combinedParams = {};
+  var name;
+
+  for (name in defaultParams) {
+    goog.asserts.assert(name.toLowerCase() == name, 'Must be lower case');
+    combinedParams[name] = defaultParams[name];
+  }
+  for (name in opt_params) {
+    var nameLower = name.toLowerCase();
+    if (nameLower in defaultParams) {
+      delete combinedParams[nameLower];
+    }
+    combinedParams[name] = opt_params[name];
+  }
+
+  var paramTags = [];
+  for (name in combinedParams) {
+    paramTags.push(
+        goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
+            'param', {'name': name, 'value': combinedParams[name]}));
+
+  }
+  return paramTags;
+};
+
+
+/**
+ * Checks that keys are not present as keys in maps.
+ * @param {!Array<string>} keys Keys that must not be present, lower-case.
+ * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=}
+ *     opt_attributes Optional attributes passed to create*().
+ * @param {!Object<string, string>=}  opt_params Optional params passed to
+ *     createObject*().
+ * @throws {Error} If any of keys exist as a key, ignoring case, in
+ *     opt_attributes or opt_params.
+ * @package
+ */
+goog.html.flash.verifyKeysNotInMaps = function(
+    keys, opt_attributes, opt_params) {
+  var verifyNotInMap = function(keys, map, type) {
+    for (var keyMap in map) {
+      var keyMapLower = keyMap.toLowerCase();
+      for (var i = 0; i < keys.length; i++) {
+        var keyToCheck = keys[i];
+        goog.asserts.assert(keyToCheck.toLowerCase() == keyToCheck);
+        if (keyMapLower == keyToCheck) {
+          throw Error('Cannot override "' + keyToCheck + '" ' + type +
+              ', got "' + keyMap + '" with value "' + map[keyMap] + '"');
+        }
+      }
+    }
+  };
+
+  verifyNotInMap(keys, opt_attributes, 'attribute');
+  verifyNotInMap(keys, opt_params, 'param');
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/html/legacyconversions.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/html/legacyconversions.js b/externs/GCL/externs/goog/html/legacyconversions.js
new file mode 100644
index 0000000..89a4c6d
--- /dev/null
+++ b/externs/GCL/externs/goog/html/legacyconversions.js
@@ -0,0 +1,200 @@
+// Copyright 2013 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 Conversions from plain string to goog.html types for use in
+ * legacy APIs that do not use goog.html types.
+ *
+ * This file provides conversions to create values of goog.html types from plain
+ * strings.  These conversions are intended for use in legacy APIs that consume
+ * HTML in the form of plain string types, but whose implementations use
+ * goog.html types internally (and expose such types in an augmented, HTML-type-
+ * safe API).
+ *
+ * IMPORTANT: No new code should use the conversion functions in this file.
+ *
+ * The conversion functions in this file are guarded with global flag
+ * (goog.html.legacyconversions.ALLOW_LEGACY_CONVERSIONS). If set to false, it
+ * effectively "locks in" an entire application to only use HTML-type-safe APIs.
+ *
+ * Intended use of the functions in this file are as follows:
+ *
+ * Many Closure and application-specific classes expose methods that consume
+ * values that in the class' implementation are forwarded to DOM APIs that can
+ * result in security vulnerabilities.  For example, goog.ui.Dialog's setContent
+ * method consumes a string that is assigned to an element's innerHTML property;
+ * if this string contains untrusted (attacker-controlled) data, this can result
+ * in a cross-site-scripting vulnerability.
+ *
+ * Widgets such as goog.ui.Dialog are being augmented to expose safe APIs
+ * expressed in terms of goog.html types.  For instance, goog.ui.Dialog has a
+ * method setSafeHtmlContent that consumes an object of type goog.html.SafeHtml,
+ * a type whose contract guarantees that its value is safe to use in HTML
+ * context, i.e. can be safely assigned to .innerHTML. An application that only
+ * uses this API is forced to only supply values of this type, i.e. values that
+ * are safe.
+ *
+ * However, the legacy method setContent cannot (for the time being) be removed
+ * from goog.ui.Dialog, due to a large number of existing callers.  The
+ * implementation of goog.ui.Dialog has been refactored to use
+ * goog.html.SafeHtml throughout.  This in turn requires that the value consumed
+ * by its setContent method is converted to goog.html.SafeHtml in an unchecked
+ * conversion. The conversion function is provided by this file:
+ * goog.html.legacyconversions.safeHtmlFromString.
+ *
+ * Note that the semantics of the conversions in goog.html.legacyconversions are
+ * very different from the ones provided by goog.html.uncheckedconversions:  The
+ * latter are for use in code where it has been established through manual
+ * security review that the value produced by a piece of code must always
+ * satisfy the SafeHtml contract (e.g., the output of a secure HTML sanitizer).
+ * In uses of goog.html.legacyconversions, this guarantee is not given -- the
+ * value in question originates in unreviewed legacy code and there is no
+ * guarantee that it satisfies the SafeHtml contract.
+ *
+ * To establish correctness with confidence, application code should be
+ * refactored to use SafeHtml instead of plain string to represent HTML markup,
+ * and to use goog.html-typed APIs (e.g., goog.ui.Dialog#setSafeHtmlContent
+ * instead of goog.ui.Dialog#setContent).
+ *
+ * To prevent introduction of new vulnerabilities, application owners can
+ * effectively disable unsafe legacy APIs by compiling with the define
+ * goog.html.legacyconversions.ALLOW_LEGACY_CONVERSIONS set to false.  When
+ * set, this define causes the conversion methods in this file to
+ * unconditionally throw an exception.
+ *
+ * Note that new code should always be compiled with
+ * ALLOW_LEGACY_CONVERSIONS=false.  At some future point, the default for this
+ * define may change to false.
+ */
+
+
+goog.provide('goog.html.legacyconversions');
+
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.SafeStyle');
+goog.require('goog.html.SafeUrl');
+goog.require('goog.html.TrustedResourceUrl');
+
+
+/**
+ * @define {boolean} Whether conversion from string to goog.html types for
+ * legacy API purposes is permitted.
+ *
+ * If false, the conversion functions in this file unconditionally throw an
+ * exception.
+ */
+goog.define('goog.html.legacyconversions.ALLOW_LEGACY_CONVERSIONS', true);
+
+
+/**
+ * Performs an "unchecked conversion" from string to SafeHtml for legacy API
+ * purposes.
+ *
+ * Unchecked conversion will not proceed if ALLOW_LEGACY_CONVERSIONS is false,
+ * and instead this function unconditionally throws an exception.
+ *
+ * @param {string} html A string to be converted to SafeHtml.
+ * @return {!goog.html.SafeHtml} The value of html, wrapped in a SafeHtml
+ *     object.
+ */
+goog.html.legacyconversions.safeHtmlFromString = function(html) {
+  goog.html.legacyconversions.throwIfConversionsDisallowed();
+  return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
+      html, null /* dir */);
+};
+
+
+/**
+ * Performs an "unchecked conversion" from string to SafeStyle for legacy API
+ * purposes.
+ *
+ * Unchecked conversion will not proceed if ALLOW_LEGACY_CONVERSIONS is false,
+ * and instead this function unconditionally throws an exception.
+ *
+ * @param {string} style A string to be converted to SafeStyle.
+ * @return {!goog.html.SafeStyle} The value of style, wrapped in a SafeStyle
+ *     object.
+ */
+goog.html.legacyconversions.safeStyleFromString = function(style) {
+  goog.html.legacyconversions.throwIfConversionsDisallowed();
+  return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(
+      style);
+};
+
+
+/**
+ * Performs an "unchecked conversion" from string to TrustedResourceUrl for
+ * legacy API purposes.
+ *
+ * Unchecked conversion will not proceed if ALLOW_LEGACY_CONVERSIONS is false,
+ * and instead this function unconditionally throws an exception.
+ *
+ * @param {string} url A string to be converted to TrustedResourceUrl.
+ * @return {!goog.html.TrustedResourceUrl} The value of url, wrapped in a
+ *     TrustedResourceUrl object.
+ */
+goog.html.legacyconversions.trustedResourceUrlFromString = function(url) {
+  goog.html.legacyconversions.throwIfConversionsDisallowed();
+  return goog.html.TrustedResourceUrl.
+      createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(url);
+};
+
+
+/**
+ * Performs an "unchecked conversion" from string to SafeUrl for legacy API
+ * purposes.
+ *
+ * Unchecked conversion will not proceed if ALLOW_LEGACY_CONVERSIONS is false,
+ * and instead this function unconditionally throws an exception.
+ *
+ * @param {string} url A string to be converted to SafeUrl.
+ * @return {!goog.html.SafeUrl} The value of url, wrapped in a SafeUrl
+ *     object.
+ */
+goog.html.legacyconversions.safeUrlFromString = function(url) {
+  goog.html.legacyconversions.throwIfConversionsDisallowed();
+  return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
+};
+
+
+/**
+ * @private {function(): undefined}
+ */
+goog.html.legacyconversions.reportCallback_ = goog.nullFunction;
+
+
+/**
+ * Sets a function that will be called every time a legacy conversion is
+ * performed. The function is called with no parameters but it can use
+ * goog.debug.getStacktrace to get a stacktrace.
+ *
+ * @param {function(): undefined} callback Error callback as defined above.
+ */
+goog.html.legacyconversions.setReportCallback = function(callback) {
+  goog.html.legacyconversions.reportCallback_ = callback;
+};
+
+
+/**
+ * Throws an exception if ALLOW_LEGACY_CONVERSIONS is false. This is useful
+ * for legacy APIs which consume HTML in the form of plain string types, but
+ * do not provide an alternative HTML-type-safe API.
+ */
+goog.html.legacyconversions.throwIfConversionsDisallowed = function() {
+  if (!goog.html.legacyconversions.ALLOW_LEGACY_CONVERSIONS) {
+    throw Error(
+        'Error: Legacy conversion from string to goog.html types is disabled');
+  }
+  goog.html.legacyconversions.reportCallback_();
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/html/safehtml.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/html/safehtml.js b/externs/GCL/externs/goog/html/safehtml.js
new file mode 100644
index 0000000..ef6a2ae
--- /dev/null
+++ b/externs/GCL/externs/goog/html/safehtml.js
@@ -0,0 +1,756 @@
+// Copyright 2013 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 The SafeHtml type and its builders.
+ *
+ * TODO(user): Link to document stating type contract.
+ */
+
+goog.provide('goog.html.SafeHtml');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.tags');
+goog.require('goog.html.SafeStyle');
+goog.require('goog.html.SafeStyleSheet');
+goog.require('goog.html.SafeUrl');
+goog.require('goog.html.TrustedResourceUrl');
+goog.require('goog.i18n.bidi.Dir');
+goog.require('goog.i18n.bidi.DirectionalString');
+goog.require('goog.object');
+goog.require('goog.string');
+goog.require('goog.string.Const');
+goog.require('goog.string.TypedString');
+
+
+
+/**
+ * A string that is safe to use in HTML context in DOM APIs and HTML documents.
+ *
+ * A SafeHtml is a string-like object that carries the security type contract
+ * that its value as a string will not cause untrusted script execution when
+ * evaluated as HTML in a browser.
+ *
+ * Values of this type are guaranteed to be safe to use in HTML contexts,
+ * such as, assignment to the innerHTML DOM property, or interpolation into
+ * a HTML template in HTML PC_DATA context, in the sense that the use will not
+ * result in a Cross-Site-Scripting vulnerability.
+ *
+ * Instances of this type must be created via the factory methods
+ * ({@code goog.html.SafeHtml.create}, {@code goog.html.SafeHtml.htmlEscape}),
+ * etc and not by invoking its constructor.  The constructor intentionally
+ * takes no parameters and the type is immutable; hence only a default instance
+ * corresponding to the empty string can be obtained via constructor invocation.
+ *
+ * @see goog.html.SafeHtml#create
+ * @see goog.html.SafeHtml#htmlEscape
+ * @constructor
+ * @final
+ * @struct
+ * @implements {goog.i18n.bidi.DirectionalString}
+ * @implements {goog.string.TypedString}
+ */
+goog.html.SafeHtml = function() {
+  /**
+   * The contained value of this SafeHtml.  The field has a purposely ugly
+   * name to make (non-compiled) code that attempts to directly access this
+   * field stand out.
+   * @private {string}
+   */
+  this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = '';
+
+  /**
+   * A type marker used to implement additional run-time type checking.
+   * @see goog.html.SafeHtml#unwrap
+   * @const
+   * @private
+   */
+  this.SAFE_HTML_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
+      goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
+
+  /**
+   * This SafeHtml's directionality, or null if unknown.
+   * @private {?goog.i18n.bidi.Dir}
+   */
+  this.dir_ = null;
+};
+
+
+/**
+ * @override
+ * @const
+ */
+goog.html.SafeHtml.prototype.implementsGoogI18nBidiDirectionalString = true;
+
+
+/** @override */
+goog.html.SafeHtml.prototype.getDirection = function() {
+  return this.dir_;
+};
+
+
+/**
+ * @override
+ * @const
+ */
+goog.html.SafeHtml.prototype.implementsGoogStringTypedString = true;
+
+
+/**
+ * Returns this SafeHtml's value a string.
+ *
+ * IMPORTANT: In code where it is security relevant that an object's type is
+ * indeed {@code SafeHtml}, use {@code goog.html.SafeHtml.unwrap} instead of
+ * this method. If in doubt, assume that it's security relevant. In particular,
+ * note that goog.html functions which return a goog.html type do not guarantee
+ * that the returned instance is of the right type. For example:
+ *
+ * <pre>
+ * var fakeSafeHtml = new String('fake');
+ * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
+ * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
+ * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
+ * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
+ * // instanceof goog.html.SafeHtml.
+ * </pre>
+ *
+ * @see goog.html.SafeHtml#unwrap
+ * @override
+ */
+goog.html.SafeHtml.prototype.getTypedStringValue = function() {
+  return this.privateDoNotAccessOrElseSafeHtmlWrappedValue_;
+};
+
+
+if (goog.DEBUG) {
+  /**
+   * Returns a debug string-representation of this value.
+   *
+   * To obtain the actual string value wrapped in a SafeHtml, use
+   * {@code goog.html.SafeHtml.unwrap}.
+   *
+   * @see goog.html.SafeHtml#unwrap
+   * @override
+   */
+  goog.html.SafeHtml.prototype.toString = function() {
+    return 'SafeHtml{' + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ +
+        '}';
+  };
+}
+
+
+/**
+ * Performs a runtime check that the provided object is indeed a SafeHtml
+ * object, and returns its value.
+ * @param {!goog.html.SafeHtml} safeHtml The object to extract from.
+ * @return {string} The SafeHtml object's contained string, unless the run-time
+ *     type check fails. In that case, {@code unwrap} returns an innocuous
+ *     string, or, if assertions are enabled, throws
+ *     {@code goog.asserts.AssertionError}.
+ */
+goog.html.SafeHtml.unwrap = function(safeHtml) {
+  // Perform additional run-time type-checking to ensure that safeHtml is indeed
+  // an instance of the expected type.  This provides some additional protection
+  // against security bugs due to application code that disables type checks.
+  // Specifically, the following checks are performed:
+  // 1. The object is an instance of the expected type.
+  // 2. The object is not an instance of a subclass.
+  // 3. The object carries a type marker for the expected type. "Faking" an
+  // object requires a reference to the type marker, which has names intended
+  // to stand out in code reviews.
+  if (safeHtml instanceof goog.html.SafeHtml &&
+      safeHtml.constructor === goog.html.SafeHtml &&
+      safeHtml.SAFE_HTML_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
+          goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
+    return safeHtml.privateDoNotAccessOrElseSafeHtmlWrappedValue_;
+  } else {
+    goog.asserts.fail('expected object of type SafeHtml, got \'' +
+                      safeHtml + '\'');
+    return 'type_error:SafeHtml';
+  }
+};
+
+
+/**
+ * Shorthand for union of types that can sensibly be converted to strings
+ * or might already be SafeHtml (as SafeHtml is a goog.string.TypedString).
+ * @private
+ * @typedef {string|number|boolean|!goog.string.TypedString|
+ *           !goog.i18n.bidi.DirectionalString}
+ */
+goog.html.SafeHtml.TextOrHtml_;
+
+
+/**
+ * Returns HTML-escaped text as a SafeHtml object.
+ *
+ * If text is of a type that implements
+ * {@code goog.i18n.bidi.DirectionalString}, the directionality of the new
+ * {@code SafeHtml} object is set to {@code text}'s directionality, if known.
+ * Otherwise, the directionality of the resulting SafeHtml is unknown (i.e.,
+ * {@code null}).
+ *
+ * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If
+ *     the parameter is of type SafeHtml it is returned directly (no escaping
+ *     is done).
+ * @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml.
+ */
+goog.html.SafeHtml.htmlEscape = function(textOrHtml) {
+  if (textOrHtml instanceof goog.html.SafeHtml) {
+    return textOrHtml;
+  }
+  var dir = null;
+  if (textOrHtml.implementsGoogI18nBidiDirectionalString) {
+    dir = textOrHtml.getDirection();
+  }
+  var textAsString;
+  if (textOrHtml.implementsGoogStringTypedString) {
+    textAsString = textOrHtml.getTypedStringValue();
+  } else {
+    textAsString = String(textOrHtml);
+  }
+  return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
+      goog.string.htmlEscape(textAsString), dir);
+};
+
+
+/**
+ * Returns HTML-escaped text as a SafeHtml object, with newlines changed to
+ * &lt;br&gt;.
+ * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If
+ *     the parameter is of type SafeHtml it is returned directly (no escaping
+ *     is done).
+ * @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml.
+ */
+goog.html.SafeHtml.htmlEscapePreservingNewlines = function(textOrHtml) {
+  if (textOrHtml instanceof goog.html.SafeHtml) {
+    return textOrHtml;
+  }
+  var html = goog.html.SafeHtml.htmlEscape(textOrHtml);
+  return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
+      goog.string.newLineToBr(goog.html.SafeHtml.unwrap(html)),
+      html.getDirection());
+};
+
+
+/**
+ * Returns HTML-escaped text as a SafeHtml object, with newlines changed to
+ * &lt;br&gt; and escaping whitespace to preserve spatial formatting. Character
+ * entity #160 is used to make it safer for XML.
+ * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text to escape. If
+ *     the parameter is of type SafeHtml it is returned directly (no escaping
+ *     is done).
+ * @return {!goog.html.SafeHtml} The escaped text, wrapped as a SafeHtml.
+ */
+goog.html.SafeHtml.htmlEscapePreservingNewlinesAndSpaces = function(
+    textOrHtml) {
+  if (textOrHtml instanceof goog.html.SafeHtml) {
+    return textOrHtml;
+  }
+  var html = goog.html.SafeHtml.htmlEscape(textOrHtml);
+  return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
+      goog.string.whitespaceEscape(goog.html.SafeHtml.unwrap(html)),
+      html.getDirection());
+};
+
+
+/**
+ * Coerces an arbitrary object into a SafeHtml object.
+ *
+ * If {@code textOrHtml} is already of type {@code goog.html.SafeHtml}, the same
+ * object is returned. Otherwise, {@code textOrHtml} is coerced to string, and
+ * HTML-escaped. If {@code textOrHtml} is of a type that implements
+ * {@code goog.i18n.bidi.DirectionalString}, its directionality, if known, is
+ * preserved.
+ *
+ * @param {!goog.html.SafeHtml.TextOrHtml_} textOrHtml The text or SafeHtml to
+ *     coerce.
+ * @return {!goog.html.SafeHtml} The resulting SafeHtml object.
+ * @deprecated Use goog.html.SafeHtml.htmlEscape.
+ */
+goog.html.SafeHtml.from = goog.html.SafeHtml.htmlEscape;
+
+
+/**
+ * @const
+ * @private
+ */
+goog.html.SafeHtml.VALID_NAMES_IN_TAG_ = /^[a-zA-Z0-9-]+$/;
+
+
+/**
+ * Set of attributes containing URL as defined at
+ * http://www.w3.org/TR/html5/index.html#attributes-1.
+ * @private @const {!Object<string,boolean>}
+ */
+goog.html.SafeHtml.URL_ATTRIBUTES_ = goog.object.createSet('action', 'cite',
+    'data', 'formaction', 'href', 'manifest', 'poster', 'src');
+
+
+/**
+ * Tags which are unsupported via create(). They might be supported via a
+ * tag-specific create method. These are tags which might require a
+ * TrustedResourceUrl in one of their attributes or a restricted type for
+ * their content.
+ * @private @const {!Object<string,boolean>}
+ */
+goog.html.SafeHtml.NOT_ALLOWED_TAG_NAMES_ = goog.object.createSet(
+    goog.dom.TagName.EMBED, goog.dom.TagName.IFRAME, goog.dom.TagName.LINK,
+    goog.dom.TagName.OBJECT, goog.dom.TagName.SCRIPT, goog.dom.TagName.STYLE,
+    goog.dom.TagName.TEMPLATE);
+
+
+/**
+ * @typedef {string|number|goog.string.TypedString|
+ *     goog.html.SafeStyle.PropertyMap}
+ * @private
+ */
+goog.html.SafeHtml.AttributeValue_;
+
+
+/**
+ * Creates a SafeHtml content consisting of a tag with optional attributes and
+ * optional content.
+ *
+ * For convenience tag names and attribute names are accepted as regular
+ * strings, instead of goog.string.Const. Nevertheless, you should not pass
+ * user-controlled values to these parameters. Note that these parameters are
+ * syntactically validated at runtime, and invalid values will result in
+ * an exception.
+ *
+ * Example usage:
+ *
+ * goog.html.SafeHtml.create('br');
+ * goog.html.SafeHtml.create('div', {'class': 'a'});
+ * goog.html.SafeHtml.create('p', {}, 'a');
+ * goog.html.SafeHtml.create('p', {}, goog.html.SafeHtml.create('br'));
+ *
+ * goog.html.SafeHtml.create('span', {
+ *   'style': {'margin': '0'}
+ * });
+ *
+ * To guarantee SafeHtml's type contract is upheld there are restrictions on
+ * attribute values and tag names.
+ *
+ * - For attributes which contain script code (on*), a goog.string.Const is
+ *   required.
+ * - For attributes which contain style (style), a goog.html.SafeStyle or a
+ *   goog.html.SafeStyle.PropertyMap is required.
+ * - For attributes which are interpreted as URLs (e.g. src, href) a
+ *   goog.html.SafeUrl or goog.string.Const is required.
+ * - For tags which can load code, more specific goog.html.SafeHtml.create*()
+ *   functions must be used. Tags which can load code and are not supported by
+ *   this function are embed, iframe, link, object, script, style, and template.
+ *
+ * @param {string} tagName The name of the tag. Only tag names consisting of
+ *     [a-zA-Z0-9-] are allowed. Tag names documented above are disallowed.
+ * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=}
+ *     opt_attributes Mapping from attribute names to their values. Only
+ *     attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or
+ *     undefined causes the attribute to be omitted.
+ * @param {!goog.html.SafeHtml.TextOrHtml_|
+ *     !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content Content to
+ *     HTML-escape and put inside the tag. This must be empty for void tags
+ *     like <br>. Array elements are concatenated.
+ * @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
+ * @throws {Error} If invalid tag name, attribute name, or attribute value is
+ *     provided.
+ * @throws {goog.asserts.AssertionError} If content for void tag is provided.
+ */
+goog.html.SafeHtml.create = function(tagName, opt_attributes, opt_content) {
+  if (!goog.html.SafeHtml.VALID_NAMES_IN_TAG_.test(tagName)) {
+    throw Error('Invalid tag name <' + tagName + '>.');
+  }
+  if (tagName.toUpperCase() in goog.html.SafeHtml.NOT_ALLOWED_TAG_NAMES_) {
+    throw Error('Tag name <' + tagName + '> is not allowed for SafeHtml.');
+  }
+  return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
+      tagName, opt_attributes, opt_content);
+};
+
+
+/**
+ * Creates a SafeHtml representing an iframe tag.
+ *
+ * By default the sandbox attribute is set to an empty value, which is the most
+ * secure option, as it confers the iframe the least privileges. If this
+ * is too restrictive then granting individual privileges is the preferable
+ * option. Unsetting the attribute entirely is the least secure option and
+ * should never be done unless it's stricly necessary.
+ *
+ * @param {goog.html.TrustedResourceUrl=} opt_src The value of the src
+ *     attribute. If null or undefined src will not be set.
+ * @param {goog.html.SafeHtml=} opt_srcdoc The value of the srcdoc attribute.
+ *     If null or undefined srcdoc will not be set.
+ * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=}
+ *     opt_attributes Mapping from attribute names to their values. Only
+ *     attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or
+ *     undefined causes the attribute to be omitted.
+ * @param {!goog.html.SafeHtml.TextOrHtml_|
+ *     !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content Content to
+ *     HTML-escape and put inside the tag. Array elements are concatenated.
+ * @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
+ * @throws {Error} If invalid tag name, attribute name, or attribute value is
+ *     provided. If opt_attributes contains the src or srcdoc attributes.
+ */
+goog.html.SafeHtml.createIframe = function(
+    opt_src, opt_srcdoc, opt_attributes, opt_content) {
+  var fixedAttributes = {};
+  fixedAttributes['src'] = opt_src || null;
+  fixedAttributes['srcdoc'] = opt_srcdoc || null;
+  var defaultAttributes = {'sandbox': ''};
+  var attributes = goog.html.SafeHtml.combineAttributes(
+      fixedAttributes, defaultAttributes, opt_attributes);
+  return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
+      'iframe', attributes, opt_content);
+};
+
+
+/**
+ * Creates a SafeHtml representing a style tag. The type attribute is set
+ * to "text/css".
+ * @param {!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>}
+ *     styleSheet Content to put inside the tag. Array elements are
+ *     concatenated.
+ * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=}
+ *     opt_attributes Mapping from attribute names to their values. Only
+ *     attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or
+ *     undefined causes the attribute to be omitted.
+ * @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
+ * @throws {Error} If invalid attribute name or attribute value is provided. If
+ *     opt_attributes contains the type attribute.
+ */
+goog.html.SafeHtml.createStyle = function(styleSheet, opt_attributes) {
+  var fixedAttributes = {'type': 'text/css'};
+  var defaultAttributes = {};
+  var attributes = goog.html.SafeHtml.combineAttributes(
+      fixedAttributes, defaultAttributes, opt_attributes);
+
+  var content = '';
+  styleSheet = goog.array.concat(styleSheet);
+  for (var i = 0; i < styleSheet.length; i++) {
+    content += goog.html.SafeStyleSheet.unwrap(styleSheet[i]);
+  }
+  // Convert to SafeHtml so that it's not HTML-escaped.
+  var htmlContent = goog.html.SafeHtml
+      .createSafeHtmlSecurityPrivateDoNotAccessOrElse(
+          content, goog.i18n.bidi.Dir.NEUTRAL);
+  return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
+      'style', attributes, htmlContent);
+};
+
+
+/**
+ * @param {string} tagName The tag name.
+ * @param {string} name The attribute name.
+ * @param {!goog.html.SafeHtml.AttributeValue_} value The attribute value.
+ * @return {string} A "name=value" string.
+ * @throws {Error} If attribute value is unsafe for the given tag and attribute.
+ * @private
+ */
+goog.html.SafeHtml.getAttrNameAndValue_ = function(tagName, name, value) {
+  // If it's goog.string.Const, allow any valid attribute name.
+  if (value instanceof goog.string.Const) {
+    value = goog.string.Const.unwrap(value);
+  } else if (name.toLowerCase() == 'style') {
+    value = goog.html.SafeHtml.getStyleValue_(value);
+  } else if (/^on/i.test(name)) {
+    // TODO(jakubvrana): Disallow more attributes with a special meaning.
+    throw Error('Attribute "' + name +
+        '" requires goog.string.Const value, "' + value + '" given.');
+  // URL attributes handled differently accroding to tag.
+  } else if (name.toLowerCase() in goog.html.SafeHtml.URL_ATTRIBUTES_) {
+    if (value instanceof goog.html.TrustedResourceUrl) {
+      value = goog.html.TrustedResourceUrl.unwrap(value);
+    } else if (value instanceof goog.html.SafeUrl) {
+      value = goog.html.SafeUrl.unwrap(value);
+    } else {
+      // TODO(user): Allow strings and sanitize them automatically,
+      // so that it's consistent with accepting a map directly for "style".
+      throw Error('Attribute "' + name + '" on tag "' + tagName +
+          '" requires goog.html.SafeUrl or goog.string.Const value, "' +
+          value + '" given.');
+    }
+  }
+
+  // Accept SafeUrl, TrustedResourceUrl, etc. for attributes which only require
+  // HTML-escaping.
+  if (value.implementsGoogStringTypedString) {
+    // Ok to call getTypedStringValue() since there's no reliance on the type
+    // contract for security here.
+    value = value.getTypedStringValue();
+  }
+
+  goog.asserts.assert(goog.isString(value) || goog.isNumber(value),
+      'String or number value expected, got ' +
+      (typeof value) + ' with value: ' + value);
+  return name + '="' + goog.string.htmlEscape(String(value)) + '"';
+};
+
+
+/**
+ * Gets value allowed in "style" attribute.
+ * @param {goog.html.SafeHtml.AttributeValue_} value It could be SafeStyle or a
+ *     map which will be passed to goog.html.SafeStyle.create.
+ * @return {string} Unwrapped value.
+ * @throws {Error} If string value is given.
+ * @private
+ */
+goog.html.SafeHtml.getStyleValue_ = function(value) {
+  if (!goog.isObject(value)) {
+    throw Error('The "style" attribute requires goog.html.SafeStyle or map ' +
+        'of style properties, ' + (typeof value) + ' given: ' + value);
+  }
+  if (!(value instanceof goog.html.SafeStyle)) {
+    // Process the property bag into a style object.
+    value = goog.html.SafeStyle.create(value);
+  }
+  return goog.html.SafeStyle.unwrap(value);
+};
+
+
+/**
+ * Creates a SafeHtml content with known directionality consisting of a tag with
+ * optional attributes and optional content.
+ * @param {!goog.i18n.bidi.Dir} dir Directionality.
+ * @param {string} tagName
+ * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} opt_attributes
+ * @param {!goog.html.SafeHtml.TextOrHtml_|
+ *     !Array<!goog.html.SafeHtml.TextOrHtml_>=} opt_content
+ * @return {!goog.html.SafeHtml} The SafeHtml content with the tag.
+ */
+goog.html.SafeHtml.createWithDir = function(dir, tagName, opt_attributes,
+    opt_content) {
+  var html = goog.html.SafeHtml.create(tagName, opt_attributes, opt_content);
+  html.dir_ = dir;
+  return html;
+};
+
+
+/**
+ * Creates a new SafeHtml object by concatenating values.
+ * @param {...(!goog.html.SafeHtml.TextOrHtml_|
+ *     !Array<!goog.html.SafeHtml.TextOrHtml_>)} var_args Values to concatenate.
+ * @return {!goog.html.SafeHtml}
+ */
+goog.html.SafeHtml.concat = function(var_args) {
+  var dir = goog.i18n.bidi.Dir.NEUTRAL;
+  var content = '';
+
+  /**
+   * @param {!goog.html.SafeHtml.TextOrHtml_|
+   *     !Array<!goog.html.SafeHtml.TextOrHtml_>} argument
+   */
+  var addArgument = function(argument) {
+    if (goog.isArray(argument)) {
+      goog.array.forEach(argument, addArgument);
+    } else {
+      var html = goog.html.SafeHtml.htmlEscape(argument);
+      content += goog.html.SafeHtml.unwrap(html);
+      var htmlDir = html.getDirection();
+      if (dir == goog.i18n.bidi.Dir.NEUTRAL) {
+        dir = htmlDir;
+      } else if (htmlDir != goog.i18n.bidi.Dir.NEUTRAL && dir != htmlDir) {
+        dir = null;
+      }
+    }
+  };
+
+  goog.array.forEach(arguments, addArgument);
+  return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
+      content, dir);
+};
+
+
+/**
+ * Creates a new SafeHtml object with known directionality by concatenating the
+ * values.
+ * @param {!goog.i18n.bidi.Dir} dir Directionality.
+ * @param {...(!goog.html.SafeHtml.TextOrHtml_|
+ *     !Array<!goog.html.SafeHtml.TextOrHtml_>)} var_args Elements of array
+ *     arguments would be processed recursively.
+ * @return {!goog.html.SafeHtml}
+ */
+goog.html.SafeHtml.concatWithDir = function(dir, var_args) {
+  var html = goog.html.SafeHtml.concat(goog.array.slice(arguments, 1));
+  html.dir_ = dir;
+  return html;
+};
+
+
+/**
+ * Type marker for the SafeHtml type, used to implement additional run-time
+ * type checking.
+ * @const
+ * @private
+ */
+goog.html.SafeHtml.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
+
+
+/**
+ * Package-internal utility method to create SafeHtml instances.
+ *
+ * @param {string} html The string to initialize the SafeHtml object with.
+ * @param {?goog.i18n.bidi.Dir} dir The directionality of the SafeHtml to be
+ *     constructed, or null if unknown.
+ * @return {!goog.html.SafeHtml} The initialized SafeHtml object.
+ * @package
+ */
+goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse = function(
+    html, dir) {
+  return new goog.html.SafeHtml().initSecurityPrivateDoNotAccessOrElse_(
+      html, dir);
+};
+
+
+/**
+ * Called from createSafeHtmlSecurityPrivateDoNotAccessOrElse(). This
+ * method exists only so that the compiler can dead code eliminate static
+ * fields (like EMPTY) when they're not accessed.
+ * @param {string} html
+ * @param {?goog.i18n.bidi.Dir} dir
+ * @return {!goog.html.SafeHtml}
+ * @private
+ */
+goog.html.SafeHtml.prototype.initSecurityPrivateDoNotAccessOrElse_ = function(
+    html, dir) {
+  this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = html;
+  this.dir_ = dir;
+  return this;
+};
+
+
+/**
+ * Like create() but does not restrict which tags can be constructed.
+ *
+ * @param {string} tagName Tag name. Set or validated by caller.
+ * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=} opt_attributes
+ * @param {(!goog.html.SafeHtml.TextOrHtml_|
+ *     !Array<!goog.html.SafeHtml.TextOrHtml_>)=} opt_content
+ * @return {!goog.html.SafeHtml}
+ * @throws {Error} If invalid or unsafe attribute name or value is provided.
+ * @throws {goog.asserts.AssertionError} If content for void tag is provided.
+ * @package
+ */
+goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse =
+    function(tagName, opt_attributes, opt_content) {
+  var dir = null;
+  var result = '<' + tagName;
+
+  if (opt_attributes) {
+    for (var name in opt_attributes) {
+      if (!goog.html.SafeHtml.VALID_NAMES_IN_TAG_.test(name)) {
+        throw Error('Invalid attribute name "' + name + '".');
+      }
+      var value = opt_attributes[name];
+      if (!goog.isDefAndNotNull(value)) {
+        continue;
+      }
+      result += ' ' +
+          goog.html.SafeHtml.getAttrNameAndValue_(tagName, name, value);
+    }
+  }
+
+  var content = opt_content;
+  if (!goog.isDefAndNotNull(content)) {
+    content = [];
+  } else if (!goog.isArray(content)) {
+    content = [content];
+  }
+
+  if (goog.dom.tags.isVoidTag(tagName.toLowerCase())) {
+    goog.asserts.assert(!content.length,
+        'Void tag <' + tagName + '> does not allow content.');
+    result += '>';
+  } else {
+    var html = goog.html.SafeHtml.concat(content);
+    result += '>' + goog.html.SafeHtml.unwrap(html) + '</' + tagName + '>';
+    dir = html.getDirection();
+  }
+
+  var dirAttribute = opt_attributes && opt_attributes['dir'];
+  if (dirAttribute) {
+    if (/^(ltr|rtl|auto)$/i.test(dirAttribute)) {
+      // If the tag has the "dir" attribute specified then its direction is
+      // neutral because it can be safely used in any context.
+      dir = goog.i18n.bidi.Dir.NEUTRAL;
+    } else {
+      dir = null;
+    }
+  }
+
+  return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
+      result, dir);
+};
+
+
+/**
+ * @param {!Object<string, string>} fixedAttributes
+ * @param {!Object<string, string>} defaultAttributes
+ * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=}
+ *     opt_attributes Optional attributes passed to create*().
+ * @return {!Object<string, goog.html.SafeHtml.AttributeValue_>}
+ * @throws {Error} If opt_attributes contains an attribute with the same name
+ *     as an attribute in fixedAttributes.
+ * @package
+ */
+goog.html.SafeHtml.combineAttributes = function(
+    fixedAttributes, defaultAttributes, opt_attributes) {
+  var combinedAttributes = {};
+  var name;
+
+  for (name in fixedAttributes) {
+    goog.asserts.assert(name.toLowerCase() == name, 'Must be lower case');
+    combinedAttributes[name] = fixedAttributes[name];
+  }
+  for (name in defaultAttributes) {
+    goog.asserts.assert(name.toLowerCase() == name, 'Must be lower case');
+    combinedAttributes[name] = defaultAttributes[name];
+  }
+
+  for (name in opt_attributes) {
+    var nameLower = name.toLowerCase();
+    if (nameLower in fixedAttributes) {
+      throw Error('Cannot override "' + nameLower + '" attribute, got "' +
+          name + '" with value "' + opt_attributes[name] + '"');
+    }
+    if (nameLower in defaultAttributes) {
+      delete combinedAttributes[nameLower];
+    }
+    combinedAttributes[name] = opt_attributes[name];
+  }
+
+  return combinedAttributes;
+};
+
+
+/**
+ * A SafeHtml instance corresponding to the HTML doctype: "<!DOCTYPE html>".
+ * @const {!goog.html.SafeHtml}
+ */
+goog.html.SafeHtml.DOCTYPE_HTML =
+    goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
+        '<!DOCTYPE html>', goog.i18n.bidi.Dir.NEUTRAL);
+
+
+/**
+ * A SafeHtml instance corresponding to the empty string.
+ * @const {!goog.html.SafeHtml}
+ */
+goog.html.SafeHtml.EMPTY =
+    goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
+        '', goog.i18n.bidi.Dir.NEUTRAL);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/html/safescript.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/html/safescript.js b/externs/GCL/externs/goog/html/safescript.js
new file mode 100644
index 0000000..83995aa
--- /dev/null
+++ b/externs/GCL/externs/goog/html/safescript.js
@@ -0,0 +1,234 @@
+// Copyright 2014 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 The SafeScript type and its builders.
+ *
+ * TODO(user): Link to document stating type contract.
+ */
+
+goog.provide('goog.html.SafeScript');
+
+goog.require('goog.asserts');
+goog.require('goog.string.Const');
+goog.require('goog.string.TypedString');
+
+
+
+/**
+ * A string-like object which represents JavaScript code and that carries the
+ * security type contract that its value, as a string, will not cause execution
+ * of unconstrained attacker controlled code (XSS) when evaluated as JavaScript
+ * in a browser.
+ *
+ * Instances of this type must be created via the factory method
+ * {@code goog.html.SafeScript.fromConstant} and not by invoking its
+ * constructor. The constructor intentionally takes no parameters and the type
+ * is immutable; hence only a default instance corresponding to the empty string
+ * can be obtained via constructor invocation.
+ *
+ * A SafeScript's string representation can safely be interpolated as the
+ * content of a script element within HTML. The SafeScript string should not be
+ * escaped before interpolation.
+ *
+ * Note that the SafeScript might contain text that is attacker-controlled but
+ * that text should have been interpolated with appropriate escaping,
+ * sanitization and/or validation into the right location in the script, such
+ * that it is highly constrained in its effect (for example, it had to match a
+ * set of whitelisted words).
+ *
+ * A SafeScript can be constructed via security-reviewed unchecked
+ * conversions. In this case producers of SafeScript must ensure themselves that
+ * the SafeScript does not contain unsafe script. Note in particular that
+ * {@code &lt;} is dangerous, even when inside JavaScript strings, and so should
+ * always be forbidden or JavaScript escaped in user controlled input. For
+ * example, if {@code &lt;/script&gt;&lt;script&gt;evil&lt;/script&gt;"} were
+ * interpolated inside a JavaScript string, it would break out of the context
+ * of the original script element and {@code evil} would execute. Also note
+ * that within an HTML script (raw text) element, HTML character references,
+ * such as "&lt;" are not allowed. See
+ * http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements.
+ *
+ * @see goog.html.SafeScript#fromConstant
+ * @constructor
+ * @final
+ * @struct
+ * @implements {goog.string.TypedString}
+ */
+goog.html.SafeScript = function() {
+  /**
+   * The contained value of this SafeScript.  The field has a purposely
+   * ugly name to make (non-compiled) code that attempts to directly access this
+   * field stand out.
+   * @private {string}
+   */
+  this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = '';
+
+  /**
+   * A type marker used to implement additional run-time type checking.
+   * @see goog.html.SafeScript#unwrap
+   * @const
+   * @private
+   */
+  this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
+      goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
+};
+
+
+/**
+ * @override
+ * @const
+ */
+goog.html.SafeScript.prototype.implementsGoogStringTypedString = true;
+
+
+/**
+ * Type marker for the SafeScript type, used to implement additional
+ * run-time type checking.
+ * @const
+ * @private
+ */
+goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
+
+
+/**
+ * Creates a SafeScript object from a compile-time constant string.
+ *
+ * @param {!goog.string.Const} script A compile-time-constant string from which
+ *     to create a SafeScript.
+ * @return {!goog.html.SafeScript} A SafeScript object initialized to
+ *     {@code script}.
+ */
+goog.html.SafeScript.fromConstant = function(script) {
+  var scriptString = goog.string.Const.unwrap(script);
+  if (scriptString.length === 0) {
+    return goog.html.SafeScript.EMPTY;
+  }
+  return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(
+      scriptString);
+};
+
+
+/**
+ * Returns this SafeScript's value as a string.
+ *
+ * IMPORTANT: In code where it is security relevant that an object's type is
+ * indeed {@code SafeScript}, use {@code goog.html.SafeScript.unwrap} instead of
+ * this method. If in doubt, assume that it's security relevant. In particular,
+ * note that goog.html functions which return a goog.html type do not guarantee
+ * the returned instance is of the right type. For example:
+ *
+ * <pre>
+ * var fakeSafeHtml = new String('fake');
+ * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
+ * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
+ * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
+ * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
+ * // instanceof goog.html.SafeHtml.
+ * </pre>
+ *
+ * @see goog.html.SafeScript#unwrap
+ * @override
+ */
+goog.html.SafeScript.prototype.getTypedStringValue = function() {
+  return this.privateDoNotAccessOrElseSafeScriptWrappedValue_;
+};
+
+
+if (goog.DEBUG) {
+  /**
+   * Returns a debug string-representation of this value.
+   *
+   * To obtain the actual string value wrapped in a SafeScript, use
+   * {@code goog.html.SafeScript.unwrap}.
+   *
+   * @see goog.html.SafeScript#unwrap
+   * @override
+   */
+  goog.html.SafeScript.prototype.toString = function() {
+    return 'SafeScript{' +
+        this.privateDoNotAccessOrElseSafeScriptWrappedValue_ + '}';
+  };
+}
+
+
+/**
+ * Performs a runtime check that the provided object is indeed a
+ * SafeScript object, and returns its value.
+ *
+ * @param {!goog.html.SafeScript} safeScript The object to extract from.
+ * @return {string} The safeScript object's contained string, unless
+ *     the run-time type check fails. In that case, {@code unwrap} returns an
+ *     innocuous string, or, if assertions are enabled, throws
+ *     {@code goog.asserts.AssertionError}.
+ */
+goog.html.SafeScript.unwrap = function(safeScript) {
+  // Perform additional Run-time type-checking to ensure that
+  // safeScript is indeed an instance of the expected type.  This
+  // provides some additional protection against security bugs due to
+  // application code that disables type checks.
+  // Specifically, the following checks are performed:
+  // 1. The object is an instance of the expected type.
+  // 2. The object is not an instance of a subclass.
+  // 3. The object carries a type marker for the expected type. "Faking" an
+  // object requires a reference to the type marker, which has names intended
+  // to stand out in code reviews.
+  if (safeScript instanceof goog.html.SafeScript &&
+      safeScript.constructor === goog.html.SafeScript &&
+      safeScript.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
+          goog.html.SafeScript.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
+    return safeScript.privateDoNotAccessOrElseSafeScriptWrappedValue_;
+  } else {
+    goog.asserts.fail(
+        'expected object of type SafeScript, got \'' + safeScript + '\'');
+    return 'type_error:SafeScript';
+  }
+};
+
+
+/**
+ * Package-internal utility method to create SafeScript instances.
+ *
+ * @param {string} script The string to initialize the SafeScript object with.
+ * @return {!goog.html.SafeScript} The initialized SafeScript object.
+ * @package
+ */
+goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse =
+    function(script) {
+  return new goog.html.SafeScript().initSecurityPrivateDoNotAccessOrElse_(
+      script);
+};
+
+
+/**
+ * Called from createSafeScriptSecurityPrivateDoNotAccessOrElse(). This
+ * method exists only so that the compiler can dead code eliminate static
+ * fields (like EMPTY) when they're not accessed.
+ * @param {string} script
+ * @return {!goog.html.SafeScript}
+ * @private
+ */
+goog.html.SafeScript.prototype.initSecurityPrivateDoNotAccessOrElse_ = function(
+    script) {
+  this.privateDoNotAccessOrElseSafeScriptWrappedValue_ = script;
+  return this;
+};
+
+
+/**
+ * A SafeScript instance corresponding to the empty string.
+ * @const {!goog.html.SafeScript}
+ */
+goog.html.SafeScript.EMPTY =
+    goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse('');

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/html/safestyle.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/html/safestyle.js b/externs/GCL/externs/goog/html/safestyle.js
new file mode 100644
index 0000000..2f9f288
--- /dev/null
+++ b/externs/GCL/externs/goog/html/safestyle.js
@@ -0,0 +1,442 @@
+// Copyright 2014 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 The SafeStyle type and its builders.
+ *
+ * TODO(user): Link to document stating type contract.
+ */
+
+goog.provide('goog.html.SafeStyle');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.string');
+goog.require('goog.string.Const');
+goog.require('goog.string.TypedString');
+
+
+
+/**
+ * A string-like object which represents a sequence of CSS declarations
+ * ({@code propertyName1: propertyvalue1; propertyName2: propertyValue2; ...})
+ * and that carries the security type contract that its value, as a string,
+ * will not cause untrusted script execution (XSS) when evaluated as CSS in a
+ * browser.
+ *
+ * Instances of this type must be created via the factory methods
+ * ({@code goog.html.SafeStyle.create} or
+ * {@code goog.html.SafeStyle.fromConstant}) and not by invoking its
+ * constructor. The constructor intentionally takes no parameters and the type
+ * is immutable; hence only a default instance corresponding to the empty string
+ * can be obtained via constructor invocation.
+ *
+ * A SafeStyle's string representation ({@link #getSafeStyleString()}) can
+ * safely:
+ * <ul>
+ *   <li>Be interpolated as the entire content of a *quoted* HTML style
+ *       attribute, or before already existing properties. The SafeStyle string
+ *       *must be HTML-attribute-escaped* (where " and ' are escaped) before
+ *       interpolation.
+ *   <li>Be interpolated as the entire content of a {}-wrapped block within a
+ *       stylesheet, or before already existing properties. The SafeStyle string
+ *       should not be escaped before interpolation. SafeStyle's contract also
+ *       guarantees that the string will not be able to introduce new properties
+ *       or elide existing ones.
+ *   <li>Be assigned to the style property of a DOM node. The SafeStyle string
+ *       should not be escaped before being assigned to the property.
+ * </ul>
+ *
+ * A SafeStyle may never contain literal angle brackets. Otherwise, it could
+ * be unsafe to place a SafeStyle into a &lt;style&gt; tag (where it can't
+ * be HTML escaped). For example, if the SafeStyle containing
+ * "{@code font: 'foo &lt;style/&gt;&lt;script&gt;evil&lt;/script&gt;'}" were
+ * interpolated within a &lt;style&gt; tag, this would then break out of the
+ * style context into HTML.
+ *
+ * A SafeStyle may contain literal single or double quotes, and as such the
+ * entire style string must be escaped when used in a style attribute (if
+ * this were not the case, the string could contain a matching quote that
+ * would escape from the style attribute).
+ *
+ * Values of this type must be composable, i.e. for any two values
+ * {@code style1} and {@code style2} of this type,
+ * {@code goog.html.SafeStyle.unwrap(style1) +
+ * goog.html.SafeStyle.unwrap(style2)} must itself be a value that satisfies
+ * the SafeStyle type constraint. This requirement implies that for any value
+ * {@code style} of this type, {@code goog.html.SafeStyle.unwrap(style)} must
+ * not end in a "property value" or "property name" context. For example,
+ * a value of {@code background:url("} or {@code font-} would not satisfy the
+ * SafeStyle contract. This is because concatenating such strings with a
+ * second value that itself does not contain unsafe CSS can result in an
+ * overall string that does. For example, if {@code javascript:evil())"} is
+ * appended to {@code background:url("}, the resulting string may result in
+ * the execution of a malicious script.
+ *
+ * TODO(user): Consider whether we should implement UTF-8 interchange
+ * validity checks and blacklisting of newlines (including Unicode ones) and
+ * other whitespace characters (\t, \f). Document here if so and also update
+ * SafeStyle.fromConstant().
+ *
+ * The following example values comply with this type's contract:
+ * <ul>
+ *   <li><pre>width: 1em;</pre>
+ *   <li><pre>height:1em;</pre>
+ *   <li><pre>width: 1em;height: 1em;</pre>
+ *   <li><pre>background:url('http://url');</pre>
+ * </ul>
+ * In addition, the empty string is safe for use in a CSS attribute.
+ *
+ * The following example values do NOT comply with this type's contract:
+ * <ul>
+ *   <li><pre>background: red</pre> (missing a trailing semi-colon)
+ *   <li><pre>background:</pre> (missing a value and a trailing semi-colon)
+ *   <li><pre>1em</pre> (missing an attribute name, which provides context for
+ *       the value)
+ * </ul>
+ *
+ * @see goog.html.SafeStyle#create
+ * @see goog.html.SafeStyle#fromConstant
+ * @see http://www.w3.org/TR/css3-syntax/
+ * @constructor
+ * @final
+ * @struct
+ * @implements {goog.string.TypedString}
+ */
+goog.html.SafeStyle = function() {
+  /**
+   * The contained value of this SafeStyle.  The field has a purposely
+   * ugly name to make (non-compiled) code that attempts to directly access this
+   * field stand out.
+   * @private {string}
+   */
+  this.privateDoNotAccessOrElseSafeStyleWrappedValue_ = '';
+
+  /**
+   * A type marker used to implement additional run-time type checking.
+   * @see goog.html.SafeStyle#unwrap
+   * @const
+   * @private
+   */
+  this.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
+      goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
+};
+
+
+/**
+ * @override
+ * @const
+ */
+goog.html.SafeStyle.prototype.implementsGoogStringTypedString = true;
+
+
+/**
+ * Type marker for the SafeStyle type, used to implement additional
+ * run-time type checking.
+ * @const
+ * @private
+ */
+goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
+
+
+/**
+ * Creates a SafeStyle object from a compile-time constant string.
+ *
+ * {@code style} should be in the format
+ * {@code name: value; [name: value; ...]} and must not have any < or >
+ * characters in it. This is so that SafeStyle's contract is preserved,
+ * allowing the SafeStyle to correctly be interpreted as a sequence of CSS
+ * declarations and without affecting the syntactic structure of any
+ * surrounding CSS and HTML.
+ *
+ * This method performs basic sanity checks on the format of {@code style}
+ * but does not constrain the format of {@code name} and {@code value}, except
+ * for disallowing tag characters.
+ *
+ * @param {!goog.string.Const} style A compile-time-constant string from which
+ *     to create a SafeStyle.
+ * @return {!goog.html.SafeStyle} A SafeStyle object initialized to
+ *     {@code style}.
+ */
+goog.html.SafeStyle.fromConstant = function(style) {
+  var styleString = goog.string.Const.unwrap(style);
+  if (styleString.length === 0) {
+    return goog.html.SafeStyle.EMPTY;
+  }
+  goog.html.SafeStyle.checkStyle_(styleString);
+  goog.asserts.assert(goog.string.endsWith(styleString, ';'),
+      'Last character of style string is not \';\': ' + styleString);
+  goog.asserts.assert(goog.string.contains(styleString, ':'),
+      'Style string must contain at least one \':\', to ' +
+      'specify a "name: value" pair: ' + styleString);
+  return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(
+      styleString);
+};
+
+
+/**
+ * Checks if the style definition is valid.
+ * @param {string} style
+ * @private
+ */
+goog.html.SafeStyle.checkStyle_ = function(style) {
+  goog.asserts.assert(!/[<>]/.test(style),
+      'Forbidden characters in style string: ' + style);
+};
+
+
+/**
+ * Returns this SafeStyle's value as a string.
+ *
+ * IMPORTANT: In code where it is security relevant that an object's type is
+ * indeed {@code SafeStyle}, use {@code goog.html.SafeStyle.unwrap} instead of
+ * this method. If in doubt, assume that it's security relevant. In particular,
+ * note that goog.html functions which return a goog.html type do not guarantee
+ * the returned instance is of the right type. For example:
+ *
+ * <pre>
+ * var fakeSafeHtml = new String('fake');
+ * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
+ * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
+ * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
+ * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
+ * // instanceof goog.html.SafeHtml.
+ * </pre>
+ *
+ * @see goog.html.SafeStyle#unwrap
+ * @override
+ */
+goog.html.SafeStyle.prototype.getTypedStringValue = function() {
+  return this.privateDoNotAccessOrElseSafeStyleWrappedValue_;
+};
+
+
+if (goog.DEBUG) {
+  /**
+   * Returns a debug string-representation of this value.
+   *
+   * To obtain the actual string value wrapped in a SafeStyle, use
+   * {@code goog.html.SafeStyle.unwrap}.
+   *
+   * @see goog.html.SafeStyle#unwrap
+   * @override
+   */
+  goog.html.SafeStyle.prototype.toString = function() {
+    return 'SafeStyle{' +
+        this.privateDoNotAccessOrElseSafeStyleWrappedValue_ + '}';
+  };
+}
+
+
+/**
+ * Performs a runtime check that the provided object is indeed a
+ * SafeStyle object, and returns its value.
+ *
+ * @param {!goog.html.SafeStyle} safeStyle The object to extract from.
+ * @return {string} The safeStyle object's contained string, unless
+ *     the run-time type check fails. In that case, {@code unwrap} returns an
+ *     innocuous string, or, if assertions are enabled, throws
+ *     {@code goog.asserts.AssertionError}.
+ */
+goog.html.SafeStyle.unwrap = function(safeStyle) {
+  // Perform additional Run-time type-checking to ensure that
+  // safeStyle is indeed an instance of the expected type.  This
+  // provides some additional protection against security bugs due to
+  // application code that disables type checks.
+  // Specifically, the following checks are performed:
+  // 1. The object is an instance of the expected type.
+  // 2. The object is not an instance of a subclass.
+  // 3. The object carries a type marker for the expected type. "Faking" an
+  // object requires a reference to the type marker, which has names intended
+  // to stand out in code reviews.
+  if (safeStyle instanceof goog.html.SafeStyle &&
+      safeStyle.constructor === goog.html.SafeStyle &&
+      safeStyle.SAFE_STYLE_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
+          goog.html.SafeStyle.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
+    return safeStyle.privateDoNotAccessOrElseSafeStyleWrappedValue_;
+  } else {
+    goog.asserts.fail(
+        'expected object of type SafeStyle, got \'' + safeStyle + '\'');
+    return 'type_error:SafeStyle';
+  }
+};
+
+
+/**
+ * Package-internal utility method to create SafeStyle instances.
+ *
+ * @param {string} style The string to initialize the SafeStyle object with.
+ * @return {!goog.html.SafeStyle} The initialized SafeStyle object.
+ * @package
+ */
+goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse =
+    function(style) {
+  return new goog.html.SafeStyle().initSecurityPrivateDoNotAccessOrElse_(style);
+};
+
+
+/**
+ * Called from createSafeStyleSecurityPrivateDoNotAccessOrElse(). This
+ * method exists only so that the compiler can dead code eliminate static
+ * fields (like EMPTY) when they're not accessed.
+ * @param {string} style
+ * @return {!goog.html.SafeStyle}
+ * @private
+ */
+goog.html.SafeStyle.prototype.initSecurityPrivateDoNotAccessOrElse_ = function(
+    style) {
+  this.privateDoNotAccessOrElseSafeStyleWrappedValue_ = style;
+  return this;
+};
+
+
+/**
+ * A SafeStyle instance corresponding to the empty string.
+ * @const {!goog.html.SafeStyle}
+ */
+goog.html.SafeStyle.EMPTY =
+    goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse('');
+
+
+/**
+ * The innocuous string generated by goog.html.SafeUrl.create when passed
+ * an unsafe value.
+ * @const {string}
+ */
+goog.html.SafeStyle.INNOCUOUS_STRING = 'zClosurez';
+
+
+/**
+ * Mapping of property names to their values.
+ * @typedef {!Object<string, goog.string.Const|string>}
+ */
+goog.html.SafeStyle.PropertyMap;
+
+
+/**
+ * Creates a new SafeStyle object from the properties specified in the map.
+ * @param {goog.html.SafeStyle.PropertyMap} map Mapping of property names to
+ *     their values, for example {'margin': '1px'}. Names must consist of
+ *     [-_a-zA-Z0-9]. Values might be strings consisting of
+ *     [-,.'"%_!# a-zA-Z0-9], where " and ' must be properly balanced.
+ *     Other values must be wrapped in goog.string.Const. Null value causes
+ *     skipping the property.
+ * @return {!goog.html.SafeStyle}
+ * @throws {Error} If invalid name is provided.
+ * @throws {goog.asserts.AssertionError} If invalid value is provided. With
+ *     disabled assertions, invalid value is replaced by
+ *     goog.html.SafeStyle.INNOCUOUS_STRING.
+ */
+goog.html.SafeStyle.create = function(map) {
+  var style = '';
+  for (var name in map) {
+    if (!/^[-_a-zA-Z0-9]+$/.test(name)) {
+      throw Error('Name allows only [-_a-zA-Z0-9], got: ' + name);
+    }
+    var value = map[name];
+    if (value == null) {
+      continue;
+    }
+    if (value instanceof goog.string.Const) {
+      value = goog.string.Const.unwrap(value);
+      // These characters can be used to change context and we don't want that
+      // even with const values.
+      goog.asserts.assert(!/[{;}]/.test(value), 'Value does not allow [{;}].');
+    } else if (!goog.html.SafeStyle.VALUE_RE_.test(value)) {
+      goog.asserts.fail(
+          'String value allows only [-,."\'%_!# a-zA-Z0-9], got: ' + value);
+      value = goog.html.SafeStyle.INNOCUOUS_STRING;
+    } else if (!goog.html.SafeStyle.hasBalancedQuotes_(value)) {
+      goog.asserts.fail('String value requires balanced quotes, got: ' + value);
+      value = goog.html.SafeStyle.INNOCUOUS_STRING;
+    }
+    style += name + ':' + value + ';';
+  }
+  if (!style) {
+    return goog.html.SafeStyle.EMPTY;
+  }
+  goog.html.SafeStyle.checkStyle_(style);
+  return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(
+      style);
+};
+
+
+/**
+ * Checks that quotes (" and ') are properly balanced inside a string. Assumes
+ * that neither escape (\) nor any other character that could result in
+ * breaking out of a string parsing context are allowed;
+ * see http://www.w3.org/TR/css3-syntax/#string-token-diagram.
+ * @param {string} value Untrusted CSS property value.
+ * @return {boolean} True if property value is safe with respect to quote
+ *     balancedness.
+ * @private
+ */
+goog.html.SafeStyle.hasBalancedQuotes_ = function(value) {
+  var outsideSingle = true;
+  var outsideDouble = true;
+  for (var i = 0; i < value.length; i++) {
+    var c = value.charAt(i);
+    if (c == "'" && outsideDouble) {
+      outsideSingle = !outsideSingle;
+    } else if (c == '"' && outsideSingle) {
+      outsideDouble = !outsideDouble;
+    }
+  }
+  return outsideSingle && outsideDouble;
+};
+
+
+// Keep in sync with the error string in create().
+/**
+ * Regular expression for safe values.
+ *
+ * Quotes (" and ') are allowed, but a check must be done elsewhere to ensure
+ * they're balanced.
+ *
+ * ',' allows multiple values to be assigned to the same property
+ * (e.g. background-attachment or font-family) and hence could allow
+ * multiple values to get injected, but that should pose no risk of XSS.
+ * @const {!RegExp}
+ * @private
+ */
+goog.html.SafeStyle.VALUE_RE_ = /^[-,."'%_!# a-zA-Z0-9]+$/;
+
+
+/**
+ * Creates a new SafeStyle object by concatenating the values.
+ * @param {...(!goog.html.SafeStyle|!Array<!goog.html.SafeStyle>)} var_args
+ *     SafeStyles to concatenate.
+ * @return {!goog.html.SafeStyle}
+ */
+goog.html.SafeStyle.concat = function(var_args) {
+  var style = '';
+
+  /**
+   * @param {!goog.html.SafeStyle|!Array<!goog.html.SafeStyle>} argument
+   */
+  var addArgument = function(argument) {
+    if (goog.isArray(argument)) {
+      goog.array.forEach(argument, addArgument);
+    } else {
+      style += goog.html.SafeStyle.unwrap(argument);
+    }
+  };
+
+  goog.array.forEach(arguments, addArgument);
+  if (!style) {
+    return goog.html.SafeStyle.EMPTY;
+  }
+  return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(
+      style);
+};


[35/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/sprite.png
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/sprite.png b/externs/GCL/externs/goog/demos/emoji/sprite.png
new file mode 100644
index 0000000..f16efa9
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/sprite.png differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/sprite2.png
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/sprite2.png b/externs/GCL/externs/goog/demos/emoji/sprite2.png
new file mode 100644
index 0000000..399d524
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/sprite2.png differ

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/emoji/unknown.gif
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/emoji/unknown.gif b/externs/GCL/externs/goog/demos/emoji/unknown.gif
new file mode 100644
index 0000000..7f0b804
Binary files /dev/null and b/externs/GCL/externs/goog/demos/emoji/unknown.gif differ


[09/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/vmlelement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/vmlelement.js b/externs/GCL/externs/goog/graphics/vmlelement.js
new file mode 100644
index 0000000..9e72b13
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/vmlelement.js
@@ -0,0 +1,438 @@
+// 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 Thin wrappers around the DOM element returned from
+ * the different draw methods of the graphics. This is the VML implementation.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+goog.provide('goog.graphics.VmlEllipseElement');
+goog.provide('goog.graphics.VmlGroupElement');
+goog.provide('goog.graphics.VmlImageElement');
+goog.provide('goog.graphics.VmlPathElement');
+goog.provide('goog.graphics.VmlRectElement');
+goog.provide('goog.graphics.VmlTextElement');
+
+
+goog.require('goog.dom');
+goog.require('goog.graphics.EllipseElement');
+goog.require('goog.graphics.GroupElement');
+goog.require('goog.graphics.ImageElement');
+goog.require('goog.graphics.PathElement');
+goog.require('goog.graphics.RectElement');
+goog.require('goog.graphics.TextElement');
+
+
+/**
+ * Returns the VML element corresponding to this object.  This method is added
+ * to several classes below.  Note that the return value of this method may
+ * change frequently in IE8, so it should not be cached externally.
+ * @return {Element} The VML element corresponding to this object.
+ * @this {goog.graphics.VmlGroupElement|goog.graphics.VmlEllipseElement|
+ *     goog.graphics.VmlRectElement|goog.graphics.VmlPathElement|
+ *     goog.graphics.VmlTextElement|goog.graphics.VmlImageElement}
+ * @private
+ */
+goog.graphics.vmlGetElement_ = function() {
+  this.element_ = this.getGraphics().getVmlElement(this.id_) || this.element_;
+  return this.element_;
+};
+
+
+
+/**
+ * Thin wrapper for VML group elements.
+ * This is an implementation of the goog.graphics.GroupElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.VmlGraphics} graphics The graphics creating
+ *     this element.
+ * @constructor
+ * @extends {goog.graphics.GroupElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.VmlGroupElement = function(element, graphics) {
+  this.id_ = element.id;
+  goog.graphics.GroupElement.call(this, element, graphics);
+};
+goog.inherits(goog.graphics.VmlGroupElement, goog.graphics.GroupElement);
+
+
+/** @override */
+goog.graphics.VmlGroupElement.prototype.getElement =
+    goog.graphics.vmlGetElement_;
+
+
+/**
+ * Remove all drawing elements from the group.
+ * @override
+ */
+goog.graphics.VmlGroupElement.prototype.clear = function() {
+  goog.dom.removeChildren(this.getElement());
+};
+
+
+/**
+ * @return {boolean} True if this group is the root canvas element.
+ * @private
+ */
+goog.graphics.VmlGroupElement.prototype.isRootElement_ = function() {
+  return this.getGraphics().getCanvasElement() == this;
+};
+
+
+/**
+ * Set the size of the group element.
+ * @param {number|string} width The width of the group element.
+ * @param {number|string} height The height of the group element.
+ * @override
+ */
+goog.graphics.VmlGroupElement.prototype.setSize = function(width, height) {
+  var element = this.getElement();
+
+  var style = element.style;
+  style.width = /** @suppress {missingRequire} */ (
+      goog.graphics.VmlGraphics.toSizePx(width));
+  style.height = /** @suppress {missingRequire} */ (
+      goog.graphics.VmlGraphics.toSizePx(height));
+
+  element.coordsize = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toSizeCoord(width) +
+      ' ' +
+      /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toSizeCoord(height);
+
+  // Don't overwrite the root element's origin.
+  if (!this.isRootElement_()) {
+    element.coordorigin = '0 0';
+  }
+};
+
+
+
+/**
+ * Thin wrapper for VML ellipse elements.
+ * This is an implementation of the goog.graphics.EllipseElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.VmlGraphics} graphics  The graphics creating
+ *     this element.
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @param {number} rx Radius length for the x-axis.
+ * @param {number} ry Radius length for the y-axis.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.EllipseElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.VmlEllipseElement = function(element, graphics,
+    cx, cy, rx, ry, stroke, fill) {
+  this.id_ = element.id;
+
+  goog.graphics.EllipseElement.call(this, element, graphics, stroke, fill);
+
+  // Store center and radius for future calls to setRadius or setCenter.
+
+  /**
+   * X coordinate of the ellipse center.
+   * @type {number}
+   */
+  this.cx = cx;
+
+
+  /**
+   * Y coordinate of the ellipse center.
+   * @type {number}
+   */
+  this.cy = cy;
+
+
+  /**
+   * Radius length for the x-axis.
+   * @type {number}
+   */
+  this.rx = rx;
+
+
+  /**
+   * Radius length for the y-axis.
+   * @type {number}
+   */
+  this.ry = ry;
+};
+goog.inherits(goog.graphics.VmlEllipseElement, goog.graphics.EllipseElement);
+
+
+/** @override */
+goog.graphics.VmlEllipseElement.prototype.getElement =
+    goog.graphics.vmlGetElement_;
+
+
+/**
+ * Update the center point of the ellipse.
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @override
+ */
+goog.graphics.VmlEllipseElement.prototype.setCenter = function(cx, cy) {
+  this.cx = cx;
+  this.cy = cy;
+  /** @suppress {missingRequire} */
+  goog.graphics.VmlGraphics.setPositionAndSize(this.getElement(),
+      cx - this.rx, cy - this.ry, this.rx * 2, this.ry * 2);
+};
+
+
+/**
+ * Update the radius of the ellipse.
+ * @param {number} rx Center X coordinate.
+ * @param {number} ry Center Y coordinate.
+ * @override
+ */
+goog.graphics.VmlEllipseElement.prototype.setRadius = function(rx, ry) {
+  this.rx = rx;
+  this.ry = ry;
+  /** @suppress {missingRequire} */
+  goog.graphics.VmlGraphics.setPositionAndSize(this.getElement(),
+      this.cx - rx, this.cy - ry, rx * 2, ry * 2);
+};
+
+
+
+/**
+ * Thin wrapper for VML rectangle elements.
+ * This is an implementation of the goog.graphics.RectElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.VmlGraphics} graphics The graphics creating
+ *     this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.RectElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.VmlRectElement = function(element, graphics, stroke, fill) {
+  this.id_ = element.id;
+  goog.graphics.RectElement.call(this, element, graphics, stroke, fill);
+};
+goog.inherits(goog.graphics.VmlRectElement, goog.graphics.RectElement);
+
+
+/** @override */
+goog.graphics.VmlRectElement.prototype.getElement =
+    goog.graphics.vmlGetElement_;
+
+
+/**
+ * Update the position of the rectangle.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @override
+ */
+goog.graphics.VmlRectElement.prototype.setPosition = function(x, y) {
+  var style = this.getElement().style;
+
+  style.left = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toPosPx(x);
+  style.top = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toPosPx(y);
+};
+
+
+/**
+ * Update the size of the rectangle.
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @override
+ */
+goog.graphics.VmlRectElement.prototype.setSize = function(width, height) {
+  var style = this.getElement().style;
+  style.width = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toSizePx(width);
+  style.height = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toSizePx(height);
+};
+
+
+
+/**
+ * Thin wrapper for VML path elements.
+ * This is an implementation of the goog.graphics.PathElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.VmlGraphics} graphics The graphics creating
+ *     this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.PathElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.VmlPathElement = function(element, graphics, stroke, fill) {
+  this.id_ = element.id;
+  goog.graphics.PathElement.call(this, element, graphics, stroke, fill);
+};
+goog.inherits(goog.graphics.VmlPathElement, goog.graphics.PathElement);
+
+
+/** @override */
+goog.graphics.VmlPathElement.prototype.getElement =
+    goog.graphics.vmlGetElement_;
+
+
+/**
+ * Update the underlying path.
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @override
+ */
+goog.graphics.VmlPathElement.prototype.setPath = function(path) {
+  /** @suppress {missingRequire} */
+  goog.graphics.VmlGraphics.setAttribute(
+      this.getElement(), 'path',
+      /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.getVmlPath(path));
+};
+
+
+
+/**
+ * Thin wrapper for VML text elements.
+ * This is an implementation of the goog.graphics.TextElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.VmlGraphics} graphics The graphics creating
+ *     this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.TextElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.VmlTextElement = function(element, graphics, stroke, fill) {
+  this.id_ = element.id;
+  goog.graphics.TextElement.call(this, element, graphics, stroke, fill);
+};
+goog.inherits(goog.graphics.VmlTextElement, goog.graphics.TextElement);
+
+
+/** @override */
+goog.graphics.VmlTextElement.prototype.getElement =
+    goog.graphics.vmlGetElement_;
+
+
+/**
+ * Update the displayed text of the element.
+ * @param {string} text The text to draw.
+ * @override
+ */
+goog.graphics.VmlTextElement.prototype.setText = function(text) {
+  /** @suppress {missingRequire} */
+  goog.graphics.VmlGraphics.setAttribute(this.getElement().childNodes[1],
+      'string', text);
+};
+
+
+
+/**
+ * Thin wrapper for VML image elements.
+ * This is an implementation of the goog.graphics.ImageElement interface.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.VmlGraphics} graphics The graphics creating
+ *     this element.
+ * @constructor
+ * @extends {goog.graphics.ImageElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.VmlImageElement = function(element, graphics) {
+  this.id_ = element.id;
+  goog.graphics.ImageElement.call(this, element, graphics);
+};
+goog.inherits(goog.graphics.VmlImageElement, goog.graphics.ImageElement);
+
+
+/** @override */
+goog.graphics.VmlImageElement.prototype.getElement =
+    goog.graphics.vmlGetElement_;
+
+
+/**
+ * Update the position of the image.
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @override
+ */
+goog.graphics.VmlImageElement.prototype.setPosition = function(x, y) {
+  var style = this.getElement().style;
+
+  style.left = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toPosPx(x);
+  style.top = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toPosPx(y);
+};
+
+
+/**
+ * Update the size of the image.
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @override
+ */
+goog.graphics.VmlImageElement.prototype.setSize = function(width, height) {
+  var style = this.getElement().style;
+  style.width = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toPosPx(width);
+  style.height = /** @suppress {missingRequire} */
+      goog.graphics.VmlGraphics.toPosPx(height);
+};
+
+
+/**
+ * Update the source of the image.
+ * @param {string} src Source of the image.
+ * @override
+ */
+goog.graphics.VmlImageElement.prototype.setSource = function(src) {
+  /** @suppress {missingRequire} */
+  goog.graphics.VmlGraphics.setAttribute(this.getElement(), 'src', src);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/vmlgraphics.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/vmlgraphics.js b/externs/GCL/externs/goog/graphics/vmlgraphics.js
new file mode 100644
index 0000000..5e0cd66
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/vmlgraphics.js
@@ -0,0 +1,948 @@
+// 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 VmlGraphics sub class that uses VML to draw the graphics.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.VmlGraphics');
+
+
+goog.require('goog.array');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.safe');
+goog.require('goog.events');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventType');
+goog.require('goog.graphics.AbstractGraphics');
+goog.require('goog.graphics.LinearGradient');
+goog.require('goog.graphics.Path');
+goog.require('goog.graphics.SolidFill');
+goog.require('goog.graphics.VmlEllipseElement');
+goog.require('goog.graphics.VmlGroupElement');
+goog.require('goog.graphics.VmlImageElement');
+goog.require('goog.graphics.VmlPathElement');
+goog.require('goog.graphics.VmlRectElement');
+goog.require('goog.graphics.VmlTextElement');
+goog.require('goog.html.uncheckedconversions');
+goog.require('goog.math');
+goog.require('goog.math.Size');
+goog.require('goog.string');
+goog.require('goog.string.Const');
+goog.require('goog.style');
+
+
+
+/**
+ * A Graphics implementation for drawing using VML.
+ * @param {string|number} width The (non-zero) width in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {string|number} height The (non-zero) height in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {?number=} opt_coordWidth The coordinate width - if
+ *     omitted or null, defaults to same as width.
+ * @param {?number=} opt_coordHeight The coordinate height - if
+ *     omitted or null, defaults to same as height.
+ * @param {goog.dom.DomHelper=} opt_domHelper The DOM helper object for the
+ *     document we want to render in.
+ * @constructor
+ * @extends {goog.graphics.AbstractGraphics}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.VmlGraphics = function(width, height,
+                                     opt_coordWidth, opt_coordHeight,
+                                     opt_domHelper) {
+  goog.graphics.AbstractGraphics.call(this, width, height,
+                                      opt_coordWidth, opt_coordHeight,
+                                      opt_domHelper);
+  this.handler_ = new goog.events.EventHandler(this);
+  this.registerDisposable(this.handler_);
+};
+goog.inherits(goog.graphics.VmlGraphics, goog.graphics.AbstractGraphics);
+
+
+/**
+ * The prefix to use for VML elements
+ * @private
+ * @type {string}
+ */
+goog.graphics.VmlGraphics.VML_PREFIX_ = 'g_vml_';
+
+
+/**
+ * The VML namespace URN
+ * @private
+ * @type {string}
+ */
+goog.graphics.VmlGraphics.VML_NS_ = 'urn:schemas-microsoft-com:vml';
+
+
+/**
+ * The VML behavior URL.
+ * @private
+ * @type {string}
+ */
+goog.graphics.VmlGraphics.VML_IMPORT_ = '#default#VML';
+
+
+/**
+ * Whether the document is using IE8 standards mode, and therefore needs hacks.
+ * @private
+ * @type {boolean}
+ */
+goog.graphics.VmlGraphics.IE8_MODE_ =
+    goog.global.document && goog.global.document.documentMode &&
+    goog.global.document.documentMode >= 8;
+
+
+/**
+ * The coordinate multiplier to allow sub-pixel rendering
+ * @type {number}
+ */
+goog.graphics.VmlGraphics.COORD_MULTIPLIER = 100;
+
+
+/**
+ * Converts the given size to a css size.  If it is a percentage, leaves it
+ * alone.  Otherwise assumes px.
+ *
+ * @param {number|string} size The size to use.
+ * @return {string} The position adjusted for COORD_MULTIPLIER.
+ */
+goog.graphics.VmlGraphics.toCssSize = function(size) {
+  return goog.isString(size) && goog.string.endsWith(size, '%') ?
+         size : parseFloat(size.toString()) + 'px';
+};
+
+
+/**
+ * Multiplies positioning coordinates by COORD_MULTIPLIER to allow sub-pixel
+ * coordinates.  Also adds a half pixel offset to match SVG.
+ *
+ * This function is internal for the VML supporting classes, and
+ * should not be used externally.
+ *
+ * @param {number|string} number A position in pixels.
+ * @return {number} The position adjusted for COORD_MULTIPLIER.
+ */
+goog.graphics.VmlGraphics.toPosCoord = function(number) {
+  return Math.round((parseFloat(number.toString()) - 0.5) *
+      goog.graphics.VmlGraphics.COORD_MULTIPLIER);
+};
+
+
+/**
+ * Add a "px" suffix to a number of pixels, and multiplies all coordinates by
+ * COORD_MULTIPLIER to allow sub-pixel coordinates.
+ *
+ * This function is internal for the VML supporting classes, and
+ * should not be used externally.
+ *
+ * @param {number|string} number A position in pixels.
+ * @return {string} The position with suffix 'px'.
+ */
+goog.graphics.VmlGraphics.toPosPx = function(number) {
+  return goog.graphics.VmlGraphics.toPosCoord(number) + 'px';
+};
+
+
+/**
+ * Multiplies the width or height coordinate by COORD_MULTIPLIER to allow
+ * sub-pixel coordinates.
+ *
+ * This function is internal for the VML supporting classes, and
+ * should not be used externally.
+ *
+ * @param {string|number} number A size in units.
+ * @return {number} The size multiplied by the correct factor.
+ */
+goog.graphics.VmlGraphics.toSizeCoord = function(number) {
+  return Math.round(parseFloat(number.toString()) *
+      goog.graphics.VmlGraphics.COORD_MULTIPLIER);
+};
+
+
+/**
+ * Add a "px" suffix to a number of pixels, and multiplies all coordinates by
+ * COORD_MULTIPLIER to allow sub-pixel coordinates.
+ *
+ * This function is internal for the VML supporting classes, and
+ * should not be used externally.
+ *
+ * @param {number|string} number A size in pixels.
+ * @return {string} The size with suffix 'px'.
+ */
+goog.graphics.VmlGraphics.toSizePx = function(number) {
+  return goog.graphics.VmlGraphics.toSizeCoord(number) + 'px';
+};
+
+
+/**
+ * Sets an attribute on the given VML element, in the way best suited to the
+ * current version of IE.  Should only be used in the goog.graphics package.
+ * @param {Element} element The element to set an attribute
+ *     on.
+ * @param {string} name The name of the attribute to set.
+ * @param {string} value The value to set it to.
+ */
+goog.graphics.VmlGraphics.setAttribute = function(element, name, value) {
+  if (goog.graphics.VmlGraphics.IE8_MODE_) {
+    element[name] = value;
+  } else {
+    element.setAttribute(name, value);
+  }
+};
+
+
+/**
+ * Event handler.
+ * @type {goog.events.EventHandler}
+ * @private
+ */
+goog.graphics.VmlGraphics.prototype.handler_;
+
+
+/**
+ * Creates a VML element. Used internally and by different VML classes.
+ * @param {string} tagName The type of element to create.
+ * @return {!Element} The created element.
+ */
+goog.graphics.VmlGraphics.prototype.createVmlElement = function(tagName) {
+  var element =
+      this.dom_.createElement(goog.graphics.VmlGraphics.VML_PREFIX_ + ':' +
+                              tagName);
+  element.id = goog.string.createUniqueString();
+  return element;
+};
+
+
+/**
+ * Returns the VML element with the given id that is a child of this graphics
+ * object.
+ * Should be considered package private, and not used externally.
+ * @param {string} id The element id to find.
+ * @return {Element} The element with the given id, or null if none is found.
+ */
+goog.graphics.VmlGraphics.prototype.getVmlElement = function(id) {
+  return this.dom_.getElement(id);
+};
+
+
+/**
+ * Resets the graphics so they will display properly on IE8.  Noop in older
+ * versions.
+ * @private
+ */
+goog.graphics.VmlGraphics.prototype.updateGraphics_ = function() {
+  if (goog.graphics.VmlGraphics.IE8_MODE_ && this.isInDocument()) {
+    // There's a risk of mXSS here, as the browser is not guaranteed to
+    // return the HTML that was originally written, when innerHTML is read.
+    // However, given that this a deprecated API and affects only IE, it seems
+    // an acceptable risk.
+    var html = goog.html.uncheckedconversions
+        .safeHtmlFromStringKnownToSatisfyTypeContract(
+            goog.string.Const.from('Assign innerHTML to itself'),
+            this.getElement().innerHTML);
+    goog.dom.safe.setInnerHtml(
+        /** @type {!Element} */ (this.getElement()), html);
+  }
+};
+
+
+/**
+ * Appends an element.
+ *
+ * @param {goog.graphics.Element} element The element wrapper.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ * @private
+ */
+goog.graphics.VmlGraphics.prototype.append_ = function(element, opt_group) {
+  var parent = opt_group || this.canvasElement;
+  parent.getElement().appendChild(element.getElement());
+  this.updateGraphics_();
+};
+
+
+/**
+ * Sets the fill for the given element.
+ * @param {goog.graphics.StrokeAndFillElement} element The element wrapper.
+ * @param {goog.graphics.Fill?} fill The fill object.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.setElementFill = function(element, fill) {
+  var vmlElement = element.getElement();
+  goog.graphics.VmlGraphics.removeFill_(vmlElement);
+  if (fill instanceof goog.graphics.SolidFill) {
+    // NOTE(arv): VML does not understand 'transparent' so hard code support
+    // for it.
+    if (fill.getColor() == 'transparent') {
+      vmlElement.filled = false;
+    } else if (fill.getOpacity() != 1) {
+      vmlElement.filled = true;
+      // Set opacity (number 0-1 is translated to percent)
+      var fillNode = this.createVmlElement('fill');
+      fillNode.opacity = Math.round(fill.getOpacity() * 100) + '%';
+      fillNode.color = fill.getColor();
+      vmlElement.appendChild(fillNode);
+    } else {
+      vmlElement.filled = true;
+      vmlElement.fillcolor = fill.getColor();
+    }
+  } else if (fill instanceof goog.graphics.LinearGradient) {
+    vmlElement.filled = true;
+    // Add a 'fill' element
+    var gradient = this.createVmlElement('fill');
+    gradient.color = fill.getColor1();
+    gradient.color2 = fill.getColor2();
+    if (goog.isNumber(fill.getOpacity1())) {
+      gradient.opacity = fill.getOpacity1();
+    }
+    if (goog.isNumber(fill.getOpacity2())) {
+      gradient.opacity2 = fill.getOpacity2();
+    }
+    var angle = goog.math.angle(fill.getX1(), fill.getY1(),
+        fill.getX2(), fill.getY2());
+    // Our angles start from 0 to the right, and grow clockwise.
+    // MSIE starts from 0 to top, and grows anti-clockwise.
+    angle = Math.round(goog.math.standardAngle(270 - angle));
+    gradient.angle = angle;
+    gradient.type = 'gradient';
+    vmlElement.appendChild(gradient);
+  } else {
+    vmlElement.filled = false;
+  }
+  this.updateGraphics_();
+};
+
+
+/**
+ * Sets the stroke for the given element.
+ * @param {goog.graphics.StrokeAndFillElement} element The element wrapper.
+ * @param {goog.graphics.Stroke?} stroke The stroke object.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.setElementStroke = function(element,
+    stroke) {
+  var vmlElement = element.getElement();
+  if (stroke) {
+    vmlElement.stroked = true;
+
+    var width = stroke.getWidth();
+    if (goog.isString(width) && width.indexOf('px') == -1) {
+      width = parseFloat(width);
+    } else {
+      width = width * this.getPixelScaleX();
+    }
+
+    var strokeElement = vmlElement.getElementsByTagName('stroke')[0];
+    if (!strokeElement) {
+      strokeElement = strokeElement || this.createVmlElement('stroke');
+      vmlElement.appendChild(strokeElement);
+    }
+    strokeElement.opacity = stroke.getOpacity();
+    strokeElement.weight = width + 'px';
+    strokeElement.color = stroke.getColor();
+  } else {
+    vmlElement.stroked = false;
+  }
+  this.updateGraphics_();
+};
+
+
+/**
+ * Set the translation and rotation of an element.
+ *
+ * If a more general affine transform is needed than this provides
+ * (e.g. skew and scale) then use setElementAffineTransform.
+ * @param {number} x The x coordinate of the translation transform.
+ * @param {number} y The y coordinate of the translation transform.
+ * @param {number} angle The angle of the rotation transform.
+ * @param {number} centerX The horizontal center of the rotation transform.
+ * @param {number} centerY The vertical center of the rotation transform.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.setElementTransform = function(element, x,
+    y, angle, centerX, centerY) {
+  var el = element.getElement();
+
+  el.style.left = goog.graphics.VmlGraphics.toPosPx(x);
+  el.style.top = goog.graphics.VmlGraphics.toPosPx(y);
+  if (angle || el.rotation) {
+    el.rotation = angle;
+    el.coordsize = goog.graphics.VmlGraphics.toSizeCoord(centerX * 2) + ' ' +
+        goog.graphics.VmlGraphics.toSizeCoord(centerY * 2);
+  }
+};
+
+
+/**
+ * Set the transformation of an element.
+ * @param {!goog.graphics.Element} element The element wrapper.
+ * @param {!goog.graphics.AffineTransform} affineTransform The
+ *     transformation applied to this element.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.setElementAffineTransform = function(
+    element, affineTransform) {
+  var t = affineTransform;
+  var vmlElement = element.getElement();
+  goog.graphics.VmlGraphics.removeSkew_(vmlElement);
+  var skewNode = this.createVmlElement('skew');
+  skewNode.on = 'true';
+  // Move the transform origin to 0px,0px of the graphics.
+  // In VML, 0,0 means the center of the element, -0.5,-0.5 left top conner of
+  // it.
+  skewNode.origin =
+      (-vmlElement.style.pixelLeft / vmlElement.style.pixelWidth - 0.5) + ',' +
+      (-vmlElement.style.pixelTop / vmlElement.style.pixelHeight - 0.5);
+  skewNode.offset = t.getTranslateX().toFixed(1) + 'px,' +
+                    t.getTranslateY().toFixed(1) + 'px';
+  skewNode.matrix = [t.getScaleX().toFixed(6), t.getShearX().toFixed(6),
+                     t.getShearY().toFixed(6), t.getScaleY().toFixed(6),
+                     0, 0].join(',');
+  vmlElement.appendChild(skewNode);
+  this.updateGraphics_();
+};
+
+
+/**
+ * Removes the skew information from a dom element.
+ * @param {Element} element DOM element.
+ * @private
+ */
+goog.graphics.VmlGraphics.removeSkew_ = function(element) {
+  goog.array.forEach(element.childNodes, function(child) {
+    if (child.tagName == 'skew') {
+      element.removeChild(child);
+    }
+  });
+};
+
+
+/**
+ * Removes the fill information from a dom element.
+ * @param {Element} element DOM element.
+ * @private
+ */
+goog.graphics.VmlGraphics.removeFill_ = function(element) {
+  element.fillcolor = '';
+  goog.array.forEach(element.childNodes, function(child) {
+    if (child.tagName == 'fill') {
+      element.removeChild(child);
+    }
+  });
+};
+
+
+/**
+ * Set top, left, width and height for an element.
+ * This function is internal for the VML supporting classes, and
+ * should not be used externally.
+ *
+ * @param {Element} element DOM element.
+ * @param {number} left Left ccordinate in pixels.
+ * @param {number} top Top ccordinate in pixels.
+ * @param {number} width Width in pixels.
+ * @param {number} height Height in pixels.
+ */
+goog.graphics.VmlGraphics.setPositionAndSize = function(
+    element, left, top, width, height) {
+  var style = element.style;
+  style.position = 'absolute';
+  style.left = goog.graphics.VmlGraphics.toPosPx(left);
+  style.top = goog.graphics.VmlGraphics.toPosPx(top);
+  style.width = goog.graphics.VmlGraphics.toSizePx(width);
+  style.height = goog.graphics.VmlGraphics.toSizePx(height);
+
+  if (element.tagName == 'shape') {
+    element.coordsize = goog.graphics.VmlGraphics.toSizeCoord(width) + ' ' +
+                        goog.graphics.VmlGraphics.toSizeCoord(height);
+  }
+};
+
+
+/**
+ * Creates an element spanning the surface.
+ *
+ * @param {string} type The type of element to create.
+ * @return {!Element} The created, positioned, and sized element.
+ * @private
+ */
+goog.graphics.VmlGraphics.prototype.createFullSizeElement_ = function(type) {
+  var element = this.createVmlElement(type);
+  var size = this.getCoordSize();
+  goog.graphics.VmlGraphics.setPositionAndSize(element, 0, 0, size.width,
+      size.height);
+  return element;
+};
+
+
+/**
+ * IE magic - if this "no-op" line is not here, the if statement below will
+ * fail intermittently.  The eval is used to prevent the JsCompiler from
+ * stripping this piece of code, which it quite reasonably thinks is doing
+ * nothing. Put it in try-catch block to prevent "Unspecified Error" when
+ * this statement is executed in a defer JS in IE.
+ * More info here:
+ * http://www.mail-archive.com/users@openlayers.org/msg01838.html
+ */
+try {
+  eval('document.namespaces');
+} catch (ex) {}
+
+
+/**
+ * Creates the DOM representation of the graphics area.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.createDom = function() {
+  var doc = this.dom_.getDocument();
+
+  // Add the namespace.
+  if (!doc.namespaces[goog.graphics.VmlGraphics.VML_PREFIX_]) {
+    if (goog.graphics.VmlGraphics.IE8_MODE_) {
+      doc.namespaces.add(goog.graphics.VmlGraphics.VML_PREFIX_,
+                         goog.graphics.VmlGraphics.VML_NS_,
+                         goog.graphics.VmlGraphics.VML_IMPORT_);
+    } else {
+      doc.namespaces.add(goog.graphics.VmlGraphics.VML_PREFIX_,
+                         goog.graphics.VmlGraphics.VML_NS_);
+    }
+
+    // We assume that we only need to add the CSS if the namespace was not
+    // present
+    var ss = doc.createStyleSheet();
+    ss.cssText = goog.graphics.VmlGraphics.VML_PREFIX_ + '\\:*' +
+                 '{behavior:url(#default#VML)}';
+  }
+
+  // Outer a DIV with overflow hidden for clipping.
+  // All inner elements are absolutly positioned on-top of this div.
+  var pixelWidth = this.width;
+  var pixelHeight = this.height;
+  var divElement = this.dom_.createDom(goog.dom.TagName.DIV, {
+    'style': 'overflow:hidden;position:relative;width:' +
+        goog.graphics.VmlGraphics.toCssSize(pixelWidth) + ';height:' +
+        goog.graphics.VmlGraphics.toCssSize(pixelHeight)
+  });
+
+  this.setElementInternal(divElement);
+
+  var group = this.createVmlElement('group');
+  var style = group.style;
+
+  style.position = 'absolute';
+  style.left = style.top = 0;
+  style.width = this.width;
+  style.height = this.height;
+  if (this.coordWidth) {
+    group.coordsize =
+        goog.graphics.VmlGraphics.toSizeCoord(this.coordWidth) + ' ' +
+        goog.graphics.VmlGraphics.toSizeCoord(
+            /** @type {number} */ (this.coordHeight));
+  } else {
+    group.coordsize = goog.graphics.VmlGraphics.toSizeCoord(pixelWidth) + ' ' +
+        goog.graphics.VmlGraphics.toSizeCoord(pixelHeight);
+  }
+
+  if (goog.isDef(this.coordLeft)) {
+    group.coordorigin = goog.graphics.VmlGraphics.toSizeCoord(this.coordLeft) +
+        ' ' + goog.graphics.VmlGraphics.toSizeCoord(this.coordTop);
+  } else {
+    group.coordorigin = '0 0';
+  }
+  divElement.appendChild(group);
+
+  this.canvasElement = new goog.graphics.VmlGroupElement(group, this);
+
+  goog.events.listen(divElement, goog.events.EventType.RESIZE, goog.bind(
+      this.handleContainerResize_, this));
+};
+
+
+/**
+ * Changes the canvas element size to match the container element size.
+ * @private
+ */
+goog.graphics.VmlGraphics.prototype.handleContainerResize_ = function() {
+  var size = goog.style.getSize(this.getElement());
+  var style = this.canvasElement.getElement().style;
+
+  if (size.width) {
+    style.width = size.width + 'px';
+    style.height = size.height + 'px';
+  } else {
+    var current = this.getElement();
+    while (current && current.currentStyle &&
+        current.currentStyle.display != 'none') {
+      current = current.parentNode;
+    }
+    if (current && current.currentStyle) {
+      this.handler_.listen(current, 'propertychange',
+          this.handleContainerResize_);
+    }
+  }
+
+  this.dispatchEvent(goog.events.EventType.RESIZE);
+};
+
+
+/**
+ * Handle property changes on hidden ancestors.
+ * @param {goog.events.BrowserEvent} e The browser event.
+ * @private
+ */
+goog.graphics.VmlGraphics.prototype.handlePropertyChange_ = function(e) {
+  var prop = e.getBrowserEvent().propertyName;
+  if (prop == 'display' || prop == 'className') {
+    this.handler_.unlisten(/** @type {Element} */(e.target),
+        'propertychange', this.handlePropertyChange_);
+    this.handleContainerResize_();
+  }
+};
+
+
+/**
+ * Changes the coordinate system position.
+ * @param {number} left The coordinate system left bound.
+ * @param {number} top The coordinate system top bound.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.setCoordOrigin = function(left, top) {
+  this.coordLeft = left;
+  this.coordTop = top;
+
+  this.canvasElement.getElement().coordorigin =
+      goog.graphics.VmlGraphics.toSizeCoord(this.coordLeft) + ' ' +
+      goog.graphics.VmlGraphics.toSizeCoord(this.coordTop);
+};
+
+
+/**
+ * Changes the coordinate size.
+ * @param {number} coordWidth The coordinate width.
+ * @param {number} coordHeight The coordinate height.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.setCoordSize = function(coordWidth,
+                                                            coordHeight) {
+  goog.graphics.VmlGraphics.superClass_.setCoordSize.apply(this, arguments);
+
+  this.canvasElement.getElement().coordsize =
+      goog.graphics.VmlGraphics.toSizeCoord(coordWidth) + ' ' +
+      goog.graphics.VmlGraphics.toSizeCoord(coordHeight);
+};
+
+
+/**
+ * Change the size of the canvas.
+ * @param {number} pixelWidth The width in pixels.
+ * @param {number} pixelHeight The height in pixels.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.setSize = function(pixelWidth,
+    pixelHeight) {
+  goog.style.setSize(this.getElement(), pixelWidth, pixelHeight);
+};
+
+
+/**
+ * @return {!goog.math.Size} Returns the number of pixels spanned by the
+ *     surface.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.getPixelSize = function() {
+  var el = this.getElement();
+  // The following relies on the fact that the size can never be 0.
+  return new goog.math.Size(el.style.pixelWidth || el.offsetWidth || 1,
+      el.style.pixelHeight || el.offsetHeight || 1);
+};
+
+
+/**
+ * Remove all drawing elements from the graphics.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.clear = function() {
+  this.canvasElement.clear();
+};
+
+
+/**
+ * Draw an ellipse.
+ *
+ * @param {number} cx Center X coordinate.
+ * @param {number} cy Center Y coordinate.
+ * @param {number} rx Radius length for the x-axis.
+ * @param {number} ry Radius length for the y-axis.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.EllipseElement} The newly created element.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.drawEllipse = function(cx, cy, rx, ry,
+    stroke, fill, opt_group) {
+  var element = this.createVmlElement('oval');
+  goog.graphics.VmlGraphics.setPositionAndSize(element, cx - rx, cy - ry,
+      rx * 2, ry * 2);
+  var wrapper = new goog.graphics.VmlEllipseElement(element, this,
+      cx, cy, rx, ry, stroke, fill);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * Draw a rectangle.
+ *
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} width Width of rectangle.
+ * @param {number} height Height of rectangle.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the
+ *    stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.RectElement} The newly created element.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.drawRect = function(x, y, width, height,
+    stroke, fill, opt_group) {
+  var element = this.createVmlElement('rect');
+  goog.graphics.VmlGraphics.setPositionAndSize(element, x, y, width, height);
+  var wrapper = new goog.graphics.VmlRectElement(element, this, stroke, fill);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * Draw an image.
+ *
+ * @param {number} x X coordinate (left).
+ * @param {number} y Y coordinate (top).
+ * @param {number} width Width of image.
+ * @param {number} height Height of image.
+ * @param {string} src Source of the image.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.ImageElement} The newly created element.
+ */
+goog.graphics.VmlGraphics.prototype.drawImage = function(x, y, width, height,
+    src, opt_group) {
+  var element = this.createVmlElement('image');
+  goog.graphics.VmlGraphics.setPositionAndSize(element, x, y, width, height);
+  goog.graphics.VmlGraphics.setAttribute(element, 'src', src);
+  var wrapper = new goog.graphics.VmlImageElement(element, this);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * Draw a text string vertically centered on a given line.
+ *
+ * @param {string} text The text to draw.
+ * @param {number} x1 X coordinate of start of line.
+ * @param {number} y1 Y coordinate of start of line.
+ * @param {number} x2 X coordinate of end of line.
+ * @param {number} y2 Y coordinate of end of line.
+ * @param {?string} align Horizontal alignment: left (default), center, right.
+ * @param {goog.graphics.Font} font Font describing the font properties.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.TextElement} The newly created element.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.drawTextOnLine = function(
+    text, x1, y1, x2, y2, align, font, stroke, fill, opt_group) {
+  var shape = this.createFullSizeElement_('shape');
+
+  var pathElement = this.createVmlElement('path');
+  var path = 'M' + goog.graphics.VmlGraphics.toPosCoord(x1) + ',' +
+             goog.graphics.VmlGraphics.toPosCoord(y1) + 'L' +
+             goog.graphics.VmlGraphics.toPosCoord(x2) + ',' +
+             goog.graphics.VmlGraphics.toPosCoord(y2) + 'E';
+  goog.graphics.VmlGraphics.setAttribute(pathElement, 'v', path);
+  goog.graphics.VmlGraphics.setAttribute(pathElement, 'textpathok', 'true');
+
+  var textPathElement = this.createVmlElement('textpath');
+  textPathElement.setAttribute('on', 'true');
+  var style = textPathElement.style;
+  style.fontSize = font.size * this.getPixelScaleX();
+  style.fontFamily = font.family;
+  if (align != null) {
+    style['v-text-align'] = align;
+  }
+  if (font.bold) {
+    style.fontWeight = 'bold';
+  }
+  if (font.italic) {
+    style.fontStyle = 'italic';
+  }
+  goog.graphics.VmlGraphics.setAttribute(textPathElement, 'string', text);
+
+  shape.appendChild(pathElement);
+  shape.appendChild(textPathElement);
+  var wrapper = new goog.graphics.VmlTextElement(shape, this, stroke, fill);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * Draw a path.
+ *
+ * @param {!goog.graphics.Path} path The path object to draw.
+ * @param {goog.graphics.Stroke?} stroke Stroke object describing the stroke.
+ * @param {goog.graphics.Fill?} fill Fill object describing the fill.
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.PathElement} The newly created element.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.drawPath = function(path, stroke, fill,
+    opt_group) {
+  var element = this.createFullSizeElement_('shape');
+  goog.graphics.VmlGraphics.setAttribute(element, 'path',
+      goog.graphics.VmlGraphics.getVmlPath(path));
+
+  var wrapper = new goog.graphics.VmlPathElement(element, this, stroke, fill);
+  this.append_(wrapper, opt_group);
+  return wrapper;
+};
+
+
+/**
+ * Returns a string representation of a logical path suitable for use in
+ * a VML element.
+ *
+ * @param {goog.graphics.Path} path The logical path.
+ * @return {string} The VML path representation.
+ * @suppress {deprecated} goog.graphics is deprecated.
+ */
+goog.graphics.VmlGraphics.getVmlPath = function(path) {
+  var list = [];
+  path.forEachSegment(function(segment, args) {
+    switch (segment) {
+      case goog.graphics.Path.Segment.MOVETO:
+        list.push('m');
+        Array.prototype.push.apply(list, goog.array.map(args,
+            goog.graphics.VmlGraphics.toSizeCoord));
+        break;
+      case goog.graphics.Path.Segment.LINETO:
+        list.push('l');
+        Array.prototype.push.apply(list, goog.array.map(args,
+            goog.graphics.VmlGraphics.toSizeCoord));
+        break;
+      case goog.graphics.Path.Segment.CURVETO:
+        list.push('c');
+        Array.prototype.push.apply(list, goog.array.map(args,
+            goog.graphics.VmlGraphics.toSizeCoord));
+        break;
+      case goog.graphics.Path.Segment.CLOSE:
+        list.push('x');
+        break;
+      case goog.graphics.Path.Segment.ARCTO:
+        var toAngle = args[2] + args[3];
+        var cx = goog.graphics.VmlGraphics.toSizeCoord(
+            args[4] - goog.math.angleDx(toAngle, args[0]));
+        var cy = goog.graphics.VmlGraphics.toSizeCoord(
+            args[5] - goog.math.angleDy(toAngle, args[1]));
+        var rx = goog.graphics.VmlGraphics.toSizeCoord(args[0]);
+        var ry = goog.graphics.VmlGraphics.toSizeCoord(args[1]);
+        // VML angles are in fd units (see http://www.w3.org/TR/NOTE-VML) and
+        // are positive counter-clockwise.
+        var fromAngle = Math.round(args[2] * -65536);
+        var extent = Math.round(args[3] * -65536);
+        list.push('ae', cx, cy, rx, ry, fromAngle, extent);
+        break;
+    }
+  });
+  return list.join(' ');
+};
+
+
+/**
+ * Create an empty group of drawing elements.
+ *
+ * @param {goog.graphics.GroupElement=} opt_group The group wrapper element
+ *     to append to. If not specified, appends to the main canvas.
+ *
+ * @return {!goog.graphics.GroupElement} The newly created group.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.createGroup = function(opt_group) {
+  var element = this.createFullSizeElement_('group');
+  var parent = opt_group || this.canvasElement;
+  parent.getElement().appendChild(element);
+  return new goog.graphics.VmlGroupElement(element, this);
+};
+
+
+/**
+ * Measure and return the width (in pixels) of a given text string.
+ * Text measurement is needed to make sure a text can fit in the allocated
+ * area. The way text length is measured is by writing it into a div that is
+ * after the visible area, measure the div width, and immediatly erase the
+ * written value.
+ *
+ * @param {string} text The text string to measure.
+ * @param {goog.graphics.Font} font The font object describing the font style.
+ *
+ * @return {number} The width in pixels of the text strings.
+ * @override
+ */
+goog.graphics.VmlGraphics.prototype.getTextWidth = function(text, font) {
+  // TODO(arv): Implement
+  return 0;
+};
+
+
+/** @override */
+goog.graphics.VmlGraphics.prototype.enterDocument = function() {
+  goog.graphics.VmlGraphics.superClass_.enterDocument.call(this);
+  this.handleContainerResize_();
+  this.updateGraphics_();
+};
+
+
+/**
+ * Disposes of the component by removing event handlers, detacing DOM nodes from
+ * the document body, and removing references to them.
+ * @override
+ * @protected
+ */
+goog.graphics.VmlGraphics.prototype.disposeInternal = function() {
+  this.canvasElement = null;
+  goog.graphics.VmlGraphics.superClass_.disposeInternal.call(this);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/history/event.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/history/event.js b/externs/GCL/externs/goog/history/event.js
new file mode 100644
index 0000000..19250df
--- /dev/null
+++ b/externs/GCL/externs/goog/history/event.js
@@ -0,0 +1,55 @@
+// Copyright 2010 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 The event object dispatched when the history changes.
+ *
+ */
+
+
+goog.provide('goog.history.Event');
+
+goog.require('goog.events.Event');
+goog.require('goog.history.EventType');
+
+
+
+/**
+ * Event object dispatched after the history state has changed.
+ * @param {string} token The string identifying the new history state.
+ * @param {boolean} isNavigation True if the event was triggered by a browser
+ *     action, such as forward or back, clicking on a link, editing the URL, or
+ *     calling {@code window.history.(go|back|forward)}.
+ *     False if the token has been changed by a {@code setToken} or
+ *     {@code replaceToken} call.
+ * @constructor
+ * @extends {goog.events.Event}
+ * @final
+ */
+goog.history.Event = function(token, isNavigation) {
+  goog.events.Event.call(this, goog.history.EventType.NAVIGATE);
+
+  /**
+   * The current history state.
+   * @type {string}
+   */
+  this.token = token;
+
+  /**
+   * Whether the event was triggered by browser navigation.
+   * @type {boolean}
+   */
+  this.isNavigation = isNavigation;
+};
+goog.inherits(goog.history.Event, goog.events.Event);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/history/eventtype.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/history/eventtype.js b/externs/GCL/externs/goog/history/eventtype.js
new file mode 100644
index 0000000..4268df3
--- /dev/null
+++ b/externs/GCL/externs/goog/history/eventtype.js
@@ -0,0 +1,30 @@
+// Copyright 2010 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 Event types for goog.history.
+ *
+ */
+
+
+goog.provide('goog.history.EventType');
+
+
+/**
+ * Event types for goog.history.
+ * @enum {string}
+ */
+goog.history.EventType = {
+  NAVIGATE: 'navigate'
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/history/history.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/history/history.js b/externs/GCL/externs/goog/history/history.js
new file mode 100644
index 0000000..af82ba0
--- /dev/null
+++ b/externs/GCL/externs/goog/history/history.js
@@ -0,0 +1,1005 @@
+// 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 Browser history stack management class.
+ *
+ * The goog.History object allows a page to create history state without leaving
+ * the current document. This allows users to, for example, hit the browser's
+ * back button without leaving the current page.
+ *
+ * The history object can be instantiated in one of two modes. In user visible
+ * mode, the current history state is shown in the browser address bar as a
+ * document location fragment (the portion of the URL after the '#'). These
+ * addresses can be bookmarked, copied and pasted into another browser, and
+ * modified directly by the user like any other URL.
+ *
+ * If the history object is created in invisible mode, the user can still
+ * affect the state using the browser forward and back buttons, but the current
+ * state is not displayed in the browser address bar. These states are not
+ * bookmarkable or editable.
+ *
+ * It is possible to use both types of history object on the same page, but not
+ * currently recommended due to browser deficiencies.
+ *
+ * Tested to work in:
+ * <ul>
+ *   <li>Firefox 1.0-4.0
+ *   <li>Internet Explorer 5.5-9.0
+ *   <li>Opera 9+
+ *   <li>Safari 4+
+ * </ul>
+ *
+ * @author brenneman@google.com (Shawn Brenneman)
+ * @see ../demos/history1.html
+ * @see ../demos/history2.html
+ */
+
+/* Some browser specific implementation notes:
+ *
+ * Firefox (through version 2.0.0.1):
+ *
+ * Ideally, navigating inside the hidden iframe could be done using
+ * about:blank#state instead of a real page on the server. Setting the hash on
+ * about:blank creates history entries, but the hash is not recorded and is lost
+ * when the user hits the back button. This is true in Opera as well. A blank
+ * HTML page must be provided for invisible states to be recorded in the iframe
+ * hash.
+ *
+ * After leaving the page with the History object and returning to it (by
+ * hitting the back button from another site), the last state of the iframe is
+ * overwritten. The most recent state is saved in a hidden input field so the
+ * previous state can be restored.
+ *
+ * Firefox does not store the previous value of dynamically generated input
+ * elements. To save the state, the hidden element must be in the HTML document,
+ * either in the original source or added with document.write. If a reference
+ * to the input element is not provided as a constructor argument, then the
+ * history object creates one using document.write, in which case the history
+ * object must be created from a script in the body element of the page.
+ *
+ * Manually editing the address field to a different hash link prevents further
+ * updates to the address bar. The page continues to work as normal, but the
+ * address shown will be incorrect until the page is reloaded.
+ *
+ * NOTE(user): It should be noted that Firefox will URL encode any non-regular
+ * ascii character, along with |space|, ", <, and >, when added to the fragment.
+ * If you expect these characters in your tokens you should consider that
+ * setToken('<b>') would result in the history fragment "%3Cb%3E", and
+ * "esp&eacute;re" would show "esp%E8re".  (IE allows unicode characters in the
+ * fragment)
+ *
+ * TODO(user): Should we encapsulate this escaping into the API for visible
+ * history and encode all characters that aren't supported by Firefox?  It also
+ * needs to be optional so apps can elect to handle the escaping themselves.
+ *
+ *
+ * Internet Explorer (through version 7.0):
+ *
+ * IE does not modify the history stack when the document fragment is changed.
+ * We create history entries instead by using document.open and document.write
+ * into a hidden iframe.
+ *
+ * IE destroys the history stack when navigating from /foo.html#someFragment to
+ * /foo.html. The workaround is to always append the # to the URL. This is
+ * somewhat unfortunate when loading the page without any # specified, because
+ * a second "click" sound will play on load as the fragment is automatically
+ * appended. If the hash is always present, this can be avoided.
+ *
+ * Manually editing the hash in the address bar in IE6 and then hitting the back
+ * button can replace the page with a blank page. This is a Bad User Experience,
+ * but probably not preventable.
+ *
+ * IE also has a bug when the page is loaded via a server redirect, setting
+ * a new hash value on the window location will force a page reload. This will
+ * happen the first time setToken is called with a new token. The only known
+ * workaround is to force a client reload early, for example by setting
+ * window.location.hash = window.location.hash, which will otherwise be a no-op.
+ *
+ * Internet Explorer 8.0, Webkit 532.1 and Gecko 1.9.2:
+ *
+ * IE8 has introduced the support to the HTML5 onhashchange event, which means
+ * we don't have to do any polling to detect fragment changes. Chrome and
+ * Firefox have added it on their newer builds, wekbit 532.1 and gecko 1.9.2.
+ * http://www.w3.org/TR/html5/history.html
+ * NOTE(goto): it is important to note that the document needs to have the
+ * <!DOCTYPE html> tag to enable the IE8 HTML5 mode. If the tag is not present,
+ * IE8 will enter IE7 compatibility mode (which can also be enabled manually).
+ *
+ * Opera (through version 9.02):
+ *
+ * Navigating through pages at a rate faster than some threshhold causes Opera
+ * to cancel all outstanding timeouts and intervals, including the location
+ * polling loop. Since this condition cannot be detected, common input events
+ * are captured to cause the loop to restart.
+ *
+ * location.replace is adding a history entry inside setHash_, despite
+ * documentation that suggests it should not.
+ *
+ *
+ * Safari (through version 2.0.4):
+ *
+ * After hitting the back button, the location.hash property is no longer
+ * readable from JavaScript. This is fixed in later WebKit builds, but not in
+ * currently shipping Safari. For now, the only recourse is to disable history
+ * states in Safari. Pages are still navigable via the History object, but the
+ * back button cannot restore previous states.
+ *
+ * Safari sets history states on navigation to a hashlink, but doesn't allow
+ * polling of the hash, so following actual anchor links in the page will create
+ * useless history entries. Using location.replace does not seem to prevent
+ * this. Not a terribly good user experience, but fixed in later Webkits.
+ *
+ *
+ * WebKit (nightly version 420+):
+ *
+ * This almost works. Returning to a page with an invisible history object does
+ * not restore the old state, however, and there is no pageshow event that fires
+ * in this browser. Holding off on finding a solution for now.
+ *
+ *
+ * HTML5 capable browsers (Firefox 4, Chrome, Safari 5)
+ *
+ * No known issues. The goog.history.Html5History class provides a simpler
+ * implementation more suitable for recent browsers. These implementations
+ * should be merged so the history class automatically invokes the correct
+ * implementation.
+ */
+
+
+goog.provide('goog.History');
+goog.provide('goog.History.Event');
+goog.provide('goog.History.EventType');
+
+goog.require('goog.Timer');
+goog.require('goog.asserts');
+goog.require('goog.dom');
+goog.require('goog.dom.InputType');
+goog.require('goog.dom.safe');
+/** @suppress {extraRequire} */
+goog.require('goog.events.Event');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.history.Event');
+goog.require('goog.history.EventType');
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.TrustedResourceUrl');
+goog.require('goog.html.legacyconversions');
+goog.require('goog.labs.userAgent.device');
+goog.require('goog.memoize');
+goog.require('goog.string');
+goog.require('goog.string.Const');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * A history management object. Can be instantiated in user-visible mode (uses
+ * the address fragment to manage state) or in hidden mode. This object should
+ * be created from a script in the document body before the document has
+ * finished loading.
+ *
+ * To store the hidden states in browsers other than IE, a hidden iframe is
+ * used. It must point to a valid html page on the same domain (which can and
+ * probably should be blank.)
+ *
+ * Sample instantiation and usage:
+ *
+ * <pre>
+ * // Instantiate history to use the address bar for state.
+ * var h = new goog.History();
+ * goog.events.listen(h, goog.history.EventType.NAVIGATE, navCallback);
+ * h.setEnabled(true);
+ *
+ * // Any changes to the location hash will call the following function.
+ * function navCallback(e) {
+ *   alert('Navigated to state "' + e.token + '"');
+ * }
+ *
+ * // The history token can also be set from code directly.
+ * h.setToken('foo');
+ * </pre>
+ *
+ * @param {boolean=} opt_invisible True to use hidden history states instead of
+ *     the user-visible location hash.
+ * @param {!goog.html.TrustedResourceUrl|string=} opt_blankPageUrl A URL to a
+ *     blank page on the same server. Required if opt_invisible is true.  If
+ *     possible pass a TrustedResourceUrl; string is supported for
+ *     backwards-compatibility only and uses goog.html.legacyconversions.
+ *     This URL is also used as the src for the iframe used to track history
+ *     state in IE (if not specified the iframe is not given a src attribute).
+ *     Access is Denied error may occur in IE7 if the window's URL's scheme
+ *     is https, and this URL is not specified.
+ * @param {HTMLInputElement=} opt_input The hidden input element to be used to
+ *     store the history token.  If not provided, a hidden input element will
+ *     be created using document.write.
+ * @param {HTMLIFrameElement=} opt_iframe The hidden iframe that will be used by
+ *     IE for pushing history state changes, or by all browsers if opt_invisible
+ *     is true. If not provided, a hidden iframe element will be created using
+ *     document.write.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.History = function(opt_invisible, opt_blankPageUrl, opt_input,
+                        opt_iframe) {
+  goog.events.EventTarget.call(this);
+
+  if (opt_invisible && !opt_blankPageUrl) {
+    throw Error('Can\'t use invisible history without providing a blank page.');
+  }
+
+  var input;
+  if (opt_input) {
+    input = opt_input;
+  } else {
+    var inputId = 'history_state' + goog.History.historyCount_;
+    var inputHtml = goog.html.SafeHtml.create('input',
+        {type: goog.dom.InputType.TEXT, name: inputId, id: inputId,
+          style: goog.string.Const.from('display:none')});
+    goog.dom.safe.documentWrite(document, inputHtml);
+    input = goog.dom.getElement(inputId);
+  }
+
+  /**
+   * An input element that stores the current iframe state. Used to restore
+   * the state when returning to the page on non-IE browsers.
+   * @type {HTMLInputElement}
+   * @private
+   */
+  this.hiddenInput_ = /** @type {HTMLInputElement} */ (input);
+
+  /**
+   * The window whose location contains the history token fragment. This is
+   * the window that contains the hidden input. It's typically the top window.
+   * It is not necessarily the same window that the js code is loaded in.
+   * @type {Window}
+   * @private
+   */
+  this.window_ = opt_input ?
+      goog.dom.getWindow(goog.dom.getOwnerDocument(opt_input)) : window;
+
+  var iframeSrc;
+  if (goog.isString(opt_blankPageUrl)) {
+    iframeSrc = goog.html.legacyconversions.trustedResourceUrlFromString(
+        opt_blankPageUrl);
+  } else {
+    iframeSrc = opt_blankPageUrl;
+  }
+
+  /**
+   * The base URL for the hidden iframe. Must refer to a document in the
+   * same domain as the main page.
+   * @type {!goog.html.TrustedResourceUrl|undefined}
+   * @private
+   */
+  this.iframeSrc_ = iframeSrc;
+
+  if (goog.userAgent.IE && !opt_blankPageUrl) {
+    if (window.location.protocol == 'https') {
+      this.iframeSrc_ = goog.html.TrustedResourceUrl.fromConstant(
+          goog.string.Const.from('https:///'));
+    } else {
+      this.iframeSrc_ = goog.html.TrustedResourceUrl.fromConstant(
+          goog.string.Const.from('javascript:""'));
+    }
+  }
+
+  /**
+   * A timer for polling the current history state for changes.
+   * @type {goog.Timer}
+   * @private
+   */
+  this.timer_ = new goog.Timer(goog.History.PollingType.NORMAL);
+  this.registerDisposable(this.timer_);
+
+  /**
+   * True if the state tokens are displayed in the address bar, false for hidden
+   * history states.
+   * @type {boolean}
+   * @private
+   */
+  this.userVisible_ = !opt_invisible;
+
+  /**
+   * An object to keep track of the history event listeners.
+   * @type {goog.events.EventHandler<!goog.History>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+  if (opt_invisible || goog.History.LEGACY_IE) {
+    var iframe;
+    if (opt_iframe) {
+      iframe = opt_iframe;
+    } else {
+      var iframeId = 'history_iframe' + goog.History.historyCount_;
+      // Using a "sandbox" attribute on the iframe might be possible, but
+      // this HTML didn't initially have it and when it was refactored
+      // to SafeHtml it was kept without it.
+      var iframeHtml = goog.html.SafeHtml.createIframe(this.iframeSrc_, null,
+          {id: iframeId, style: goog.string.Const.from('display:none'),
+            sandbox: undefined});
+      goog.dom.safe.documentWrite(document, iframeHtml);
+      iframe = goog.dom.getElement(iframeId);
+    }
+
+    /**
+     * Internet Explorer uses a hidden iframe for all history changes. Other
+     * browsers use the iframe only for pushing invisible states.
+     * @type {HTMLIFrameElement}
+     * @private
+     */
+    this.iframe_ = /** @type {HTMLIFrameElement} */ (iframe);
+
+    /**
+     * Whether the hidden iframe has had a document written to it yet in this
+     * session.
+     * @type {boolean}
+     * @private
+     */
+    this.unsetIframe_ = true;
+  }
+
+  if (goog.History.LEGACY_IE) {
+    // IE relies on the hidden input to restore the history state from previous
+    // sessions, but input values are only restored after window.onload. Set up
+    // a callback to poll the value after the onload event.
+    this.eventHandler_.listen(this.window_,
+                              goog.events.EventType.LOAD,
+                              this.onDocumentLoaded);
+
+    /**
+     * IE-only variable for determining if the document has loaded.
+     * @type {boolean}
+     * @protected
+     */
+    this.documentLoaded = false;
+
+    /**
+     * IE-only variable for storing whether the history object should be enabled
+     * once the document finishes loading.
+     * @type {boolean}
+     * @private
+     */
+    this.shouldEnable_ = false;
+  }
+
+  // Set the initial history state.
+  if (this.userVisible_) {
+    this.setHash_(this.getToken(), true);
+  } else {
+    this.setIframeToken_(this.hiddenInput_.value);
+  }
+
+  goog.History.historyCount_++;
+};
+goog.inherits(goog.History, goog.events.EventTarget);
+
+
+/**
+ * Status of when the object is active and dispatching events.
+ * @type {boolean}
+ * @private
+ */
+goog.History.prototype.enabled_ = false;
+
+
+/**
+ * Whether the object is performing polling with longer intervals. This can
+ * occur for instance when setting the location of the iframe when in invisible
+ * mode and the server that is hosting the blank html page is down. In FF, this
+ * will cause the location of the iframe to no longer be accessible, with
+ * permision denied exceptions being thrown on every access of the history
+ * token. When this occurs, the polling interval is elongated. This causes
+ * exceptions to be thrown at a lesser rate while allowing for the history
+ * object to resurrect itself when the html page becomes accessible.
+ * @type {boolean}
+ * @private
+ */
+goog.History.prototype.longerPolling_ = false;
+
+
+/**
+ * The last token set by the history object, used to poll for changes.
+ * @type {?string}
+ * @private
+ */
+goog.History.prototype.lastToken_ = null;
+
+
+/**
+ * Whether the browser supports HTML5 history management's onhashchange event.
+ * {@link http://www.w3.org/TR/html5/history.html}. IE 9 in compatibility mode
+ * indicates that onhashchange is in window, but testing reveals the event
+ * isn't actually fired.
+ * @return {boolean} Whether onhashchange is supported.
+ */
+goog.History.isOnHashChangeSupported = goog.memoize(function() {
+  return goog.userAgent.IE ?
+      goog.userAgent.isDocumentModeOrHigher(8) :
+      'onhashchange' in goog.global;
+});
+
+
+/**
+ * Whether the current browser is Internet Explorer prior to version 8. Many IE
+ * specific workarounds developed before version 8 are unnecessary in more
+ * current versions.
+ * @type {boolean}
+ */
+goog.History.LEGACY_IE = goog.userAgent.IE &&
+    !goog.userAgent.isDocumentModeOrHigher(8);
+
+
+/**
+ * Whether the browser always requires the hash to be present. Internet Explorer
+ * before version 8 will reload the HTML page if the hash is omitted.
+ * @type {boolean}
+ */
+goog.History.HASH_ALWAYS_REQUIRED = goog.History.LEGACY_IE;
+
+
+/**
+ * If not null, polling in the user invisible mode will be disabled until this
+ * token is seen. This is used to prevent a race condition where the iframe
+ * hangs temporarily while the location is changed.
+ * @type {?string}
+ * @private
+ */
+goog.History.prototype.lockedToken_ = null;
+
+
+/** @override */
+goog.History.prototype.disposeInternal = function() {
+  goog.History.superClass_.disposeInternal.call(this);
+  this.eventHandler_.dispose();
+  this.setEnabled(false);
+};
+
+
+/**
+ * Starts or stops the History polling loop. When enabled, the History object
+ * will immediately fire an event for the current location. The caller can set
+ * up event listeners between the call to the constructor and the call to
+ * setEnabled.
+ *
+ * On IE, actual startup may be delayed until the iframe and hidden input
+ * element have been loaded and can be polled. This behavior is transparent to
+ * the caller.
+ *
+ * @param {boolean} enable Whether to enable the history polling loop.
+ */
+goog.History.prototype.setEnabled = function(enable) {
+
+  if (enable == this.enabled_) {
+    return;
+  }
+
+  if (goog.History.LEGACY_IE && !this.documentLoaded) {
+    // Wait until the document has actually loaded before enabling the
+    // object or any saved state from a previous session will be lost.
+    this.shouldEnable_ = enable;
+    return;
+  }
+
+  if (enable) {
+    if (goog.userAgent.OPERA) {
+      // Capture events for common user input so we can restart the timer in
+      // Opera if it fails. Yes, this is distasteful. See operaDefibrillator_.
+      this.eventHandler_.listen(this.window_.document,
+                                goog.History.INPUT_EVENTS_,
+                                this.operaDefibrillator_);
+    } else if (goog.userAgent.GECKO) {
+      // Firefox will not restore the correct state after navigating away from
+      // and then back to the page with the history object. This can be fixed
+      // by restarting the history object on the pageshow event.
+      this.eventHandler_.listen(this.window_, 'pageshow', this.onShow_);
+    }
+
+    // TODO(user): make HTML5 and invisible history work by listening to the
+    // iframe # changes instead of the window.
+    if (goog.History.isOnHashChangeSupported() &&
+        this.userVisible_) {
+      this.eventHandler_.listen(
+          this.window_, goog.events.EventType.HASHCHANGE, this.onHashChange_);
+      this.enabled_ = true;
+      this.dispatchEvent(new goog.history.Event(this.getToken(), false));
+    } else if (!(goog.userAgent.IE && !goog.labs.userAgent.device.isMobile()) ||
+               this.documentLoaded) {
+      // Start dispatching history events if all necessary loading has
+      // completed (always true for browsers other than IE.)
+      this.eventHandler_.listen(this.timer_, goog.Timer.TICK,
+          goog.bind(this.check_, this, true));
+
+      this.enabled_ = true;
+
+      // Initialize last token at startup except on IE < 8, where the last token
+      // must only be set in conjunction with IFRAME updates, or the IFRAME will
+      // start out of sync and remove any pre-existing URI fragment.
+      if (!goog.History.LEGACY_IE) {
+        this.lastToken_ = this.getToken();
+        this.dispatchEvent(new goog.history.Event(this.getToken(), false));
+      }
+
+      this.timer_.start();
+    }
+
+  } else {
+    this.enabled_ = false;
+    this.eventHandler_.removeAll();
+    this.timer_.stop();
+  }
+};
+
+
+/**
+ * Callback for the window onload event in IE. This is necessary to read the
+ * value of the hidden input after restoring a history session. The value of
+ * input elements is not viewable until after window onload for some reason (the
+ * iframe state is similarly unavailable during the loading phase.)  If
+ * setEnabled is called before the iframe has completed loading, the history
+ * object will actually be enabled at this point.
+ * @protected
+ */
+goog.History.prototype.onDocumentLoaded = function() {
+  this.documentLoaded = true;
+
+  if (this.hiddenInput_.value) {
+    // Any saved value in the hidden input can only be read after the document
+    // has been loaded due to an IE limitation. Restore the previous state if
+    // it has been set.
+    this.setIframeToken_(this.hiddenInput_.value, true);
+  }
+
+  this.setEnabled(this.shouldEnable_);
+};
+
+
+/**
+ * Handler for the Gecko pageshow event. Restarts the history object so that the
+ * correct state can be restored in the hash or iframe.
+ * @param {goog.events.BrowserEvent} e The browser event.
+ * @private
+ */
+goog.History.prototype.onShow_ = function(e) {
+  // NOTE(user): persisted is a property passed in the pageshow event that
+  // indicates whether the page is being persisted from the cache or is being
+  // loaded for the first time.
+  if (e.getBrowserEvent()['persisted']) {
+    this.setEnabled(false);
+    this.setEnabled(true);
+  }
+};
+
+
+/**
+ * Handles HTML5 onhashchange events on browsers where it is supported.
+ * This is very similar to {@link #check_}, except that it is not executed
+ * continuously. It is only used when
+ * {@code goog.History.isOnHashChangeSupported()} is true.
+ * @param {goog.events.BrowserEvent} e The browser event.
+ * @private
+ */
+goog.History.prototype.onHashChange_ = function(e) {
+  var hash = this.getLocationFragment_(this.window_);
+  if (hash != this.lastToken_) {
+    this.update_(hash, true);
+  }
+};
+
+
+/**
+ * @return {string} The current token.
+ */
+goog.History.prototype.getToken = function() {
+  if (this.lockedToken_ != null) {
+    return this.lockedToken_;
+  } else if (this.userVisible_) {
+    return this.getLocationFragment_(this.window_);
+  } else {
+    return this.getIframeToken_() || '';
+  }
+};
+
+
+/**
+ * Sets the history state. When user visible states are used, the URL fragment
+ * will be set to the provided token.  Sometimes it is necessary to set the
+ * history token before the document title has changed, in this case IE's
+ * history drop down can be out of sync with the token.  To get around this
+ * problem, the app can pass in a title to use with the hidden iframe.
+ * @param {string} token The history state identifier.
+ * @param {string=} opt_title Optional title used when setting the hidden iframe
+ *     title in IE.
+ */
+goog.History.prototype.setToken = function(token, opt_title) {
+  this.setHistoryState_(token, false, opt_title);
+};
+
+
+/**
+ * Replaces the current history state without affecting the rest of the history
+ * stack.
+ * @param {string} token The history state identifier.
+ * @param {string=} opt_title Optional title used when setting the hidden iframe
+ *     title in IE.
+ */
+goog.History.prototype.replaceToken = function(token, opt_title) {
+  this.setHistoryState_(token, true, opt_title);
+};
+
+
+/**
+ * Gets the location fragment for the current URL.  We don't use location.hash
+ * directly as the browser helpfully urlDecodes the string for us which can
+ * corrupt the tokens.  For example, if we want to store: label/%2Froot it would
+ * be returned as label//root.
+ * @param {Window} win The window object to use.
+ * @return {string} The fragment.
+ * @private
+ */
+goog.History.prototype.getLocationFragment_ = function(win) {
+  var href = win.location.href;
+  var index = href.indexOf('#');
+  return index < 0 ? '' : href.substring(index + 1);
+};
+
+
+/**
+ * Sets the history state. When user visible states are used, the URL fragment
+ * will be set to the provided token. Setting opt_replace to true will cause the
+ * navigation to occur, but will replace the current history entry without
+ * affecting the length of the stack.
+ *
+ * @param {string} token The history state identifier.
+ * @param {boolean} replace Set to replace the current history entry instead of
+ *    appending a new history state.
+ * @param {string=} opt_title Optional title used when setting the hidden iframe
+ *     title in IE.
+ * @private
+ */
+goog.History.prototype.setHistoryState_ = function(token, replace, opt_title) {
+  if (this.getToken() != token) {
+    if (this.userVisible_) {
+      this.setHash_(token, replace);
+
+      if (!goog.History.isOnHashChangeSupported()) {
+        if (goog.userAgent.IE && !goog.labs.userAgent.device.isMobile()) {
+          // IE must save state using the iframe.
+          this.setIframeToken_(token, replace, opt_title);
+        }
+      }
+
+      // This condition needs to be called even if
+      // goog.History.isOnHashChangeSupported() is true so the NAVIGATE event
+      // fires sychronously.
+      if (this.enabled_) {
+        this.check_(false);
+      }
+    } else {
+      // Fire the event immediately so that setting history is synchronous, but
+      // set a suspendToken so that polling doesn't trigger a 'back'.
+      this.setIframeToken_(token, replace);
+      this.lockedToken_ = this.lastToken_ = this.hiddenInput_.value = token;
+      this.dispatchEvent(new goog.history.Event(token, false));
+    }
+  }
+};
+
+
+/**
+ * Sets or replaces the URL fragment. The token does not need to be URL encoded
+ * according to the URL specification, though certain characters (like newline)
+ * are automatically stripped.
+ *
+ * If opt_replace is not set, non-IE browsers will append a new entry to the
+ * history list. Setting the hash does not affect the history stack in IE
+ * (unless there is a pre-existing named anchor for that hash.)
+ *
+ * Older versions of Webkit cannot query the location hash, but it still can be
+ * set. If we detect one of these versions, always replace instead of creating
+ * new history entries.
+ *
+ * window.location.replace replaces the current state from the history stack.
+ * http://www.whatwg.org/specs/web-apps/current-work/#dom-location-replace
+ * http://www.whatwg.org/specs/web-apps/current-work/#replacement-enabled
+ *
+ * @param {string} token The new string to set.
+ * @param {boolean=} opt_replace Set to true to replace the current token
+ *    without appending a history entry.
+ * @private
+ */
+goog.History.prototype.setHash_ = function(token, opt_replace) {
+  // If the page uses a BASE element, setting location.hash directly will
+  // navigate away from the current document. Also, the original URL path may
+  // possibly change from HTML5 history pushState. To account for these, the
+  // full path is always specified.
+  var loc = this.window_.location;
+  var url = loc.href.split('#')[0];
+
+  // If a hash has already been set, then removing it programmatically will
+  // reload the page. Once there is a hash, we won't remove it.
+  var hasHash = goog.string.contains(loc.href, '#');
+
+  if (goog.History.HASH_ALWAYS_REQUIRED || hasHash || token) {
+    url += '#' + token;
+  }
+
+  if (url != loc.href) {
+    if (opt_replace) {
+      loc.replace(url);
+    } else {
+      loc.href = url;
+    }
+  }
+};
+
+
+/**
+ * Sets the hidden iframe state. On IE, this is accomplished by writing a new
+ * document into the iframe. In Firefox, the iframe's URL fragment stores the
+ * state instead.
+ *
+ * Older versions of webkit cannot set the iframe, so ignore those browsers.
+ *
+ * @param {string} token The new string to set.
+ * @param {boolean=} opt_replace Set to true to replace the current iframe state
+ *     without appending a new history entry.
+ * @param {string=} opt_title Optional title used when setting the hidden iframe
+ *     title in IE.
+ * @private
+ */
+goog.History.prototype.setIframeToken_ = function(token,
+                                                  opt_replace,
+                                                  opt_title) {
+  if (this.unsetIframe_ || token != this.getIframeToken_()) {
+
+    this.unsetIframe_ = false;
+    token = goog.string.urlEncode(token);
+
+    if (goog.userAgent.IE) {
+      // Caching the iframe document results in document permission errors after
+      // leaving the page and returning. Access it anew each time instead.
+      var doc = goog.dom.getFrameContentDocument(this.iframe_);
+
+      doc.open('text/html', opt_replace ? 'replace' : undefined);
+      var iframeSourceHtml = goog.html.SafeHtml.concat(
+          goog.html.SafeHtml.create('title', {},
+              (opt_title || this.window_.document.title)),
+          goog.html.SafeHtml.create('body', {}, token));
+      goog.dom.safe.documentWrite(doc, iframeSourceHtml);
+      doc.close();
+    } else {
+      goog.asserts.assertInstanceof(
+          this.iframeSrc_, goog.html.TrustedResourceUrl,
+          'this.iframeSrc_ must be set on calls to setIframeToken_');
+      var url = goog.html.TrustedResourceUrl.unwrap(
+          /** @type {!goog.html.TrustedResourceUrl} */ (this.iframeSrc_)) +
+              '#' + token;
+
+      // In Safari, it is possible for the contentWindow of the iframe to not
+      // be present when the page is loading after a reload.
+      var contentWindow = this.iframe_.contentWindow;
+      if (contentWindow) {
+        if (opt_replace) {
+          contentWindow.location.replace(url);
+        } else {
+          contentWindow.location.href = url;
+        }
+      }
+    }
+  }
+};
+
+
+/**
+ * Return the current state string from the hidden iframe. On internet explorer,
+ * this is stored as a string in the document body. Other browsers use the
+ * location hash of the hidden iframe.
+ *
+ * Older versions of webkit cannot access the iframe location, so always return
+ * null in that case.
+ *
+ * @return {?string} The state token saved in the iframe (possibly null if the
+ *     iframe has never loaded.).
+ * @private
+ */
+goog.History.prototype.getIframeToken_ = function() {
+  if (goog.userAgent.IE) {
+    var doc = goog.dom.getFrameContentDocument(this.iframe_);
+    return doc.body ? goog.string.urlDecode(doc.body.innerHTML) : null;
+  } else {
+    // In Safari, it is possible for the contentWindow of the iframe to not
+    // be present when the page is loading after a reload.
+    var contentWindow = this.iframe_.contentWindow;
+    if (contentWindow) {
+      var hash;
+      /** @preserveTry */
+      try {
+        // Iframe tokens are urlEncoded
+        hash = goog.string.urlDecode(this.getLocationFragment_(contentWindow));
+      } catch (e) {
+        // An exception will be thrown if the location of the iframe can not be
+        // accessed (permission denied). This can occur in FF if the the server
+        // that is hosting the blank html page goes down and then a new history
+        // token is set. The iframe will navigate to an error page, and the
+        // location of the iframe can no longer be accessed. Due to the polling,
+        // this will cause constant exceptions to be thrown. In this case,
+        // we enable longer polling. We do not have to attempt to reset the
+        // iframe token because (a) we already fired the NAVIGATE event when
+        // setting the token, (b) we can rely on the locked token for current
+        // state, and (c) the token is still in the history and
+        // accesible on forward/back.
+        if (!this.longerPolling_) {
+          this.setLongerPolling_(true);
+        }
+
+        return null;
+      }
+
+      // There was no exception when getting the hash so turn off longer polling
+      // if it is on.
+      if (this.longerPolling_) {
+        this.setLongerPolling_(false);
+      }
+
+      return hash || null;
+    } else {
+      return null;
+    }
+  }
+};
+
+
+/**
+ * Checks the state of the document fragment and the iframe title to detect
+ * navigation changes. If {@code goog.HistoryisOnHashChangeSupported()} is
+ * {@code false}, then this runs approximately twenty times per second.
+ * @param {boolean} isNavigation True if the event was initiated by a browser
+ *     action, false if it was caused by a setToken call. See
+ *     {@link goog.history.Event}.
+ * @private
+ */
+goog.History.prototype.check_ = function(isNavigation) {
+  if (this.userVisible_) {
+    var hash = this.getLocationFragment_(this.window_);
+    if (hash != this.lastToken_) {
+      this.update_(hash, isNavigation);
+    }
+  }
+
+  // Old IE uses the iframe for both visible and non-visible versions.
+  if (!this.userVisible_ || goog.History.LEGACY_IE) {
+    var token = this.getIframeToken_() || '';
+    if (this.lockedToken_ == null || token == this.lockedToken_) {
+      this.lockedToken_ = null;
+      if (token != this.lastToken_) {
+        this.update_(token, isNavigation);
+      }
+    }
+  }
+};
+
+
+/**
+ * Updates the current history state with a given token. Called after a change
+ * to the location or the iframe state is detected by poll_.
+ *
+ * @param {string} token The new history state.
+ * @param {boolean} isNavigation True if the event was initiated by a browser
+ *     action, false if it was caused by a setToken call. See
+ *     {@link goog.history.Event}.
+ * @private
+ */
+goog.History.prototype.update_ = function(token, isNavigation) {
+  this.lastToken_ = this.hiddenInput_.value = token;
+
+  if (this.userVisible_) {
+    if (goog.History.LEGACY_IE) {
+      this.setIframeToken_(token);
+    }
+
+    this.setHash_(token);
+  } else {
+    this.setIframeToken_(token);
+  }
+
+  this.dispatchEvent(new goog.history.Event(this.getToken(), isNavigation));
+};
+
+
+/**
+ * Sets if the history oject should use longer intervals when polling.
+ *
+ * @param {boolean} longerPolling Whether to enable longer polling.
+ * @private
+ */
+goog.History.prototype.setLongerPolling_ = function(longerPolling) {
+  if (this.longerPolling_ != longerPolling) {
+    this.timer_.setInterval(longerPolling ?
+        goog.History.PollingType.LONG : goog.History.PollingType.NORMAL);
+  }
+  this.longerPolling_ = longerPolling;
+};
+
+
+/**
+ * Opera cancels all outstanding timeouts and intervals after any rapid
+ * succession of navigation events, including the interval used to detect
+ * navigation events. This function restarts the interval so that navigation can
+ * continue. Ideally, only events which would be likely to cause a navigation
+ * change (mousedown and keydown) would be bound to this function. Since Opera
+ * seems to ignore keydown events while the alt key is pressed (such as
+ * alt-left or right arrow), this function is also bound to the much more
+ * frequent mousemove event. This way, when the update loop freezes, it will
+ * unstick itself as the user wiggles the mouse in frustration.
+ * @private
+ */
+goog.History.prototype.operaDefibrillator_ = function() {
+  this.timer_.stop();
+  this.timer_.start();
+};
+
+
+/**
+ * List of user input event types registered in Opera to restart the history
+ * timer (@see goog.History#operaDefibrillator_).
+ * @type {Array<string>}
+ * @private
+ */
+goog.History.INPUT_EVENTS_ = [
+  goog.events.EventType.MOUSEDOWN,
+  goog.events.EventType.KEYDOWN,
+  goog.events.EventType.MOUSEMOVE
+];
+
+
+/**
+ * Counter for the number of goog.History objects that have been instantiated.
+ * Used to create unique IDs.
+ * @type {number}
+ * @private
+ */
+goog.History.historyCount_ = 0;
+
+
+/**
+ * Types of polling. The values are in ms of the polling interval.
+ * @enum {number}
+ */
+goog.History.PollingType = {
+  NORMAL: 150,
+  LONG: 10000
+};
+
+
+/**
+ * Constant for the history change event type.
+ * @enum {string}
+ * @deprecated Use goog.history.EventType.
+ */
+goog.History.EventType = goog.history.EventType;
+
+
+
+/**
+ * Constant for the history change event type.
+ * @param {string} token The string identifying the new history state.
+ * @extends {goog.events.Event}
+ * @constructor
+ * @deprecated Use goog.history.Event.
+ * @final
+ */
+goog.History.Event = goog.history.Event;


[11/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/element.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/element.js b/externs/GCL/externs/goog/graphics/element.js
new file mode 100644
index 0000000..5a7bc8f
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/element.js
@@ -0,0 +1,164 @@
+// 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 A thin wrapper around the DOM element returned from
+ * the different draw methods of the graphics implementation, and
+ * all interfaces that the various element types support.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.Element');
+
+goog.require('goog.asserts');
+goog.require('goog.events');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.Listenable');
+goog.require('goog.graphics.AffineTransform');
+goog.require('goog.math');
+
+
+
+/**
+ * Base class for a thin wrapper around the DOM element returned from
+ * the different draw methods of the graphics.
+ * You should not construct objects from this constructor. The graphics
+ * will return the object for you.
+ * @param {Element} element  The DOM element to wrap.
+ * @param {goog.graphics.AbstractGraphics} graphics  The graphics creating
+ *     this element.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.Element = function(element, graphics) {
+  goog.events.EventTarget.call(this);
+  this.element_ = element;
+  this.graphics_ = graphics;
+  // Overloading EventTarget field to state that this is not a custom event.
+  // TODO(user) Should be handled in EventTarget.js (see bug 846824).
+  this[goog.events.Listenable.IMPLEMENTED_BY_PROP] = false;
+};
+goog.inherits(goog.graphics.Element, goog.events.EventTarget);
+
+
+/**
+ * The graphics object that contains this element.
+ * @type {goog.graphics.AbstractGraphics?}
+ * @private
+ */
+goog.graphics.Element.prototype.graphics_ = null;
+
+
+/**
+ * The native browser element this class wraps.
+ * @type {Element}
+ * @private
+ */
+goog.graphics.Element.prototype.element_ = null;
+
+
+/**
+ * The transformation applied to this element.
+ * @type {goog.graphics.AffineTransform?}
+ * @private
+ */
+goog.graphics.Element.prototype.transform_ = null;
+
+
+/**
+ * Returns the underlying object.
+ * @return {Element} The underlying element.
+ */
+goog.graphics.Element.prototype.getElement = function() {
+  return this.element_;
+};
+
+
+/**
+ * Returns the graphics.
+ * @return {goog.graphics.AbstractGraphics} The graphics that created the
+ *     element.
+ */
+goog.graphics.Element.prototype.getGraphics = function() {
+  return this.graphics_;
+};
+
+
+/**
+ * Set the translation and rotation of the element.
+ *
+ * If a more general affine transform is needed than this provides
+ * (e.g. skew and scale) then use setTransform.
+ * @param {number} x The x coordinate of the translation transform.
+ * @param {number} y The y coordinate of the translation transform.
+ * @param {number} rotate The angle of the rotation transform.
+ * @param {number} centerX The horizontal center of the rotation transform.
+ * @param {number} centerY The vertical center of the rotation transform.
+ */
+goog.graphics.Element.prototype.setTransformation = function(x, y, rotate,
+    centerX, centerY) {
+  this.transform_ = goog.graphics.AffineTransform.getRotateInstance(
+      goog.math.toRadians(rotate), centerX, centerY).translate(x, y);
+  this.getGraphics().setElementTransform(this, x, y, rotate, centerX, centerY);
+};
+
+
+/**
+ * @return {!goog.graphics.AffineTransform} The transformation applied to
+ *     this element.
+ */
+goog.graphics.Element.prototype.getTransform = function() {
+  return this.transform_ ? this.transform_.clone() :
+      new goog.graphics.AffineTransform();
+};
+
+
+/**
+ * Set the affine transform of the element.
+ * @param {!goog.graphics.AffineTransform} affineTransform The
+ *     transformation applied to this element.
+ */
+goog.graphics.Element.prototype.setTransform = function(affineTransform) {
+  this.transform_ = affineTransform.clone();
+  this.getGraphics().setElementAffineTransform(this, affineTransform);
+};
+
+
+/** @override */
+goog.graphics.Element.prototype.addEventListener = function(
+    type, handler, opt_capture, opt_handlerScope) {
+  goog.events.listen(this.element_, type, handler, opt_capture,
+      opt_handlerScope);
+};
+
+
+/** @override */
+goog.graphics.Element.prototype.removeEventListener = function(
+    type, handler, opt_capture, opt_handlerScope) {
+  goog.events.unlisten(this.element_, type, handler, opt_capture,
+      opt_handlerScope);
+};
+
+
+/** @override */
+goog.graphics.Element.prototype.disposeInternal = function() {
+  goog.graphics.Element.superClass_.disposeInternal.call(this);
+  goog.asserts.assert(this.element_);
+  goog.events.removeAll(this.element_);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/ellipseelement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/ellipseelement.js b/externs/GCL/externs/goog/graphics/ellipseelement.js
new file mode 100644
index 0000000..975b462
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/ellipseelement.js
@@ -0,0 +1,63 @@
+// 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 A thin wrapper around the DOM element for ellipses.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.EllipseElement');
+
+goog.require('goog.graphics.StrokeAndFillElement');
+
+
+
+/**
+ * Interface for a graphics ellipse element.
+ * You should not construct objects from this constructor. The graphics
+ * will return an implementation of this interface for you.
+ * @param {Element} element The DOM element to wrap.
+ * @param {goog.graphics.AbstractGraphics} graphics The graphics creating
+ *     this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke to use for this element.
+ * @param {goog.graphics.Fill?} fill The fill to use for this element.
+ * @constructor
+ * @extends {goog.graphics.StrokeAndFillElement}
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.EllipseElement = function(element, graphics, stroke, fill) {
+  goog.graphics.StrokeAndFillElement.call(this, element, graphics, stroke,
+      fill);
+};
+goog.inherits(goog.graphics.EllipseElement, goog.graphics.StrokeAndFillElement);
+
+
+/**
+ * Update the center point of the ellipse.
+ * @param {number} cx  Center X coordinate.
+ * @param {number} cy  Center Y coordinate.
+ */
+goog.graphics.EllipseElement.prototype.setCenter = goog.abstractMethod;
+
+
+/**
+ * Update the radius of the ellipse.
+ * @param {number} rx  Radius length for the x-axis.
+ * @param {number} ry  Radius length for the y-axis.
+ */
+goog.graphics.EllipseElement.prototype.setRadius = goog.abstractMethod;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/ext/coordinates.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/ext/coordinates.js b/externs/GCL/externs/goog/graphics/ext/coordinates.js
new file mode 100644
index 0000000..42385fe
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/ext/coordinates.js
@@ -0,0 +1,159 @@
+// 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 Graphics utility functions for advanced coordinates.
+ *
+ * This file assists the use of advanced coordinates in goog.graphics.  Coords
+ * can be specified as simple numbers which will correspond to units in the
+ * graphics element's coordinate space.  Alternately, coords can be expressed
+ * in pixels, meaning no matter what tranformations or coordinate system changes
+ * are present, the number of pixel changes will remain constant.  Coords can
+ * also be expressed as percentages of their parent's size.
+ *
+ * This file also allows for elements to have margins, expressable in any of
+ * the ways described above.
+ *
+ * Additional pieces of advanced coordinate functionality can (soon) be found in
+ * element.js and groupelement.js.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.graphics.ext.coordinates');
+
+goog.require('goog.string');
+
+
+/**
+ * Cache of boolean values.  For a given string (key), is it special? (value)
+ * @type {Object}
+ * @private
+ */
+goog.graphics.ext.coordinates.specialCoordinateCache_ = {};
+
+
+/**
+ * Determines if the given coordinate is a percent based coordinate or an
+ * expression with a percent based component.
+ * @param {string} coord The coordinate to test.
+ * @return {boolean} Whether the coordinate contains the string '%'.
+ * @private
+ */
+goog.graphics.ext.coordinates.isPercent_ = function(coord) {
+  return goog.string.contains(coord, '%');
+};
+
+
+/**
+ * Determines if the given coordinate is a pixel based coordinate or an
+ * expression with a pixel based component.
+ * @param {string} coord The coordinate to test.
+ * @return {boolean} Whether the coordinate contains the string 'px'.
+ * @private
+ */
+goog.graphics.ext.coordinates.isPixels_ = function(coord) {
+  return goog.string.contains(coord, 'px');
+};
+
+
+/**
+ * Determines if the given coordinate is special - i.e. not just a number.
+ * @param {string|number|null} coord The coordinate to test.
+ * @return {boolean} Whether the coordinate is special.
+ */
+goog.graphics.ext.coordinates.isSpecial = function(coord) {
+  var cache = goog.graphics.ext.coordinates.specialCoordinateCache_;
+
+  if (!(coord in cache)) {
+    cache[coord] = goog.isString(coord) && (
+        goog.graphics.ext.coordinates.isPercent_(coord) ||
+        goog.graphics.ext.coordinates.isPixels_(coord));
+  }
+
+  return cache[coord];
+};
+
+
+/**
+ * Returns the value of the given expression in the given context.
+ *
+ * Should be treated as package scope.
+ *
+ * @param {string|number} coord The coordinate to convert.
+ * @param {number} size The size of the parent element.
+ * @param {number} scale The ratio of pixels to units.
+ * @return {number} The number of coordinate space units that corresponds to
+ *     this coordinate.
+ */
+goog.graphics.ext.coordinates.computeValue = function(coord, size, scale) {
+  var number = parseFloat(String(coord));
+  if (goog.isString(coord)) {
+    if (goog.graphics.ext.coordinates.isPercent_(coord)) {
+      return number * size / 100;
+    } else if (goog.graphics.ext.coordinates.isPixels_(coord)) {
+      return number / scale;
+    }
+  }
+
+  return number;
+};
+
+
+/**
+ * Converts the given coordinate to a number value in units.
+ *
+ * Should be treated as package scope.
+ *
+ * @param {string|number} coord The coordinate to retrieve the value for.
+ * @param {boolean|undefined} forMaximum Whether we are computing the largest
+ *     value this coordinate would be in a parent of no size.  The container
+ *     size in this case should be set to the size of the current element.
+ * @param {number} containerSize The unit value of the size of the container of
+ *     this element.  Should be set to the minimum width of this element if
+ *     forMaximum is true.
+ * @param {number} scale The ratio of pixels to units.
+ * @param {Object=} opt_cache Optional (but highly recommend) object to store
+ *     cached computations in.  The calling class should manage clearing out
+ *     the cache when the scale or containerSize changes.
+ * @return {number} The correct number of coordinate space units.
+ */
+goog.graphics.ext.coordinates.getValue = function(coord, forMaximum,
+    containerSize, scale, opt_cache) {
+  if (!goog.isNumber(coord)) {
+    var cacheString = opt_cache && ((forMaximum ? 'X' : '') + coord);
+
+    if (opt_cache && cacheString in opt_cache) {
+      coord = opt_cache[cacheString];
+    } else {
+      if (goog.graphics.ext.coordinates.isSpecial(
+          /** @type {string} */ (coord))) {
+        coord = goog.graphics.ext.coordinates.computeValue(coord,
+            containerSize, scale);
+      } else {
+        // Simple coordinates just need to be converted from a string to a
+        // number.
+        coord = parseFloat(/** @type {string} */ (coord));
+      }
+
+      // Cache the result.
+      if (opt_cache) {
+        opt_cache[cacheString] = coord;
+      }
+    }
+  }
+
+  return coord;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/ext/element.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/ext/element.js b/externs/GCL/externs/goog/graphics/ext/element.js
new file mode 100644
index 0000000..546c8c3
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/ext/element.js
@@ -0,0 +1,963 @@
+// 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 A thicker wrapper around the DOM element returned from
+ * the different draw methods of the graphics implementation, and
+ * all interfaces that the various element types support.
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.graphics.ext.Element');
+
+goog.require('goog.events.EventTarget');
+goog.require('goog.functions');
+goog.require('goog.graphics.ext.coordinates');
+
+
+
+/**
+ * Base class for a wrapper around the goog.graphics wrapper that enables
+ * more advanced functionality.
+ * @param {goog.graphics.ext.Group?} group Parent for this element.
+ * @param {goog.graphics.Element} wrapper The thin wrapper to wrap.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.graphics.ext.Element = function(group, wrapper) {
+  goog.events.EventTarget.call(this);
+  this.wrapper_ = wrapper;
+  this.graphics_ = group ? group.getGraphics() : this;
+
+  this.xPosition_ = new goog.graphics.ext.Element.Position_(this, true);
+  this.yPosition_ = new goog.graphics.ext.Element.Position_(this, false);
+
+  // Handle parent / child relationships.
+  if (group) {
+    this.parent_ = group;
+    this.parent_.addChild(this);
+  }
+};
+goog.inherits(goog.graphics.ext.Element, goog.events.EventTarget);
+
+
+/**
+ * The graphics object that contains this element.
+ * @type {goog.graphics.ext.Graphics|goog.graphics.ext.Element}
+ * @private
+ */
+goog.graphics.ext.Element.prototype.graphics_;
+
+
+/**
+ * The goog.graphics wrapper this class wraps.
+ * @type {goog.graphics.Element}
+ * @private
+ */
+goog.graphics.ext.Element.prototype.wrapper_;
+
+
+/**
+ * The group or surface containing this element.
+ * @type {goog.graphics.ext.Group|undefined}
+ * @private
+ */
+goog.graphics.ext.Element.prototype.parent_;
+
+
+/**
+ * Whether or not computation of this element's position or size depends on its
+ * parent's size.
+ * @type {boolean}
+ * @private
+ */
+goog.graphics.ext.Element.prototype.parentDependent_ = false;
+
+
+/**
+ * Whether the element has pending transformations.
+ * @type {boolean}
+ * @private
+ */
+goog.graphics.ext.Element.prototype.needsTransform_ = false;
+
+
+/**
+ * The current angle of rotation, expressed in degrees.
+ * @type {number}
+ * @private
+ */
+goog.graphics.ext.Element.prototype.rotation_ = 0;
+
+
+/**
+ * Object representing the x position and size of the element.
+ * @type {goog.graphics.ext.Element.Position_}
+ * @private
+ */
+goog.graphics.ext.Element.prototype.xPosition_;
+
+
+/**
+ * Object representing the y position and size of the element.
+ * @type {goog.graphics.ext.Element.Position_}
+ * @private
+ */
+goog.graphics.ext.Element.prototype.yPosition_;
+
+
+/** @return {goog.graphics.Element} The underlying thin wrapper. */
+goog.graphics.ext.Element.prototype.getWrapper = function() {
+  return this.wrapper_;
+};
+
+
+/**
+ * @return {goog.graphics.ext.Element|goog.graphics.ext.Graphics} The graphics
+ *     surface the element is a part of.
+ */
+goog.graphics.ext.Element.prototype.getGraphics = function() {
+  return this.graphics_;
+};
+
+
+/**
+ * Returns the graphics implementation.
+ * @return {goog.graphics.AbstractGraphics} The underlying graphics
+ *     implementation drawing this element's wrapper.
+ * @protected
+ */
+goog.graphics.ext.Element.prototype.getGraphicsImplementation = function() {
+  return this.graphics_.getImplementation();
+};
+
+
+/**
+ * @return {goog.graphics.ext.Group|undefined} The parent of this element.
+ */
+goog.graphics.ext.Element.prototype.getParent = function() {
+  return this.parent_;
+};
+
+
+// GENERAL POSITIONING
+
+
+/**
+ * Internal convenience method for setting position - either as a left/top,
+ * center/middle, or right/bottom value.  Only one should be specified.
+ * @param {goog.graphics.ext.Element.Position_} position The position object to
+ *     set the value on.
+ * @param {number|string} value The value of the coordinate.
+ * @param {goog.graphics.ext.Element.PositionType_} type The type of the
+ *     coordinate.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ * @private
+ */
+goog.graphics.ext.Element.prototype.setPosition_ = function(position, value,
+    type, opt_chain) {
+  position.setPosition(value, type);
+  this.computeIsParentDependent_(position);
+
+  this.needsTransform_ = true;
+  if (!opt_chain) {
+    this.transform();
+  }
+};
+
+
+/**
+ * Sets the width/height of the element.
+ * @param {goog.graphics.ext.Element.Position_} position The position object to
+ *     set the value on.
+ * @param {string|number} size The new width/height value.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ * @private
+ */
+goog.graphics.ext.Element.prototype.setSize_ = function(position, size,
+    opt_chain) {
+  if (position.setSize(size)) {
+    this.needsTransform_ = true;
+
+    this.computeIsParentDependent_(position);
+
+    if (!opt_chain) {
+      this.reset();
+    }
+  } else if (!opt_chain && this.isPendingTransform()) {
+    this.reset();
+  }
+};
+
+
+/**
+ * Sets the minimum width/height of the element.
+ * @param {goog.graphics.ext.Element.Position_} position The position object to
+ *     set the value on.
+ * @param {string|number} minSize The minimum width/height of the element.
+ * @private
+ */
+goog.graphics.ext.Element.prototype.setMinSize_ = function(position, minSize) {
+  position.setMinSize(minSize);
+  this.needsTransform_ = true;
+  this.computeIsParentDependent_(position);
+};
+
+
+// HORIZONTAL POSITIONING
+
+
+/**
+ * @return {number} The distance from the left edge of this element to the left
+ *     edge of its parent, specified in units of the parent's coordinate system.
+ */
+goog.graphics.ext.Element.prototype.getLeft = function() {
+  return this.xPosition_.getStart();
+};
+
+
+/**
+ * Sets the left coordinate of the element.  Overwrites any previous value of
+ * left, center, or right for this element.
+ * @param {string|number} left The left coordinate.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ */
+goog.graphics.ext.Element.prototype.setLeft = function(left, opt_chain) {
+  this.setPosition_(this.xPosition_,
+      left,
+      goog.graphics.ext.Element.PositionType_.START,
+      opt_chain);
+};
+
+
+/**
+ * @return {number} The right coordinate of the element, in units of the
+ *     parent's coordinate system.
+ */
+goog.graphics.ext.Element.prototype.getRight = function() {
+  return this.xPosition_.getEnd();
+};
+
+
+/**
+ * Sets the right coordinate of the element.  Overwrites any previous value of
+ * left, center, or right for this element.
+ * @param {string|number} right The right coordinate.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ */
+goog.graphics.ext.Element.prototype.setRight = function(right, opt_chain) {
+  this.setPosition_(this.xPosition_,
+      right,
+      goog.graphics.ext.Element.PositionType_.END,
+      opt_chain);
+};
+
+
+/**
+ * @return {number} The center coordinate of the element, in units of the
+ * parent's coordinate system.
+ */
+goog.graphics.ext.Element.prototype.getCenter = function() {
+  return this.xPosition_.getMiddle();
+};
+
+
+/**
+ * Sets the center coordinate of the element.  Overwrites any previous value of
+ * left, center, or right for this element.
+ * @param {string|number} center The center coordinate.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ */
+goog.graphics.ext.Element.prototype.setCenter = function(center, opt_chain) {
+  this.setPosition_(this.xPosition_,
+      center,
+      goog.graphics.ext.Element.PositionType_.MIDDLE,
+      opt_chain);
+};
+
+
+// VERTICAL POSITIONING
+
+
+/**
+ * @return {number} The distance from the top edge of this element to the top
+ *     edge of its parent, specified in units of the parent's coordinate system.
+ */
+goog.graphics.ext.Element.prototype.getTop = function() {
+  return this.yPosition_.getStart();
+};
+
+
+/**
+ * Sets the top coordinate of the element.  Overwrites any previous value of
+ * top, middle, or bottom for this element.
+ * @param {string|number} top The top coordinate.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ */
+goog.graphics.ext.Element.prototype.setTop = function(top, opt_chain) {
+  this.setPosition_(this.yPosition_,
+      top,
+      goog.graphics.ext.Element.PositionType_.START,
+      opt_chain);
+};
+
+
+/**
+ * @return {number} The bottom coordinate of the element, in units of the
+ *     parent's coordinate system.
+ */
+goog.graphics.ext.Element.prototype.getBottom = function() {
+  return this.yPosition_.getEnd();
+};
+
+
+/**
+ * Sets the bottom coordinate of the element.  Overwrites any previous value of
+ * top, middle, or bottom for this element.
+ * @param {string|number} bottom The bottom coordinate.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ */
+goog.graphics.ext.Element.prototype.setBottom = function(bottom, opt_chain) {
+  this.setPosition_(this.yPosition_,
+      bottom,
+      goog.graphics.ext.Element.PositionType_.END,
+      opt_chain);
+};
+
+
+/**
+ * @return {number} The middle coordinate of the element, in units of the
+ *     parent's coordinate system.
+ */
+goog.graphics.ext.Element.prototype.getMiddle = function() {
+  return this.yPosition_.getMiddle();
+};
+
+
+/**
+ * Sets the middle coordinate of the element.  Overwrites any previous value of
+ * top, middle, or bottom for this element
+ * @param {string|number} middle The middle coordinate.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ */
+goog.graphics.ext.Element.prototype.setMiddle = function(middle, opt_chain) {
+  this.setPosition_(this.yPosition_,
+      middle,
+      goog.graphics.ext.Element.PositionType_.MIDDLE,
+      opt_chain);
+};
+
+
+// DIMENSIONS
+
+
+/**
+ * @return {number} The width of the element, in units of the parent's
+ *     coordinate system.
+ */
+goog.graphics.ext.Element.prototype.getWidth = function() {
+  return this.xPosition_.getSize();
+};
+
+
+/**
+ * Sets the width of the element.
+ * @param {string|number} width The new width value.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ */
+goog.graphics.ext.Element.prototype.setWidth = function(width, opt_chain) {
+  this.setSize_(this.xPosition_, width, opt_chain);
+};
+
+
+/**
+ * @return {number} The minimum width of the element, in units of the parent's
+ *     coordinate system.
+ */
+goog.graphics.ext.Element.prototype.getMinWidth = function() {
+  return this.xPosition_.getMinSize();
+};
+
+
+/**
+ * Sets the minimum width of the element.
+ * @param {string|number} minWidth The minimum width of the element.
+ */
+goog.graphics.ext.Element.prototype.setMinWidth = function(minWidth) {
+  this.setMinSize_(this.xPosition_, minWidth);
+};
+
+
+/**
+ * @return {number} The height of the element, in units of the parent's
+ *     coordinate system.
+ */
+goog.graphics.ext.Element.prototype.getHeight = function() {
+  return this.yPosition_.getSize();
+};
+
+
+/**
+ * Sets the height of the element.
+ * @param {string|number} height The new height value.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ */
+goog.graphics.ext.Element.prototype.setHeight = function(height, opt_chain) {
+  this.setSize_(this.yPosition_, height, opt_chain);
+};
+
+
+/**
+ * @return {number} The minimum height of the element, in units of the parent's
+ *     coordinate system.
+ */
+goog.graphics.ext.Element.prototype.getMinHeight = function() {
+  return this.yPosition_.getMinSize();
+};
+
+
+/**
+ * Sets the minimum height of the element.
+ * @param {string|number} minHeight The minimum height of the element.
+ */
+goog.graphics.ext.Element.prototype.setMinHeight = function(minHeight) {
+  this.setMinSize_(this.yPosition_, minHeight);
+};
+
+
+// BOUNDS SHORTCUTS
+
+
+/**
+ * Shortcut for setting the left and top position.
+ * @param {string|number} left The left coordinate.
+ * @param {string|number} top The top coordinate.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ */
+goog.graphics.ext.Element.prototype.setPosition = function(left, top,
+                                                           opt_chain) {
+  this.setLeft(left, true);
+  this.setTop(top, opt_chain);
+};
+
+
+/**
+ * Shortcut for setting the width and height.
+ * @param {string|number} width The new width value.
+ * @param {string|number} height The new height value.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ */
+goog.graphics.ext.Element.prototype.setSize = function(width, height,
+                                                       opt_chain) {
+  this.setWidth(width, true);
+  this.setHeight(height, opt_chain);
+};
+
+
+/**
+ * Shortcut for setting the left, top, width, and height.
+ * @param {string|number} left The left coordinate.
+ * @param {string|number} top The top coordinate.
+ * @param {string|number} width The new width value.
+ * @param {string|number} height The new height value.
+ * @param {boolean=} opt_chain Optional flag to specify this function is part
+ *     of a chain of calls and therefore transformations should be set as
+ *     pending but not yet performed.
+ */
+goog.graphics.ext.Element.prototype.setBounds = function(left, top, width,
+                                                         height, opt_chain) {
+  this.setLeft(left, true);
+  this.setTop(top, true);
+  this.setWidth(width, true);
+  this.setHeight(height, opt_chain);
+};
+
+
+// MAXIMUM BOUNDS
+
+
+/**
+ * @return {number} An estimate of the maximum x extent this element would have
+ *     in a parent of no width.
+ */
+goog.graphics.ext.Element.prototype.getMaxX = function() {
+  return this.xPosition_.getMaxPosition();
+};
+
+
+/**
+ * @return {number} An estimate of the maximum y extent this element would have
+ *     in a parent of no height.
+ */
+goog.graphics.ext.Element.prototype.getMaxY = function() {
+  return this.yPosition_.getMaxPosition();
+};
+
+
+// RESET
+
+
+/**
+ * Reset the element.  This is called when the element changes size, or when
+ * the coordinate system changes in a way that would affect pixel based
+ * rendering
+ */
+goog.graphics.ext.Element.prototype.reset = function() {
+  this.xPosition_.resetCache();
+  this.yPosition_.resetCache();
+
+  this.redraw();
+
+  this.needsTransform_ = true;
+  this.transform();
+};
+
+
+/**
+ * Overridable function for subclass specific reset.
+ * @protected
+ */
+goog.graphics.ext.Element.prototype.redraw = goog.nullFunction;
+
+
+// PARENT DEPENDENCY
+
+
+/**
+ * Computes whether the element is still parent dependent.
+ * @param {goog.graphics.ext.Element.Position_} position The recently changed
+ *     position object.
+ * @private
+ */
+goog.graphics.ext.Element.prototype.computeIsParentDependent_ = function(
+    position) {
+  this.parentDependent_ = position.isParentDependent() ||
+      this.xPosition_.isParentDependent() ||
+      this.yPosition_.isParentDependent() ||
+      this.checkParentDependent();
+};
+
+
+/**
+ * Returns whether this element's bounds depend on its parents.
+ *
+ * This function should be treated as if it has package scope.
+ * @return {boolean} Whether this element's bounds depend on its parents.
+ */
+goog.graphics.ext.Element.prototype.isParentDependent = function() {
+  return this.parentDependent_;
+};
+
+
+/**
+ * Overridable function for subclass specific parent dependency.
+ * @return {boolean} Whether this shape's bounds depends on its parent's.
+ * @protected
+ */
+goog.graphics.ext.Element.prototype.checkParentDependent =
+    goog.functions.FALSE;
+
+
+// ROTATION
+
+
+/**
+ * Set the rotation of this element.
+ * @param {number} angle The angle of rotation, in degrees.
+ */
+goog.graphics.ext.Element.prototype.setRotation = function(angle) {
+  if (this.rotation_ != angle) {
+    this.rotation_ = angle;
+
+    this.needsTransform_ = true;
+    this.transform();
+  }
+};
+
+
+/**
+ * @return {number} The angle of rotation of this element, in degrees.
+ */
+goog.graphics.ext.Element.prototype.getRotation = function() {
+  return this.rotation_;
+};
+
+
+// TRANSFORMS
+
+
+/**
+ * Called by the parent when the parent has transformed.
+ *
+ * Should be treated as package scope.
+ */
+goog.graphics.ext.Element.prototype.parentTransform = function() {
+  this.needsTransform_ = this.needsTransform_ || this.parentDependent_;
+};
+
+
+/**
+ * @return {boolean} Whether this element has pending transforms.
+ */
+goog.graphics.ext.Element.prototype.isPendingTransform = function() {
+  return this.needsTransform_;
+};
+
+
+/**
+ * Performs a pending transform.
+ * @protected
+ */
+goog.graphics.ext.Element.prototype.transform = function() {
+  if (this.isPendingTransform()) {
+    this.needsTransform_ = false;
+
+    this.wrapper_.setTransformation(
+        this.getLeft(),
+        this.getTop(),
+        this.rotation_,
+        (this.getWidth() || 1) / 2,
+        (this.getHeight() || 1) / 2);
+
+    // TODO(robbyw): this._fireEvent('transform', [ this ]);
+  }
+};
+
+
+// PIXEL SCALE
+
+
+/**
+ * @return {number} Returns the number of pixels per unit in the x direction.
+ */
+goog.graphics.ext.Element.prototype.getPixelScaleX = function() {
+  return this.getGraphics().getPixelScaleX();
+};
+
+
+/**
+ * @return {number} Returns the number of pixels per unit in the y direction.
+ */
+goog.graphics.ext.Element.prototype.getPixelScaleY = function() {
+  return this.getGraphics().getPixelScaleY();
+};
+
+
+// EVENT HANDLING
+
+
+/** @override */
+goog.graphics.ext.Element.prototype.disposeInternal = function() {
+  goog.graphics.ext.Element.superClass_.disposeInternal.call();
+  this.wrapper_.dispose();
+};
+
+
+// INTERNAL POSITION OBJECT
+
+
+/**
+ * Position specification types.  Start corresponds to left/top, middle to
+ * center/middle, and end to right/bottom.
+ * @enum {number}
+ * @private
+ */
+goog.graphics.ext.Element.PositionType_ = {
+  START: 0,
+  MIDDLE: 1,
+  END: 2
+};
+
+
+
+/**
+ * Manages a position and size, either horizontal or vertical.
+ * @param {goog.graphics.ext.Element} element The element the position applies
+ *     to.
+ * @param {boolean} horizontal Whether the position is horizontal or vertical.
+ * @constructor
+ * @private
+ */
+goog.graphics.ext.Element.Position_ = function(element, horizontal) {
+  this.element_ = element;
+  this.horizontal_ = horizontal;
+};
+
+
+/**
+ * @return {!Object} The coordinate value computation cache.
+ * @private
+ */
+goog.graphics.ext.Element.Position_.prototype.getCoordinateCache_ = function() {
+  return this.coordinateCache_ || (this.coordinateCache_ = {});
+};
+
+
+/**
+ * @return {number} The size of the parent's coordinate space.
+ * @private
+ */
+goog.graphics.ext.Element.Position_.prototype.getParentSize_ = function() {
+  var parent = this.element_.getParent();
+  return this.horizontal_ ?
+      parent.getCoordinateWidth() :
+      parent.getCoordinateHeight();
+};
+
+
+/**
+ * @return {number} The minimum width/height of the element.
+ */
+goog.graphics.ext.Element.Position_.prototype.getMinSize = function() {
+  return this.getValue_(this.minSize_);
+};
+
+
+/**
+ * Sets the minimum width/height of the element.
+ * @param {string|number} minSize The minimum width/height of the element.
+ */
+goog.graphics.ext.Element.Position_.prototype.setMinSize = function(minSize) {
+  this.minSize_ = minSize;
+  this.resetCache();
+};
+
+
+/**
+ * @return {number} The width/height of the element.
+ */
+goog.graphics.ext.Element.Position_.prototype.getSize = function() {
+  return Math.max(this.getValue_(this.size_), this.getMinSize());
+};
+
+
+/**
+ * Sets the width/height of the element.
+ * @param {string|number} size The width/height of the element.
+ * @return {boolean} Whether the value was changed.
+ */
+goog.graphics.ext.Element.Position_.prototype.setSize = function(size) {
+  if (size != this.size_) {
+    this.size_ = size;
+    this.resetCache();
+    return true;
+  }
+  return false;
+};
+
+
+/**
+ * Converts the given x coordinate to a number value in units.
+ * @param {string|number} v The coordinate to retrieve the value for.
+ * @param {boolean=} opt_forMaximum Whether we are computing the largest value
+ *     this coordinate would be in a parent of no size.
+ * @return {number} The correct number of coordinate space units.
+ * @private
+ */
+goog.graphics.ext.Element.Position_.prototype.getValue_ = function(v,
+    opt_forMaximum) {
+  if (!goog.graphics.ext.coordinates.isSpecial(v)) {
+    return parseFloat(String(v));
+  }
+
+  var cache = this.getCoordinateCache_();
+  var scale = this.horizontal_ ?
+      this.element_.getPixelScaleX() :
+      this.element_.getPixelScaleY();
+
+  var containerSize;
+  if (opt_forMaximum) {
+    containerSize = goog.graphics.ext.coordinates.computeValue(
+        this.size_ || 0, 0, scale);
+  } else {
+    var parent = this.element_.getParent();
+    containerSize = this.horizontal_ ? parent.getWidth() : parent.getHeight();
+  }
+
+  return goog.graphics.ext.coordinates.getValue(v, opt_forMaximum,
+      containerSize, scale, cache);
+};
+
+
+/**
+ * @return {number} The distance from the left/top edge of this element to the
+ *     left/top edge of its parent, specified in units of the parent's
+ *     coordinate system.
+ */
+goog.graphics.ext.Element.Position_.prototype.getStart = function() {
+  if (this.cachedValue_ == null) {
+    var value = this.getValue_(this.distance_);
+    if (this.distanceType_ == goog.graphics.ext.Element.PositionType_.START) {
+      this.cachedValue_ = value;
+    } else if (this.distanceType_ ==
+               goog.graphics.ext.Element.PositionType_.MIDDLE) {
+      this.cachedValue_ = value + (this.getParentSize_() - this.getSize()) / 2;
+    } else {
+      this.cachedValue_ = this.getParentSize_() - value - this.getSize();
+    }
+  }
+
+  return this.cachedValue_;
+};
+
+
+/**
+ * @return {number} The middle coordinate of the element, in units of the
+ *     parent's coordinate system.
+ */
+goog.graphics.ext.Element.Position_.prototype.getMiddle = function() {
+  return this.distanceType_ == goog.graphics.ext.Element.PositionType_.MIDDLE ?
+      this.getValue_(this.distance_) :
+      (this.getParentSize_() - this.getSize()) / 2 - this.getStart();
+};
+
+
+/**
+ * @return {number} The end coordinate of the element, in units of the
+ *     parent's coordinate system.
+ */
+goog.graphics.ext.Element.Position_.prototype.getEnd = function() {
+  return this.distanceType_ == goog.graphics.ext.Element.PositionType_.END ?
+      this.getValue_(this.distance_) :
+      this.getParentSize_() - this.getStart() - this.getSize();
+};
+
+
+/**
+ * Sets the position, either as a left/top, center/middle, or right/bottom
+ * value.
+ * @param {number|string} value The value of the coordinate.
+ * @param {goog.graphics.ext.Element.PositionType_} type The type of the
+ *     coordinate.
+ */
+goog.graphics.ext.Element.Position_.prototype.setPosition = function(value,
+    type) {
+  this.distance_ = value;
+  this.distanceType_ = type;
+
+  // Clear cached value.
+  this.cachedValue_ = null;
+};
+
+
+/**
+ * @return {number} An estimate of the maximum x/y extent this element would
+ *     have in a parent of no width/height.
+ */
+goog.graphics.ext.Element.Position_.prototype.getMaxPosition = function() {
+  // TODO(robbyw): Handle transformed or rotated coordinates
+  // TODO(robbyw): Handle pixel based sizes?
+
+  return this.getValue_(this.distance_ || 0) + (
+      goog.graphics.ext.coordinates.isSpecial(this.size_) ? 0 : this.getSize());
+};
+
+
+/**
+ * Resets the caches of position values and coordinate values.
+ */
+goog.graphics.ext.Element.Position_.prototype.resetCache = function() {
+  this.coordinateCache_ = null;
+  this.cachedValue_ = null;
+};
+
+
+/**
+ * @return {boolean} Whether the size or position of this element depends on
+ *     the size of the parent element.
+ */
+goog.graphics.ext.Element.Position_.prototype.isParentDependent = function() {
+  return this.distanceType_ != goog.graphics.ext.Element.PositionType_.START ||
+      goog.graphics.ext.coordinates.isSpecial(this.size_) ||
+      goog.graphics.ext.coordinates.isSpecial(this.minSize_) ||
+      goog.graphics.ext.coordinates.isSpecial(this.distance_);
+};
+
+
+/**
+ * The lazy loaded distance from the parent's top/left edge to this element's
+ * top/left edge expressed in the parent's coordinate system.  We cache this
+ * because it is most freqeuently requested by the element and it is easy to
+ * compute middle and end values from it.
+ * @type {?number}
+ * @private
+ */
+goog.graphics.ext.Element.Position_.prototype.cachedValue_ = null;
+
+
+/**
+ * A cache of computed x coordinates.
+ * @type {Object}
+ * @private
+ */
+goog.graphics.ext.Element.Position_.prototype.coordinateCache_ = null;
+
+
+/**
+ * The minimum width/height of this element, as specified by the caller.
+ * @type {string|number}
+ * @private
+ */
+goog.graphics.ext.Element.Position_.prototype.minSize_ = 0;
+
+
+/**
+ * The width/height of this object, as specified by the caller.
+ * @type {string|number}
+ * @private
+ */
+goog.graphics.ext.Element.Position_.prototype.size_ = 0;
+
+
+/**
+ * The coordinate of this object, as specified by the caller.  The type of
+ * coordinate is specified by distanceType_.
+ * @type {string|number}
+ * @private
+ */
+goog.graphics.ext.Element.Position_.prototype.distance_ = 0;
+
+
+/**
+ * The coordinate type specified by distance_.
+ * @type {goog.graphics.ext.Element.PositionType_}
+ * @private
+ */
+goog.graphics.ext.Element.Position_.prototype.distanceType_ =
+    goog.graphics.ext.Element.PositionType_.START;
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/ext/ellipse.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/ext/ellipse.js b/externs/GCL/externs/goog/graphics/ext/ellipse.js
new file mode 100644
index 0000000..db77524
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/ext/ellipse.js
@@ -0,0 +1,60 @@
+// 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 A thick wrapper around ellipses.
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.graphics.ext.Ellipse');
+
+goog.require('goog.graphics.ext.StrokeAndFillElement');
+
+
+
+/**
+ * Wrapper for a graphics ellipse element.
+ * @param {goog.graphics.ext.Group} group Parent for this element.
+ * @constructor
+ * @extends {goog.graphics.ext.StrokeAndFillElement}
+ * @final
+ */
+goog.graphics.ext.Ellipse = function(group) {
+  // Initialize with some stock values.
+  var wrapper = group.getGraphicsImplementation().drawEllipse(1, 1, 2, 2, null,
+      null, group.getWrapper());
+  goog.graphics.ext.StrokeAndFillElement.call(this, group, wrapper);
+};
+goog.inherits(goog.graphics.ext.Ellipse,
+              goog.graphics.ext.StrokeAndFillElement);
+
+
+/**
+ * Redraw the ellipse.  Called when the coordinate system is changed.
+ * @protected
+ * @override
+ */
+goog.graphics.ext.Ellipse.prototype.redraw = function() {
+  goog.graphics.ext.Ellipse.superClass_.redraw.call(this);
+
+  // Our position is already transformed in transform_, but because this is an
+  // ellipse we need to position the center.
+  var xRadius = this.getWidth() / 2;
+  var yRadius = this.getHeight() / 2;
+  var wrapper = this.getWrapper();
+  wrapper.setCenter(xRadius, yRadius);
+  wrapper.setRadius(xRadius, yRadius);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/ext/ext.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/ext/ext.js b/externs/GCL/externs/goog/graphics/ext/ext.js
new file mode 100644
index 0000000..b3ff4e3
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/ext/ext.js
@@ -0,0 +1,31 @@
+// 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 Extended graphics namespace.
+ * @suppress {extraRequire} All the requires in this file are "extra"
+ * because this file is not actually using them.
+ */
+
+
+goog.provide('goog.graphics.ext');
+
+goog.require('goog.graphics.ext.Ellipse');
+goog.require('goog.graphics.ext.Graphics');
+goog.require('goog.graphics.ext.Group');
+goog.require('goog.graphics.ext.Image');
+goog.require('goog.graphics.ext.Rectangle');
+goog.require('goog.graphics.ext.Shape');
+goog.require('goog.graphics.ext.coordinates');

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/ext/graphics.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/ext/graphics.js b/externs/GCL/externs/goog/graphics/ext/graphics.js
new file mode 100644
index 0000000..a3c1a54
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/ext/graphics.js
@@ -0,0 +1,218 @@
+// 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 Graphics surface type.
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.graphics.ext.Graphics');
+
+goog.require('goog.events');
+goog.require('goog.events.EventType');
+goog.require('goog.graphics');
+goog.require('goog.graphics.ext.Group');
+
+
+
+/**
+ * Wrapper for a graphics surface.
+ * @param {string|number} width The width in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {string|number} height The height in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {?number=} opt_coordWidth The coordinate width - if
+ *     omitted or null, defaults to same as width.
+ * @param {?number=} opt_coordHeight The coordinate height. - if
+ *     omitted or null, defaults to same as height.
+ * @param {goog.dom.DomHelper=} opt_domHelper The DOM helper object for the
+ *     document we want to render in.
+ * @param {boolean=} opt_isSimple Flag used to indicate the graphics object will
+ *     be drawn to in a single pass, and the fastest implementation for this
+ *     scenario should be favored.  NOTE: Setting to true may result in
+ *     degradation of text support.
+ * @constructor
+ * @extends {goog.graphics.ext.Group}
+ * @final
+ */
+goog.graphics.ext.Graphics = function(width, height, opt_coordWidth,
+    opt_coordHeight, opt_domHelper, opt_isSimple) {
+  var surface = opt_isSimple ?
+      goog.graphics.createSimpleGraphics(width, height,
+          opt_coordWidth, opt_coordHeight, opt_domHelper) :
+      goog.graphics.createGraphics(width, height,
+          opt_coordWidth, opt_coordHeight, opt_domHelper);
+  this.implementation_ = surface;
+
+  goog.graphics.ext.Group.call(this, null, surface.getCanvasElement());
+
+  goog.events.listen(surface, goog.events.EventType.RESIZE,
+      this.updateChildren, false, this);
+};
+goog.inherits(goog.graphics.ext.Graphics, goog.graphics.ext.Group);
+
+
+/**
+ * The root level graphics implementation.
+ * @type {goog.graphics.AbstractGraphics}
+ * @private
+ */
+goog.graphics.ext.Graphics.prototype.implementation_;
+
+
+/**
+ * @return {goog.graphics.AbstractGraphics} The graphics implementation layer.
+ */
+goog.graphics.ext.Graphics.prototype.getImplementation = function() {
+  return this.implementation_;
+};
+
+
+/**
+ * Changes the coordinate size.
+ * @param {number} coordWidth The coordinate width.
+ * @param {number} coordHeight The coordinate height.
+ */
+goog.graphics.ext.Graphics.prototype.setCoordSize = function(coordWidth,
+                                                             coordHeight) {
+  this.implementation_.setCoordSize(coordWidth, coordHeight);
+  goog.graphics.ext.Graphics.superClass_.setSize.call(this, coordWidth,
+      coordHeight);
+};
+
+
+/**
+ * @return {goog.math.Size} The coordinate size.
+ */
+goog.graphics.ext.Graphics.prototype.getCoordSize = function() {
+  return this.implementation_.getCoordSize();
+};
+
+
+/**
+ * Changes the coordinate system position.
+ * @param {number} left The coordinate system left bound.
+ * @param {number} top The coordinate system top bound.
+ */
+goog.graphics.ext.Graphics.prototype.setCoordOrigin = function(left, top) {
+  this.implementation_.setCoordOrigin(left, top);
+};
+
+
+/**
+ * @return {!goog.math.Coordinate} The coordinate system position.
+ */
+goog.graphics.ext.Graphics.prototype.getCoordOrigin = function() {
+  return this.implementation_.getCoordOrigin();
+};
+
+
+/**
+ * Change the size of the canvas.
+ * @param {number} pixelWidth The width in pixels.
+ * @param {number} pixelHeight The height in pixels.
+ */
+goog.graphics.ext.Graphics.prototype.setPixelSize = function(pixelWidth,
+                                                        pixelHeight) {
+  this.implementation_.setSize(pixelWidth, pixelHeight);
+
+  var coordSize = this.getCoordSize();
+  goog.graphics.ext.Graphics.superClass_.setSize.call(this, coordSize.width,
+      coordSize.height);
+};
+
+
+/**
+ * @return {goog.math.Size?} Returns the number of pixels spanned by the
+ *     surface, or null if the size could not be computed due to the size being
+ *     specified in percentage points and the component not being in the
+ *     document.
+ */
+goog.graphics.ext.Graphics.prototype.getPixelSize = function() {
+  return this.implementation_.getPixelSize();
+};
+
+
+/**
+ * @return {number} The coordinate width of the canvas.
+ * @override
+ */
+goog.graphics.ext.Graphics.prototype.getWidth = function() {
+  return this.implementation_.getCoordSize().width;
+};
+
+
+/**
+ * @return {number} The coordinate width of the canvas.
+ * @override
+ */
+goog.graphics.ext.Graphics.prototype.getHeight = function() {
+  return this.implementation_.getCoordSize().height;
+};
+
+
+/**
+ * @return {number} Returns the number of pixels per unit in the x direction.
+ * @override
+ */
+goog.graphics.ext.Graphics.prototype.getPixelScaleX = function() {
+  return this.implementation_.getPixelScaleX();
+};
+
+
+/**
+ * @return {number} Returns the number of pixels per unit in the y direction.
+ * @override
+ */
+goog.graphics.ext.Graphics.prototype.getPixelScaleY = function() {
+  return this.implementation_.getPixelScaleY();
+};
+
+
+/**
+ * @return {Element} The root element of the graphics surface.
+ */
+goog.graphics.ext.Graphics.prototype.getElement = function() {
+  return this.implementation_.getElement();
+};
+
+
+/**
+ * Renders the underlying graphics.
+ *
+ * @param {Element} parentElement Parent element to render the component into.
+ */
+goog.graphics.ext.Graphics.prototype.render = function(parentElement) {
+  this.implementation_.render(parentElement);
+};
+
+
+/**
+ * Never transform a surface.
+ * @override
+ */
+goog.graphics.ext.Graphics.prototype.transform = goog.nullFunction;
+
+
+/**
+ * Called from the parent class, this method resets any pre-computed positions
+ * and sizes.
+ * @protected
+ * @override
+ */
+goog.graphics.ext.Graphics.prototype.redraw = function() {
+  this.transformChildren();
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/ext/group.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/ext/group.js b/externs/GCL/externs/goog/graphics/ext/group.js
new file mode 100644
index 0000000..03479ad
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/ext/group.js
@@ -0,0 +1,216 @@
+// 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 A thicker wrapper around graphics groups.
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.graphics.ext.Group');
+
+goog.require('goog.array');
+goog.require('goog.graphics.ext.Element');
+
+
+
+/**
+ * Wrapper for a graphics group.
+ * @param {goog.graphics.ext.Group} group Parent for this element. Can
+ *     be null if this is a Graphics instance.
+ * @param {goog.graphics.GroupElement=} opt_wrapper The thin wrapper
+ *     to wrap. If omitted, a new group will be created. Must be included
+ *     when group is null.
+ * @constructor
+ * @extends {goog.graphics.ext.Element}
+ */
+goog.graphics.ext.Group = function(group, opt_wrapper) {
+  opt_wrapper = opt_wrapper || group.getGraphicsImplementation().createGroup(
+      group.getWrapper());
+  goog.graphics.ext.Element.call(this, group, opt_wrapper);
+
+  /**
+   * Array of child elements this group contains.
+   * @type {Array<goog.graphics.ext.Element>}
+   * @private
+   */
+  this.children_ = [];
+};
+goog.inherits(goog.graphics.ext.Group, goog.graphics.ext.Element);
+
+
+/**
+ * Add an element to the group.  This should be treated as package local, as
+ * it is called by the draw* methods.
+ * @param {!goog.graphics.ext.Element} element The element to add.
+ * @param {boolean=} opt_chain Whether this addition is part of a longer set
+ *     of element additions.
+ */
+goog.graphics.ext.Group.prototype.addChild = function(element, opt_chain) {
+  if (!goog.array.contains(this.children_, element)) {
+    this.children_.push(element);
+  }
+
+  var transformed = this.growToFit_(element);
+
+  if (element.isParentDependent()) {
+    element.parentTransform();
+  }
+
+  if (!opt_chain && element.isPendingTransform()) {
+    element.reset();
+  }
+
+  if (transformed) {
+    this.reset();
+  }
+};
+
+
+/**
+ * Remove an element from the group.
+ * @param {goog.graphics.ext.Element} element The element to remove.
+ */
+goog.graphics.ext.Group.prototype.removeChild = function(element) {
+  goog.array.remove(this.children_, element);
+
+  // TODO(robbyw): shape.fireEvent('delete')
+
+  this.getGraphicsImplementation().removeElement(element.getWrapper());
+};
+
+
+/**
+ * Calls the given function on each of this component's children in order.  If
+ * {@code opt_obj} is provided, it will be used as the 'this' object in the
+ * function when called.  The function should take two arguments:  the child
+ * component and its 0-based index.  The return value is ignored.
+ * @param {Function} f The function to call for every child component; should
+ *    take 2 arguments (the child and its index).
+ * @param {Object=} opt_obj Used as the 'this' object in f when called.
+ */
+goog.graphics.ext.Group.prototype.forEachChild = function(f, opt_obj) {
+  if (this.children_) {
+    goog.array.forEach(this.children_, f, opt_obj);
+  }
+};
+
+
+/**
+ * @return {goog.graphics.GroupElement} The underlying thin wrapper.
+ * @override
+ */
+goog.graphics.ext.Group.prototype.getWrapper;
+
+
+/**
+ * Reset the element.
+ * @override
+ */
+goog.graphics.ext.Group.prototype.reset = function() {
+  goog.graphics.ext.Group.superClass_.reset.call(this);
+
+  this.updateChildren();
+};
+
+
+/**
+ * Called from the parent class, this method resets any pre-computed positions
+ * and sizes.
+ * @protected
+ * @override
+ */
+goog.graphics.ext.Group.prototype.redraw = function() {
+  this.getWrapper().setSize(this.getWidth(), this.getHeight());
+  this.transformChildren();
+};
+
+
+/**
+ * Transform the children that need to be transformed.
+ * @protected
+ */
+goog.graphics.ext.Group.prototype.transformChildren = function() {
+  this.forEachChild(function(child) {
+    if (child.isParentDependent()) {
+      child.parentTransform();
+    }
+  });
+};
+
+
+/**
+ * As part of the reset process, update child elements.
+ */
+goog.graphics.ext.Group.prototype.updateChildren = function() {
+  this.forEachChild(function(child) {
+    if (child.isParentDependent() || child.isPendingTransform()) {
+      child.reset();
+    } else if (child.updateChildren) {
+      child.updateChildren();
+    }
+  });
+};
+
+
+/**
+ * When adding an element, grow this group's bounds to fit it.
+ * @param {!goog.graphics.ext.Element} element The added element.
+ * @return {boolean} Whether the size of this group changed.
+ * @private
+ */
+goog.graphics.ext.Group.prototype.growToFit_ = function(element) {
+  var transformed = false;
+
+  var x = element.getMaxX();
+  if (x > this.getWidth()) {
+    this.setMinWidth(x);
+    transformed = true;
+  }
+
+  var y = element.getMaxY();
+  if (y > this.getHeight()) {
+    this.setMinHeight(y);
+    transformed = true;
+  }
+
+  return transformed;
+};
+
+
+/**
+ * @return {number} The width of the element's coordinate space.
+ */
+goog.graphics.ext.Group.prototype.getCoordinateWidth = function() {
+  return this.getWidth();
+};
+
+
+/**
+ * @return {number} The height of the element's coordinate space.
+ */
+goog.graphics.ext.Group.prototype.getCoordinateHeight = function() {
+  return this.getHeight();
+};
+
+
+/**
+ * Remove all drawing elements from the group.
+ */
+goog.graphics.ext.Group.prototype.clear = function() {
+  while (this.children_.length) {
+    this.removeChild(this.children_[0]);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/ext/image.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/ext/image.js b/externs/GCL/externs/goog/graphics/ext/image.js
new file mode 100644
index 0000000..ec24e1d
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/ext/image.js
@@ -0,0 +1,64 @@
+// 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 A thick wrapper around images.
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.graphics.ext.Image');
+
+goog.require('goog.graphics.ext.Element');
+
+
+
+/**
+ * Wrapper for a graphics image element.
+ * @param {goog.graphics.ext.Group} group Parent for this element.
+ * @param {string} src The path to the image to display.
+ * @constructor
+ * @extends {goog.graphics.ext.Element}
+ * @final
+ */
+goog.graphics.ext.Image = function(group, src) {
+  // Initialize with some stock values.
+  var wrapper = group.getGraphicsImplementation().drawImage(0, 0, 1, 1, src,
+      group.getWrapper());
+  goog.graphics.ext.Element.call(this, group, wrapper);
+};
+goog.inherits(goog.graphics.ext.Image, goog.graphics.ext.Element);
+
+
+/**
+ * Redraw the image.  Called when the coordinate system is changed.
+ * @protected
+ * @override
+ */
+goog.graphics.ext.Image.prototype.redraw = function() {
+  goog.graphics.ext.Image.superClass_.redraw.call(this);
+
+  // Our position is already handled bu transform_.
+  this.getWrapper().setSize(this.getWidth(), this.getHeight());
+};
+
+
+/**
+ * Update the source of the image.
+ * @param {string} src  Source of the image.
+ */
+goog.graphics.ext.Image.prototype.setSource = function(src) {
+  this.getWrapper().setSource(src);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/ext/path.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/ext/path.js b/externs/GCL/externs/goog/graphics/ext/path.js
new file mode 100644
index 0000000..de550aa
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/ext/path.js
@@ -0,0 +1,142 @@
+// 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 A thick wrapper around paths.
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.graphics.ext.Path');
+
+goog.require('goog.graphics.AffineTransform');
+goog.require('goog.graphics.Path');
+goog.require('goog.math.Rect');
+
+
+
+/**
+ * Creates a path object
+ * @constructor
+ * @extends {goog.graphics.Path}
+ * @final
+ */
+goog.graphics.ext.Path = function() {
+  goog.graphics.Path.call(this);
+};
+goog.inherits(goog.graphics.ext.Path, goog.graphics.Path);
+
+
+/**
+ * Optional cached or user specified bounding box.  A user may wish to
+ * precompute a bounding box to save time and include more accurate
+ * computations.
+ * @type {goog.math.Rect?}
+ * @private
+ */
+goog.graphics.ext.Path.prototype.bounds_ = null;
+
+
+/**
+ * Clones the path.
+ * @return {!goog.graphics.ext.Path} A clone of this path.
+ * @override
+ */
+goog.graphics.ext.Path.prototype.clone = function() {
+  var output = /** @type {goog.graphics.ext.Path} */
+      (goog.graphics.ext.Path.superClass_.clone.call(this));
+  output.bounds_ = this.bounds_ && this.bounds_.clone();
+  return output;
+};
+
+
+/**
+ * Transforms the path. Only simple paths are transformable. Attempting
+ * to transform a non-simple path will throw an error.
+ * @param {!goog.graphics.AffineTransform} tx The transformation to perform.
+ * @return {!goog.graphics.ext.Path} The path itself.
+ * @override
+ */
+goog.graphics.ext.Path.prototype.transform = function(tx) {
+  goog.graphics.ext.Path.superClass_.transform.call(this, tx);
+
+  // Make sure the precomputed bounds are cleared when the path is transformed.
+  this.bounds_ = null;
+
+  return this;
+};
+
+
+/**
+ * Modify the bounding box of the path.  This may cause the path to be
+ * simplified (i.e. arcs converted to curves) as a side-effect.
+ * @param {number} deltaX How far to translate the x coordinates.
+ * @param {number} deltaY How far to translate the y coordinates.
+ * @param {number} xFactor After translation, all x coordinates are multiplied
+ *     by this number.
+ * @param {number} yFactor After translation, all y coordinates are multiplied
+ *     by this number.
+ * @return {!goog.graphics.ext.Path} The path itself.
+ */
+goog.graphics.ext.Path.prototype.modifyBounds = function(deltaX, deltaY,
+    xFactor, yFactor) {
+  if (!this.isSimple()) {
+    var simple = goog.graphics.Path.createSimplifiedPath(this);
+    this.clear();
+    this.appendPath(simple);
+  }
+
+  return this.transform(goog.graphics.AffineTransform.getScaleInstance(
+      xFactor, yFactor).translate(deltaX, deltaY));
+};
+
+
+/**
+ * Set the precomputed bounds.
+ * @param {goog.math.Rect?} bounds The bounds to use, or set to null to clear
+ *     and recompute on the next call to getBoundingBox.
+ */
+goog.graphics.ext.Path.prototype.useBoundingBox = function(bounds) {
+  this.bounds_ = bounds && bounds.clone();
+};
+
+
+/**
+ * @return {goog.math.Rect?} The bounding box of the path, or null if the
+ *     path is empty.
+ */
+goog.graphics.ext.Path.prototype.getBoundingBox = function() {
+  if (!this.bounds_ && !this.isEmpty()) {
+    var minY;
+    var minX = minY = Number.POSITIVE_INFINITY;
+    var maxY;
+    var maxX = maxY = Number.NEGATIVE_INFINITY;
+
+    var simplePath = this.isSimple() ? this :
+        goog.graphics.Path.createSimplifiedPath(this);
+    simplePath.forEachSegment(function(type, points) {
+      for (var i = 0, len = points.length; i < len; i += 2) {
+        minX = Math.min(minX, points[i]);
+        maxX = Math.max(maxX, points[i]);
+        minY = Math.min(minY, points[i + 1]);
+        maxY = Math.max(maxY, points[i + 1]);
+      }
+    });
+
+    this.bounds_ = new goog.math.Rect(minX, minY, maxX - minX, maxY - minY);
+  }
+
+  return this.bounds_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/ext/rectangle.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/ext/rectangle.js b/externs/GCL/externs/goog/graphics/ext/rectangle.js
new file mode 100644
index 0000000..d05c8b1
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/ext/rectangle.js
@@ -0,0 +1,55 @@
+// 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 A thick wrapper around rectangles.
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.graphics.ext.Rectangle');
+
+goog.require('goog.graphics.ext.StrokeAndFillElement');
+
+
+
+/**
+ * Wrapper for a graphics rectangle element.
+ * @param {goog.graphics.ext.Group} group Parent for this element.
+ * @constructor
+ * @extends {goog.graphics.ext.StrokeAndFillElement}
+ * @final
+ */
+goog.graphics.ext.Rectangle = function(group) {
+  // Initialize with some stock values.
+  var wrapper = group.getGraphicsImplementation().drawRect(0, 0, 1, 1, null,
+      null, group.getWrapper());
+  goog.graphics.ext.StrokeAndFillElement.call(this, group, wrapper);
+};
+goog.inherits(goog.graphics.ext.Rectangle,
+              goog.graphics.ext.StrokeAndFillElement);
+
+
+/**
+ * Redraw the rectangle.  Called when the coordinate system is changed.
+ * @protected
+ * @override
+ */
+goog.graphics.ext.Rectangle.prototype.redraw = function() {
+  goog.graphics.ext.Rectangle.superClass_.redraw.call(this);
+
+  // Our position is already handled by transform_.
+  this.getWrapper().setSize(this.getWidth(), this.getHeight());
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/ext/shape.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/ext/shape.js b/externs/GCL/externs/goog/graphics/ext/shape.js
new file mode 100644
index 0000000..3f80e82
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/ext/shape.js
@@ -0,0 +1,145 @@
+// 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 A thick wrapper around shapes with custom paths.
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.graphics.ext.Shape');
+
+goog.require('goog.graphics.ext.StrokeAndFillElement');
+
+
+
+/**
+ * Wrapper for a graphics shape element.
+ * @param {goog.graphics.ext.Group} group Parent for this element.
+ * @param {!goog.graphics.ext.Path} path  The path to draw.
+ * @param {boolean=} opt_autoSize Optional flag to specify the path should
+ *     automatically resize to fit the element.  Defaults to false.
+ * @constructor
+ * @extends {goog.graphics.ext.StrokeAndFillElement}
+ * @final
+ */
+goog.graphics.ext.Shape = function(group, path, opt_autoSize) {
+  this.autoSize_ = !!opt_autoSize;
+
+  var graphics = group.getGraphicsImplementation();
+  var wrapper = graphics.drawPath(path, null, null,
+      group.getWrapper());
+  goog.graphics.ext.StrokeAndFillElement.call(this, group, wrapper);
+  this.setPath(path);
+};
+goog.inherits(goog.graphics.ext.Shape, goog.graphics.ext.StrokeAndFillElement);
+
+
+/**
+ * Whether or not to automatically resize the shape's path when the element
+ * itself is resized.
+ * @type {boolean}
+ * @private
+ */
+goog.graphics.ext.Shape.prototype.autoSize_ = false;
+
+
+/**
+ * The original path, specified by the caller.
+ * @type {goog.graphics.Path}
+ * @private
+ */
+goog.graphics.ext.Shape.prototype.path_;
+
+
+/**
+ * The bounding box of the original path.
+ * @type {goog.math.Rect?}
+ * @private
+ */
+goog.graphics.ext.Shape.prototype.boundingBox_ = null;
+
+
+/**
+ * The scaled path.
+ * @type {goog.graphics.Path}
+ * @private
+ */
+goog.graphics.ext.Shape.prototype.scaledPath_;
+
+
+/**
+ * Get the path drawn by this shape.
+ * @return {goog.graphics.Path?} The path drawn by this shape.
+ */
+goog.graphics.ext.Shape.prototype.getPath = function() {
+  return this.path_;
+};
+
+
+/**
+ * Set the path to draw.
+ * @param {goog.graphics.ext.Path} path The path to draw.
+ */
+goog.graphics.ext.Shape.prototype.setPath = function(path) {
+  this.path_ = path;
+
+  if (this.autoSize_) {
+    this.boundingBox_ = path.getBoundingBox();
+  }
+
+  this.scaleAndSetPath_();
+};
+
+
+/**
+ * Scale the internal path to fit.
+ * @private
+ */
+goog.graphics.ext.Shape.prototype.scaleAndSetPath_ = function() {
+  this.scaledPath_ = this.boundingBox_ ? this.path_.clone().modifyBounds(
+      -this.boundingBox_.left, -this.boundingBox_.top,
+      this.getWidth() / (this.boundingBox_.width || 1),
+      this.getHeight() / (this.boundingBox_.height || 1)) : this.path_;
+
+  var wrapper = this.getWrapper();
+  if (wrapper) {
+    wrapper.setPath(this.scaledPath_);
+  }
+};
+
+
+/**
+ * Redraw the ellipse.  Called when the coordinate system is changed.
+ * @protected
+ * @override
+ */
+goog.graphics.ext.Shape.prototype.redraw = function() {
+  goog.graphics.ext.Shape.superClass_.redraw.call(this);
+  if (this.autoSize_) {
+    this.scaleAndSetPath_();
+  }
+};
+
+
+/**
+ * @return {boolean} Whether the shape is parent dependent.
+ * @protected
+ * @override
+ */
+goog.graphics.ext.Shape.prototype.checkParentDependent = function() {
+  return this.autoSize_ ||
+      goog.graphics.ext.Shape.superClass_.checkParentDependent.call(this);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/ext/strokeandfillelement.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/ext/strokeandfillelement.js b/externs/GCL/externs/goog/graphics/ext/strokeandfillelement.js
new file mode 100644
index 0000000..4ad69f3
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/ext/strokeandfillelement.js
@@ -0,0 +1,70 @@
+// 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 A thick wrapper around elements with stroke and fill.
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.graphics.ext.StrokeAndFillElement');
+
+goog.require('goog.graphics.ext.Element');
+
+
+
+/**
+ * Interface for a graphics element that has a stroke and fill.
+ * This is the base interface for ellipse, rectangle and other
+ * shape interfaces.
+ * You should not construct objects from this constructor. Use a subclass.
+ * @param {goog.graphics.ext.Group} group Parent for this element.
+ * @param {goog.graphics.StrokeAndFillElement} wrapper The thin wrapper to wrap.
+ * @constructor
+ * @extends {goog.graphics.ext.Element}
+ */
+goog.graphics.ext.StrokeAndFillElement = function(group, wrapper) {
+  goog.graphics.ext.Element.call(this, group, wrapper);
+};
+goog.inherits(goog.graphics.ext.StrokeAndFillElement,
+    goog.graphics.ext.Element);
+
+
+/**
+ * Sets the fill for this element.
+ * @param {goog.graphics.Fill?} fill The fill object.
+ */
+goog.graphics.ext.StrokeAndFillElement.prototype.setFill = function(fill) {
+  this.getWrapper().setFill(fill);
+};
+
+
+/**
+ * Sets the stroke for this element.
+ * @param {goog.graphics.Stroke?} stroke The stroke object.
+ */
+goog.graphics.ext.StrokeAndFillElement.prototype.setStroke = function(stroke) {
+  this.getWrapper().setStroke(stroke);
+};
+
+
+/**
+ * Redraw the rectangle.  Called when the coordinate system is changed.
+ * @protected
+ * @override
+ */
+goog.graphics.ext.StrokeAndFillElement.prototype.redraw = function() {
+  this.getWrapper().reapplyStroke();
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/fill.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/fill.js b/externs/GCL/externs/goog/graphics/fill.js
new file mode 100644
index 0000000..92e460e
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/fill.js
@@ -0,0 +1,46 @@
+// 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 Represents a fill goog.graphics.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.graphics.Fill');
+
+
+
+/**
+ * Creates a fill object
+ * @constructor
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.Fill = function() {};
+
+
+/**
+ * @return {string} The start color of a gradient fill.
+ */
+goog.graphics.Fill.prototype.getColor1 = goog.abstractMethod;
+
+
+/**
+ * @return {string} The end color of a gradient fill.
+ */
+goog.graphics.Fill.prototype.getColor2 = goog.abstractMethod;
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/font.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/font.js b/externs/GCL/externs/goog/graphics/font.js
new file mode 100644
index 0000000..f58bf41
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/font.js
@@ -0,0 +1,64 @@
+// 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 Represents a font to be used with a Renderer.
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/graphics/basicelements.html
+ */
+
+
+goog.provide('goog.graphics.Font');
+
+
+
+/**
+ * This class represents a font to be used with a renderer.
+ * @param {number} size  The font size.
+ * @param {string} family  The font family.
+ * @constructor
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ * @final
+ */
+goog.graphics.Font = function(size, family) {
+  /**
+   * Font size.
+   * @type {number}
+   */
+  this.size = size;
+  // TODO(arv): Is this in pixels or drawing units based on the coord size?
+
+  /**
+   * The name of the font family to use, can be a comma separated string.
+   * @type {string}
+   */
+  this.family = family;
+};
+
+
+/**
+ * Indication if text should be bolded
+ * @type {boolean}
+ */
+goog.graphics.Font.prototype.bold = false;
+
+
+/**
+ * Indication if text should be in italics
+ * @type {boolean}
+ */
+goog.graphics.Font.prototype.italic = false;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/graphics/graphics.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/graphics/graphics.js b/externs/GCL/externs/goog/graphics/graphics.js
new file mode 100644
index 0000000..0bde5b5
--- /dev/null
+++ b/externs/GCL/externs/goog/graphics/graphics.js
@@ -0,0 +1,142 @@
+// 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 Graphics utility functions and factory methods.
+ * @author arv@google.com (Erik Arvidsson)
+ * @see ../demos/graphics/advancedcoordinates.html
+ * @see ../demos/graphics/advancedcoordinates2.html
+ * @see ../demos/graphics/basicelements.html
+ * @see ../demos/graphics/events.html
+ * @see ../demos/graphics/modifyelements.html
+ * @see ../demos/graphics/tiger.html
+ */
+
+
+goog.provide('goog.graphics');
+
+goog.require('goog.dom');
+goog.require('goog.graphics.CanvasGraphics');
+goog.require('goog.graphics.SvgGraphics');
+goog.require('goog.graphics.VmlGraphics');
+goog.require('goog.userAgent');
+
+
+/**
+ * Returns an instance of goog.graphics.AbstractGraphics that knows how to draw
+ * for the current platform (A factory for the proper Graphics implementation)
+ * @param {string|number} width The width in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {string|number} height The height in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {?number=} opt_coordWidth The optional coordinate width - if
+ *     omitted or null, defaults to same as width.
+ * @param {?number=} opt_coordHeight The optional coordinate height - if
+ *     omitted or null, defaults to same as height.
+ * @param {goog.dom.DomHelper=} opt_domHelper The DOM helper object for the
+ *     document we want to render in.
+ * @return {!goog.graphics.AbstractGraphics} The created instance.
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.createGraphics = function(width, height, opt_coordWidth,
+    opt_coordHeight, opt_domHelper) {
+  var graphics;
+  // On IE9 and above, SVG is available, except in compatibility mode.
+  // We check createElementNS on document object that is not exist in
+  // compatibility mode.
+  if (goog.userAgent.IE &&
+      (!goog.userAgent.isVersionOrHigher('9') ||
+       !(opt_domHelper || goog.dom.getDomHelper()).
+           getDocument().createElementNS)) {
+    graphics = new goog.graphics.VmlGraphics(width, height,
+        opt_coordWidth, opt_coordHeight, opt_domHelper);
+  } else if (goog.userAgent.WEBKIT &&
+             (!goog.userAgent.isVersionOrHigher('420') ||
+              goog.userAgent.MOBILE)) {
+    graphics = new goog.graphics.CanvasGraphics(width, height,
+        opt_coordWidth, opt_coordHeight, opt_domHelper);
+  } else {
+    graphics = new goog.graphics.SvgGraphics(width, height,
+        opt_coordWidth, opt_coordHeight, opt_domHelper);
+  }
+
+  // Create the dom now, because all drawing methods require that the
+  // main dom element (the canvas) has been already created.
+  graphics.createDom();
+
+  return graphics;
+};
+
+
+/**
+ * Returns an instance of goog.graphics.AbstractGraphics that knows how to draw
+ * for the current platform (A factory for the proper Graphics implementation)
+ * @param {string|number} width The width in pixels.  Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {string|number} height The height in pixels.   Strings
+ *     expressing percentages of parent with (e.g. '80%') are also accepted.
+ * @param {?number=} opt_coordWidth The optional coordinate width, defaults to
+ *     same as width.
+ * @param {?number=} opt_coordHeight The optional coordinate height, defaults to
+ *     same as height.
+ * @param {goog.dom.DomHelper=} opt_domHelper The DOM helper object for the
+ *     document we want to render in.
+ * @return {!goog.graphics.AbstractGraphics} The created instance.
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.createSimpleGraphics = function(width, height,
+    opt_coordWidth, opt_coordHeight, opt_domHelper) {
+  if (goog.userAgent.MAC && goog.userAgent.GECKO &&
+      !goog.userAgent.isVersionOrHigher('1.9a')) {
+    // Canvas is 6x faster than SVG on Mac FF 2.0
+    var graphics = new goog.graphics.CanvasGraphics(
+        width, height, opt_coordWidth, opt_coordHeight,
+        opt_domHelper);
+    graphics.createDom();
+    return graphics;
+  }
+
+  // Otherwise, defer to normal graphics object creation.
+  return goog.graphics.createGraphics(width, height, opt_coordWidth,
+      opt_coordHeight, opt_domHelper);
+};
+
+
+/**
+ * Static function to check if the current browser has Graphics support.
+ * @return {boolean} True if the current browser has Graphics support.
+ * @deprecated goog.graphics is deprecated. It existed to abstract over browser
+ *     differences before the canvas tag was widely supported.  See
+ *     http://en.wikipedia.org/wiki/Canvas_element for details.
+ */
+goog.graphics.isBrowserSupported = function() {
+  if (goog.userAgent.IE) {
+    return goog.userAgent.isVersionOrHigher('5.5');
+  }
+  if (goog.userAgent.GECKO) {
+    return goog.userAgent.isVersionOrHigher('1.8');
+  }
+  if (goog.userAgent.OPERA) {
+    return goog.userAgent.isVersionOrHigher('9.0');
+  }
+  if (goog.userAgent.WEBKIT) {
+    return goog.userAgent.isVersionOrHigher('412');
+  }
+  return false;
+};


[34/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/graphics/tigerdata.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/graphics/tigerdata.js b/externs/GCL/externs/goog/demos/graphics/tigerdata.js
new file mode 100644
index 0000000..633c55c
--- /dev/null
+++ b/externs/GCL/externs/goog/demos/graphics/tigerdata.js
@@ -0,0 +1,2841 @@
+// 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 This data is generated from an SVG image of a tiger.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+var tigerData = [{f: '#fff', s: {c: '#000', w: 0.172},
+ p: [{t: 'M', p: [77.696, 284.285]},
+ {t: 'C', p: [77.696, 284.285, 77.797, 286.179, 76.973, 286.16]},
+ {t: 'C', p: [76.149, 286.141, 59.695, 238.066, 39.167, 240.309]},
+ {t: 'C', p: [39.167, 240.309, 56.95, 232.956, 77.696, 284.285]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: {c: '#000', w: 0.172},
+ p: [{t: 'M', p: [81.226, 281.262]},
+ {t: 'C', p: [81.226, 281.262, 80.677, 283.078, 79.908, 282.779]},
+ {t: 'C', p: [79.14, 282.481, 80.023, 231.675, 59.957, 226.801]},
+ {t: 'C', p: [59.957, 226.801, 79.18, 225.937, 81.226, 281.262]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: {c: '#000', w: 0.172},
+ p: [{t: 'M', p: [108.716, 323.59]},
+ {t: 'C', p: [108.716, 323.59, 110.352, 324.55, 109.882, 325.227]},
+ {t: 'C', p: [109.411, 325.904, 60.237, 313.102, 50.782, 331.459]},
+ {t: 'C', p: [50.782, 331.459, 54.461, 312.572, 108.716, 323.59]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: {c: '#000', w: 0.172},
+ p: [{t: 'M', p: [105.907, 333.801]},
+ {t: 'C', p: [105.907, 333.801, 107.763, 334.197, 107.529, 334.988]},
+ {t: 'C', p: [107.296, 335.779, 56.593, 339.121, 53.403, 359.522]},
+ {t: 'C', p: [53.403, 359.522, 50.945, 340.437, 105.907, 333.801]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: {c: '#000', w: 0.172},
+ p: [{t: 'M', p: [101.696, 328.276]},
+ {t: 'C', p: [101.696, 328.276, 103.474, 328.939, 103.128, 329.687]},
+ {t: 'C', p: [102.782, 330.435, 52.134, 326.346, 46.002, 346.064]},
+ {t: 'C', p: [46.002, 346.064, 46.354, 326.825, 101.696, 328.276]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: {c: '#000', w: 0.172},
+ p: [{t: 'M', p: [90.991, 310.072]},
+ {t: 'C', p: [90.991, 310.072, 92.299, 311.446, 91.66, 311.967]},
+ {t: 'C', p: [91.021, 312.488, 47.278, 286.634, 33.131, 301.676]},
+ {t: 'C', p: [33.131, 301.676, 41.872, 284.533, 90.991, 310.072]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: {c: '#000', w: 0.172},
+ p: [{t: 'M', p: [83.446, 314.263]},
+ {t: 'C', p: [83.446, 314.263, 84.902, 315.48, 84.326, 316.071]},
+ {t: 'C', p: [83.75, 316.661, 37.362, 295.922, 25.008, 312.469]},
+ {t: 'C', p: [25.008, 312.469, 31.753, 294.447, 83.446, 314.263]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: {c: '#000', w: 0.172},
+ p: [{t: 'M', p: [80.846, 318.335]},
+ {t: 'C', p: [80.846, 318.335, 82.454, 319.343, 81.964, 320.006]},
+ {t: 'C', p: [81.474, 320.669, 32.692, 306.446, 22.709, 324.522]},
+ {t: 'C', p: [22.709, 324.522, 26.934, 305.749, 80.846, 318.335]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: {c: '#000', w: 0.172},
+ p: [{t: 'M', p: [91.58, 318.949]},
+ {t: 'C', p: [91.58, 318.949, 92.702, 320.48, 92.001, 320.915]},
+ {t: 'C', p: [91.3, 321.35, 51.231, 290.102, 35.273, 303.207]},
+ {t: 'C', p: [35.273, 303.207, 46.138, 287.326, 91.58, 318.949]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: {c: '#000', w: 0.172},
+ p: [{t: 'M', p: [71.8, 290]},
+ {t: 'C', p: [71.8, 290, 72.4, 291.8, 71.6, 292]},
+ {t: 'C', p: [70.8, 292.2, 42.2, 250.2, 22.999, 257.8]},
+ {t: 'C', p: [22.999, 257.8, 38.2, 246, 71.8, 290]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: {c: '#000', w: 0.172},
+ p: [{t: 'M', p: [72.495, 296.979]},
+ {t: 'C', p: [72.495, 296.979, 73.47, 298.608, 72.731, 298.975]},
+ {t: 'C', p: [71.993, 299.343, 35.008, 264.499, 17.899, 276.061]},
+ {t: 'C', p: [17.899, 276.061, 30.196, 261.261, 72.495, 296.979]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: {c: '#000', w: 0.172},
+ p: [{t: 'M', p: [72.38, 301.349]},
+ {t: 'C', p: [72.38, 301.349, 73.502, 302.88, 72.801, 303.315]},
+ {t: 'C', p: [72.1, 303.749, 32.031, 272.502, 16.073, 285.607]},
+ {t: 'C', p: [16.073, 285.607, 26.938, 269.726, 72.38, 301.349]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: '#000', p: [{t: 'M', p: [70.17, 303.065]},
+ {t: 'C', p: [70.673, 309.113, 71.661, 315.682, 73.4, 318.801]},
+ {t: 'C', p: [73.4, 318.801, 69.8, 331.201, 78.6, 344.401]},
+ {t: 'C', p: [78.6, 344.401, 78.2, 351.601, 79.8, 354.801]},
+ {t: 'C', p: [79.8, 354.801, 83.8, 363.201, 88.6, 364.001]},
+ {t: 'C', p: [92.484, 364.648, 101.207, 367.717, 111.068, 369.121]},
+ {t: 'C', p: [111.068, 369.121, 128.2, 383.201, 125, 396.001]},
+ {t: 'C', p: [125, 396.001, 124.6, 412.401, 121, 414.001]},
+ {t: 'C', p: [121, 414.001, 132.6, 402.801, 123, 419.601]},
+ {t: 'L', p: [118.6, 438.401]},
+ {t: 'C', p: [118.6, 438.401, 144.2, 416.801, 128.6, 435.201]},
+ {t: 'L', p: [118.6, 461.201]},
+ {t: 'C', p: [118.6, 461.201, 138.2, 442.801, 131, 451.201]},
+ {t: 'L', p: [127.8, 460.001]},
+ {t: 'C', p: [127.8, 460.001, 171, 432.801, 140.2, 462.401]},
+ {t: 'C', p: [140.2, 462.401, 148.2, 458.801, 152.6, 461.601]},
+ {t: 'C', p: [152.6, 461.601, 159.4, 460.401, 158.6, 462.001]},
+ {t: 'C', p: [158.6, 462.001, 137.8, 472.401, 134.2, 490.801]},
+ {t: 'C', p: [134.2, 490.801, 142.6, 480.801, 139.4, 491.601]},
+ {t: 'L', p: [139.8, 503.201]},
+ {t: 'C', p: [139.8, 503.201, 143.8, 481.601, 143.4, 519.201]},
+ {t: 'C', p: [143.4, 519.201, 162.6, 501.201, 151, 522.001]},
+ {t: 'L', p: [151, 538.801]},
+ {t: 'C', p: [151, 538.801, 166.2, 522.401, 159.8, 535.201]},
+ {t: 'C', p: [159.8, 535.201, 169.8, 526.401, 165.8, 541.601]},
+ {t: 'C', p: [165.8, 541.601, 165, 552.001, 169.4, 540.801]},
+ {t: 'C', p: [169.4, 540.801, 185.4, 510.201, 179.4, 536.401]},
+ {t: 'C', p: [179.4, 536.401, 178.6, 555.601, 183.4, 540.801]},
+ {t: 'C', p: [183.4, 540.801, 183.8, 551.201, 193, 558.401]},
+ {t: 'C', p: [193, 558.401, 191.8, 507.601, 204.6, 543.601]},
+ {t: 'L', p: [208.6, 560.001]},
+ {t: 'C', p: [208.6, 560.001, 211.4, 550.801, 211, 545.601]},
+ {t: 'C', p: [211, 545.601, 225.8, 529.201, 219, 553.601]},
+ {t: 'C', p: [219, 553.601, 234.2, 530.801, 231, 544.001]},
+ {t: 'C', p: [231, 544.001, 223.4, 560.001, 225, 564.801]},
+ {t: 'C', p: [225, 564.801, 241.8, 530.001, 243, 528.401]},
+ {t: 'C', p: [243, 528.401, 241, 570.802, 251.8, 534.801]},
+ {t: 'C', p: [251.8, 534.801, 257.4, 546.801, 254.6, 551.201]},
+ {t: 'C', p: [254.6, 551.201, 262.6, 543.201, 261.8, 540.001]},
+ {t: 'C', p: [261.8, 540.001, 266.4, 531.801, 269.2, 545.401]},
+ {t: 'C', p: [269.2, 545.401, 271, 554.801, 272.6, 551.601]},
+ {t: 'C', p: [272.6, 551.601, 276.6, 575.602, 277.8, 552.801]},
+ {t: 'C', p: [277.8, 552.801, 279.4, 539.201, 272.2, 527.601]},
+ {t: 'C', p: [272.2, 527.601, 273, 524.401, 270.2, 520.401]},
+ {t: 'C', p: [270.2, 520.401, 283.8, 542.001, 276.6, 513.201]},
+ {t: 'C', p: [276.6, 513.201, 287.801, 521.201, 289.001, 521.201]},
+ {t: 'C', p: [289.001, 521.201, 275.4, 498.001, 284.2, 502.801]},
+ {t: 'C', p: [284.2, 502.801, 279, 492.401, 297.001, 504.401]},
+ {t: 'C', p: [297.001, 504.401, 281, 488.401, 298.601, 498.001]},
+ {t: 'C', p: [298.601, 498.001, 306.601, 504.401, 299.001, 494.401]},
+ {t: 'C', p: [299.001, 494.401, 284.6, 478.401, 306.601, 496.401]},
+ {t: 'C', p: [306.601, 496.401, 318.201, 512.801, 319.001, 515.601]},
+ {t: 'C', p: [319.001, 515.601, 309.001, 486.401, 304.601, 483.601]},
+ {t: 'C', p: [304.601, 483.601, 313.001, 447.201, 354.201, 462.801]},
+ {t: 'C', p: [354.201, 462.801, 361.001, 480.001, 365.401, 461.601]},
+ {t: 'C', p: [365.401, 461.601, 378.201, 455.201, 389.401, 482.801]},
+ {t: 'C', p: [389.401, 482.801, 393.401, 469.201, 392.601, 466.401]},
+ {t: 'C', p: [392.601, 466.401, 399.401, 467.601, 398.601, 466.401]},
+ {t: 'C', p: [398.601, 466.401, 411.801, 470.801, 413.001, 470.001]},
+ {t: 'C', p: [413.001, 470.001, 419.801, 476.801, 420.201, 473.201]},
+ {t: 'C', p: [420.201, 473.201, 429.401, 476.001, 427.401, 472.401]},
+ {t: 'C', p: [427.401, 472.401, 436.201, 488.001, 436.601, 491.601]},
+ {t: 'L', p: [439.001, 477.601]},
+ {t: 'L', p: [441.001, 480.401]},
+ {t: 'C', p: [441.001, 480.401, 442.601, 472.801, 441.801, 471.601]},
+ {t: 'C', p: [441.001, 470.401, 461.801, 478.401, 466.601, 499.201]},
+ {t: 'L', p: [468.601, 507.601]},
+ {t: 'C', p: [468.601, 507.601, 474.601, 492.801, 473.001, 488.801]},
+ {t: 'C', p: [473.001, 488.801, 478.201, 489.601, 478.601, 494.001]},
+ {t: 'C', p: [478.601, 494.001, 482.601, 470.801, 477.801, 464.801]},
+ {t: 'C', p: [477.801, 464.801, 482.201, 464.001, 483.401, 467.601]},
+ {t: 'L', p: [483.401, 460.401]},
+ {t: 'C', p: [483.401, 460.401, 490.601, 461.201, 490.601, 458.801]},
+ {t: 'C', p: [490.601, 458.801, 495.001, 454.801, 497.001, 459.601]},
+ {t: 'C', p: [497.001, 459.601, 484.601, 424.401, 503.001, 443.601]},
+ {t: 'C', p: [503.001, 443.601, 510.201, 454.401, 506.601, 435.601]},
+ {t: 'C', p: [503.001, 416.801, 499.001, 415.201, 503.801, 414.801]},
+ {t: 'C', p: [503.801, 414.801, 504.601, 411.201, 502.601, 409.601]},
+ {t: 'C', p: [500.601, 408.001, 503.801, 409.601, 503.801, 409.601]},
+ {t: 'C', p: [503.801, 409.601, 508.601, 413.601, 503.401, 391.601]},
+ {t: 'C', p: [503.401, 391.601, 509.801, 393.201, 497.801, 364.001]},
+ {t: 'C', p: [497.801, 364.001, 500.601, 361.601, 496.601, 353.201]},
+ {t: 'C', p: [496.601, 353.201, 504.601, 357.601, 507.401, 356.001]},
+ {t: 'C', p: [507.401, 356.001, 507.001, 354.401, 503.801, 350.401]},
+ {t: 'C', p: [503.801, 350.401, 482.201, 295.6, 502.601, 317.601]},
+ {t: 'C', p: [502.601, 317.601, 514.451, 331.151, 508.051, 308.351]},
+ {t: 'C', p: [508.051, 308.351, 498.94, 284.341, 499.717, 280.045]},
+ {t: 'L', p: [70.17, 303.065]},
+ {t: 'z', p: []}]},
+
+{f: '#cc7226', s: '#000', p: [{t: 'M', p: [499.717, 280.245]},
+ {t: 'C', p: [500.345, 280.426, 502.551, 281.55, 503.801, 283.2]},
+ {t: 'C', p: [503.801, 283.2, 510.601, 294, 505.401, 275.6]},
+ {t: 'C', p: [505.401, 275.6, 496.201, 246.8, 505.001, 258]},
+ {t: 'C', p: [505.001, 258, 511.001, 265.2, 507.801, 251.6]},
+ {t: 'C', p: [503.936, 235.173, 501.401, 228.8, 501.401, 228.8]},
+ {t: 'C', p: [501.401, 228.8, 513.001, 233.6, 486.201, 194]},
+ {t: 'L', p: [495.001, 197.6]},
+ {t: 'C', p: [495.001, 197.6, 475.401, 158, 453.801, 152.8]},
+ {t: 'L', p: [445.801, 146.8]},
+ {t: 'C', p: [445.801, 146.8, 484.201, 108.8, 471.401, 72]},
+ {t: 'C', p: [471.401, 72, 464.601, 66.8, 455.001, 76]},
+ {t: 'C', p: [455.001, 76, 448.601, 80.8, 442.601, 79.2]},
+ {t: 'C', p: [442.601, 79.2, 411.801, 80.4, 409.801, 80.4]},
+ {t: 'C', p: [407.801, 80.4, 373.001, 43.2, 307.401, 60.8]},
+ {t: 'C', p: [307.401, 60.8, 302.201, 62.8, 297.801, 61.6]},
+ {t: 'C', p: [297.801, 61.6, 279.4, 45.6, 230.6, 68.4]},
+ {t: 'C', p: [230.6, 68.4, 220.6, 70.4, 219, 70.4]},
+ {t: 'C', p: [217.4, 70.4, 214.6, 70.4, 206.6, 76.8]},
+ {t: 'C', p: [198.6, 83.2, 198.2, 84, 196.2, 85.6]},
+ {t: 'C', p: [196.2, 85.6, 179.8, 96.8, 175, 97.6]},
+ {t: 'C', p: [175, 97.6, 163.4, 104, 159, 114]},
+ {t: 'L', p: [155.4, 115.2]},
+ {t: 'C', p: [155.4, 115.2, 153.8, 122.4, 153.4, 123.6]},
+ {t: 'C', p: [153.4, 123.6, 148.6, 127.2, 147.8, 132.8]},
+ {t: 'C', p: [147.8, 132.8, 139, 138.8, 139.4, 143.2]},
+ {t: 'C', p: [139.4, 143.2, 137.8, 148.4, 137, 153.2]},
+ {t: 'C', p: [137, 153.2, 129.8, 158, 130.6, 160.8]},
+ {t: 'C', p: [130.6, 160.8, 123, 174.8, 124.2, 181.6]},
+ {t: 'C', p: [124.2, 181.6, 117.8, 181.2, 115, 183.6]},
+ {t: 'C', p: [115, 183.6, 114.2, 188.4, 112.6, 188.8]},
+ {t: 'C', p: [112.6, 188.8, 109.8, 190, 112.2, 194]},
+ {t: 'C', p: [112.2, 194, 110.6, 196.8, 110.2, 198.4]},
+ {t: 'C', p: [110.2, 198.4, 111, 201.2, 106.6, 206.8]},
+ {t: 'C', p: [106.6, 206.8, 100.2, 225.6, 102.2, 230.8]},
+ {t: 'C', p: [102.2, 230.8, 102.6, 235.6, 99.8, 237.2]},
+ {t: 'C', p: [99.8, 237.2, 96.2, 236.8, 104.6, 248.8]},
+ {t: 'C', p: [104.6, 248.8, 105.4, 250, 102.2, 252.4]},
+ {t: 'C', p: [102.2, 252.4, 85, 256, 82.6, 272.4]},
+ {t: 'C', p: [82.6, 272.4, 69, 287.2, 69, 292.4]},
+ {t: 'C', p: [69, 294.705, 69.271, 297.852, 69.97, 302.465]},
+ {t: 'C', p: [69.97, 302.465, 69.4, 310.801, 97, 311.601]},
+ {t: 'C', p: [124.6, 312.401, 499.717, 280.245, 499.717, 280.245]},
+ {t: 'z', p: []}]},
+
+{f: '#cc7226', s: null, p: [{t: 'M', p: [84.4, 302.6]},
+ {t: 'C', p: [59.4, 263.2, 73.8, 319.601, 73.8, 319.601]},
+ {t: 'C', p: [82.6, 354.001, 212.2, 316.401, 212.2, 316.401]},
+ {t: 'C', p: [212.2, 316.401, 381.001, 286, 392.201, 282]},
+ {t: 'C', p: [403.401, 278, 498.601, 284.4, 498.601, 284.4]},
+ {t: 'L', p: [493.001, 267.6]},
+ {t: 'C', p: [428.201, 221.2, 409.001, 244.4, 395.401, 240.4]},
+ {t: 'C', p: [381.801, 236.4, 384.201, 246, 381.001, 246.8]},
+ {t: 'C', p: [377.801, 247.6, 338.601, 222.8, 332.201, 223.6]},
+ {t: 'C', p: [325.801, 224.4, 300.459, 200.649, 315.401, 232.4]},
+ {t: 'C', p: [331.401, 266.4, 257, 271.6, 240.2, 260.4]},
+ {t: 'C', p: [223.4, 249.2, 247.4, 278.8, 247.4, 278.8]},
+ {t: 'C', p: [265.8, 298.8, 231.4, 282, 231.4, 282]},
+ {t: 'C', p: [197, 269.2, 173, 294.8, 169.8, 295.6]},
+ {t: 'C', p: [166.6, 296.4, 161.8, 299.6, 161, 293.2]},
+ {t: 'C', p: [160.2, 286.8, 152.69, 270.099, 121, 296.4]},
+ {t: 'C', p: [101, 313.001, 87.2, 291, 87.2, 291]},
+ {t: 'L', p: [84.4, 302.6]},
+ {t: 'z', p: []}]},
+
+{f: '#e87f3a', s: null, p: [{t: 'M', p: [333.51, 225.346]},
+ {t: 'C', p: [327.11, 226.146, 301.743, 202.407, 316.71, 234.146]},
+ {t: 'C', p: [333.31, 269.346, 258.31, 273.346, 241.51, 262.146]},
+ {t: 'C', p: [224.709, 250.946, 248.71, 280.546, 248.71, 280.546]},
+ {t: 'C', p: [267.11, 300.546, 232.709, 283.746, 232.709, 283.746]},
+ {t: 'C', p: [198.309, 270.946, 174.309, 296.546, 171.109, 297.346]},
+ {t: 'C', p: [167.909, 298.146, 163.109, 301.346, 162.309, 294.946]},
+ {t: 'C', p: [161.509, 288.546, 154.13, 272.012, 122.309, 298.146]},
+ {t: 'C', p: [101.073, 315.492, 87.582, 294.037, 87.582, 294.037]},
+ {t: 'L', p: [84.382, 304.146]},
+ {t: 'C', p: [59.382, 264.346, 74.454, 322.655, 74.454, 322.655]},
+ {t: 'C', p: [83.255, 357.056, 213.509, 318.146, 213.509, 318.146]},
+ {t: 'C', p: [213.509, 318.146, 382.31, 287.746, 393.51, 283.746]},
+ {t: 'C', p: [404.71, 279.746, 499.038, 286.073, 499.038, 286.073]},
+ {t: 'L', p: [493.51, 268.764]},
+ {t: 'C', p: [428.71, 222.364, 410.31, 246.146, 396.71, 242.146]},
+ {t: 'C', p: [383.11, 238.146, 385.51, 247.746, 382.31, 248.546]},
+ {t: 'C', p: [379.11, 249.346, 339.91, 224.546, 333.51, 225.346]},
+ {t: 'z', p: []}]},
+
+{f: '#ea8c4d', s: null, p: [{t: 'M', p: [334.819, 227.091]},
+ {t: 'C', p: [328.419, 227.891, 303.685, 203.862, 318.019, 235.891]},
+ {t: 'C', p: [334.219, 272.092, 259.619, 275.092, 242.819, 263.892]},
+ {t: 'C', p: [226.019, 252.692, 250.019, 282.292, 250.019, 282.292]},
+ {t: 'C', p: [268.419, 302.292, 234.019, 285.492, 234.019, 285.492]},
+ {t: 'C', p: [199.619, 272.692, 175.618, 298.292, 172.418, 299.092]},
+ {t: 'C', p: [169.218, 299.892, 164.418, 303.092, 163.618, 296.692]},
+ {t: 'C', p: [162.818, 290.292, 155.57, 273.925, 123.618, 299.892]},
+ {t: 'C', p: [101.145, 317.983, 87.964, 297.074, 87.964, 297.074]},
+ {t: 'L', p: [84.364, 305.692]},
+ {t: 'C', p: [60.564, 266.692, 75.109, 325.71, 75.109, 325.71]},
+ {t: 'C', p: [83.909, 360.11, 214.819, 319.892, 214.819, 319.892]},
+ {t: 'C', p: [214.819, 319.892, 383.619, 289.492, 394.819, 285.492]},
+ {t: 'C', p: [406.019, 281.492, 499.474, 287.746, 499.474, 287.746]},
+ {t: 'L', p: [494.02, 269.928]},
+ {t: 'C', p: [429.219, 223.528, 411.619, 247.891, 398.019, 243.891]},
+ {t: 'C', p: [384.419, 239.891, 386.819, 249.491, 383.619, 250.292]},
+ {t: 'C', p: [380.419, 251.092, 341.219, 226.291, 334.819, 227.091]},
+ {t: 'z', p: []}]},
+
+{f: '#ec9961', s: null, p: [{t: 'M', p: [336.128, 228.837]},
+ {t: 'C', p: [329.728, 229.637, 304.999, 205.605, 319.328, 237.637]},
+ {t: 'C', p: [336.128, 275.193, 260.394, 276.482, 244.128, 265.637]},
+ {t: 'C', p: [227.328, 254.437, 251.328, 284.037, 251.328, 284.037]},
+ {t: 'C', p: [269.728, 304.037, 235.328, 287.237, 235.328, 287.237]},
+ {t: 'C', p: [200.928, 274.437, 176.928, 300.037, 173.728, 300.837]},
+ {t: 'C', p: [170.528, 301.637, 165.728, 304.837, 164.928, 298.437]},
+ {t: 'C', p: [164.128, 292.037, 157.011, 275.839, 124.927, 301.637]},
+ {t: 'C', p: [101.218, 320.474, 88.345, 300.11, 88.345, 300.11]},
+ {t: 'L', p: [84.345, 307.237]},
+ {t: 'C', p: [62.545, 270.437, 75.764, 328.765, 75.764, 328.765]},
+ {t: 'C', p: [84.564, 363.165, 216.128, 321.637, 216.128, 321.637]},
+ {t: 'C', p: [216.128, 321.637, 384.928, 291.237, 396.129, 287.237]},
+ {t: 'C', p: [407.329, 283.237, 499.911, 289.419, 499.911, 289.419]},
+ {t: 'L', p: [494.529, 271.092]},
+ {t: 'C', p: [429.729, 224.691, 412.929, 249.637, 399.329, 245.637]},
+ {t: 'C', p: [385.728, 241.637, 388.128, 251.237, 384.928, 252.037]},
+ {t: 'C', p: [381.728, 252.837, 342.528, 228.037, 336.128, 228.837]},
+ {t: 'z', p: []}]},
+
+{f: '#eea575', s: null, p: [{t: 'M', p: [337.438, 230.583]},
+ {t: 'C', p: [331.037, 231.383, 306.814, 207.129, 320.637, 239.383]},
+ {t: 'C', p: [337.438, 278.583, 262.237, 278.583, 245.437, 267.383]},
+ {t: 'C', p: [228.637, 256.183, 252.637, 285.783, 252.637, 285.783]},
+ {t: 'C', p: [271.037, 305.783, 236.637, 288.983, 236.637, 288.983]},
+ {t: 'C', p: [202.237, 276.183, 178.237, 301.783, 175.037, 302.583]},
+ {t: 'C', p: [171.837, 303.383, 167.037, 306.583, 166.237, 300.183]},
+ {t: 'C', p: [165.437, 293.783, 158.452, 277.752, 126.237, 303.383]},
+ {t: 'C', p: [101.291, 322.965, 88.727, 303.146, 88.727, 303.146]},
+ {t: 'L', p: [84.327, 308.783]},
+ {t: 'C', p: [64.527, 273.982, 76.418, 331.819, 76.418, 331.819]},
+ {t: 'C', p: [85.218, 366.22, 217.437, 323.383, 217.437, 323.383]},
+ {t: 'C', p: [217.437, 323.383, 386.238, 292.983, 397.438, 288.983]},
+ {t: 'C', p: [408.638, 284.983, 500.347, 291.092, 500.347, 291.092]},
+ {t: 'L', p: [495.038, 272.255]},
+ {t: 'C', p: [430.238, 225.855, 414.238, 251.383, 400.638, 247.383]},
+ {t: 'C', p: [387.038, 243.383, 389.438, 252.983, 386.238, 253.783]},
+ {t: 'C', p: [383.038, 254.583, 343.838, 229.783, 337.438, 230.583]},
+ {t: 'z', p: []}]},
+
+{f: '#f1b288', s: null, p: [{t: 'M', p: [338.747, 232.328]},
+ {t: 'C', p: [332.347, 233.128, 306.383, 209.677, 321.947, 241.128]},
+ {t: 'C', p: [341.147, 279.928, 263.546, 280.328, 246.746, 269.128]},
+ {t: 'C', p: [229.946, 257.928, 253.946, 287.528, 253.946, 287.528]},
+ {t: 'C', p: [272.346, 307.528, 237.946, 290.728, 237.946, 290.728]},
+ {t: 'C', p: [203.546, 277.928, 179.546, 303.528, 176.346, 304.328]},
+ {t: 'C', p: [173.146, 305.128, 168.346, 308.328, 167.546, 301.928]},
+ {t: 'C', p: [166.746, 295.528, 159.892, 279.665, 127.546, 305.128]},
+ {t: 'C', p: [101.364, 325.456, 89.109, 306.183, 89.109, 306.183]},
+ {t: 'L', p: [84.309, 310.328]},
+ {t: 'C', p: [66.309, 277.128, 77.073, 334.874, 77.073, 334.874]},
+ {t: 'C', p: [85.873, 369.274, 218.746, 325.128, 218.746, 325.128]},
+ {t: 'C', p: [218.746, 325.128, 387.547, 294.728, 398.747, 290.728]},
+ {t: 'C', p: [409.947, 286.728, 500.783, 292.764, 500.783, 292.764]},
+ {t: 'L', p: [495.547, 273.419]},
+ {t: 'C', p: [430.747, 227.019, 415.547, 253.128, 401.947, 249.128]},
+ {t: 'C', p: [388.347, 245.128, 390.747, 254.728, 387.547, 255.528]},
+ {t: 'C', p: [384.347, 256.328, 345.147, 231.528, 338.747, 232.328]},
+ {t: 'z', p: []}]},
+
+{f: '#f3bf9c', s: null, p: [{t: 'M', p: [340.056, 234.073]},
+ {t: 'C', p: [333.655, 234.873, 307.313, 211.613, 323.255, 242.873]},
+ {t: 'C', p: [343.656, 282.874, 264.855, 282.074, 248.055, 270.874]},
+ {t: 'C', p: [231.255, 259.674, 255.255, 289.274, 255.255, 289.274]},
+ {t: 'C', p: [273.655, 309.274, 239.255, 292.474, 239.255, 292.474]},
+ {t: 'C', p: [204.855, 279.674, 180.855, 305.274, 177.655, 306.074]},
+ {t: 'C', p: [174.455, 306.874, 169.655, 310.074, 168.855, 303.674]},
+ {t: 'C', p: [168.055, 297.274, 161.332, 281.578, 128.855, 306.874]},
+ {t: 'C', p: [101.436, 327.947, 89.491, 309.219, 89.491, 309.219]},
+ {t: 'L', p: [84.291, 311.874]},
+ {t: 'C', p: [68.291, 281.674, 77.727, 337.929, 77.727, 337.929]},
+ {t: 'C', p: [86.527, 372.329, 220.055, 326.874, 220.055, 326.874]},
+ {t: 'C', p: [220.055, 326.874, 388.856, 296.474, 400.056, 292.474]},
+ {t: 'C', p: [411.256, 288.474, 501.22, 294.437, 501.22, 294.437]},
+ {t: 'L', p: [496.056, 274.583]},
+ {t: 'C', p: [431.256, 228.183, 416.856, 254.874, 403.256, 250.874]},
+ {t: 'C', p: [389.656, 246.873, 392.056, 256.474, 388.856, 257.274]},
+ {t: 'C', p: [385.656, 258.074, 346.456, 233.273, 340.056, 234.073]},
+ {t: 'z', p: []}]},
+
+{f: '#f5ccb0', s: null, p: [{t: 'M', p: [341.365, 235.819]},
+ {t: 'C', p: [334.965, 236.619, 307.523, 213.944, 324.565, 244.619]},
+ {t: 'C', p: [346.565, 284.219, 266.164, 283.819, 249.364, 272.619]},
+ {t: 'C', p: [232.564, 261.419, 256.564, 291.019, 256.564, 291.019]},
+ {t: 'C', p: [274.964, 311.019, 240.564, 294.219, 240.564, 294.219]},
+ {t: 'C', p: [206.164, 281.419, 182.164, 307.019, 178.964, 307.819]},
+ {t: 'C', p: [175.764, 308.619, 170.964, 311.819, 170.164, 305.419]},
+ {t: 'C', p: [169.364, 299.019, 162.773, 283.492, 130.164, 308.619]},
+ {t: 'C', p: [101.509, 330.438, 89.873, 312.256, 89.873, 312.256]},
+ {t: 'L', p: [84.273, 313.419]},
+ {t: 'C', p: [69.872, 285.019, 78.382, 340.983, 78.382, 340.983]},
+ {t: 'C', p: [87.182, 375.384, 221.364, 328.619, 221.364, 328.619]},
+ {t: 'C', p: [221.364, 328.619, 390.165, 298.219, 401.365, 294.219]},
+ {t: 'C', p: [412.565, 290.219, 501.656, 296.11, 501.656, 296.11]},
+ {t: 'L', p: [496.565, 275.746]},
+ {t: 'C', p: [431.765, 229.346, 418.165, 256.619, 404.565, 252.619]},
+ {t: 'C', p: [390.965, 248.619, 393.365, 258.219, 390.165, 259.019]},
+ {t: 'C', p: [386.965, 259.819, 347.765, 235.019, 341.365, 235.819]},
+ {t: 'z', p: []}]},
+
+{f: '#f8d8c4', s: null, p: [{t: 'M', p: [342.674, 237.565]},
+ {t: 'C', p: [336.274, 238.365, 308.832, 215.689, 325.874, 246.365]},
+ {t: 'C', p: [347.874, 285.965, 267.474, 285.565, 250.674, 274.365]},
+ {t: 'C', p: [233.874, 263.165, 257.874, 292.765, 257.874, 292.765]},
+ {t: 'C', p: [276.274, 312.765, 241.874, 295.965, 241.874, 295.965]},
+ {t: 'C', p: [207.473, 283.165, 183.473, 308.765, 180.273, 309.565]},
+ {t: 'C', p: [177.073, 310.365, 172.273, 313.565, 171.473, 307.165]},
+ {t: 'C', p: [170.673, 300.765, 164.214, 285.405, 131.473, 310.365]},
+ {t: 'C', p: [101.582, 332.929, 90.255, 315.293, 90.255, 315.293]},
+ {t: 'L', p: [84.255, 314.965]},
+ {t: 'C', p: [70.654, 288.564, 79.037, 344.038, 79.037, 344.038]},
+ {t: 'C', p: [87.837, 378.438, 222.673, 330.365, 222.673, 330.365]},
+ {t: 'C', p: [222.673, 330.365, 391.474, 299.965, 402.674, 295.965]},
+ {t: 'C', p: [413.874, 291.965, 502.093, 297.783, 502.093, 297.783]},
+ {t: 'L', p: [497.075, 276.91]},
+ {t: 'C', p: [432.274, 230.51, 419.474, 258.365, 405.874, 254.365]},
+ {t: 'C', p: [392.274, 250.365, 394.674, 259.965, 391.474, 260.765]},
+ {t: 'C', p: [388.274, 261.565, 349.074, 236.765, 342.674, 237.565]},
+ {t: 'z', p: []}]},
+
+{f: '#fae5d7', s: null, p: [{t: 'M', p: [343.983, 239.31]},
+ {t: 'C', p: [337.583, 240.11, 310.529, 217.223, 327.183, 248.11]},
+ {t: 'C', p: [349.183, 288.91, 268.783, 287.31, 251.983, 276.11]},
+ {t: 'C', p: [235.183, 264.91, 259.183, 294.51, 259.183, 294.51]},
+ {t: 'C', p: [277.583, 314.51, 243.183, 297.71, 243.183, 297.71]},
+ {t: 'C', p: [208.783, 284.91, 184.783, 310.51, 181.583, 311.31]},
+ {t: 'C', p: [178.382, 312.11, 173.582, 315.31, 172.782, 308.91]},
+ {t: 'C', p: [171.982, 302.51, 165.654, 287.318, 132.782, 312.11]},
+ {t: 'C', p: [101.655, 335.42, 90.637, 318.329, 90.637, 318.329]},
+ {t: 'L', p: [84.236, 316.51]},
+ {t: 'C', p: [71.236, 292.51, 79.691, 347.093, 79.691, 347.093]},
+ {t: 'C', p: [88.491, 381.493, 223.983, 332.11, 223.983, 332.11]},
+ {t: 'C', p: [223.983, 332.11, 392.783, 301.71, 403.983, 297.71]},
+ {t: 'C', p: [415.183, 293.71, 502.529, 299.456, 502.529, 299.456]},
+ {t: 'L', p: [497.583, 278.074]},
+ {t: 'C', p: [432.783, 231.673, 420.783, 260.11, 407.183, 256.11]},
+ {t: 'C', p: [393.583, 252.11, 395.983, 261.71, 392.783, 262.51]},
+ {t: 'C', p: [389.583, 263.31, 350.383, 238.51, 343.983, 239.31]},
+ {t: 'z', p: []}]},
+
+{f: '#fcf2eb', s: null, p: [{t: 'M', p: [345.292, 241.055]},
+ {t: 'C', p: [338.892, 241.855, 312.917, 218.411, 328.492, 249.855]},
+ {t: 'C', p: [349.692, 292.656, 270.092, 289.056, 253.292, 277.856]},
+ {t: 'C', p: [236.492, 266.656, 260.492, 296.256, 260.492, 296.256]},
+ {t: 'C', p: [278.892, 316.256, 244.492, 299.456, 244.492, 299.456]},
+ {t: 'C', p: [210.092, 286.656, 186.092, 312.256, 182.892, 313.056]},
+ {t: 'C', p: [179.692, 313.856, 174.892, 317.056, 174.092, 310.656]},
+ {t: 'C', p: [173.292, 304.256, 167.095, 289.232, 134.092, 313.856]},
+ {t: 'C', p: [101.727, 337.911, 91.018, 321.365, 91.018, 321.365]},
+ {t: 'L', p: [84.218, 318.056]},
+ {t: 'C', p: [71.418, 294.856, 80.346, 350.147, 80.346, 350.147]},
+ {t: 'C', p: [89.146, 384.547, 225.292, 333.856, 225.292, 333.856]},
+ {t: 'C', p: [225.292, 333.856, 394.093, 303.456, 405.293, 299.456]},
+ {t: 'C', p: [416.493, 295.456, 502.965, 301.128, 502.965, 301.128]},
+ {t: 'L', p: [498.093, 279.237]},
+ {t: 'C', p: [433.292, 232.837, 422.093, 261.856, 408.493, 257.856]},
+ {t: 'C', p: [394.893, 253.855, 397.293, 263.456, 394.093, 264.256]},
+ {t: 'C', p: [390.892, 265.056, 351.692, 240.255, 345.292, 241.055]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: null, p: [{t: 'M', p: [84.2, 319.601]},
+ {t: 'C', p: [71.4, 297.6, 81, 353.201, 81, 353.201]},
+ {t: 'C', p: [89.8, 387.601, 226.6, 335.601, 226.6, 335.601]},
+ {t: 'C', p: [226.6, 335.601, 395.401, 305.2, 406.601, 301.2]},
+ {t: 'C', p: [417.801, 297.2, 503.401, 302.8, 503.401, 302.8]},
+ {t: 'L', p: [498.601, 280.4]},
+ {t: 'C', p: [433.801, 234, 423.401, 263.6, 409.801, 259.6]},
+ {t: 'C', p: [396.201, 255.6, 398.601, 265.2, 395.401, 266]},
+ {t: 'C', p: [392.201, 266.8, 353.001, 242, 346.601, 242.8]},
+ {t: 'C', p: [340.201, 243.6, 314.981, 219.793, 329.801, 251.6]},
+ {t: 'C', p: [352.028, 299.307, 269.041, 289.227, 254.6, 279.6]},
+ {t: 'C', p: [237.8, 268.4, 261.8, 298, 261.8, 298]},
+ {t: 'C', p: [280.2, 318.001, 245.8, 301.2, 245.8, 301.2]},
+ {t: 'C', p: [211.4, 288.4, 187.4, 314.001, 184.2, 314.801]},
+ {t: 'C', p: [181, 315.601, 176.2, 318.801, 175.4, 312.401]},
+ {t: 'C', p: [174.6, 306, 168.535, 291.144, 135.4, 315.601]},
+ {t: 'C', p: [101.8, 340.401, 91.4, 324.401, 91.4, 324.401]},
+ {t: 'L', p: [84.2, 319.601]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [125.8, 349.601]},
+ {t: 'C', p: [125.8, 349.601, 118.6, 361.201, 139.4, 374.401]},
+ {t: 'C', p: [139.4, 374.401, 140.8, 375.801, 122.8, 371.601]},
+ {t: 'C', p: [122.8, 371.601, 116.6, 369.601, 115, 359.201]},
+ {t: 'C', p: [115, 359.201, 110.2, 354.801, 105.4, 349.201]},
+ {t: 'C', p: [100.6, 343.601, 125.8, 349.601, 125.8, 349.601]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [265.8, 302]},
+ {t: 'C', p: [265.8, 302, 283.498, 328.821, 282.9, 333.601]},
+ {t: 'C', p: [281.6, 344.001, 281.4, 353.601, 284.6, 357.601]},
+ {t: 'C', p: [287.801, 361.601, 296.601, 394.801, 296.601, 394.801]},
+ {t: 'C', p: [296.601, 394.801, 296.201, 396.001, 308.601, 358.001]},
+ {t: 'C', p: [308.601, 358.001, 320.201, 342.001, 300.201, 323.601]},
+ {t: 'C', p: [300.201, 323.601, 265, 294.8, 265.8, 302]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [145.8, 376.401]},
+ {t: 'C', p: [145.8, 376.401, 157, 383.601, 142.6, 414.801]},
+ {t: 'L', p: [149, 412.401]},
+ {t: 'C', p: [149, 412.401, 148.2, 423.601, 145, 426.001]},
+ {t: 'L', p: [152.2, 422.801]},
+ {t: 'C', p: [152.2, 422.801, 157, 430.801, 153, 435.601]},
+ {t: 'C', p: [153, 435.601, 169.8, 443.601, 169, 450.001]},
+ {t: 'C', p: [169, 450.001, 175.4, 442.001, 171.4, 435.601]},
+ {t: 'C', p: [167.4, 429.201, 160.2, 433.201, 161, 414.801]},
+ {t: 'L', p: [152.2, 418.001]},
+ {t: 'C', p: [152.2, 418.001, 157.8, 409.201, 157.8, 402.801]},
+ {t: 'L', p: [149.8, 405.201]},
+ {t: 'C', p: [149.8, 405.201, 165.269, 378.623, 154.6, 377.201]},
+ {t: 'C', p: [148.6, 376.401, 145.8, 376.401, 145.8, 376.401]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [178.2, 393.201]},
+ {t: 'C', p: [178.2, 393.201, 181, 388.801, 178.2, 389.601]},
+ {t: 'C', p: [175.4, 390.401, 144.2, 405.201, 138.2, 414.801]},
+ {t: 'C', p: [138.2, 414.801, 172.6, 390.401, 178.2, 393.201]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [188.6, 401.201]},
+ {t: 'C', p: [188.6, 401.201, 191.4, 396.801, 188.6, 397.601]},
+ {t: 'C', p: [185.8, 398.401, 154.6, 413.201, 148.6, 422.801]},
+ {t: 'C', p: [148.6, 422.801, 183, 398.401, 188.6, 401.201]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [201.8, 386.001]},
+ {t: 'C', p: [201.8, 386.001, 204.6, 381.601, 201.8, 382.401]},
+ {t: 'C', p: [199, 383.201, 167.8, 398.001, 161.8, 407.601]},
+ {t: 'C', p: [161.8, 407.601, 196.2, 383.201, 201.8, 386.001]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [178.6, 429.601]},
+ {t: 'C', p: [178.6, 429.601, 178.6, 423.601, 175.8, 424.401]},
+ {t: 'C', p: [173, 425.201, 137, 442.801, 131, 452.401]},
+ {t: 'C', p: [131, 452.401, 173, 426.801, 178.6, 429.601]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [179.8, 418.801]},
+ {t: 'C', p: [179.8, 418.801, 181, 414.001, 178.2, 414.801]},
+ {t: 'C', p: [176.2, 414.801, 149.8, 426.401, 143.8, 436.001]},
+ {t: 'C', p: [143.8, 436.001, 173.4, 414.401, 179.8, 418.801]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [165.4, 466.401]},
+ {t: 'L', p: [155.4, 474.001]},
+ {t: 'C', p: [155.4, 474.001, 165.8, 466.401, 169.4, 467.601]},
+ {t: 'C', p: [169.4, 467.601, 162.6, 478.801, 161.8, 484.001]},
+ {t: 'C', p: [161.8, 484.001, 172.2, 471.201, 177.8, 471.601]},
+ {t: 'C', p: [177.8, 471.601, 185.4, 472.001, 185.4, 482.801]},
+ {t: 'C', p: [185.4, 482.801, 191, 472.401, 194.2, 472.801]},
+ {t: 'C', p: [194.2, 472.801, 195.4, 479.201, 194.2, 486.001]},
+ {t: 'C', p: [194.2, 486.001, 198.2, 478.401, 202.2, 480.001]},
+ {t: 'C', p: [202.2, 480.001, 208.6, 478.001, 207.8, 489.601]},
+ {t: 'C', p: [207.8, 489.601, 207.8, 500.001, 207, 502.801]},
+ {t: 'C', p: [207, 502.801, 212.6, 476.401, 215, 476.001]},
+ {t: 'C', p: [215, 476.001, 223, 474.801, 227.8, 483.601]},
+ {t: 'C', p: [227.8, 483.601, 223.8, 476.001, 228.6, 478.001]},
+ {t: 'C', p: [228.6, 478.001, 239.4, 479.601, 242.6, 486.401]},
+ {t: 'C', p: [242.6, 486.401, 235.8, 474.401, 241.4, 477.601]},
+ {t: 'C', p: [241.4, 477.601, 248.2, 477.601, 249.4, 484.001]},
+ {t: 'C', p: [249.4, 484.001, 257.8, 505.201, 259.8, 506.801]},
+ {t: 'C', p: [259.8, 506.801, 252.2, 485.201, 253.8, 485.201]},
+ {t: 'C', p: [253.8, 485.201, 251.8, 473.201, 257, 488.001]},
+ {t: 'C', p: [257, 488.001, 253.8, 474.001, 259.4, 474.801]},
+ {t: 'C', p: [265, 475.601, 269.4, 485.601, 277.8, 483.201]},
+ {t: 'C', p: [277.8, 483.201, 287.401, 488.801, 289.401, 419.601]},
+ {t: 'L', p: [165.4, 466.401]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [170.2, 373.601]},
+ {t: 'C', p: [170.2, 373.601, 185, 367.601, 225, 373.601]},
+ {t: 'C', p: [225, 373.601, 232.2, 374.001, 239, 365.201]},
+ {t: 'C', p: [245.8, 356.401, 272.6, 349.201, 279, 351.201]},
+ {t: 'L', p: [288.601, 357.601]},
+ {t: 'L', p: [289.401, 358.801]},
+ {t: 'C', p: [289.401, 358.801, 301.801, 369.201, 302.201, 376.801]},
+ {t: 'C', p: [302.601, 384.401, 287.801, 432.401, 278.2, 448.401]},
+ {t: 'C', p: [268.6, 464.401, 259, 476.801, 239.8, 474.401]},
+ {t: 'C', p: [239.8, 474.401, 219, 470.401, 193.4, 474.401]},
+ {t: 'C', p: [193.4, 474.401, 164.2, 472.801, 161.4, 464.801]},
+ {t: 'C', p: [158.6, 456.801, 172.6, 441.601, 172.6, 441.601]},
+ {t: 'C', p: [172.6, 441.601, 177, 433.201, 175.8, 418.801]},
+ {t: 'C', p: [174.6, 404.401, 175, 376.401, 170.2, 373.601]},
+ {t: 'z', p: []}]},
+
+{f: '#e5668c', s: null, p: [{t: 'M', p: [192.2, 375.601]},
+ {t: 'C', p: [200.6, 394.001, 171, 459.201, 171, 459.201]},
+ {t: 'C', p: [169, 460.801, 183.66, 466.846, 193.8, 464.401]},
+ {t: 'C', p: [204.746, 461.763, 245, 466.001, 245, 466.001]},
+ {t: 'C', p: [268.6, 450.401, 281.4, 406.001, 281.4, 406.001]},
+ {t: 'C', p: [281.4, 406.001, 291.801, 382.001, 274.2, 378.801]},
+ {t: 'C', p: [256.6, 375.601, 192.2, 375.601, 192.2, 375.601]},
+ {t: 'z', p: []}]},
+
+{f: '#b23259', s: null, p: [{t: 'M', p: [190.169, 406.497]},
+ {t: 'C', p: [193.495, 393.707, 195.079, 381.906, 192.2, 375.601]},
+ {t: 'C', p: [192.2, 375.601, 254.6, 382.001, 265.8, 361.201]},
+ {t: 'C', p: [270.041, 353.326, 284.801, 384.001, 284.4, 393.601]},
+ {t: 'C', p: [284.4, 393.601, 221.4, 408.001, 206.6, 396.801]},
+ {t: 'L', p: [190.169, 406.497]},
+ {t: 'z', p: []}]},
+
+{f: '#a5264c', s: null, p: [{t: 'M', p: [194.6, 422.801]},
+ {t: 'C', p: [194.6, 422.801, 196.6, 430.001, 194.2, 434.001]},
+ {t: 'C', p: [194.2, 434.001, 192.6, 434.801, 191.4, 435.201]},
+ {t: 'C', p: [191.4, 435.201, 192.6, 438.801, 198.6, 440.401]},
+ {t: 'C', p: [198.6, 440.401, 200.6, 444.801, 203, 445.201]},
+ {t: 'C', p: [205.4, 445.601, 210.2, 451.201, 214.2, 450.001]},
+ {t: 'C', p: [218.2, 448.801, 229.4, 444.801, 229.4, 444.801]},
+ {t: 'C', p: [229.4, 444.801, 235, 441.601, 243.8, 445.201]},
+ {t: 'C', p: [243.8, 445.201, 246.175, 444.399, 246.6, 440.401]},
+ {t: 'C', p: [247.1, 435.701, 250.2, 432.001, 252.2, 430.001]},
+ {t: 'C', p: [254.2, 428.001, 263.8, 415.201, 262.6, 414.801]},
+ {t: 'C', p: [261.4, 414.401, 194.6, 422.801, 194.6, 422.801]},
+ {t: 'z', p: []}]},
+
+{f: '#ff727f', s: '#000', p: [{t: 'M', p: [190.2, 374.401]},
+ {t: 'C', p: [190.2, 374.401, 187.4, 396.801, 190.6, 405.201]},
+ {t: 'C', p: [193.8, 413.601, 193, 415.601, 192.2, 419.601]},
+ {t: 'C', p: [191.4, 423.601, 195.8, 433.601, 201.4, 439.601]},
+ {t: 'L', p: [213.4, 441.201]},
+ {t: 'C', p: [213.4, 441.201, 228.6, 437.601, 237.8, 440.401]},
+ {t: 'C', p: [237.8, 440.401, 246.794, 441.744, 250.2, 426.801]},
+ {t: 'C', p: [250.2, 426.801, 255, 420.401, 262.2, 417.601]},
+ {t: 'C', p: [269.4, 414.801, 276.6, 373.201, 272.6, 365.201]},
+ {t: 'C', p: [268.6, 357.201, 254.2, 352.801, 238.2, 368.401]},
+ {t: 'C', p: [222.2, 384.001, 220.2, 367.201, 190.2, 374.401]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [191.8, 449.201]},
+ {t: 'C', p: [191.8, 449.201, 191, 447.201, 186.6, 446.801]},
+ {t: 'C', p: [186.6, 446.801, 164.2, 443.201, 155.8, 430.801]},
+ {t: 'C', p: [155.8, 430.801, 149, 425.201, 153.4, 436.801]},
+ {t: 'C', p: [153.4, 436.801, 163.8, 457.201, 170.6, 460.001]},
+ {t: 'C', p: [170.6, 460.001, 187, 464.001, 191.8, 449.201]},
+ {t: 'z', p: []}]},
+
+{f: '#cc3f4c', s: null, p: [{t: 'M', p: [271.742, 385.229]},
+ {t: 'C', p: [272.401, 377.323, 274.354, 368.709, 272.6, 365.201]},
+ {t: 'C', p: [266.154, 352.307, 249.181, 357.695, 238.2, 368.401]},
+ {t: 'C', p: [222.2, 384.001, 220.2, 367.201, 190.2, 374.401]},
+ {t: 'C', p: [190.2, 374.401, 188.455, 388.364, 189.295, 398.376]},
+ {t: 'C', p: [189.295, 398.376, 226.6, 386.801, 227.4, 392.401]},
+ {t: 'C', p: [227.4, 392.401, 229, 389.201, 238.2, 389.201]},
+ {t: 'C', p: [247.4, 389.201, 270.142, 388.029, 271.742, 385.229]},
+ {t: 'z', p: []}]},
+
+{f: null, s: {c: '#a51926', w: 2},
+ p: [{t: 'M', p: [228.6, 375.201]},
+ {t: 'C', p: [228.6, 375.201, 233.4, 380.001, 229.8, 389.601]},
+ {t: 'C', p: [229.8, 389.601, 215.4, 405.601, 217.4, 419.601]}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [180.6, 460.001]},
+ {t: 'C', p: [180.6, 460.001, 176.2, 447.201, 185, 454.001]},
+ {t: 'C', p: [185, 454.001, 189.8, 456.001, 188.6, 457.601]},
+ {t: 'C', p: [187.4, 459.201, 181.8, 463.201, 180.6, 460.001]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [185.64, 461.201]},
+ {t: 'C', p: [185.64, 461.201, 182.12, 450.961, 189.16, 456.401]},
+ {t: 'C', p: [189.16, 456.401, 193.581, 458.849, 192.04, 459.281]},
+ {t: 'C', p: [187.48, 460.561, 192.04, 463.121, 185.64, 461.201]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [190.44, 461.201]},
+ {t: 'C', p: [190.44, 461.201, 186.92, 450.961, 193.96, 456.401]},
+ {t: 'C', p: [193.96, 456.401, 198.335, 458.711, 196.84, 459.281]},
+ {t: 'C', p: [193.48, 460.561, 196.84, 463.121, 190.44, 461.201]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [197.04, 461.401]},
+ {t: 'C', p: [197.04, 461.401, 193.52, 451.161, 200.56, 456.601]},
+ {t: 'C', p: [200.56, 456.601, 204.943, 458.933, 203.441, 459.481]},
+ {t: 'C', p: [200.48, 460.561, 203.441, 463.321, 197.04, 461.401]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [203.52, 461.321]},
+ {t: 'C', p: [203.52, 461.321, 200, 451.081, 207.041, 456.521]},
+ {t: 'C', p: [207.041, 456.521, 210.881, 458.121, 209.921, 459.401]},
+ {t: 'C', p: [208.961, 460.681, 209.921, 463.241, 203.52, 461.321]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [210.2, 462.001]},
+ {t: 'C', p: [210.2, 462.001, 205.4, 449.601, 214.6, 456.001]},
+ {t: 'C', p: [214.6, 456.001, 219.4, 458.001, 218.2, 459.601]},
+ {t: 'C', p: [217, 461.201, 218.2, 464.401, 210.2, 462.001]},
+ {t: 'z', p: []}]},
+
+{f: null, s: {c: '#a5264c', w: 2},
+ p: [{t: 'M', p: [181.8, 444.801]},
+ {t: 'C', p: [181.8, 444.801, 195, 442.001, 201, 445.201]},
+ {t: 'C', p: [201, 445.201, 207, 446.401, 208.2, 446.001]},
+ {t: 'C', p: [209.4, 445.601, 212.6, 445.201, 212.6, 445.201]}]},
+
+{f: null, s: {c: '#a5264c', w: 2},
+ p: [{t: 'M', p: [215.8, 453.601]},
+ {t: 'C', p: [215.8, 453.601, 227.8, 440.001, 239.8, 444.401]},
+ {t: 'C', p: [246.816, 446.974, 245.8, 443.601, 246.6, 440.801]},
+ {t: 'C', p: [247.4, 438.001, 247.6, 433.801, 252.6, 430.801]}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [233, 437.601]},
+ {t: 'C', p: [233, 437.601, 229, 426.801, 226.2, 439.601]},
+ {t: 'C', p: [223.4, 452.401, 220.2, 456.001, 218.6, 458.801]},
+ {t: 'C', p: [218.6, 458.801, 218.6, 464.001, 227, 463.601]},
+ {t: 'C', p: [227, 463.601, 237.8, 463.201, 238.2, 460.401]},
+ {t: 'C', p: [238.6, 457.601, 237, 446.001, 233, 437.601]},
+ {t: 'z', p: []}]},
+
+{f: null, s: {c: '#a5264c', w: 2},
+ p: [{t: 'M', p: [247, 444.801]},
+ {t: 'C', p: [247, 444.801, 250.6, 442.401, 253, 443.601]}]},
+
+{f: null, s: {c: '#a5264c', w: 2},
+ p: [{t: 'M', p: [253.5, 428.401]},
+ {t: 'C', p: [253.5, 428.401, 256.4, 423.501, 261.2, 422.701]}]},
+
+{f: '#b2b2b2', s: null, p: [{t: 'M', p: [174.2, 465.201]},
+ {t: 'C', p: [174.2, 465.201, 192.2, 468.401, 196.6, 466.801]},
+ {t: 'C', p: [196.6, 466.801, 205.4, 466.801, 197, 468.801]},
+ {t: 'C', p: [197, 468.801, 184.2, 468.801, 176.2, 467.601]},
+ {t: 'C', p: [176.2, 467.601, 164.6, 462.001, 174.2, 465.201]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [188.2, 372.001]},
+ {t: 'C', p: [188.2, 372.001, 205.8, 372.001, 207.8, 372.801]},
+ {t: 'C', p: [207.8, 372.801, 215, 403.601, 211.4, 411.201]},
+ {t: 'C', p: [211.4, 411.201, 210.2, 414.001, 207.4, 408.401]},
+ {t: 'C', p: [207.4, 408.401, 189, 375.601, 185.8, 373.601]},
+ {t: 'C', p: [182.6, 371.601, 187, 372.001, 188.2, 372.001]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [111.1, 369.301]},
+ {t: 'C', p: [111.1, 369.301, 120, 371.001, 132.6, 373.601]},
+ {t: 'C', p: [132.6, 373.601, 137.4, 396.001, 140.6, 400.801]},
+ {t: 'C', p: [143.8, 405.601, 140.2, 405.601, 136.6, 402.801]},
+ {t: 'C', p: [133, 400.001, 118.2, 386.001, 116.2, 381.601]},
+ {t: 'C', p: [114.2, 377.201, 111.1, 369.301, 111.1, 369.301]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [132.961, 373.818]},
+ {t: 'C', p: [132.961, 373.818, 138.761, 375.366, 139.77, 377.581]},
+ {t: 'C', p: [140.778, 379.795, 138.568, 383.092, 138.568, 383.092]},
+ {t: 'C', p: [138.568, 383.092, 137.568, 386.397, 136.366, 384.235]},
+ {t: 'C', p: [135.164, 382.072, 132.292, 374.412, 132.961, 373.818]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [133, 373.601]},
+ {t: 'C', p: [133, 373.601, 136.6, 378.801, 140.2, 378.801]},
+ {t: 'C', p: [143.8, 378.801, 144.182, 378.388, 147, 379.001]},
+ {t: 'C', p: [151.6, 380.001, 151.2, 378.001, 157.8, 379.201]},
+ {t: 'C', p: [160.44, 379.681, 163, 378.801, 165.8, 380.001]},
+ {t: 'C', p: [168.6, 381.201, 171.8, 380.401, 173, 378.401]},
+ {t: 'C', p: [174.2, 376.401, 179, 372.201, 179, 372.201]},
+ {t: 'C', p: [179, 372.201, 166.2, 374.001, 163.4, 374.801]},
+ {t: 'C', p: [163.4, 374.801, 141, 376.001, 133, 373.601]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [177.6, 373.801]},
+ {t: 'C', p: [177.6, 373.801, 171.15, 377.301, 170.75, 379.701]},
+ {t: 'C', p: [170.35, 382.101, 176, 385.801, 176, 385.801]},
+ {t: 'C', p: [176, 385.801, 178.75, 390.401, 179.35, 388.001]},
+ {t: 'C', p: [179.95, 385.601, 178.4, 374.201, 177.6, 373.801]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [140.115, 379.265]},
+ {t: 'C', p: [140.115, 379.265, 147.122, 390.453, 147.339, 379.242]},
+ {t: 'C', p: [147.339, 379.242, 147.896, 377.984, 146.136, 377.962]},
+ {t: 'C', p: [140.061, 377.886, 141.582, 373.784, 140.115, 379.265]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [147.293, 379.514]},
+ {t: 'C', p: [147.293, 379.514, 155.214, 390.701, 154.578, 379.421]},
+ {t: 'C', p: [154.578, 379.421, 154.585, 379.089, 152.832, 378.936]},
+ {t: 'C', p: [148.085, 378.522, 148.43, 374.004, 147.293, 379.514]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [154.506, 379.522]},
+ {t: 'C', p: [154.506, 379.522, 162.466, 390.15, 161.797, 380.484]},
+ {t: 'C', p: [161.797, 380.484, 161.916, 379.251, 160.262, 378.95]},
+ {t: 'C', p: [156.37, 378.244, 156.159, 374.995, 154.506, 379.522]},
+ {t: 'z', p: []}]},
+
+{f: '#ffc', s: {c: '#000', w: 0.5},
+ p: [{t: 'M', p: [161.382, 379.602]},
+ {t: 'C', p: [161.382, 379.602, 169.282, 391.163, 169.63, 381.382]},
+ {t: 'C', p: [169.63, 381.382, 171.274, 380.004, 169.528, 379.782]},
+ {t: 'C', p: [163.71, 379.042, 164.508, 374.588, 161.382, 379.602]},
+ {t: 'z', p: []}]},
+
+{f: '#e5e5b2', s: null, p: [{t: 'M', p: [125.208, 383.132]},
+ {t: 'L', p: [117.55, 381.601]},
+ {t: 'C', p: [114.95, 376.601, 112.85, 370.451, 112.85, 370.451]},
+ {t: 'C', p: [112.85, 370.451, 119.2, 371.451, 131.7, 374.251]},
+ {t: 'C', p: [131.7, 374.251, 132.576, 377.569, 134.048, 383.364]},
+ {t: 'L', p: [125.208, 383.132]},
+ {t: 'z', p: []}]},
+
+{f: '#e5e5b2', s: null, p: [{t: 'M', p: [190.276, 378.47]},
+ {t: 'C', p: [188.61, 375.964, 187.293, 374.206, 186.643, 373.8]},
+ {t: 'C', p: [183.63, 371.917, 187.773, 372.294, 188.902, 372.294]},
+ {t: 'C', p: [188.902, 372.294, 205.473, 372.294, 207.356, 373.047]},
+ {t: 'C', p: [207.356, 373.047, 207.88, 375.289, 208.564, 378.68]},
+ {t: 'C', p: [208.564, 378.68, 198.476, 376.67, 190.276, 378.47]},
+ {t: 'z', p: []}]},
+
+{f: '#cc7226', s: null, p: [{t: 'M', p: [243.88, 240.321]},
+ {t: 'C', p: [271.601, 244.281, 297.121, 208.641, 298.881, 198.96]},
+ {t: 'C', p: [300.641, 189.28, 290.521, 177.4, 290.521, 177.4]},
+ {t: 'C', p: [291.841, 174.32, 287.001, 160.24, 281.721, 151]},
+ {t: 'C', p: [276.441, 141.76, 260.54, 142.734, 243, 141.76]},
+ {t: 'C', p: [227.16, 140.88, 208.68, 164.2, 207.36, 165.96]},
+ {t: 'C', p: [206.04, 167.72, 212.2, 206.001, 213.52, 211.721]},
+ {t: 'C', p: [214.84, 217.441, 212.2, 243.841, 212.2, 243.841]},
+ {t: 'C', p: [246.44, 234.741, 216.16, 236.361, 243.88, 240.321]},
+ {t: 'z', p: []}]},
+
+{f: '#ea8e51', s: null, p: [{t: 'M', p: [208.088, 166.608]},
+ {t: 'C', p: [206.792, 168.336, 212.84, 205.921, 214.136, 211.537]},
+ {t: 'C', p: [215.432, 217.153, 212.84, 243.073, 212.84, 243.073]},
+ {t: 'C', p: [245.512, 234.193, 216.728, 235.729, 243.944, 239.617]},
+ {t: 'C', p: [271.161, 243.505, 296.217, 208.513, 297.945, 199.008]},
+ {t: 'C', p: [299.673, 189.504, 289.737, 177.84, 289.737, 177.84]},
+ {t: 'C', p: [291.033, 174.816, 286.281, 160.992, 281.097, 151.92]},
+ {t: 'C', p: [275.913, 142.848, 260.302, 143.805, 243.08, 142.848]},
+ {t: 'C', p: [227.528, 141.984, 209.384, 164.88, 208.088, 166.608]},
+ {t: 'z', p: []}]},
+
+{f: '#efaa7c', s: null, p: [{t: 'M', p: [208.816, 167.256]},
+ {t: 'C', p: [207.544, 168.952, 213.48, 205.841, 214.752, 211.353]},
+ {t: 'C', p: [216.024, 216.865, 213.48, 242.305, 213.48, 242.305]},
+ {t: 'C', p: [244.884, 233.145, 217.296, 235.097, 244.008, 238.913]},
+ {t: 'C', p: [270.721, 242.729, 295.313, 208.385, 297.009, 199.056]},
+ {t: 'C', p: [298.705, 189.728, 288.953, 178.28, 288.953, 178.28]},
+ {t: 'C', p: [290.225, 175.312, 285.561, 161.744, 280.473, 152.84]},
+ {t: 'C', p: [275.385, 143.936, 260.063, 144.875, 243.16, 143.936]},
+ {t: 'C', p: [227.896, 143.088, 210.088, 165.56, 208.816, 167.256]},
+ {t: 'z', p: []}]},
+
+{f: '#f4c6a8', s: null, p: [{t: 'M', p: [209.544, 167.904]},
+ {t: 'C', p: [208.296, 169.568, 214.12, 205.761, 215.368, 211.169]},
+ {t: 'C', p: [216.616, 216.577, 214.12, 241.537, 214.12, 241.537]},
+ {t: 'C', p: [243.556, 232.497, 217.864, 234.465, 244.072, 238.209]},
+ {t: 'C', p: [270.281, 241.953, 294.409, 208.257, 296.073, 199.105]},
+ {t: 'C', p: [297.737, 189.952, 288.169, 178.72, 288.169, 178.72]},
+ {t: 'C', p: [289.417, 175.808, 284.841, 162.496, 279.849, 153.76]},
+ {t: 'C', p: [274.857, 145.024, 259.824, 145.945, 243.24, 145.024]},
+ {t: 'C', p: [228.264, 144.192, 210.792, 166.24, 209.544, 167.904]},
+ {t: 'z', p: []}]},
+
+{f: '#f9e2d3', s: null, p: [{t: 'M', p: [210.272, 168.552]},
+ {t: 'C', p: [209.048, 170.184, 214.76, 205.681, 215.984, 210.985]},
+ {t: 'C', p: [217.208, 216.289, 214.76, 240.769, 214.76, 240.769]},
+ {t: 'C', p: [242.628, 231.849, 218.432, 233.833, 244.136, 237.505]},
+ {t: 'C', p: [269.841, 241.177, 293.505, 208.129, 295.137, 199.152]},
+ {t: 'C', p: [296.769, 190.176, 287.385, 179.16, 287.385, 179.16]},
+ {t: 'C', p: [288.609, 176.304, 284.121, 163.248, 279.225, 154.68]},
+ {t: 'C', p: [274.329, 146.112, 259.585, 147.015, 243.32, 146.112]},
+ {t: 'C', p: [228.632, 145.296, 211.496, 166.92, 210.272, 168.552]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: null, p: [{t: 'M', p: [244.2, 236.8]},
+ {t: 'C', p: [269.4, 240.4, 292.601, 208, 294.201, 199.2]},
+ {t: 'C', p: [295.801, 190.4, 286.601, 179.6, 286.601, 179.6]},
+ {t: 'C', p: [287.801, 176.8, 283.4, 164, 278.6, 155.6]},
+ {t: 'C', p: [273.8, 147.2, 259.346, 148.086, 243.4, 147.2]},
+ {t: 'C', p: [229, 146.4, 212.2, 167.6, 211, 169.2]},
+ {t: 'C', p: [209.8, 170.8, 215.4, 205.6, 216.6, 210.8]},
+ {t: 'C', p: [217.8, 216, 215.4, 240, 215.4, 240]},
+ {t: 'C', p: [240.9, 231.4, 219, 233.2, 244.2, 236.8]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [290.601, 202.8]},
+ {t: 'C', p: [290.601, 202.8, 262.8, 210.4, 251.2, 208.8]},
+ {t: 'C', p: [251.2, 208.8, 235.4, 202.2, 226.6, 224]},
+ {t: 'C', p: [226.6, 224, 223, 231.2, 221, 233.2]},
+ {t: 'C', p: [219, 235.2, 290.601, 202.8, 290.601, 202.8]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [294.401, 200.6]},
+ {t: 'C', p: [294.401, 200.6, 265.4, 212.8, 255.4, 212.4]},
+ {t: 'C', p: [255.4, 212.4, 239, 207.8, 230.6, 222.4]},
+ {t: 'C', p: [230.6, 222.4, 222.2, 231.6, 219, 233.2]},
+ {t: 'C', p: [219, 233.2, 218.6, 234.8, 225, 230.8]},
+ {t: 'L', p: [235.4, 236]},
+ {t: 'C', p: [235.4, 236, 250.2, 245.6, 259.8, 229.6]},
+ {t: 'C', p: [259.8, 229.6, 263.8, 218.4, 263.8, 216.4]},
+ {t: 'C', p: [263.8, 214.4, 285, 208.8, 286.601, 208.4]},
+ {t: 'C', p: [288.201, 208, 294.801, 203.8, 294.401, 200.6]},
+ {t: 'z', p: []}]},
+
+{f: '#99cc32', s: null, p: [{t: 'M', p: [247, 236.514]},
+ {t: 'C', p: [240.128, 236.514, 231.755, 232.649, 231.755, 226.4]},
+ {t: 'C', p: [231.755, 220.152, 240.128, 213.887, 247, 213.887]},
+ {t: 'C', p: [253.874, 213.887, 259.446, 218.952, 259.446, 225.2]},
+ {t: 'C', p: [259.446, 231.449, 253.874, 236.514, 247, 236.514]},
+ {t: 'z', p: []}]},
+
+{f: '#659900', s: null, p: [{t: 'M', p: [243.377, 219.83]},
+ {t: 'C', p: [238.531, 220.552, 233.442, 222.055, 233.514, 221.839]},
+ {t: 'C', p: [235.054, 217.22, 241.415, 213.887, 247, 213.887]},
+ {t: 'C', p: [251.296, 213.887, 255.084, 215.865, 257.32, 218.875]},
+ {t: 'C', p: [257.32, 218.875, 252.004, 218.545, 243.377, 219.83]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: null, p: [{t: 'M', p: [255.4, 219.6]},
+ {t: 'C', p: [255.4, 219.6, 251, 216.4, 251, 218.6]},
+ {t: 'C', p: [251, 218.6, 254.6, 223, 255.4, 219.6]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [245.4, 227.726]},
+ {t: 'C', p: [242.901, 227.726, 240.875, 225.7, 240.875, 223.2]},
+ {t: 'C', p: [240.875, 220.701, 242.901, 218.675, 245.4, 218.675]},
+ {t: 'C', p: [247.9, 218.675, 249.926, 220.701, 249.926, 223.2]},
+ {t: 'C', p: [249.926, 225.7, 247.9, 227.726, 245.4, 227.726]},
+ {t: 'z', p: []}]},
+
+{f: '#cc7226', s: null, p: [{t: 'M', p: [141.4, 214.4]},
+ {t: 'C', p: [141.4, 214.4, 138.2, 193.2, 140.6, 188.8]},
+ {t: 'C', p: [140.6, 188.8, 151.4, 178.8, 151, 175.2]},
+ {t: 'C', p: [151, 175.2, 150.6, 157.2, 149.4, 156.4]},
+ {t: 'C', p: [148.2, 155.6, 140.6, 149.6, 134.6, 156]},
+ {t: 'C', p: [134.6, 156, 124.2, 174, 125, 180.4]},
+ {t: 'L', p: [125, 182.4]},
+ {t: 'C', p: [125, 182.4, 117.4, 182, 115.8, 184]},
+ {t: 'C', p: [115.8, 184, 114.6, 189.2, 113.4, 189.6]},
+ {t: 'C', p: [113.4, 189.6, 110.6, 192, 112.6, 194.8]},
+ {t: 'C', p: [112.6, 194.8, 110.6, 197.2, 111, 201.2]},
+ {t: 'L', p: [118.6, 205.2]},
+ {t: 'C', p: [118.6, 205.2, 120.6, 219.6, 131.4, 224.8]},
+ {t: 'C', p: [136.236, 227.129, 139.4, 220.4, 141.4, 214.4]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: null, p: [{t: 'M', p: [140.4, 212.56]},
+ {t: 'C', p: [140.4, 212.56, 137.52, 193.48, 139.68, 189.52]},
+ {t: 'C', p: [139.68, 189.52, 149.4, 180.52, 149.04, 177.28]},
+ {t: 'C', p: [149.04, 177.28, 148.68, 161.08, 147.6, 160.36]},
+ {t: 'C', p: [146.52, 159.64, 139.68, 154.24, 134.28, 160]},
+ {t: 'C', p: [134.28, 160, 124.92, 176.2, 125.64, 181.96]},
+ {t: 'L', p: [125.64, 183.76]},
+ {t: 'C', p: [125.64, 183.76, 118.8, 183.4, 117.36, 185.2]},
+ {t: 'C', p: [117.36, 185.2, 116.28, 189.88, 115.2, 190.24]},
+ {t: 'C', p: [115.2, 190.24, 112.68, 192.4, 114.48, 194.92]},
+ {t: 'C', p: [114.48, 194.92, 112.68, 197.08, 113.04, 200.68]},
+ {t: 'L', p: [119.88, 204.28]},
+ {t: 'C', p: [119.88, 204.28, 121.68, 217.24, 131.4, 221.92]},
+ {t: 'C', p: [135.752, 224.015, 138.6, 217.96, 140.4, 212.56]},
+ {t: 'z', p: []}]},
+
+{f: '#eb955c', s: null, p: [{t: 'M', p: [148.95, 157.39]},
+ {t: 'C', p: [147.86, 156.53, 140.37, 150.76, 134.52, 157]},
+ {t: 'C', p: [134.52, 157, 124.38, 174.55, 125.16, 180.79]},
+ {t: 'L', p: [125.16, 182.74]},
+ {t: 'C', p: [125.16, 182.74, 117.75, 182.35, 116.19, 184.3]},
+ {t: 'C', p: [116.19, 184.3, 115.02, 189.37, 113.85, 189.76]},
+ {t: 'C', p: [113.85, 189.76, 111.12, 192.1, 113.07, 194.83]},
+ {t: 'C', p: [113.07, 194.83, 111.12, 197.17, 111.51, 201.07]},
+ {t: 'L', p: [118.92, 204.97]},
+ {t: 'C', p: [118.92, 204.97, 120.87, 219.01, 131.4, 224.08]},
+ {t: 'C', p: [136.114, 226.35, 139.2, 219.79, 141.15, 213.94]},
+ {t: 'C', p: [141.15, 213.94, 138.03, 193.27, 140.37, 188.98]},
+ {t: 'C', p: [140.37, 188.98, 150.9, 179.23, 150.51, 175.72]},
+ {t: 'C', p: [150.51, 175.72, 150.12, 158.17, 148.95, 157.39]},
+ {t: 'z', p: []}]},
+
+{f: '#f2b892', s: null, p: [{t: 'M', p: [148.5, 158.38]},
+ {t: 'C', p: [147.52, 157.46, 140.14, 151.92, 134.44, 158]},
+ {t: 'C', p: [134.44, 158, 124.56, 175.1, 125.32, 181.18]},
+ {t: 'L', p: [125.32, 183.08]},
+ {t: 'C', p: [125.32, 183.08, 118.1, 182.7, 116.58, 184.6]},
+ {t: 'C', p: [116.58, 184.6, 115.44, 189.54, 114.3, 189.92]},
+ {t: 'C', p: [114.3, 189.92, 111.64, 192.2, 113.54, 194.86]},
+ {t: 'C', p: [113.54, 194.86, 111.64, 197.14, 112.02, 200.94]},
+ {t: 'L', p: [119.24, 204.74]},
+ {t: 'C', p: [119.24, 204.74, 121.14, 218.42, 131.4, 223.36]},
+ {t: 'C', p: [135.994, 225.572, 139, 219.18, 140.9, 213.48]},
+ {t: 'C', p: [140.9, 213.48, 137.86, 193.34, 140.14, 189.16]},
+ {t: 'C', p: [140.14, 189.16, 150.4, 179.66, 150.02, 176.24]},
+ {t: 'C', p: [150.02, 176.24, 149.64, 159.14, 148.5, 158.38]},
+ {t: 'z', p: []}]},
+
+{f: '#f8dcc8', s: null, p: [{t: 'M', p: [148.05, 159.37]},
+ {t: 'C', p: [147.18, 158.39, 139.91, 153.08, 134.36, 159]},
+ {t: 'C', p: [134.36, 159, 124.74, 175.65, 125.48, 181.57]},
+ {t: 'L', p: [125.48, 183.42]},
+ {t: 'C', p: [125.48, 183.42, 118.45, 183.05, 116.97, 184.9]},
+ {t: 'C', p: [116.97, 184.9, 115.86, 189.71, 114.75, 190.08]},
+ {t: 'C', p: [114.75, 190.08, 112.16, 192.3, 114.01, 194.89]},
+ {t: 'C', p: [114.01, 194.89, 112.16, 197.11, 112.53, 200.81]},
+ {t: 'L', p: [119.56, 204.51]},
+ {t: 'C', p: [119.56, 204.51, 121.41, 217.83, 131.4, 222.64]},
+ {t: 'C', p: [135.873, 224.794, 138.8, 218.57, 140.65, 213.02]},
+ {t: 'C', p: [140.65, 213.02, 137.69, 193.41, 139.91, 189.34]},
+ {t: 'C', p: [139.91, 189.34, 149.9, 180.09, 149.53, 176.76]},
+ {t: 'C', p: [149.53, 176.76, 149.16, 160.11, 148.05, 159.37]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: null, p: [{t: 'M', p: [140.4, 212.46]},
+ {t: 'C', p: [140.4, 212.46, 137.52, 193.48, 139.68, 189.52]},
+ {t: 'C', p: [139.68, 189.52, 149.4, 180.52, 149.04, 177.28]},
+ {t: 'C', p: [149.04, 177.28, 148.68, 161.08, 147.6, 160.36]},
+ {t: 'C', p: [146.84, 159.32, 139.68, 154.24, 134.28, 160]},
+ {t: 'C', p: [134.28, 160, 124.92, 176.2, 125.64, 181.96]},
+ {t: 'L', p: [125.64, 183.76]},
+ {t: 'C', p: [125.64, 183.76, 118.8, 183.4, 117.36, 185.2]},
+ {t: 'C', p: [117.36, 185.2, 116.28, 189.88, 115.2, 190.24]},
+ {t: 'C', p: [115.2, 190.24, 112.68, 192.4, 114.48, 194.92]},
+ {t: 'C', p: [114.48, 194.92, 112.68, 197.08, 113.04, 200.68]},
+ {t: 'L', p: [119.88, 204.28]},
+ {t: 'C', p: [119.88, 204.28, 121.68, 217.24, 131.4, 221.92]},
+ {t: 'C', p: [135.752, 224.015, 138.6, 217.86, 140.4, 212.46]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [137.3, 206.2]},
+ {t: 'C', p: [137.3, 206.2, 115.7, 196, 114.8, 195.2]},
+ {t: 'C', p: [114.8, 195.2, 123.9, 203.4, 124.7, 203.4]},
+ {t: 'C', p: [125.5, 203.4, 137.3, 206.2, 137.3, 206.2]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [120.2, 200]},
+ {t: 'C', p: [120.2, 200, 138.6, 203.6, 138.6, 208]},
+ {t: 'C', p: [138.6, 210.912, 138.357, 224.331, 133, 222.8]},
+ {t: 'C', p: [124.6, 220.4, 128.2, 206, 120.2, 200]},
+ {t: 'z', p: []}]},
+
+{f: '#99cc32', s: null, p: [{t: 'M', p: [128.6, 203.8]},
+ {t: 'C', p: [128.6, 203.8, 137.578, 205.274, 138.6, 208]},
+ {t: 'C', p: [139.2, 209.6, 139.863, 217.908, 134.4, 219]},
+ {t: 'C', p: [129.848, 219.911, 127.618, 209.69, 128.6, 203.8]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [214.595, 246.349]},
+ {t: 'C', p: [214.098, 244.607, 215.409, 244.738, 217.2, 244.2]},
+ {t: 'C', p: [219.2, 243.6, 231.4, 239.8, 232.2, 237.2]},
+ {t: 'C', p: [233, 234.6, 246.2, 239, 246.2, 239]},
+ {t: 'C', p: [248, 239.8, 252.4, 242.4, 252.4, 242.4]},
+ {t: 'C', p: [257.2, 243.6, 263.8, 244, 263.8, 244]},
+ {t: 'C', p: [266.2, 245, 269.6, 247.8, 269.6, 247.8]},
+ {t: 'C', p: [284.2, 258, 296.601, 250.8, 296.601, 250.8]},
+ {t: 'C', p: [316.601, 244.2, 310.601, 227, 310.601, 227]},
+ {t: 'C', p: [307.601, 218, 310.801, 214.6, 310.801, 214.6]},
+ {t: 'C', p: [311.001, 210.8, 318.201, 217.2, 318.201, 217.2]},
+ {t: 'C', p: [320.801, 221.4, 321.601, 226.4, 321.601, 226.4]},
+ {t: 'C', p: [329.601, 237.6, 326.201, 219.8, 326.201, 219.8]},
+ {t: 'C', p: [326.401, 218.8, 323.601, 215.2, 323.601, 214]},
+ {t: 'C', p: [323.601, 212.8, 321.801, 209.4, 321.801, 209.4]},
+ {t: 'C', p: [318.801, 206, 321.201, 199, 321.201, 199]},
+ {t: 'C', p: [323.001, 185.2, 320.801, 187, 320.801, 187]},
+ {t: 'C', p: [319.601, 185.2, 310.401, 195.2, 310.401, 195.2]},
+ {t: 'C', p: [308.201, 198.6, 302.201, 200.2, 302.201, 200.2]},
+ {t: 'C', p: [299.401, 202, 296.001, 200.6, 296.001, 200.6]},
+ {t: 'C', p: [293.401, 200.2, 287.801, 207.2, 287.801, 207.2]},
+ {t: 'C', p: [290.601, 207, 293.001, 211.4, 295.401, 211.6]},
+ {t: 'C', p: [297.801, 211.8, 299.601, 209.2, 301.201, 208.6]},
+ {t: 'C', p: [302.801, 208, 305.601, 213.8, 305.601, 213.8]},
+ {t: 'C', p: [306.001, 216.4, 300.401, 221.2, 300.401, 221.2]},
+ {t: 'C', p: [300.001, 225.8, 298.401, 224.2, 298.401, 224.2]},
+ {t: 'C', p: [295.401, 223.6, 294.201, 227.4, 293.201, 232]},
+ {t: 'C', p: [292.201, 236.6, 288.001, 237, 288.001, 237]},
+ {t: 'C', p: [286.401, 244.4, 285.2, 241.4, 285.2, 241.4]},
+ {t: 'C', p: [285, 235.8, 279, 241.6, 279, 241.6]},
+ {t: 'C', p: [277.8, 243.6, 273.2, 241.4, 273.2, 241.4]},
+ {t: 'C', p: [266.4, 239.4, 268.8, 237.4, 268.8, 237.4]},
+ {t: 'C', p: [270.6, 235.2, 281.8, 237.4, 281.8, 237.4]},
+ {t: 'C', p: [284, 235.8, 276, 231.8, 276, 231.8]},
+ {t: 'C', p: [275.4, 230, 276.4, 225.6, 276.4, 225.6]},
+ {t: 'C', p: [277.6, 222.4, 284.4, 216.8, 284.4, 216.8]},
+ {t: 'C', p: [293.801, 215.6, 291.001, 214, 291.001, 214]},
+ {t: 'C', p: [284.801, 208.8, 279, 216.4, 279, 216.4]},
+ {t: 'C', p: [276.8, 222.6, 259.4, 237.6, 259.4, 237.6]},
+ {t: 'C', p: [254.6, 241, 257.2, 234.2, 253.2, 237.6]},
+ {t: 'C', p: [249.2, 241, 228.6, 232, 228.6, 232]},
+ {t: 'C', p: [217.038, 230.807, 214.306, 246.549, 210.777, 243.429]},
+ {t: 'C', p: [210.777, 243.429, 216.195, 251.949, 214.595, 246.349]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [409.401, 80]},
+ {t: 'C', p: [409.401, 80, 383.801, 88, 381.001, 106.8]},
+ {t: 'C', p: [381.001, 106.8, 378.601, 129.6, 399.001, 147.2]},
+ {t: 'C', p: [399.001, 147.2, 399.401, 153.6, 401.401, 156.8]},
+ {t: 'C', p: [401.401, 156.8, 399.801, 161.6, 418.601, 154]},
+ {t: 'L', p: [445.801, 145.6]},
+ {t: 'C', p: [445.801, 145.6, 452.201, 143.2, 457.401, 134.4]},
+ {t: 'C', p: [462.601, 125.6, 477.801, 106.8, 474.201, 81.6]},
+ {t: 'C', p: [474.201, 81.6, 475.401, 70.4, 469.401, 70]},
+ {t: 'C', p: [469.401, 70, 461.001, 68.4, 453.801, 76]},
+ {t: 'C', p: [453.801, 76, 447.001, 79.2, 444.601, 78.8]},
+ {t: 'L', p: [409.401, 80]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [464.022, 79.01]},
+ {t: 'C', p: [464.022, 79.01, 466.122, 70.08, 461.282, 74.92]},
+ {t: 'C', p: [461.282, 74.92, 454.242, 80.64, 446.761, 80.64]},
+ {t: 'C', p: [446.761, 80.64, 432.241, 82.84, 427.841, 96.04]},
+ {t: 'C', p: [427.841, 96.04, 423.881, 122.88, 431.801, 128.6]},
+ {t: 'C', p: [431.801, 128.6, 436.641, 136.08, 443.681, 129.48]},
+ {t: 'C', p: [450.722, 122.88, 466.222, 92.65, 464.022, 79.01]},
+ {t: 'z', p: []}]},
+
+{f: '#323232', s: null, p: [{t: 'M', p: [463.648, 79.368]},
+ {t: 'C', p: [463.648, 79.368, 465.738, 70.624, 460.986, 75.376]},
+ {t: 'C', p: [460.986, 75.376, 454.074, 80.992, 446.729, 80.992]},
+ {t: 'C', p: [446.729, 80.992, 432.473, 83.152, 428.153, 96.112]},
+ {t: 'C', p: [428.153, 96.112, 424.265, 122.464, 432.041, 128.08]},
+ {t: 'C', p: [432.041, 128.08, 436.793, 135.424, 443.705, 128.944]},
+ {t: 'C', p: [450.618, 122.464, 465.808, 92.76, 463.648, 79.368]},
+ {t: 'z', p: []}]},
+
+{f: '#666', s: null, p: [{t: 'M', p: [463.274, 79.726]},
+ {t: 'C', p: [463.274, 79.726, 465.354, 71.168, 460.69, 75.832]},
+ {t: 'C', p: [460.69, 75.832, 453.906, 81.344, 446.697, 81.344]},
+ {t: 'C', p: [446.697, 81.344, 432.705, 83.464, 428.465, 96.184]},
+ {t: 'C', p: [428.465, 96.184, 424.649, 122.048, 432.281, 127.56]},
+ {t: 'C', p: [432.281, 127.56, 436.945, 134.768, 443.729, 128.408]},
+ {t: 'C', p: [450.514, 122.048, 465.394, 92.87, 463.274, 79.726]},
+ {t: 'z', p: []}]},
+
+{f: '#999', s: null, p: [{t: 'M', p: [462.9, 80.084]},
+ {t: 'C', p: [462.9, 80.084, 464.97, 71.712, 460.394, 76.288]},
+ {t: 'C', p: [460.394, 76.288, 453.738, 81.696, 446.665, 81.696]},
+ {t: 'C', p: [446.665, 81.696, 432.937, 83.776, 428.777, 96.256]},
+ {t: 'C', p: [428.777, 96.256, 425.033, 121.632, 432.521, 127.04]},
+ {t: 'C', p: [432.521, 127.04, 437.097, 134.112, 443.753, 127.872]},
+ {t: 'C', p: [450.41, 121.632, 464.98, 92.98, 462.9, 80.084]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [462.526, 80.442]},
+ {t: 'C', p: [462.526, 80.442, 464.586, 72.256, 460.098, 76.744]},
+ {t: 'C', p: [460.098, 76.744, 453.569, 82.048, 446.633, 82.048]},
+ {t: 'C', p: [446.633, 82.048, 433.169, 84.088, 429.089, 96.328]},
+ {t: 'C', p: [429.089, 96.328, 425.417, 121.216, 432.761, 126.52]},
+ {t: 'C', p: [432.761, 126.52, 437.249, 133.456, 443.777, 127.336]},
+ {t: 'C', p: [450.305, 121.216, 464.566, 93.09, 462.526, 80.442]},
+ {t: 'z', p: []}]},
+
+{f: '#fff', s: null, p: [{t: 'M', p: [462.151, 80.8]},
+ {t: 'C', p: [462.151, 80.8, 464.201, 72.8, 459.801, 77.2]},
+ {t: 'C', p: [459.801, 77.2, 453.401, 82.4, 446.601, 82.4]},
+ {t: 'C', p: [446.601, 82.4, 433.401, 84.4, 429.401, 96.4]},
+ {t: 'C', p: [429.401, 96.4, 425.801, 120.8, 433.001, 126]},
+ {t: 'C', p: [433.001, 126, 437.401, 132.8, 443.801, 126.8]},
+ {t: 'C', p: [450.201, 120.8, 464.151, 93.2, 462.151, 80.8]},
+ {t: 'z', p: []}]},
+
+{f: '#992600', s: null, p: [{t: 'M', p: [250.6, 284]},
+ {t: 'C', p: [250.6, 284, 230.2, 264.8, 222.2, 264]},
+ {t: 'C', p: [222.2, 264, 187.8, 260, 173, 278]},
+ {t: 'C', p: [173, 278, 190.6, 257.6, 218.2, 263.2]},
+ {t: 'C', p: [218.2, 263.2, 196.6, 258.8, 184.2, 262]},
+ {t: 'C', p: [184.2, 262, 167.4, 262, 157.8, 276]},
+ {t: 'L', p: [155, 280.8]},
+ {t: 'C', p: [155, 280.8, 159, 266, 177.4, 260]},
+ {t: 'C', p: [177.4, 260, 200.2, 255.2, 211, 260]},
+ {t: 'C', p: [211, 260, 189.4, 253.2, 179.4, 255.2]},
+ {t: 'C', p: [179.4, 255.2, 149, 252.8, 136.2, 279.2]},
+ {t: 'C', p: [136.2, 279.2, 140.2, 264.8, 155, 257.6]},
+ {t: 'C', p: [155, 257.6, 168.6, 248.8, 189, 251.6]},
+ {t: 'C', p: [189, 251.6, 203.4, 254.8, 208.6, 257.2]},
+ {t: 'C', p: [213.8, 259.6, 212.6, 256.8, 204.2, 252]},
+ {t: 'C', p: [204.2, 252, 198.6, 242, 184.6, 242.4]},
+ {t: 'C', p: [184.6, 242.4, 141.8, 246, 131.4, 258]},
+ {t: 'C', p: [131.4, 258, 145, 246.8, 155.4, 244]},
+ {t: 'C', p: [155.4, 244, 177.8, 236, 186.2, 236.8]},
+ {t: 'C', p: [186.2, 236.8, 211, 237.8, 218.6, 233.8]},
+ {t: 'C', p: [218.6, 233.8, 207.4, 238.8, 210.6, 242]},
+ {t: 'C', p: [213.8, 245.2, 220.6, 252.8, 220.6, 254]},
+ {t: 'C', p: [220.6, 255.2, 244.8, 277.3, 248.4, 281.7]},
+ {t: 'L', p: [250.6, 284]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [389, 478]},
+ {t: 'C', p: [389, 478, 373.5, 441.5, 361, 432]},
+ {t: 'C', p: [361, 432, 387, 448, 390.5, 466]},
+ {t: 'C', p: [390.5, 466, 390.5, 476, 389, 478]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [436, 485.5]},
+ {t: 'C', p: [436, 485.5, 409.5, 430.5, 391, 406.5]},
+ {t: 'C', p: [391, 406.5, 434.5, 444, 439.5, 470.5]},
+ {t: 'L', p: [440, 476]},
+ {t: 'L', p: [437, 473.5]},
+ {t: 'C', p: [437, 473.5, 436.5, 482.5, 436, 485.5]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [492.5, 437]},
+ {t: 'C', p: [492.5, 437, 430, 377.5, 428.5, 375]},
+ {t: 'C', p: [428.5, 375, 489, 441, 492, 448.5]},
+ {t: 'C', p: [492, 448.5, 490, 439.5, 492.5, 437]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [304, 480.5]},
+ {t: 'C', p: [304, 480.5, 323.5, 428.5, 342.5, 451]},
+ {t: 'C', p: [342.5, 451, 357.5, 461, 357, 464]},
+ {t: 'C', p: [357, 464, 353, 457.5, 335, 458]},
+ {t: 'C', p: [335, 458, 316, 455, 304, 480.5]},
+ {t: 'z', p: []}]},
+
+{f: '#ccc', s: null, p: [{t: 'M', p: [494.5, 353]},
+ {t: 'C', p: [494.5, 353, 449.5, 324.5, 442, 323]},
+ {t: 'C', p: [430.193, 320.639, 491.5, 352, 496.5, 362.5]},
+ {t: 'C', p: [496.5, 362.5, 498.5, 360, 494.5, 353]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [343.801, 459.601]},
+ {t: 'C', p: [343.801, 459.601, 364.201, 457.601, 371.001, 450.801]},
+ {t: 'L', p: [375.401, 454.401]},
+ {t: 'L', p: [393.001, 416.001]},
+ {t: 'L', p: [396.601, 421.201]},
+ {t: 'C', p: [396.601, 421.201, 411.001, 406.401, 410.201, 398.401]},
+ {t: 'C', p: [409.401, 390.401, 423.001, 404.401, 423.001, 404.401]},
+ {t: 'C', p: [423.001, 404.401, 422.201, 392.801, 429.401, 399.601]},
+ {t: 'C', p: [429.401, 399.601, 427.001, 384.001, 435.401, 392.001]},
+ {t: 'C', p: [435.401, 392.001, 424.864, 361.844, 447.401, 387.601]},
+ {t: 'C', p: [453.001, 394.001, 448.601, 387.201, 448.601, 387.201]},
+ {t: 'C', p: [448.601, 387.201, 422.601, 339.201, 444.201, 353.601]},
+ {t: 'C', p: [444.201, 353.601, 446.201, 330.801, 445.001, 326.401]},
+ {t: 'C', p: [443.801, 322.001, 441.801, 299.6, 437.001, 294.4]},
+ {t: 'C', p: [432.201, 289.2, 437.401, 287.6, 443.001, 292.8]},
+ {t: 'C', p: [443.001, 292.8, 431.801, 268.8, 445.001, 280.8]},
+ {t: 'C', p: [445.001, 280.8, 441.401, 265.6, 437.001, 262.8]},
+ {t: 'C', p: [437.001, 262.8, 431.401, 245.6, 446.601, 256.4]},
+ {t: 'C', p: [446.601, 256.4, 442.201, 244, 439.001, 240.8]},
+ {t: 'C', p: [439.001, 240.8, 427.401, 213.2, 434.601, 218]},
+ {t: 'L', p: [439.001, 221.6]},
+ {t: 'C', p: [439.001, 221.6, 432.201, 207.6, 438.601, 212]},
+ {t: 'C', p: [445.001, 216.4, 445.001, 216, 445.001, 216]},
+ {t: 'C', p: [445.001, 216, 423.801, 182.8, 444.201, 200.4]},
+ {t: 'C', p: [444.201, 200.4, 436.042, 186.482, 432.601, 179.6]},
+ {t: 'C', p: [432.601, 179.6, 413.801, 159.2, 428.201, 165.6]},
+ {t: 'L', p: [433.001, 167.2]},
+ {t: 'C', p: [433.001, 167.2, 424.201, 157.2, 416.201, 155.6]},
+ {t: 'C', p: [408.201, 154, 418.601, 147.6, 425.001, 149.6]},
+ {t: 'C', p: [431.401, 151.6, 447.001, 159.2, 447.001, 159.2]},
+ {t: 'C', p: [447.001, 159.2, 459.801, 178, 463.801, 178.4]},
+ {t: 'C', p: [463.801, 178.4, 443.801, 170.8, 449.801, 178.8]},
+ {t: 'C', p: [449.801, 178.8, 464.201, 192.8, 457.001, 192.4]},
+ {t: 'C', p: [457.001, 192.4, 451.001, 199.6, 455.801, 208.4]},
+ {t: 'C', p: [455.801, 208.4, 437.342, 190.009, 452.201, 215.6]},
+ {t: 'L', p: [459.001, 232]},
+ {t: 'C', p: [459.001, 232, 434.601, 207.2, 445.801, 229.2]},
+ {t: 'C', p: [445.801, 229.2, 463.001, 252.8, 465.001, 253.2]},
+ {t: 'C', p: [467.001, 253.6, 471.401, 262.4, 471.401, 262.4]},
+ {t: 'L', p: [467.001, 260.4]},
+ {t: 'L', p: [472.201, 269.2]},
+ {t: 'C', p: [472.201, 269.2, 461.001, 257.2, 467.001, 270.4]},
+ {t: 'L', p: [472.601, 284.8]},
+ {t: 'C', p: [472.601, 284.8, 452.201, 262.8, 465.801, 292.4]},
+ {t: 'C', p: [465.801, 292.4, 449.401, 287.2, 458.201, 304.4]},
+ {t: 'C', p: [458.201, 304.4, 456.601, 320.401, 457.001, 325.601]},
+ {t: 'C', p: [457.401, 330.801, 458.601, 359.201, 454.201, 367.201]},
+ {t: 'C', p: [449.801, 375.201, 460.201, 394.401, 462.201, 398.401]},
+ {t: 'C', p: [464.201, 402.401, 467.801, 413.201, 459.001, 404.001]},
+ {t: 'C', p: [450.201, 394.801, 454.601, 400.401, 456.601, 409.201]},
+ {t: 'C', p: [458.601, 418.001, 464.601, 433.601, 463.801, 439.201]},
+ {t: 'C', p: [463.801, 439.201, 462.601, 440.401, 459.401, 436.801]},
+ {t: 'C', p: [459.401, 436.801, 444.601, 414.001, 446.201, 428.401]},
+ {t: 'C', p: [446.201, 428.401, 445.001, 436.401, 441.801, 445.201]},
+ {t: 'C', p: [441.801, 445.201, 438.601, 456.001, 438.601, 447.201]},
+ {t: 'C', p: [438.601, 447.201, 435.401, 430.401, 432.601, 438.001]},
+ {t: 'C', p: [429.801, 445.601, 426.201, 451.601, 423.401, 454.001]},
+ {t: 'C', p: [420.601, 456.401, 415.401, 433.601, 414.201, 444.001]},
+ {t: 'C', p: [414.201, 444.001, 402.201, 431.601, 397.401, 448.001]},
+ {t: 'L', p: [385.801, 464.401]},
+ {t: 'C', p: [385.801, 464.401, 385.401, 452.001, 384.201, 458.001]},
+ {t: 'C', p: [384.201, 458.001, 354.201, 464.001, 343.801, 459.601]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [309.401, 102.8]},
+ {t: 'C', p: [309.401, 102.8, 297.801, 94.8, 293.801, 95.2]},
+ {t: 'C', p: [289.801, 95.6, 321.401, 86.4, 362.601, 114]},
+ {t: 'C', p: [362.601, 114, 367.401, 116.8, 371.001, 116.4]},
+ {t: 'C', p: [371.001, 116.4, 374.201, 118.8, 371.401, 122.4]},
+ {t: 'C', p: [371.401, 122.4, 362.601, 132, 373.801, 143.2]},
+ {t: 'C', p: [373.801, 143.2, 392.201, 150, 386.601, 141.2]},
+ {t: 'C', p: [386.601, 141.2, 397.401, 145.2, 399.801, 149.2]},
+ {t: 'C', p: [402.201, 153.2, 401.001, 149.2, 401.001, 149.2]},
+ {t: 'C', p: [401.001, 149.2, 394.601, 142, 388.601, 136.8]},
+ {t: 'C', p: [388.601, 136.8, 383.401, 134.8, 380.601, 126.4]},
+ {t: 'C', p: [377.801, 118, 375.401, 108, 379.801, 104.8]},
+ {t: 'C', p: [379.801, 104.8, 375.801, 109.2, 376.601, 105.2]},
+ {t: 'C', p: [377.401, 101.2, 381.001, 97.6, 382.601, 97.2]},
+ {t: 'C', p: [384.201, 96.8, 400.601, 81, 407.401, 80.6]},
+ {t: 'C', p: [407.401, 80.6, 398.201, 82, 395.201, 81]},
+ {t: 'C', p: [392.201, 80, 365.601, 68.6, 359.601, 67.4]},
+ {t: 'C', p: [359.601, 67.4, 342.801, 60.8, 354.801, 62.8]},
+ {t: 'C', p: [354.801, 62.8, 390.601, 66.6, 408.801, 79.8]},
+ {t: 'C', p: [408.801, 79.8, 401.601, 71.4, 383.201, 64.4]},
+ {t: 'C', p: [383.201, 64.4, 361.001, 51.8, 325.801, 56.8]},
+ {t: 'C', p: [325.801, 56.8, 308.001, 60, 300.201, 61.8]},
+ {t: 'C', p: [300.201, 61.8, 297.601, 61.2, 297.001, 60.8]},
+ {t: 'C', p: [296.401, 60.4, 284.6, 51.4, 257, 58.4]},
+ {t: 'C', p: [257, 58.4, 240, 63, 231.4, 67.8]},
+ {t: 'C', p: [231.4, 67.8, 216.2, 69, 212.6, 72.2]},
+ {t: 'C', p: [212.6, 72.2, 194, 86.8, 192, 87.6]},
+ {t: 'C', p: [190, 88.4, 178.6, 96, 177.8, 96.4]},
+ {t: 'C', p: [177.8, 96.4, 202.4, 89.8, 204.8, 87.4]},
+ {t: 'C', p: [207.2, 85, 224.6, 82.4, 227, 83.8]},
+ {t: 'C', p: [229.4, 85.2, 237.8, 84.6, 228.2, 85.2]},
+ {t: 'C', p: [228.2, 85.2, 303.801, 100, 304.601, 102]},
+ {t: 'C', p: [305.401, 104, 309.401, 102.8, 309.401, 102.8]},
+ {t: 'z', p: []}]},
+
+{f: '#cc7226', s: null, p: [{t: 'M', p: [380.801, 93.6]},
+ {t: 'C', p: [380.801, 93.6, 370.601, 86.2, 368.601, 86.2]},
+ {t: 'C', p: [366.601, 86.2, 354.201, 76, 350.001, 76.4]},
+ {t: 'C', p: [345.801, 76.8, 333.601, 66.8, 306.201, 75]},
+ {t: 'C', p: [306.201, 75, 305.601, 73, 309.201, 72.2]},
+ {t: 'C', p: [309.201, 72.2, 315.601, 70, 316.001, 69.4]},
+ {t: 'C', p: [316.001, 69.4, 336.201, 65.2, 343.401, 68.8]},
+ {t: 'C', p: [343.401, 68.8, 352.601, 71.4, 358.801, 77.6]},
+ {t: 'C', p: [358.801, 77.6, 370.001, 80.8, 373.201, 79.8]},
+ {t: 'C', p: [373.201, 79.8, 382.001, 82, 382.401, 83.8]},
+ {t: 'C', p: [382.401, 83.8, 388.201, 86.8, 386.401, 89.4]},
+ {t: 'C', p: [386.401, 89.4, 386.801, 91, 380.801, 93.6]},
+ {t: 'z', p: []}]},
+
+{f: '#cc7226', s: null, p: [{t: 'M', p: [368.33, 91.491]},
+ {t: 'C', p: [369.137, 92.123, 370.156, 92.221, 370.761, 93.03]},
+ {t: 'C', p: [370.995, 93.344, 370.706, 93.67, 370.391, 93.767]},
+ {t: 'C', p: [369.348, 94.084, 368.292, 93.514, 367.15, 94.102]},
+ {t: 'C', p: [366.748, 94.309, 366.106, 94.127, 365.553, 93.978]},
+ {t: 'C', p: [363.921, 93.537, 362.092, 93.512, 360.401, 94.2]},
+ {t: 'C', p: [358.416, 93.071, 356.056, 93.655, 353.975, 92.654]},
+ {t: 'C', p: [353.917, 92.627, 353.695, 92.973, 353.621, 92.946]},
+ {t: 'C', p: [350.575, 91.801, 346.832, 92.084, 344.401, 89.8]},
+ {t: 'C', p: [341.973, 89.388, 339.616, 88.926, 337.188, 88.246]},
+ {t: 'C', p: [335.37, 87.737, 333.961, 86.748, 332.341, 85.916]},
+ {t: 'C', p: [330.964, 85.208, 329.507, 84.686, 327.973, 84.314]},
+ {t: 'C', p: [326.11, 83.862, 324.279, 83.974, 322.386, 83.454]},
+ {t: 'C', p: [322.293, 83.429, 322.101, 83.773, 322.019, 83.746]},
+ {t: 'C', p: [321.695, 83.638, 321.405, 83.055, 321.234, 83.108]},
+ {t: 'C', p: [319.553, 83.63, 318.065, 82.658, 316.401, 83]},
+ {t: 'C', p: [315.223, 81.776, 313.495, 82.021, 311.949, 81.579]},
+ {t: 'C', p: [308.985, 80.731, 305.831, 82.001, 302.801, 81]},
+ {t: 'C', p: [306.914, 79.158, 311.601, 80.39, 315.663, 78.321]},
+ {t: 'C', p: [317.991, 77.135, 320.653, 78.237, 323.223, 77.477]},
+ {t: 'C', p: [323.71, 77.333, 324.401, 77.131, 324.801, 77.8]},
+ {t: 'C', p: [324.935, 77.665, 325.117, 77.426, 325.175, 77.454]},
+ {t: 'C', p: [327.625, 78.611, 329.94, 79.885, 332.422, 80.951]},
+ {t: 'C', p: [332.763, 81.097, 333.295, 80.865, 333.547, 81.067]},
+ {t: 'C', p: [335.067, 82.283, 337.01, 82.18, 338.401, 83.4]},
+ {t: 'C', p: [340.099, 82.898, 341.892, 83.278, 343.621, 82.654]},
+ {t: 'C', p: [343.698, 82.627, 343.932, 82.968, 343.965, 82.946]},
+ {t: 'C', p: [345.095, 82.198, 346.25, 82.469, 347.142, 82.773]},
+ {t: 'C', p: [347.48, 82.888, 348.143, 83.135, 348.448, 83.209]},
+ {t: 'C', p: [349.574, 83.485, 350.43, 83.965, 351.609, 84.148]},
+ {t: 'C', p: [351.723, 84.166, 351.908, 83.826, 351.98, 83.854]},
+ {t: 'C', p: [353.103, 84.292, 354.145, 84.236, 354.801, 85.4]},
+ {t: 'C', p: [354.936, 85.265, 355.101, 85.027, 355.183, 85.054]},
+ {t: 'C', p: [356.21, 85.392, 356.859, 86.147, 357.96, 86.388]},
+ {t: 'C', p: [358.445, 86.494, 359.057, 87.12, 359.633, 87.296]},
+ {t: 'C', p: [362.025, 88.027, 363.868, 89.556, 366.062, 90.451]},
+ {t: 'C', p: [366.821, 90.761, 367.697, 90.995, 368.33, 91.491]},
+ {t: 'z', p: []}]},
+
+{f: '#cc7226', s: null, p: [{t: 'M', p: [291.696, 77.261]},
+ {t: 'C', p: [289.178, 75.536, 286.81, 74.43, 284.368, 72.644]},
+ {t: 'C', p: [284.187, 72.511, 283.827, 72.681, 283.625, 72.559]},
+ {t: 'C', p: [282.618, 71.95, 281.73, 71.369, 280.748, 70.673]},
+ {t: 'C', p: [280.209, 70.291, 279.388, 70.302, 278.88, 70.044]},
+ {t: 'C', p: [276.336, 68.752, 273.707, 68.194, 271.2, 67]},
+ {t: 'C', p: [271.882, 66.362, 273.004, 66.606, 273.6, 65.8]},
+ {t: 'C', p: [273.795, 66.08, 274.033, 66.364, 274.386, 66.173]},
+ {t: 'C', p: [276.064, 65.269, 277.914, 65.116, 279.59, 65.206]},
+ {t: 'C', p: [281.294, 65.298, 283.014, 65.603, 284.789, 65.875]},
+ {t: 'C', p: [285.096, 65.922, 285.295, 66.445, 285.618, 66.542]},
+ {t: 'C', p: [287.846, 67.205, 290.235, 66.68, 292.354, 67.518]},
+ {t: 'C', p: [293.945, 68.147, 295.515, 68.97, 296.754, 70.245]},
+ {t: 'C', p: [297.006, 70.505, 296.681, 70.806, 296.401, 71]},
+ {t: 'C', p: [296.789, 70.891, 297.062, 71.097, 297.173, 71.41]},
+ {t: 'C', p: [297.257, 71.649, 297.257, 71.951, 297.173, 72.19]},
+ {t: 'C', p: [297.061, 72.502, 296.782, 72.603, 296.408, 72.654]},
+ {t: 'C', p: [295.001, 72.844, 296.773, 71.464, 296.073, 71.912]},
+ {t: 'C', p: [294.8, 72.726, 295.546, 74.132, 294.801, 75.4]},
+ {t: 'C', p: [294.521, 75.206, 294.291, 74.988, 294.401, 74.6]},
+ {t: 'C', p: [294.635, 75.122, 294.033, 75.412, 293.865, 75.728]},
+ {t: 'C', p: [293.48, 76.453, 292.581, 77.868, 291.696, 77.261]},
+ {t: 'z', p: []}]},
+
+{f: '#cc7226', s: null, p: [{t: 'M', p: [259.198, 84.609]},
+ {t: 'C', p: [256.044, 83.815, 252.994, 83.93, 249.978, 82.654]},
+ {t: 'C', p: [249.911, 82.626, 249.688, 82.973, 249.624, 82.946]},
+ {t: 'C', p: [248.258, 82.352, 247.34, 81.386, 246.264, 80.34]},
+ {t: 'C', p: [245.351, 79.452, 243.693, 79.839, 242.419, 79.352]},
+ {t: 'C', p: [242.095, 79.228, 241.892, 78.716, 241.591, 78.677]},
+ {t: 'C', p: [240.372, 78.52, 239.445, 77.571, 238.4, 77]},
+ {t: 'C', p: [240.736, 76.205, 243.147, 76.236, 245.609, 75.852]},
+ {t: 'C', p: [245.722, 75.834, 245.867, 76.155, 246, 76.155]},
+ {t: 'C', p: [246.136, 76.155, 246.266, 75.934, 246.4, 75.8]},
+ {t: 'C', p: [246.595, 76.08, 246.897, 76.406, 247.154, 76.152]},
+ {t: 'C', p: [247.702, 75.612, 248.258, 75.802, 248.798, 75.842]},
+ {t: 'C', p: [248.942, 75.852, 249.067, 76.155, 249.2, 76.155]},
+ {t: 'C', p: [249.336, 76.155, 249.467, 75.844, 249.6, 75.844]},
+ {t: 'C', p: [249.736, 75.845, 249.867, 76.155, 250, 76.155]},
+ {t: 'C', p: [250.136, 76.155, 250.266, 75.934, 250.4, 75.8]},
+ {t: 'C', p: [251.092, 76.582, 251.977, 76.028, 252.799, 76.207]},
+ {t: 'C', p: [253.837, 76.434, 254.104, 77.582, 255.178, 77.88]},
+ {t: 'C', p: [259.893, 79.184, 264.03, 81.329, 268.393, 83.416]},
+ {t: 'C', p: [268.7, 83.563, 268.91, 83.811, 268.8, 84.2]},
+ {t: 'C', p: [269.067, 84.2, 269.38, 84.112, 269.57, 84.244]},
+ {t: 'C', p: [270.628, 84.976, 271.669, 85.524, 272.366, 86.622]},
+ {t: 'C', p: [272.582, 86.961, 272.253, 87.368, 272.02, 87.316]},
+ {t: 'C', p: [267.591, 86.321, 263.585, 85.713, 259.198, 84.609]},
+ {t: 'z', p: []}]},
+
+{f: '#cc7226', s: null, p: [{t: 'M', p: [245.338, 128.821]},
+ {t: 'C', p: [243.746, 127.602, 243.162, 125.571, 242.034, 123.779]},
+ {t: 'C', p: [241.82, 123.439, 242.094, 123.125, 242.411, 123.036]},
+ {t: 'C', p: [242.971, 122.877, 243.514, 123.355, 243.923, 123.557]},
+ {t: 'C', p: [245.668, 124.419, 247.203, 125.661, 249.2, 125.8]},
+ {t: 'C', p: [251.19, 128.034, 255.45, 128.419, 255.457, 131.8]},
+ {t: 'C', p: [255.458, 132.659, 254.03, 131.741, 253.6, 132.6]},
+ {t: 'C', p: [251.149, 131.597, 248.76, 131.7, 246.38, 130.233]},
+ {t: 'C', p: [245.763, 129.852, 246.093, 129.399, 245.338, 128.821]},
+ {t: 'z', p: []}]},
+
+{f: '#cc7226', s: null, p: [{t: 'M', p: [217.8, 76.244]},
+ {t: 'C', p: [217.935, 76.245, 224.966, 76.478, 224.949, 76.592]},
+ {t: 'C', p: [224.904, 76.901, 217.174, 77.95, 216.81, 77.78]},
+ {t: 'C', p: [216.646, 77.704, 209.134, 80.134, 209, 80]},
+ {t: 'C', p: [209.268, 79.865, 217.534, 76.244, 217.8, 76.244]},
+ {t: 'z', p: []}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [233.2, 86]},
+ {t: 'C', p: [233.2, 86, 218.4, 87.8, 214, 89]},
+ {t: 'C', p: [209.6, 90.2, 191, 97.8, 188, 99.8]},
+ {t: 'C', p: [188, 99.8, 174.6, 105.2, 157.6, 125.2]},
+ {t: 'C', p: [157.6, 125.2, 165.2, 121.8, 167.4, 119]},
+ {t: 'C', p: [167.4, 119, 181, 106.4, 180.8, 109]},
+ {t: 'C', p: [180.8, 109, 193, 100.4, 192.4, 102.6]},
+ {t: 'C', p: [192.4, 102.6, 216.8, 91.4, 214.8, 94.6]},
+ {t: 'C', p: [214.8, 94.6, 236.4, 90, 235.4, 92]},
+ {t: 'C', p: [235.4, 92, 254.2, 96.4, 251.4, 96.6]},
+ {t: 'C', p: [251.4, 96.6, 245.6, 97.8, 252, 101.4]},
+ {t: 'C', p: [252, 101.4, 248.6, 105.8, 243.2, 101.8]},
+ {t: 'C', p: [237.8, 97.8, 240.8, 100, 235.8, 101]},
+ {t: 'C', p: [235.8, 101, 233.2, 101.8, 228.6, 97.8]},
+ {t: 'C', p: [228.6, 97.8, 223, 93.2, 214.2, 96.8]},
+ {t: 'C', p: [214.2, 96.8, 183.6, 109.4, 181.6, 110]},
+ {t: 'C', p: [181.6, 110, 178, 112.8, 175.6, 116.4]},
+ {t: 'C', p: [175.6, 116.4, 169.8, 120.8, 166.8, 122.2]},
+ {t: 'C', p: [166.8, 122.2, 154, 133.8, 152.8, 135.2]},
+ {t: 'C', p: [152.8, 135.2, 149.4, 140.4, 148.6, 140.8]},
+ {t: 'C', p: [148.6, 140.8, 155, 137, 157, 135]},
+ {t: 'C', p: [157, 135, 171, 125, 176.4, 124.2]},
+ {t: 'C', p: [176.4, 124.2, 180.8, 121.2, 181.6, 119.8]},
+ {t: 'C', p: [181.6, 119.8, 196, 110.6, 200.2, 110.6]},
+ {t: 'C', p: [200.2, 110.6, 209.4, 115.8, 211.8, 108.8]},
+ {t: 'C', p: [211.8, 108.8, 217.6, 107, 223.2, 108.2]},
+ {t: 'C', p: [223.2, 108.2, 226.4, 105.6, 225.6, 103.4]},
+ {t: 'C', p: [225.6, 103.4, 227.2, 101.6, 228.2, 105.4]},
+ {t: 'C', p: [228.2, 105.4, 231.6, 109, 236.4, 107]},
+ {t: 'C', p: [236.4, 107, 240.4, 106.8, 238.4, 109.2]},
+ {t: 'C', p: [238.4, 109.2, 234, 113, 222.2, 113.2]},
+ {t: 'C', p: [222.2, 113.2, 209.8, 113.8, 193.4, 121.4]},
+ {t: 'C', p: [193.4, 121.4, 163.6, 131.8, 154.4, 142.2]},
+ {t: 'C', p: [154.4, 142.2, 148, 151, 142.6, 152.2]},
+ {t: 'C', p: [142.6, 152.2, 136.8, 153, 130.8, 160.4]},
+ {t: 'C', p: [130.8, 160.4, 140.6, 154.6, 149.6, 154.6]},
+ {t: 'C', p: [149.6, 154.6, 153.6, 152.2, 149.8, 155.8]},
+ {t: 'C', p: [149.8, 155.8, 146.2, 163.4, 147.8, 168.8]},
+ {t: 'C', p: [147.8, 168.8, 147.2, 174, 146.4, 175.6]},
+ {t: 'C', p: [146.4, 175.6, 138.6, 188.4, 138.6, 190.8]},
+ {t: 'C', p: [138.6, 193.2, 139.8, 203, 140.2, 203.6]},
+ {t: 'C', p: [140.6, 204.2, 139.2, 202, 143, 204.4]},
+ {t: 'C', p: [146.8, 206.8, 149.6, 208.4, 150.4, 211.2]},
+ {t: 'C', p: [151.2, 214, 148.4, 205.8, 148.2, 204]},
+ {t: 'C', p: [148, 202.2, 143.8, 195, 144.6, 192.6]},
+ {t: 'C', p: [144.6, 192.6, 145.6, 193.6, 146.4, 195]},
+ {t: 'C', p: [146.4, 195, 145.8, 194.4, 146.4, 190.8]},
+ {t: 'C', p: [146.4, 190.8, 147.2, 185.6, 148.6, 182.4]},
+ {t: 'C', p: [150, 179.2, 152, 175.4, 152.4, 174.6]},
+ {t: 'C', p: [152.8, 173.8, 152.8, 168, 154.2, 170.6]},
+ {t: 'L', p: [157.6, 173.2]},
+ {t: 'C', p: [157.6, 173.2, 154.8, 170.6, 157, 168.4]},
+ {t: 'C', p: [157, 168.4, 156, 162.8, 157.8, 160.2]},
+ {t: 'C', p: [157.8, 160.2, 164.8, 151.8, 166.4, 150.8]},
+ {t: 'C', p: [168, 149.8, 166.6, 150.2, 166.6, 150.2]},
+ {t: 'C', p: [166.6, 150.2, 172.6, 146, 166.8, 147.6]},
+ {t: 'C', p: [166.8, 147.6, 162.8, 149.2, 159.8, 149.2]},
+ {t: 'C', p: [159.8, 149.2, 152.2, 151.2, 156.2, 147]},
+ {t: 'C', p: [160.2, 142.8, 170.2, 137.4, 174, 137.6]},
+ {t: 'L', p: [174.8, 139.2]},
+ {t: 'L', p: [186, 136.8]},
+ {t: 'L', p: [184.8, 137.6]},
+ {t: 'C', p: [184.8, 137.6, 184.6, 137.4, 188.8, 137]},
+ {t: 'C', p: [193, 136.6, 198.8, 138, 200.2, 136.2]},
+ {t: 'C', p: [201.6, 134.4, 205, 133.4, 204.6, 134.8]},
+ {t: 'C', p: [204.2, 136.2, 204, 138.2, 204, 138.2]},
+ {t: 'C', p: [204, 138.2, 209, 132.4, 208.4, 134.6]},
+ {t: 'C', p: [207.8, 136.8, 199.6, 142, 198.2, 148.2]},
+ {t: 'L', p: [208.6, 140]},
+ {t: 'L', p: [212.2, 137]},
+ {t: 'C', p: [212.2, 137, 215.8, 139.2, 216, 137.6]},
+ {t: 'C', p: [216.2, 136, 220.8, 130.2, 222, 130.4]},
+ {t: 'C', p: [223.2, 130.6, 225.2, 127.8, 225, 130.4]},
+ {t: 'C', p: [224.8, 133, 232.4, 138.4, 232.4, 138.4]},
+ {t: 'C', p: [232.4, 138.4, 235.6, 136.6, 237, 138]},
+ {t: 'C', p: [238.4, 139.4, 242.6, 118.2, 242.6, 118.2]},
+ {t: 'L', p: [267.6, 107.6]},
+ {t: 'L', p: [311.201, 104.2]},
+ {t: 'L', p: [294.201, 97.4]},
+ {t: 'L', p: [233.2, 86]},
+ {t: 'z', p: []}]},
+
+{f: null, s: {c: '#4c0000', w: 2},
+ p: [{t: 'M', p: [251.4, 285]},
+ {t: 'C', p: [251.4, 285, 236.4, 268.2, 228, 265.6]},
+ {t: 'C', p: [228, 265.6, 214.6, 258.8, 190, 266.6]}]},
+
+{f: null, s: {c: '#4c0000', w: 2},
+ p: [{t: 'M', p: [224.8, 264.2]},
+ {t: 'C', p: [224.8, 264.2, 199.6, 256.2, 184.2, 260.4]},
+ {t: 'C', p: [184.2, 260.4, 165.8, 262.4, 157.4, 276.2]}]},
+
+{f: null, s: {c: '#4c0000', w: 2},
+ p: [{t: 'M', p: [221.2, 263]},
+ {t: 'C', p: [221.2, 263, 204.2, 255.8, 189.4, 253.6]},
+ {t: 'C', p: [189.4, 253.6, 172.8, 251, 156.2, 258.2]},
+ {t: 'C', p: [156.2, 258.2, 144, 264.2, 138.6, 274.4]}]},
+
+{f: null, s: {c: '#4c0000', w: 2},
+ p: [{t: 'M', p: [222.2, 263.4]},
+ {t: 'C', p: [222.2, 263.4, 206.8, 252.4, 205.8, 251]},
+ {t: 'C', p: [205.8, 251, 198.8, 240, 185.8, 239.6]},
+ {t: 'C', p: [185.8, 239.6, 164.4, 240.4, 147.2, 248.4]}]},
+
+{f: '#000', s: null, p: [{t: 'M', p: [220.895, 254.407]},
+ {t: 'C', p: [222.437, 255.87, 249.4, 284.8, 249.4, 284.8]},
+ {t: 'C', p: [284.6, 321.401, 256.6, 287.2, 256.6, 287.2]},
+ {t: 'C', p: [249, 282.4, 239.8, 263.6, 239.8, 263.6]},
+ {t: 'C', p: [238.6, 260.8, 253.8, 270.8, 253.8, 270.8]},
+ {t: 'C', p: [257.8, 271.6, 271.4, 290.8, 271.4, 290.8]},
+ {t: 'C', p: [264.6, 288.4, 269.4, 295.6, 269.4, 295.6]},
+ {t: 'C', p: [272.2, 297.6, 292.601, 313.201, 292.601, 313.201]},
+ {t: 'C', p: [296.201, 317.201, 300.201, 318.801, 300.201, 318.801]},
+ {t: 'C', p: [314.201, 313.601, 307.801, 326.801, 307.801, 326.801]},
+ {t: 'C', p: [310.201, 333.601, 315.801, 322.001, 315.801, 322.001]},
+ {t: 'C', p: [327.001, 305.2, 310.601, 307.601, 310.601, 307.601]},
+ {t: 'C', p: [280.6, 310.401, 273.8, 294.4, 273.8, 294.4]},
+ {t: 'C', p: [271.4, 292, 280.2, 294.4, 280.2, 294.4]},
+ {t: 'C', p: [288.601, 296.4, 273, 282, 273, 282]},
+ {t: 'C', p: [275.4, 282, 284.6, 288.8, 284.6, 288.8]},
+ {t: 'C', p: [295.001, 298, 297.001, 296, 297.001, 296]},
+ {t: 'C', p: [315.001, 287.2, 325.401, 294.8, 325.401, 294.8]},
+ {t: 'C', p: [327.401, 296.4, 321.801, 303.2, 323.401, 308.401]},
+ {t: 'C', p: [325.001, 313.601, 329.801, 326.001, 329.801, 326.001]},
+ {t: 'C', p: [327.401, 327.601, 327.801, 338.401, 327.801, 338.401]},
+ {t: 'C', p: [344.601, 361.601, 335.001, 359.601, 335.001, 359.601]},
+ {t: 'C', p: [319.401, 359.201, 334.201, 366.801, 334.201, 366.801]},
+ {t: 'C', p: [337.401, 368.801, 346.201, 376.001, 346.201, 376.001]},
+ {t: 'C', p: [343.401, 374.801, 341.801, 380.001, 341.801, 380.001]},
+ {t: 'C', p: [346.601, 384.001, 343.801, 388.801, 343.801, 388.801]},
+ {t: 'C', p: [337.801, 390.001, 336.601, 394.001, 336.601, 394.001]},
+ {t: 'C', p: [343.401, 402.001, 333.401, 402.401, 333.401, 402.401]},
+ {t: 'C', p: [337.001, 406.801, 332.201, 418.801, 332.201, 418.801]},
+ {t: 'C', p: [327.401, 418.801, 321.001, 424.401, 321.001, 424.401]},
+ {t: 'C', p: [323.401, 429.201, 313.001, 434.801, 313.001, 434.801]},
+ {t: 'C', p: [304.601, 436.401, 307.401, 443.201, 307.401, 443.201]},
+ {t: 'C', p: [299.401, 449.201, 297.001, 465.201, 297.001, 465.201]},
+ {t: 'C', p: [296.201, 475.601, 293.801, 478.801, 299.001, 476.801]},
+ {t: 'C', p: [304.201, 474.801, 303.401, 462.401, 303.401, 462.401]},
+ {t: 'C', p: [298.601, 446.801, 341.401, 430.801, 341.401, 430.801]},
+ {t: 'C', p: [345.401, 429.201, 346.201, 424.001, 346.201, 424.001]},
+ {t: 'C', p: [348.201, 424.401, 357.001, 432.001, 357.001, 432.001]},
+ {t: 'C', p: [364.601, 443.201, 365.001, 434.001, 365.001, 434.001]},
+ {t: 'C', p: [366.201, 430.401, 364.601, 424.401, 364.601, 424.401]},
+ {t: 'C', p: [370.601, 402.801, 356.601, 396.401, 356.601, 396.401]},
+ {t: 'C', p: [346.601, 362.801, 360.601, 371.201, 360.601, 371.201]},
+ {t: 'C', p: [363.401, 376.801, 374.201, 382.001, 374.201, 382.001]},
+ {t: 'L', p: [377.801, 379.601]},
+ {t: 'C', p: [376.201, 374.801, 384.601, 368.801, 384.601, 368.801]},
+ {t: 'C', p: [387.401, 375.201, 393.401, 367.201, 393.401, 367.201]},
+ {t: 'C', p: [397.001, 342.801, 409.401, 357.201, 409.401, 357.201]},
+ {t: 'C', p: [413.401, 358.401, 414.601, 351.601, 414.601, 351.601]},
+ {t: 'C', p: [418.201, 341.201, 414.601, 327.601, 414.601, 327.601]},
+ {t: 'C', p: [418.201, 327.201, 427.801, 333.201, 427.801, 333.201]},
+ {t: 'C', p: [430.601, 329.601, 421.401, 312.801, 425.401, 315.201]},
+ {t: 'C', p: [429.401, 317.601, 433.801, 319.201, 433.801, 319.201]},
+ {t: 'C', p: [434.601, 317.201, 424.601, 304.801, 424.601, 304.801]},
+ {t: 'C', p: [420.201, 302, 415.001, 281.6, 415.001, 281.6]},
+ {t: 'C', p: [422.201, 285.2, 412.201, 270, 412.201, 270]},
+ {t: 'C', p: [412.201, 266.8, 418.201, 255.6, 418.201, 255.6]},
+ {t: 'C', p: [417.401, 248.8, 418.201, 249.2, 418.201, 249.2]},
+ {t: 'C', p: [421.001, 250.4, 429.001, 252, 422.201, 245.6]},
+ {t: 'C', p: [415.401, 239.2, 423.001, 234.4, 423.001, 234.4]},
+ {t: 'C', p: [427.401, 231.6, 413.801, 232, 413.801, 232]},
+ {t: 'C', p: [408.601, 227.6, 409.001, 223.6, 409.001, 223.6]},
+ {t: 'C', p: [417.001, 225.6, 402.601, 211.2, 400.201, 207.6]},
+ {t: 'C', p: [397.801, 204, 407.401, 198.8, 407.401, 198.8]},
+ {t: 'C', p: [420.601, 195.2, 409.001, 192, 409.001, 192]},
+ {t: 'C', p: [389.401, 192.4, 400.201, 181.6, 400.201, 181.6]},
+ {t: 'C', p: [406.201, 182, 404.601, 179.6, 404.601, 179.6]},
+ {t: 'C', p: [399.401, 178.4, 389.801, 172, 389.801, 172]},
+ {t: 'C', p: [385.801, 168.4, 389.401, 169.2, 389.401, 169.2]},
+ {t: 'C', p: [406.201, 170.4, 377.401, 159.2, 377.401, 159.2]},
+ {t: 'C', p: [385.401, 159.2, 367.401, 148.8, 367.401, 148.8]},
+ {t: 'C', p: [365.401, 147.2, 362.201, 139.6, 362.201, 139.6]},
+ {t: 'C', p: [356.201, 134.4, 351.401, 127.6, 351.401, 127.6]},
+ {t: 'C', p: [351.001, 123.2, 346.201, 118.4, 346.201, 118.4]},
+ {t: 'C', p: [334.601, 104.8, 329.001, 105.2, 329.001, 105.2]},
+ {t: 'C', p: [314.201, 101.6, 309.001, 102.4, 309.001, 102.4]},
+ {t: 'L', p: [256.2, 106.8]},
+ {t: 'C', p: [229.8, 119.6, 237.6, 140.6, 237.6, 140.6]},
+ {t: 'C', p: [244, 149, 253.2, 145.2, 253.2, 145.2]},
+ {t: 'C', p: [257.8, 139, 269.4, 141.2, 269.4, 141.2]},
+ {t: 'C', p: [289.801, 144.4, 287.201, 140.8, 287.201, 140.8]},
+ {t: 'C', p: [284.801, 136.2, 268.6, 130, 268.4, 129.4]},
+ {t: 'C', p: [268.2, 128.8, 259.4, 125.4, 259.4, 125.4]},
+ {t: 'C', p: [256.4, 124.2, 252, 115, 252, 115]},
+ {t: 'C', p: [248.8, 111.6, 264.6, 117.4, 264.6, 117.4]},
+ {t: 'C', p: [263.4, 118.4, 270.8, 122.4, 270.8, 122.4]},
+ {t: 'C', p: [288.201, 121.4, 298.801, 132.2, 298.801, 132.2]},
+ {t: 'C', p: [309.601, 148.8, 309.801, 140.6, 309.801, 140.6]},
+ {t: 'C', p: [312.601, 131.2, 300.801, 110, 300.801, 110]},
+ {t: 'C', p: [301.201, 108, 309.401, 114.6, 309.401, 114.6]},
+ {t: 'C', p: [310.801, 112.6, 311.601, 118.4, 311.601, 118.4]},
+ {t: 'C', p: [311.801, 120.8, 315.601, 128.8, 315.601, 128.8]},
+ {t: 'C', p: [318.401, 141.8, 322.001, 134.4, 322.001, 134.4]},
+ {t: 'L', p: [326.601, 143.8]},
+ {t: 'C', p: [328.001, 146.4, 322.001, 154, 322.001, 154]},
+ {t: 'C', p: [321.801, 156.8, 322.601, 156.6, 317.001, 164.2]},
+ {t: 'C', p: [311.401, 171.8, 314.801, 176.2, 314.801, 176.2]},
+ {t: 'C', p: [313.401, 182.8, 322.201, 182.4, 322.201, 182.4]},
+ {t: 'C', p: [324.801, 184.6, 328.201, 184.6, 328.201, 184.6]},
+ {t: 'C', p: [330.001, 186.6, 332.401, 186, 332.401, 186]},
+ {t: 'C', p: [334.001, 182.2, 340.201, 184.2, 340.201, 184.2]},
+ {t: 'C', p: [341.601, 181.8, 349.801, 181.4, 349.801, 181.4]},
+ {t: 'C', p: [350.801, 178.8, 351.201, 177.2, 354.601, 176.6]},
+ {t: 'C', p: [358.001, 176, 333.401, 133, 333.401, 133]},
+ {t: 'C', p: [339.801, 132.2, 331.601, 119.8, 331.601, 119.8]},
+ {t: 'C', p: [329.401, 113.2, 340.801, 127.8, 343.001, 129.2]},
+ {t: 'C', p: [345.201, 130.6, 346.201, 132.8, 344.601, 132.6]},
+ {t: 'C', p: [343.001, 132.4, 341.201, 134.6, 342.601, 134.8]},
+ {t: 'C', p: [344.001, 135, 357.001, 150, 360.401, 160.2]},
+ {t: 'C', p: [363.801, 170.4, 369.801, 174.4, 376.001, 180.4]},
+ {t: 'C', p: [382.201, 186.4, 381.401, 210.6, 381.401, 210.6]},
+ {t: 'C', p: [381.001, 219.4, 387.001, 230, 387.001, 230]},
+ {t: 'C', p: [389.001, 233.8, 384.801, 252, 384.801, 252]},
+ {t: 

<TRUNCATED>

[39/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/date/relativewithplurals.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/date/relativewithplurals.js b/externs/GCL/externs/goog/date/relativewithplurals.js
new file mode 100644
index 0000000..09a697e
--- /dev/null
+++ b/externs/GCL/externs/goog/date/relativewithplurals.js
@@ -0,0 +1,120 @@
+// 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 Code to make goog.date.relative plurals-aware.
+ */
+
+goog.provide('goog.date.relativeWithPlurals');
+
+goog.require('goog.date.relative');
+goog.require('goog.date.relative.Unit');
+goog.require('goog.i18n.MessageFormat');
+
+
+/**
+ * Gets a localized relative date string for a given delta and unit.
+ * @param {number} delta Number of minutes/hours/days.
+ * @param {boolean} future Whether the delta is in the future.
+ * @param {goog.date.relative.Unit} unit The units the delta is in.
+ * @return {string} The message.
+ * @private
+ */
+goog.date.relativeWithPlurals.formatTimeDelta_ =
+    function(delta, future, unit) {
+  if (!future && unit == goog.date.relative.Unit.MINUTES) {
+    /**
+     * @desc Relative date indicating how many minutes ago something happened.
+     */
+    var MSG_MINUTES_AGO_ICU =
+        goog.getMsg('{NUM, plural, ' +
+            '=0 {# minutes ago}' +
+            '=1 {# minute ago}' +
+            'other {# minutes ago}}');
+
+    return new goog.i18n.MessageFormat(MSG_MINUTES_AGO_ICU).
+        format({'NUM': delta});
+
+  } else if (future && unit == goog.date.relative.Unit.MINUTES) {
+    /**
+     * @desc Relative date indicating in how many minutes something happens.
+     */
+    var MSG_IN_MINUTES_ICU =
+        goog.getMsg('{NUM, plural, ' +
+            '=0 {in # minutes}' +
+            '=1 {in # minute}' +
+            'other {in # minutes}}');
+
+    return new goog.i18n.MessageFormat(MSG_IN_MINUTES_ICU).
+        format({'NUM': delta});
+
+  } else if (!future && unit == goog.date.relative.Unit.HOURS) {
+    /**
+     * @desc Relative date indicating how many hours ago something happened.
+     */
+    var MSG_HOURS_AGO_ICU =
+        goog.getMsg('{NUM, plural, ' +
+            '=0 {# hours ago}' +
+            '=1 {# hour ago}' +
+            'other {# hours ago}}');
+
+    return new goog.i18n.MessageFormat(MSG_HOURS_AGO_ICU).
+        format({'NUM': delta});
+
+  } else if (future && unit == goog.date.relative.Unit.HOURS) {
+    /**
+     * @desc Relative date indicating in how many hours something happens.
+     */
+    var MSG_IN_HOURS_ICU =
+        goog.getMsg('{NUM, plural, ' +
+            '=0 {in # hours}' +
+            '=1 {in # hour}' +
+            'other {in # hours}}');
+
+    return new goog.i18n.MessageFormat(MSG_IN_HOURS_ICU).
+        format({'NUM': delta});
+
+  } else if (!future && unit == goog.date.relative.Unit.DAYS) {
+    /**
+     * @desc Relative date indicating how many days ago something happened.
+     */
+    var MSG_DAYS_AGO_ICU =
+        goog.getMsg('{NUM, plural, ' +
+            '=0 {# days ago}' +
+            '=1 {# day ago}' +
+            'other {# days ago}}');
+
+    return new goog.i18n.MessageFormat(MSG_DAYS_AGO_ICU).
+        format({'NUM': delta});
+
+  } else if (future && unit == goog.date.relative.Unit.DAYS) {
+    /**
+     * @desc Relative date indicating in how many days something happens.
+     */
+    var MSG_IN_DAYS_ICU =
+        goog.getMsg('{NUM, plural, ' +
+            '=0 {in # days}' +
+            '=1 {in # day}' +
+            'other {in # days}}');
+
+    return new goog.i18n.MessageFormat(MSG_IN_DAYS_ICU).
+        format({'NUM': delta});
+
+  } else {
+    return '';
+  }
+};
+
+goog.date.relative.setTimeDeltaFormatter(
+    goog.date.relativeWithPlurals.formatTimeDelta_);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/date/utcdatetime.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/date/utcdatetime.js b/externs/GCL/externs/goog/date/utcdatetime.js
new file mode 100644
index 0000000..eeffb31
--- /dev/null
+++ b/externs/GCL/externs/goog/date/utcdatetime.js
@@ -0,0 +1,191 @@
+// 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 Locale independent date/time class.
+ *
+ */
+
+goog.provide('goog.date.UtcDateTime');
+
+goog.require('goog.date');
+goog.require('goog.date.Date');
+goog.require('goog.date.DateTime');
+goog.require('goog.date.Interval');
+
+
+
+/**
+ * Class representing a date/time in GMT+0 time zone, without daylight saving.
+ * Defaults to current date and time if none is specified. The get... and the
+ * getUTC... methods are equivalent.
+ *
+ * @param {number|goog.date.DateLike=} opt_year Four digit UTC year or a
+ *     date-like object.  If not set, the created object will contain the
+ *     date determined by goog.now().
+ * @param {number=} opt_month UTC month, 0 = Jan, 11 = Dec.
+ * @param {number=} opt_date UTC date of month, 1 - 31.
+ * @param {number=} opt_hours UTC hours, 0 - 23.
+ * @param {number=} opt_minutes UTC minutes, 0 - 59.
+ * @param {number=} opt_seconds UTC seconds, 0 - 59.
+ * @param {number=} opt_milliseconds UTC milliseconds, 0 - 999.
+ * @constructor
+ * @struct
+ * @extends {goog.date.DateTime}
+ */
+goog.date.UtcDateTime = function(opt_year, opt_month, opt_date, opt_hours,
+                                 opt_minutes, opt_seconds, opt_milliseconds) {
+  var timestamp;
+  if (goog.isNumber(opt_year)) {
+    timestamp = Date.UTC(opt_year, opt_month || 0, opt_date || 1,
+                         opt_hours || 0, opt_minutes || 0, opt_seconds || 0,
+                         opt_milliseconds || 0);
+  } else {
+    timestamp = opt_year ? opt_year.getTime() : goog.now();
+  }
+  this.date = new Date(timestamp);
+};
+goog.inherits(goog.date.UtcDateTime, goog.date.DateTime);
+
+
+/**
+ * @param {number} timestamp Number of milliseconds since Epoch.
+ * @return {!goog.date.UtcDateTime}
+ */
+goog.date.UtcDateTime.fromTimestamp = function(timestamp) {
+  var date = new goog.date.UtcDateTime();
+  date.setTime(timestamp);
+  return date;
+};
+
+
+/**
+ * Creates a DateTime from a UTC datetime string expressed in ISO 8601 format.
+ *
+ * @param {string} formatted A date or datetime expressed in ISO 8601 format.
+ * @return {goog.date.UtcDateTime} Parsed date or null if parse fails.
+ */
+goog.date.UtcDateTime.fromIsoString = function(formatted) {
+  var ret = new goog.date.UtcDateTime(2000);
+  return goog.date.setIso8601DateTime(ret, formatted) ? ret : null;
+};
+
+
+/**
+ * Clones the UtcDateTime object.
+ *
+ * @return {!goog.date.UtcDateTime} A clone of the datetime object.
+ * @override
+ */
+goog.date.UtcDateTime.prototype.clone = function() {
+  var date = new goog.date.UtcDateTime(this.date);
+  date.setFirstDayOfWeek(this.getFirstDayOfWeek());
+  date.setFirstWeekCutOffDay(this.getFirstWeekCutOffDay());
+  return date;
+};
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.add = function(interval) {
+  if (interval.years || interval.months) {
+    var yearsMonths = new goog.date.Interval(interval.years, interval.months);
+    goog.date.Date.prototype.add.call(this, yearsMonths);
+  }
+  var daysAndTimeMillis = 1000 * (
+      interval.seconds + 60 * (
+          interval.minutes + 60 * (
+              interval.hours + 24 * interval.days)));
+  this.date = new Date(this.date.getTime() + daysAndTimeMillis);
+};
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.getTimezoneOffset = function() {
+  return 0;
+};
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.getFullYear =
+    goog.date.DateTime.prototype.getUTCFullYear;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.getMonth =
+    goog.date.DateTime.prototype.getUTCMonth;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.getDate =
+    goog.date.DateTime.prototype.getUTCDate;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.getHours =
+    goog.date.DateTime.prototype.getUTCHours;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.getMinutes =
+    goog.date.DateTime.prototype.getUTCMinutes;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.getSeconds =
+    goog.date.DateTime.prototype.getUTCSeconds;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.getMilliseconds =
+    goog.date.DateTime.prototype.getUTCMilliseconds;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.getDay =
+    goog.date.DateTime.prototype.getUTCDay;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.setFullYear =
+    goog.date.DateTime.prototype.setUTCFullYear;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.setMonth =
+    goog.date.DateTime.prototype.setUTCMonth;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.setDate =
+    goog.date.DateTime.prototype.setUTCDate;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.setHours =
+    goog.date.DateTime.prototype.setUTCHours;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.setMinutes =
+    goog.date.DateTime.prototype.setUTCMinutes;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.setSeconds =
+    goog.date.DateTime.prototype.setUTCSeconds;
+
+
+/** @override */
+goog.date.UtcDateTime.prototype.setMilliseconds =
+    goog.date.DateTime.prototype.setUTCMilliseconds;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/db/cursor.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/db/cursor.js b/externs/GCL/externs/goog/db/cursor.js
new file mode 100644
index 0000000..d8a4da7
--- /dev/null
+++ b/externs/GCL/externs/goog/db/cursor.js
@@ -0,0 +1,215 @@
+// 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 Wrapper for a IndexedDB cursor.
+ *
+ */
+
+
+goog.provide('goog.db.Cursor');
+
+goog.require('goog.async.Deferred');
+goog.require('goog.db.Error');
+goog.require('goog.debug');
+goog.require('goog.events.EventTarget');
+
+
+
+/**
+ * Creates a new IDBCursor wrapper object. Should not be created directly,
+ * access cursor through object store.
+ * @see goog.db.ObjectStore#openCursor
+ *
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @final
+ */
+goog.db.Cursor = function() {
+  goog.db.Cursor.base(this, 'constructor');
+};
+goog.inherits(goog.db.Cursor, goog.events.EventTarget);
+
+
+/**
+ * Underlying IndexedDB cursor object.
+ *
+ * @type {IDBCursor}
+ * @private
+ */
+goog.db.Cursor.prototype.cursor_ = null;
+
+
+/**
+ * Advances the cursor to the next position along its direction. When new data
+ * is available, the NEW_DATA event will be fired. If the cursor has reached the
+ * end of the range it will fire the COMPLETE event. If opt_key is specified it
+ * will advance to the key it matches in its direction.
+ *
+ * This wraps the native #continue method on the underlying object.
+ *
+ * @param {IDBKeyType=} opt_key The optional key to advance to.
+ */
+goog.db.Cursor.prototype.next = function(opt_key) {
+  if (opt_key) {
+    this.cursor_['continue'](opt_key);
+  } else {
+    this.cursor_['continue']();
+  }
+};
+
+
+/**
+ * Updates the value at the current position of the cursor in the object store.
+ * If the cursor points to a value that has just been deleted, a new value is
+ * created.
+ *
+ * @param {*} value The value to be stored.
+ * @return {!goog.async.Deferred} The resulting deferred request.
+ */
+goog.db.Cursor.prototype.update = function(value) {
+  var msg = 'updating via cursor with value ';
+  var d = new goog.async.Deferred();
+  var request;
+
+  try {
+    request = this.cursor_.update(value);
+  } catch (err) {
+    msg += goog.debug.deepExpose(value);
+    d.errback(goog.db.Error.fromException(err, msg));
+    return d;
+  }
+  request.onsuccess = function(ev) {
+    d.callback();
+  };
+  request.onerror = function(ev) {
+    msg += goog.debug.deepExpose(value);
+    d.errback(goog.db.Error.fromRequest(ev.target, msg));
+  };
+  return d;
+};
+
+
+/**
+ * Deletes the value at the cursor's position, without changing the cursor's
+ * position. Once the value is deleted, the cursor's value is set to null.
+ *
+ * @return {!goog.async.Deferred} The resulting deferred request.
+ */
+goog.db.Cursor.prototype.remove = function() {
+  var msg = 'deleting via cursor';
+  var d = new goog.async.Deferred();
+  var request;
+
+  try {
+    request = this.cursor_['delete']();
+  } catch (err) {
+    d.errback(goog.db.Error.fromException(err, msg));
+    return d;
+  }
+  request.onsuccess = function(ev) {
+    d.callback();
+  };
+  request.onerror = function(ev) {
+    d.errback(goog.db.Error.fromRequest(ev.target, msg));
+  };
+  return d;
+};
+
+
+/**
+ * @return {*} The value for the value at the cursor's position. Undefined
+ *     if no current value, or null if value has just been deleted.
+ */
+goog.db.Cursor.prototype.getValue = function() {
+  return this.cursor_['value'];
+};
+
+
+/**
+ * @return {IDBKeyType} The key for the value at the cursor's position. If
+ *     the cursor is outside its range, this is undefined.
+ */
+goog.db.Cursor.prototype.getKey = function() {
+  return this.cursor_.key;
+};
+
+
+/**
+ * Opens a value cursor from IDBObjectStore or IDBIndex over the specified key
+ * range. Returns a cursor object which is able to iterate over the given range.
+ * @param {!(IDBObjectStore|IDBIndex)} source Data source to open cursor.
+ * @param {!goog.db.KeyRange=} opt_range The key range. If undefined iterates
+ *     over the whole data source.
+ * @param {!goog.db.Cursor.Direction=} opt_direction The direction. If undefined
+ *     moves in a forward direction with duplicates.
+ * @return {!goog.db.Cursor} The cursor.
+ * @throws {goog.db.Error} If there was a problem opening the cursor.
+ */
+goog.db.Cursor.openCursor = function(source, opt_range, opt_direction) {
+  var cursor = new goog.db.Cursor();
+  var request;
+
+  try {
+    var range = opt_range ? opt_range.range() : null;
+    if (opt_direction) {
+      request = source.openCursor(range, opt_direction);
+    } else {
+      request = source.openCursor(range);
+    }
+  } catch (ex) {
+    cursor.dispose();
+    throw goog.db.Error.fromException(ex, source.name);
+  }
+  request.onsuccess = function(e) {
+    cursor.cursor_ = e.target.result || null;
+    if (cursor.cursor_) {
+      cursor.dispatchEvent(goog.db.Cursor.EventType.NEW_DATA);
+    } else {
+      cursor.dispatchEvent(goog.db.Cursor.EventType.COMPLETE);
+    }
+  };
+  request.onerror = function(e) {
+    cursor.dispatchEvent(goog.db.Cursor.EventType.ERROR);
+  };
+  return cursor;
+};
+
+
+/**
+ * Possible cursor directions.
+ * @see http://www.w3.org/TR/IndexedDB/#idl-def-IDBCursor
+ *
+ * @enum {string}
+ */
+goog.db.Cursor.Direction = {
+  NEXT: 'next',
+  NEXT_NO_DUPLICATE: 'nextunique',
+  PREV: 'prev',
+  PREV_NO_DUPLICATE: 'prevunique'
+};
+
+
+/**
+ * Event types that the cursor can dispatch. COMPLETE events are dispatched when
+ * a cursor is depleted of values, a NEW_DATA event if there is new data
+ * available, and ERROR if an error occurred.
+ *
+ * @enum {string}
+ */
+goog.db.Cursor.EventType = {
+  COMPLETE: 'c',
+  ERROR: 'e',
+  NEW_DATA: 'n'
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/db/db.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/db/db.js b/externs/GCL/externs/goog/db/db.js
new file mode 100644
index 0000000..17149c4
--- /dev/null
+++ b/externs/GCL/externs/goog/db/db.js
@@ -0,0 +1,185 @@
+// Copyright 2011 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 Wrappers for the HTML5 IndexedDB. The wrappers export nearly
+ * the same interface as the standard API, but return goog.async.Deferred
+ * objects instead of request objects and use Closure events. The wrapper works
+ * and has been tested on Chrome version 22+. It may work on older Chrome
+ * versions, but they aren't explicitly supported.
+ *
+ * Example usage:
+ *
+ *  <code>
+ *  goog.db.openDatabase('mydb', 1, function(ev, db, tx) {
+ *    db.createObjectStore('mystore');
+ *  }).addCallback(function(db) {
+ *    var putTx = db.createTransaction(
+ *        [],
+ *        goog.db.Transaction.TransactionMode.READ_WRITE);
+ *    var store = putTx.objectStore('mystore');
+ *    store.put('value', 'key');
+ *    goog.listen(putTx, goog.db.Transaction.EventTypes.COMPLETE, function() {
+ *      var getTx = db.createTransaction([]);
+ *      var request = getTx.objectStore('mystore').get('key');
+ *      request.addCallback(function(result) {
+ *        ...
+ *      });
+ *  });
+ *  </code>
+ *
+ */
+
+
+goog.provide('goog.db');
+goog.provide('goog.db.BlockedCallback');
+goog.provide('goog.db.UpgradeNeededCallback');
+
+goog.require('goog.asserts');
+goog.require('goog.async.Deferred');
+goog.require('goog.db.Error');
+goog.require('goog.db.IndexedDb');
+goog.require('goog.db.Transaction');
+
+
+/**
+ * The IndexedDB factory object.
+ *
+ * @type {IDBFactory}
+ * @private
+ */
+goog.db.indexedDb_ = goog.global.indexedDB || goog.global.mozIndexedDB ||
+    goog.global.webkitIndexedDB || goog.global.moz_indexedDB;
+
+
+/**
+ * A callback that's called if a blocked event is received. When a database is
+ * supposed to be deleted or upgraded (i.e. versionchange), and there are open
+ * connections to this database, a block event will be fired to prevent the
+ * operations from going through until all such open connections are closed.
+ * This callback can be used to notify users that they should close other tabs
+ * that have open connections, or to close the connections manually. Databases
+ * can also listen for the {@link goog.db.IndexedDb.EventType.VERSION_CHANGE}
+ * event to automatically close themselves when they're blocking such
+ * operations.
+ *
+ * This is passed a VersionChangeEvent that has the version of the database
+ * before it was deleted, and "null" as the new version.
+ *
+ * @typedef {function(!goog.db.IndexedDb.VersionChangeEvent)}
+ */
+goog.db.BlockedCallback;
+
+
+/**
+ * A callback that's called when opening a database whose internal version is
+ * lower than the version passed to {@link goog.db.openDatabase}.
+ *
+ * This callback is passed three arguments: a VersionChangeEvent with both the
+ * old version and the new version of the database; the database that's being
+ * opened, for which you can create and delete object stores; and the version
+ * change transaction, with which you can abort the version change.
+ *
+ * Note that the transaction is not active, which means that it can't be used to
+ * make changes to the database. However, since there is a transaction running,
+ * you can't create another one via {@link goog.db.IndexedDb.createTransaction}.
+ * This means that it's not possible to manipulate the database other than
+ * creating or removing object stores in this callback.
+ *
+ * @typedef {function(!goog.db.IndexedDb.VersionChangeEvent,
+ *                    !goog.db.IndexedDb,
+ *                    !goog.db.Transaction)}
+ */
+goog.db.UpgradeNeededCallback;
+
+
+/**
+ * Opens a database connection and wraps it.
+ *
+ * @param {string} name The name of the database to open.
+ * @param {number=} opt_version The expected version of the database. If this is
+ *     larger than the actual version, opt_onUpgradeNeeded will be called
+ *     (possibly after opt_onBlocked; see {@link goog.db.BlockedCallback}). If
+ *     this is passed, opt_onUpgradeNeeded must be passed as well.
+ * @param {goog.db.UpgradeNeededCallback=} opt_onUpgradeNeeded Called if
+ *     opt_version is greater than the old version of the database. If
+ *     opt_version is passed, this must be passed as well.
+ * @param {goog.db.BlockedCallback=} opt_onBlocked Called if there are active
+ *     connections to the database.
+ * @return {!goog.async.Deferred} The deferred database object.
+ */
+goog.db.openDatabase = function(name, opt_version, opt_onUpgradeNeeded,
+                                opt_onBlocked) {
+  goog.asserts.assert(
+      goog.isDef(opt_version) == goog.isDef(opt_onUpgradeNeeded),
+      'opt_version must be passed to goog.db.openDatabase if and only if ' +
+          'opt_onUpgradeNeeded is also passed');
+
+  var d = new goog.async.Deferred();
+  var openRequest = opt_version ?
+      goog.db.indexedDb_.open(name, opt_version) :
+      goog.db.indexedDb_.open(name);
+  openRequest.onsuccess = function(ev) {
+    var db = new goog.db.IndexedDb(ev.target.result);
+    d.callback(db);
+  };
+  openRequest.onerror = function(ev) {
+    var msg = 'opening database ' + name;
+    d.errback(goog.db.Error.fromRequest(ev.target, msg));
+  };
+  openRequest.onupgradeneeded = function(ev) {
+    if (!opt_onUpgradeNeeded) return;
+    var db = new goog.db.IndexedDb(ev.target.result);
+    opt_onUpgradeNeeded(
+        new goog.db.IndexedDb.VersionChangeEvent(ev.oldVersion, ev.newVersion),
+        db,
+        new goog.db.Transaction(ev.target.transaction, db));
+  };
+  openRequest.onblocked = function(ev) {
+    if (opt_onBlocked) {
+      opt_onBlocked(new goog.db.IndexedDb.VersionChangeEvent(
+          ev.oldVersion, ev.newVersion));
+    }
+  };
+  return d;
+};
+
+
+/**
+ * Deletes a database once all open connections have been closed.
+ *
+ * @param {string} name The name of the database to delete.
+ * @param {goog.db.BlockedCallback=} opt_onBlocked Called if there are active
+ *     connections to the database.
+ * @return {!goog.async.Deferred} A deferred object that will fire once the
+ *     database is deleted.
+ */
+goog.db.deleteDatabase = function(name, opt_onBlocked) {
+  var d = new goog.async.Deferred();
+  var deleteRequest = goog.db.indexedDb_.deleteDatabase(name);
+  deleteRequest.onsuccess = function(ev) {
+    d.callback();
+  };
+  deleteRequest.onerror = function(ev) {
+    var msg = 'deleting database ' + name;
+    d.errback(goog.db.Error.fromRequest(ev.target, msg));
+  };
+  deleteRequest.onblocked = function(ev) {
+    if (opt_onBlocked) {
+      opt_onBlocked(new goog.db.IndexedDb.VersionChangeEvent(
+          ev.oldVersion, ev.newVersion));
+    }
+  };
+  return d;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/db/error1.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/db/error1.js b/externs/GCL/externs/goog/db/error1.js
new file mode 100644
index 0000000..9589f89
--- /dev/null
+++ b/externs/GCL/externs/goog/db/error1.js
@@ -0,0 +1,364 @@
+// Copyright 2011 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 Error classes for the IndexedDB wrapper.
+ *
+ */
+
+
+goog.provide('goog.db.Error');
+goog.provide('goog.db.Error.ErrorCode');
+goog.provide('goog.db.Error.ErrorName');
+goog.provide('goog.db.Error.VersionChangeBlockedError');
+
+goog.require('goog.debug.Error');
+
+
+
+/**
+ * A database error. Since the stack trace can be unhelpful in an asynchronous
+ * context, the error provides a message about where it was produced.
+ *
+ * @param {number|!DOMError} error The DOMError instance returned by the
+ *     browser for Chrome22+, or an error code for previous versions.
+ * @param {string} context A description of where the error occured.
+ * @param {string=} opt_message Additional message.
+ * @constructor
+ * @extends {goog.debug.Error}
+ * @final
+ */
+goog.db.Error = function(error, context, opt_message) {
+  var errorCode = null;
+  var internalError = null;
+  if (goog.isNumber(error)) {
+    errorCode = error;
+    internalError = {name: goog.db.Error.getName(errorCode)};
+  } else {
+    internalError = error;
+    errorCode = goog.db.Error.getCode(error.name);
+  }
+
+  /**
+   * The code for this error.
+   *
+   * @type {number}
+   */
+  this.code = errorCode;
+
+  /**
+   * The DOMException as returned by the browser.
+   *
+   * @type {!DOMError}
+   * @private
+   */
+  this.error_ = /** @type {!DOMError} */ (internalError);
+
+  var msg = 'Error ' + context + ': ' + this.getName();
+  if (opt_message) {
+    msg += ', ' + opt_message;
+  }
+  goog.db.Error.base(this, 'constructor', msg);
+};
+goog.inherits(goog.db.Error, goog.debug.Error);
+
+
+/**
+ * @return {string} The name of the error.
+ */
+goog.db.Error.prototype.getName = function()  {
+  return this.error_.name;
+};
+
+
+
+/**
+ * A specific kind of database error. If a Version Change is unable to proceed
+ * due to other open database connections, it will block and this error will be
+ * thrown.
+ *
+ * @constructor
+ * @extends {goog.debug.Error}
+ * @final
+ */
+goog.db.Error.VersionChangeBlockedError = function() {
+  goog.db.Error.VersionChangeBlockedError.base(
+      this, 'constructor', 'Version change blocked');
+};
+goog.inherits(goog.db.Error.VersionChangeBlockedError, goog.debug.Error);
+
+
+/**
+ * Synthetic error codes for database errors, for use when IndexedDB
+ * support is not available. This numbering differs in practice
+ * from the browser implementations, but it is not meant to be reliable:
+ * this object merely ensures that goog.db.Error is loadable on platforms
+ * that do not support IndexedDB.
+ *
+ * @enum {number}
+ * @private
+ */
+goog.db.Error.DatabaseErrorCode_ = {
+  UNKNOWN_ERR: 1,
+  NON_TRANSIENT_ERR: 2,
+  NOT_FOUND_ERR: 3,
+  CONSTRAINT_ERR: 4,
+  DATA_ERR: 5,
+  NOT_ALLOWED_ERR: 6,
+  TRANSACTION_INACTIVE_ERR: 7,
+  ABORT_ERR: 8,
+  READ_ONLY_ERR: 9,
+  TRANSIENT_ERR: 10,
+  TIMEOUT_ERR: 11,
+  QUOTA_ERR: 12,
+  INVALID_ACCESS_ERR: 13,
+  INVALID_STATE_ERR: 14
+};
+
+
+/**
+ * Error codes for database errors.
+ * @see http://www.w3.org/TR/IndexedDB/#idl-def-IDBDatabaseException
+ *
+ * @enum {number}
+ */
+goog.db.Error.ErrorCode = {
+  UNKNOWN_ERR: (goog.global.IDBDatabaseException ||
+      goog.global.webkitIDBDatabaseException ||
+      goog.db.Error.DatabaseErrorCode_).UNKNOWN_ERR,
+  NON_TRANSIENT_ERR: (goog.global.IDBDatabaseException ||
+      goog.global.webkitIDBDatabaseException ||
+      goog.db.Error.DatabaseErrorCode_).NON_TRANSIENT_ERR,
+  NOT_FOUND_ERR: (goog.global.IDBDatabaseException ||
+      goog.global.webkitIDBDatabaseException ||
+      goog.db.Error.DatabaseErrorCode_).NOT_FOUND_ERR,
+  CONSTRAINT_ERR: (goog.global.IDBDatabaseException ||
+      goog.global.webkitIDBDatabaseException ||
+      goog.db.Error.DatabaseErrorCode_).CONSTRAINT_ERR,
+  DATA_ERR: (goog.global.IDBDatabaseException ||
+      goog.global.webkitIDBDatabaseException ||
+      goog.db.Error.DatabaseErrorCode_).DATA_ERR,
+  NOT_ALLOWED_ERR: (goog.global.IDBDatabaseException ||
+      goog.global.webkitIDBDatabaseException ||
+      goog.db.Error.DatabaseErrorCode_).NOT_ALLOWED_ERR,
+  TRANSACTION_INACTIVE_ERR: (goog.global.IDBDatabaseException ||
+      goog.global.webkitIDBDatabaseException ||
+      goog.db.Error.DatabaseErrorCode_).TRANSACTION_INACTIVE_ERR,
+  ABORT_ERR: (goog.global.IDBDatabaseException ||
+      goog.global.webkitIDBDatabaseException ||
+      goog.db.Error.DatabaseErrorCode_).ABORT_ERR,
+  READ_ONLY_ERR: (goog.global.IDBDatabaseException ||
+      goog.global.webkitIDBDatabaseException ||
+      goog.db.Error.DatabaseErrorCode_).READ_ONLY_ERR,
+  TIMEOUT_ERR: (goog.global.IDBDatabaseException ||
+      goog.global.webkitIDBDatabaseException ||
+      goog.db.Error.DatabaseErrorCode_).TIMEOUT_ERR,
+  QUOTA_ERR: (goog.global.IDBDatabaseException ||
+      goog.global.webkitIDBDatabaseException ||
+      goog.db.Error.DatabaseErrorCode_).QUOTA_ERR,
+  INVALID_ACCESS_ERR: (goog.global.DOMException ||
+      goog.db.Error.DatabaseErrorCode_).INVALID_ACCESS_ERR,
+  INVALID_STATE_ERR: (goog.global.DOMException ||
+      goog.db.Error.DatabaseErrorCode_).INVALID_STATE_ERR
+};
+
+
+/**
+ * Translates an error code into a more useful message.
+ *
+ * @param {number} code Error code.
+ * @return {string} A debug message.
+ */
+goog.db.Error.getMessage = function(code) {
+  switch (code) {
+    case goog.db.Error.ErrorCode.UNKNOWN_ERR:
+      return 'Unknown error';
+    case goog.db.Error.ErrorCode.NON_TRANSIENT_ERR:
+      return 'Invalid operation';
+    case goog.db.Error.ErrorCode.NOT_FOUND_ERR:
+      return 'Required database object not found';
+    case goog.db.Error.ErrorCode.CONSTRAINT_ERR:
+      return 'Constraint unsatisfied';
+    case goog.db.Error.ErrorCode.DATA_ERR:
+      return 'Invalid data';
+    case goog.db.Error.ErrorCode.NOT_ALLOWED_ERR:
+      return 'Operation disallowed';
+    case goog.db.Error.ErrorCode.TRANSACTION_INACTIVE_ERR:
+      return 'Transaction not active';
+    case goog.db.Error.ErrorCode.ABORT_ERR:
+      return 'Request aborted';
+    case goog.db.Error.ErrorCode.READ_ONLY_ERR:
+      return 'Modifying operation not allowed in a read-only transaction';
+    case goog.db.Error.ErrorCode.TIMEOUT_ERR:
+      return 'Transaction timed out';
+    case goog.db.Error.ErrorCode.QUOTA_ERR:
+      return 'Database storage space quota exceeded';
+    case goog.db.Error.ErrorCode.INVALID_ACCESS_ERR:
+      return 'Invalid operation';
+    case goog.db.Error.ErrorCode.INVALID_STATE_ERR:
+      return 'Invalid state';
+    default:
+      return 'Unrecognized exception with code ' + code;
+  }
+};
+
+
+/**
+ * Names of all possible errors as returned from the browser.
+ * @see http://www.w3.org/TR/IndexedDB/#exceptions
+ * @enum {string}
+ */
+goog.db.Error.ErrorName = {
+  ABORT_ERR: 'AbortError',
+  CONSTRAINT_ERR: 'ConstraintError',
+  DATA_CLONE_ERR: 'DataCloneError',
+  DATA_ERR: 'DataError',
+  INVALID_ACCESS_ERR: 'InvalidAccessError',
+  INVALID_STATE_ERR: 'InvalidStateError',
+  NOT_FOUND_ERR: 'NotFoundError',
+  QUOTA_EXCEEDED_ERR: 'QuotaExceededError',
+  READ_ONLY_ERR: 'ReadOnlyError',
+  SYNTAX_ERROR: 'SyntaxError',
+  TIMEOUT_ERR: 'TimeoutError',
+  TRANSACTION_INACTIVE_ERR: 'TransactionInactiveError',
+  UNKNOWN_ERR: 'UnknownError',
+  VERSION_ERR: 'VersionError'
+};
+
+
+/**
+ * Translates an error name to an error code. This is purely kept for backwards
+ * compatibility with Chrome21.
+ *
+ * @param {string} name The name of the erorr.
+ * @return {number} The error code corresponding to the error.
+ */
+goog.db.Error.getCode = function(name) {
+  switch (name) {
+    case goog.db.Error.ErrorName.UNKNOWN_ERR:
+      return goog.db.Error.ErrorCode.UNKNOWN_ERR;
+    case goog.db.Error.ErrorName.NOT_FOUND_ERR:
+      return goog.db.Error.ErrorCode.NOT_FOUND_ERR;
+    case goog.db.Error.ErrorName.CONSTRAINT_ERR:
+      return goog.db.Error.ErrorCode.CONSTRAINT_ERR;
+    case goog.db.Error.ErrorName.DATA_ERR:
+      return goog.db.Error.ErrorCode.DATA_ERR;
+    case goog.db.Error.ErrorName.TRANSACTION_INACTIVE_ERR:
+      return goog.db.Error.ErrorCode.TRANSACTION_INACTIVE_ERR;
+    case goog.db.Error.ErrorName.ABORT_ERR:
+      return goog.db.Error.ErrorCode.ABORT_ERR;
+    case goog.db.Error.ErrorName.READ_ONLY_ERR:
+      return goog.db.Error.ErrorCode.READ_ONLY_ERR;
+    case goog.db.Error.ErrorName.TIMEOUT_ERR:
+      return goog.db.Error.ErrorCode.TIMEOUT_ERR;
+    case goog.db.Error.ErrorName.QUOTA_EXCEEDED_ERR:
+      return goog.db.Error.ErrorCode.QUOTA_ERR;
+    case goog.db.Error.ErrorName.INVALID_ACCESS_ERR:
+      return goog.db.Error.ErrorCode.INVALID_ACCESS_ERR;
+    case goog.db.Error.ErrorName.INVALID_STATE_ERR:
+      return goog.db.Error.ErrorCode.INVALID_STATE_ERR;
+    default:
+      return goog.db.Error.ErrorCode.UNKNOWN_ERR;
+  }
+};
+
+
+/**
+ * Converts an error code used by the old spec, to an error name used by the
+ * latest spec.
+ * @see http://www.w3.org/TR/IndexedDB/#exceptions
+ *
+ * @param {!goog.db.Error.ErrorCode|number} code The error code to convert.
+ * @return {!goog.db.Error.ErrorName} The corresponding name of the error.
+ */
+goog.db.Error.getName = function(code) {
+  switch (code) {
+    case goog.db.Error.ErrorCode.UNKNOWN_ERR:
+      return goog.db.Error.ErrorName.UNKNOWN_ERR;
+    case goog.db.Error.ErrorCode.NOT_FOUND_ERR:
+      return goog.db.Error.ErrorName.NOT_FOUND_ERR;
+    case goog.db.Error.ErrorCode.CONSTRAINT_ERR:
+      return goog.db.Error.ErrorName.CONSTRAINT_ERR;
+    case goog.db.Error.ErrorCode.DATA_ERR:
+      return goog.db.Error.ErrorName.DATA_ERR;
+    case goog.db.Error.ErrorCode.TRANSACTION_INACTIVE_ERR:
+      return goog.db.Error.ErrorName.TRANSACTION_INACTIVE_ERR;
+    case goog.db.Error.ErrorCode.ABORT_ERR:
+      return goog.db.Error.ErrorName.ABORT_ERR;
+    case goog.db.Error.ErrorCode.READ_ONLY_ERR:
+      return goog.db.Error.ErrorName.READ_ONLY_ERR;
+    case goog.db.Error.ErrorCode.TIMEOUT_ERR:
+      return goog.db.Error.ErrorName.TIMEOUT_ERR;
+    case goog.db.Error.ErrorCode.QUOTA_ERR:
+      return goog.db.Error.ErrorName.QUOTA_EXCEEDED_ERR;
+    case goog.db.Error.ErrorCode.INVALID_ACCESS_ERR:
+      return goog.db.Error.ErrorName.INVALID_ACCESS_ERR;
+    case goog.db.Error.ErrorCode.INVALID_STATE_ERR:
+      return goog.db.Error.ErrorName.INVALID_STATE_ERR;
+    default:
+      return goog.db.Error.ErrorName.UNKNOWN_ERR;
+  }
+};
+
+
+/**
+ * Constructs an goog.db.Error instance from an IDBRequest. This abstraction is
+ * necessary to provide backwards compatibility with Chrome21.
+ *
+ * @param {!IDBRequest} request The request that failed.
+ * @param {string} message The error message to add to err if it's wrapped.
+ * @return {!goog.db.Error} The error that caused the failure.
+ */
+goog.db.Error.fromRequest = function(request, message) {
+  if ('error' in request) {
+    // Chrome 21 and before.
+    return new goog.db.Error(request.error, message);
+  } else if ('name' in request) {
+    // Chrome 22+.
+    var errorName = goog.db.Error.getName(request.errorCode);
+    return new goog.db.Error(
+        /**@type {!DOMError} */ ({name: errorName}), message);
+  } else {
+    return new goog.db.Error(/** @type {!DOMError} */ (
+        {name: goog.db.Error.ErrorName.UNKNOWN_ERR}), message);
+  }
+};
+
+
+/**
+ * Constructs an goog.db.Error instance from an DOMException. This abstraction
+ * is necessary to provide backwards compatibility with Chrome21.
+ *
+ * @param {!IDBDatabaseException} ex The exception that was thrown.
+ * @param {string} message The error message to add to err if it's wrapped.
+ * @return {!goog.db.Error} The error that caused the failure.
+ * @suppress {invalidCasts} The cast from IDBDatabaseException to DOMError
+ *     is invalid and will not compile.
+ */
+goog.db.Error.fromException = function(ex, message) {
+  if ('name' in ex) {
+    // Chrome 22+.
+    var errorMessage = message + ': ' + ex.message;
+    return new goog.db.Error(/** @type {!DOMError} */ (ex), errorMessage);
+  } else if ('code' in ex) {
+    // Chrome 21 and before.
+    var errorName = goog.db.Error.getName(ex.code);
+    var errorMessage = message + ': ' + ex.message;
+    return new goog.db.Error(
+        /** @type {!DOMError} */ ({name: errorName}), errorMessage);
+  } else {
+    return new goog.db.Error(/** @type {!DOMError} */ (
+        {name: goog.db.Error.ErrorName.UNKNOWN_ERR}), message);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/db/index.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/db/index.js b/externs/GCL/externs/goog/db/index.js
new file mode 100644
index 0000000..7951e24
--- /dev/null
+++ b/externs/GCL/externs/goog/db/index.js
@@ -0,0 +1,246 @@
+// Copyright 2011 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 Wrapper for an IndexedDB index.
+ *
+ */
+
+
+goog.provide('goog.db.Index');
+
+goog.require('goog.async.Deferred');
+goog.require('goog.db.Cursor');
+goog.require('goog.db.Error');
+goog.require('goog.debug');
+
+
+
+/**
+ * Creates an IDBIndex wrapper object. Indexes are associated with object
+ * stores and provide methods for looking up objects based on their non-key
+ * properties. Should not be created directly, access through the object store
+ * it belongs to.
+ * @see goog.db.ObjectStore#getIndex
+ *
+ * @param {!IDBIndex} index Underlying IDBIndex object.
+ * @constructor
+ * @final
+ */
+goog.db.Index = function(index) {
+  /**
+   * Underlying IndexedDB index object.
+   *
+   * @type {!IDBIndex}
+   * @private
+   */
+  this.index_ = index;
+};
+
+
+/**
+ * @return {string} Name of the index.
+ */
+goog.db.Index.prototype.getName = function() {
+  return this.index_.name;
+};
+
+
+/**
+ * @return {string} Key path of the index.
+ */
+goog.db.Index.prototype.getKeyPath = function() {
+  return this.index_.keyPath;
+};
+
+
+/**
+ * @return {boolean} True if the index enforces that there is only one object
+ *     for each unique value it indexes on.
+ */
+goog.db.Index.prototype.isUnique = function() {
+  return this.index_.unique;
+};
+
+
+/**
+ * Helper function for get and getKey.
+ *
+ * @param {string} fn Function name to call on the index to get the request.
+ * @param {string} msg Message to give to the error.
+ * @param {IDBKeyType} key The key to look up in the index.
+ * @return {!goog.async.Deferred} The resulting deferred object.
+ * @private
+ */
+goog.db.Index.prototype.get_ = function(fn, msg, key) {
+  var d = new goog.async.Deferred();
+  var request;
+  try {
+    request = this.index_[fn](key);
+  } catch (err) {
+    msg += ' with key ' + goog.debug.deepExpose(key);
+    d.errback(goog.db.Error.fromException(err, msg));
+    return d;
+  }
+  request.onsuccess = function(ev) {
+    d.callback(ev.target.result);
+  };
+  request.onerror = function(ev) {
+    msg += ' with key ' + goog.debug.deepExpose(key);
+    d.errback(goog.db.Error.fromRequest(ev.target, msg));
+  };
+  return d;
+};
+
+
+/**
+ * Fetches a single object from the object store. Even if there are multiple
+ * objects that match the given key, this method will get only one of them.
+ *
+ * @param {IDBKeyType} key Key to look up in the index.
+ * @return {!goog.async.Deferred} The deferred object for the given record.
+ */
+goog.db.Index.prototype.get = function(key) {
+  return this.get_('get', 'getting from index ' + this.getName(), key);
+};
+
+
+/**
+ * Looks up a single object from the object store and gives back the key that
+ * it's listed under in the object store. Even if there are multiple records
+ * that match the given key, this method returns the first.
+ *
+ * @param {IDBKeyType} key Key to look up in the index.
+ * @return {!goog.async.Deferred} The deferred key for the record that matches
+ *     the key.
+ */
+goog.db.Index.prototype.getKey = function(key) {
+  return this.get_('getKey', 'getting key from index ' + this.getName(), key);
+};
+
+
+/**
+ * Helper function for getAll and getAllKeys.
+ *
+ * @param {string} fn Function name to call on the index to get the request.
+ * @param {string} msg Message to give to the error.
+ * @param {IDBKeyType=} opt_key Key to look up in the index.
+ * @return {!goog.async.Deferred} The resulting deferred array of objects.
+ * @private
+ */
+goog.db.Index.prototype.getAll_ = function(fn, msg, opt_key) {
+  // This is the most common use of IDBKeyRange. If more specific uses of
+  // cursors are needed then a full wrapper should be created.
+  var IDBKeyRange = goog.global.IDBKeyRange || goog.global.webkitIDBKeyRange;
+  var d = new goog.async.Deferred();
+  var request;
+  try {
+    if (opt_key) {
+      request = this.index_[fn](IDBKeyRange.only(opt_key));
+    } else {
+      request = this.index_[fn]();
+    }
+  } catch (err) {
+    if (opt_key) {
+      msg += ' for key ' + goog.debug.deepExpose(opt_key);
+    }
+    d.errback(goog.db.Error.fromException(err, msg));
+    return d;
+  }
+  var result = [];
+  request.onsuccess = function(ev) {
+    var cursor = ev.target.result;
+    if (cursor) {
+      result.push(cursor.value);
+      cursor['continue']();
+    } else {
+      d.callback(result);
+    }
+  };
+  request.onerror = function(ev) {
+    if (opt_key) {
+      msg += ' for key ' + goog.debug.deepExpose(opt_key);
+    }
+    d.errback(goog.db.Error.fromRequest(ev.target, msg));
+  };
+  return d;
+};
+
+
+/**
+ * Gets all indexed objects. If the key is provided, gets all indexed objects
+ * that match the key instead.
+ *
+ * @param {IDBKeyType=} opt_key Key to look up in the index.
+ * @return {!goog.async.Deferred} A deferred array of objects that match the
+ *     key.
+ */
+goog.db.Index.prototype.getAll = function(opt_key) {
+  return this.getAll_(
+      'openCursor',
+      'getting all from index ' + this.getName(),
+      opt_key);
+};
+
+
+/**
+ * Gets the keys to look up all the indexed objects. If the key is provided,
+ * gets all records for objects that match the key instead.
+ *
+ * @param {IDBKeyType=} opt_key Key to look up in the index.
+ * @return {!goog.async.Deferred} A deferred array of keys for objects that
+ *     match the key.
+ */
+goog.db.Index.prototype.getAllKeys = function(opt_key) {
+  return this.getAll_(
+      'openKeyCursor',
+      'getting all keys from index ' + this.getName(),
+      opt_key);
+};
+
+
+/**
+ * Opens a cursor over the specified key range. Returns a cursor object which is
+ * able to iterate over the given range.
+ *
+ * Example usage:
+ *
+ * <code>
+ *  var cursor = index.openCursor(goog.db.Range.bound('a', 'c'));
+ *
+ *  var key = goog.events.listen(
+ *      cursor, goog.db.Cursor.EventType.NEW_DATA,
+ *      function() {
+ *        // Do something with data.
+ *        cursor.next();
+ *      });
+ *
+ *  goog.events.listenOnce(
+ *      cursor, goog.db.Cursor.EventType.COMPLETE,
+ *      function() {
+ *        // Clean up listener, and perform a finishing operation on the data.
+ *        goog.events.unlistenByKey(key);
+ *      });
+ * </code>
+ *
+ * @param {!goog.db.KeyRange=} opt_range The key range. If undefined iterates
+ *     over the whole object store.
+ * @param {!goog.db.Cursor.Direction=} opt_direction The direction. If undefined
+ *     moves in a forward direction with duplicates.
+ * @return {!goog.db.Cursor} The cursor.
+ * @throws {goog.db.Error} If there was a problem opening the cursor.
+ */
+goog.db.Index.prototype.openCursor = function(opt_range, opt_direction) {
+  return goog.db.Cursor.openCursor(this.index_, opt_range, opt_direction);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/db/indexeddb.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/db/indexeddb.js b/externs/GCL/externs/goog/db/indexeddb.js
new file mode 100644
index 0000000..33ad3aa
--- /dev/null
+++ b/externs/GCL/externs/goog/db/indexeddb.js
@@ -0,0 +1,353 @@
+// Copyright 2011 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 Wrapper for an IndexedDB database.
+ *
+ */
+
+
+goog.provide('goog.db.IndexedDb');
+
+goog.require('goog.async.Deferred');
+goog.require('goog.db.Error');
+goog.require('goog.db.ObjectStore');
+goog.require('goog.db.Transaction');
+goog.require('goog.events.Event');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+
+
+
+/**
+ * Creates an IDBDatabase wrapper object. The database object has methods for
+ * setting the version to change the structure of the database and for creating
+ * transactions to get or modify the stored records. Should not be created
+ * directly, call {@link goog.db.openDatabase} to set up the connection.
+ *
+ * @param {!IDBDatabase} db Underlying IndexedDB database object.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @final
+ */
+goog.db.IndexedDb = function(db) {
+  goog.db.IndexedDb.base(this, 'constructor');
+
+  /**
+   * Underlying IndexedDB database object.
+   *
+   * @type {!IDBDatabase}
+   * @private
+   */
+  this.db_ = db;
+
+  /**
+   * Internal event handler that listens to IDBDatabase events.
+   * @type {!goog.events.EventHandler<!goog.db.IndexedDb>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+  this.eventHandler_.listen(
+      this.db_,
+      goog.db.IndexedDb.EventType.ABORT,
+      goog.bind(
+          this.dispatchEvent,
+          this,
+          goog.db.IndexedDb.EventType.ABORT));
+  this.eventHandler_.listen(
+      this.db_,
+      goog.db.IndexedDb.EventType.ERROR,
+      this.dispatchError_);
+  this.eventHandler_.listen(
+      this.db_,
+      goog.db.IndexedDb.EventType.VERSION_CHANGE,
+      this.dispatchVersionChange_);
+  this.eventHandler_.listen(
+      this.db_,
+      goog.db.IndexedDb.EventType.CLOSE,
+      goog.bind(
+          this.dispatchEvent,
+          this,
+          goog.db.IndexedDb.EventType.CLOSE));
+};
+goog.inherits(goog.db.IndexedDb, goog.events.EventTarget);
+
+
+/**
+ * True iff the database connection is open.
+ *
+ * @type {boolean}
+ * @private
+ */
+goog.db.IndexedDb.prototype.open_ = true;
+
+
+/**
+ * Dispatches a wrapped error event based on the given event.
+ *
+ * @param {Event} ev The error event given to the underlying IDBDatabase.
+ * @private
+ */
+goog.db.IndexedDb.prototype.dispatchError_ = function(ev) {
+  this.dispatchEvent({
+    type: goog.db.IndexedDb.EventType.ERROR,
+    errorCode: /** @type {IDBRequest} */ (ev.target).errorCode
+  });
+};
+
+
+/**
+ * Dispatches a wrapped version change event based on the given event.
+ *
+ * @param {Event} ev The version change event given to the underlying
+ *     IDBDatabase.
+ * @private
+ */
+goog.db.IndexedDb.prototype.dispatchVersionChange_ = function(ev) {
+  this.dispatchEvent(new goog.db.IndexedDb.VersionChangeEvent(
+      ev.oldVersion, ev.newVersion));
+};
+
+
+/**
+ * Closes the database connection. Metadata queries can still be made after this
+ * method is called, but otherwise this wrapper should not be used further.
+ */
+goog.db.IndexedDb.prototype.close = function() {
+  if (this.open_) {
+    this.db_.close();
+    this.open_ = false;
+  }
+};
+
+
+/**
+ * @return {boolean} Whether a connection is open and the database can be used.
+ */
+goog.db.IndexedDb.prototype.isOpen = function() {
+  return this.open_;
+};
+
+
+/**
+ * @return {string} The name of this database.
+ */
+goog.db.IndexedDb.prototype.getName = function() {
+  return this.db_.name;
+};
+
+
+/**
+ * @return {string} The current database version.
+ */
+goog.db.IndexedDb.prototype.getVersion = function() {
+  return this.db_.version;
+};
+
+
+/**
+ * @return {DOMStringList} List of object stores in this database.
+ */
+goog.db.IndexedDb.prototype.getObjectStoreNames = function() {
+  return this.db_.objectStoreNames;
+};
+
+
+/**
+ * Creates an object store in this database. Can only be called inside a
+ * {@link goog.db.UpgradeNeededCallback} or the callback for the Deferred
+ * returned from #setVersion.
+ *
+ * @param {string} name Name for the new object store.
+ * @param {Object=} opt_params Options object. The available options are:
+ *     keyPath, which is a string and determines what object attribute
+ *     to use as the key when storing objects in this object store; and
+ *     autoIncrement, which is a boolean, which defaults to false and determines
+ *     whether the object store should automatically generate keys for stored
+ *     objects. If keyPath is not provided and autoIncrement is false, then all
+ *     insert operations must provide a key as a parameter.
+ * @return {!goog.db.ObjectStore} The newly created object store.
+ * @throws {goog.db.Error} If there's a problem creating the object store.
+ */
+goog.db.IndexedDb.prototype.createObjectStore = function(name, opt_params) {
+  try {
+    return new goog.db.ObjectStore(this.db_.createObjectStore(
+        name, opt_params));
+  } catch (ex) {
+    throw goog.db.Error.fromException(ex, 'creating object store ' + name);
+  }
+};
+
+
+/**
+ * Deletes an object store. Can only be called inside a
+ * {@link goog.db.UpgradeNeededCallback} or the callback for the Deferred
+ * returned from #setVersion.
+ *
+ * @param {string} name Name of the object store to delete.
+ * @throws {goog.db.Error} If there's a problem deleting the object store.
+ */
+goog.db.IndexedDb.prototype.deleteObjectStore = function(name) {
+  try {
+    this.db_.deleteObjectStore(name);
+  } catch (ex) {
+    throw goog.db.Error.fromException(ex, 'deleting object store ' + name);
+  }
+};
+
+
+/**
+ * Updates the version of the database and returns a Deferred transaction.
+ * The database's structure can be changed inside this Deferred's callback, but
+ * nowhere else. This means adding or deleting object stores, and adding or
+ * deleting indexes. The version change will not succeed unless there are no
+ * other connections active for this database anywhere. A new database
+ * connection should be opened after the version change is finished to pick
+ * up changes.
+ *
+ * This is deprecated, and only supported on Chrome prior to version 25. New
+ * applications should use the version parameter to {@link goog.db.openDatabase}
+ * instead.
+ *
+ * @param {string} version The new version of the database.
+ * @return {!goog.async.Deferred} The deferred transaction for changing the
+ *     version.
+ */
+goog.db.IndexedDb.prototype.setVersion = function(version) {
+  var self = this;
+  var d = new goog.async.Deferred();
+  var request = this.db_.setVersion(version);
+  request.onsuccess = function(ev) {
+    // the transaction is in the result field (the transaction field is null
+    // for version change requests)
+    d.callback(new goog.db.Transaction(ev.target.result, self));
+  };
+  request.onerror = function(ev) {
+    // If a version change is blocked, onerror and onblocked may both fire.
+    // Check d.hasFired() to avoid an AlreadyCalledError.
+    if (!d.hasFired()) {
+      d.errback(goog.db.Error.fromRequest(ev.target, 'setting version'));
+    }
+  };
+  request.onblocked = function(ev) {
+    // If a version change is blocked, onerror and onblocked may both fire.
+    // Check d.hasFired() to avoid an AlreadyCalledError.
+    if (!d.hasFired()) {
+      d.errback(new goog.db.Error.VersionChangeBlockedError());
+    }
+  };
+  return d;
+};
+
+
+/**
+ * Creates a new transaction.
+ *
+ * @param {!Array<string>} storeNames A list of strings that contains the
+ *     transaction's scope, the object stores that this transaction can operate
+ *     on.
+ * @param {goog.db.Transaction.TransactionMode=} opt_mode The mode of the
+ *     transaction. If not present, the default is READ_ONLY. For VERSION_CHANGE
+ *     transactions call {@link goog.db.IndexedDB#setVersion} instead.
+ * @return {!goog.db.Transaction} The wrapper for the newly created transaction.
+ * @throws {goog.db.Error} If there's a problem creating the transaction.
+ */
+goog.db.IndexedDb.prototype.createTransaction = function(storeNames, opt_mode) {
+  try {
+    // IndexedDB on Chrome 22+ requires that opt_mode not be passed rather than
+    // be explicitly passed as undefined.
+    var transaction = opt_mode ?
+        this.db_.transaction(storeNames, opt_mode) :
+        this.db_.transaction(storeNames);
+    return new goog.db.Transaction(transaction, this);
+  } catch (ex) {
+    throw goog.db.Error.fromException(ex, 'creating transaction');
+  }
+};
+
+
+/** @override */
+goog.db.IndexedDb.prototype.disposeInternal = function() {
+  goog.db.IndexedDb.base(this, 'disposeInternal');
+  this.eventHandler_.dispose();
+};
+
+
+/**
+ * Event types fired by a database.
+ *
+ * @enum {string} The event types for the web socket.
+ */
+goog.db.IndexedDb.EventType = {
+
+  /**
+   * Fired when a transaction is aborted and the event bubbles to its database.
+   */
+  ABORT: 'abort',
+
+  /**
+   * Fired when the database connection is forcibly closed by the browser,
+   * without an explicit call to IDBDatabase#close. This behavior is not in the
+   * spec yet but will be added since it is necessary, see
+   * https://www.w3.org/Bugs/Public/show_bug.cgi?id=22540.
+   */
+  CLOSE: 'close',
+
+  /**
+   * Fired when a transaction has an error.
+   */
+  ERROR: 'error',
+
+  /**
+   * Fired when someone (possibly in another window) is attempting to modify the
+   * structure of the database. Since a change can only be made when there are
+   * no active database connections, this usually means that the database should
+   * be closed so that the other client can make its changes.
+   */
+  VERSION_CHANGE: 'versionchange'
+};
+
+
+
+/**
+ * Event representing a (possibly attempted) change in the database structure.
+ *
+ * At time of writing, no Chrome versions support oldVersion or newVersion. See
+ * http://crbug.com/153122.
+ *
+ * @param {number} oldVersion The previous version of the database.
+ * @param {number} newVersion The version the database is being or has been
+ *     updated to.
+ * @constructor
+ * @extends {goog.events.Event}
+ * @final
+ */
+goog.db.IndexedDb.VersionChangeEvent = function(oldVersion, newVersion) {
+  goog.db.IndexedDb.VersionChangeEvent.base(
+      this, 'constructor', goog.db.IndexedDb.EventType.VERSION_CHANGE);
+
+  /**
+   * The previous version of the database.
+   * @type {number}
+   */
+  this.oldVersion = oldVersion;
+
+  /**
+   * The version the database is being or has been updated to.
+   * @type {number}
+   */
+  this.newVersion = newVersion;
+};
+goog.inherits(goog.db.IndexedDb.VersionChangeEvent, goog.events.Event);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/db/keyrange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/db/keyrange.js b/externs/GCL/externs/goog/db/keyrange.js
new file mode 100644
index 0000000..d1e4099
--- /dev/null
+++ b/externs/GCL/externs/goog/db/keyrange.js
@@ -0,0 +1,118 @@
+// 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 Wrapper for a IndexedDB key range.
+ *
+ */
+
+
+goog.provide('goog.db.KeyRange');
+
+
+
+/**
+ * Creates a new IDBKeyRange wrapper object. Should not be created directly,
+ * instead use one of the static factory methods. For example:
+ * @see goog.db.KeyRange.bound
+ * @see goog.db.KeyRange.lowerBound
+ *
+ * @param {!IDBKeyRange} range Underlying IDBKeyRange object.
+ * @constructor
+ * @final
+ */
+goog.db.KeyRange = function(range) {
+  /**
+   * Underlying IDBKeyRange object.
+   *
+   * @type {!IDBKeyRange}
+   * @private
+   */
+  this.range_ = range;
+};
+
+
+/**
+ * The IDBKeyRange.
+ * @type {!Object}
+ * @private
+ */
+goog.db.KeyRange.IDB_KEY_RANGE_ = goog.global.IDBKeyRange ||
+    goog.global.webkitIDBKeyRange;
+
+
+/**
+ * Creates a new key range for a single value.
+ *
+ * @param {IDBKeyType} key The single value in the range.
+ * @return {!goog.db.KeyRange} The key range.
+ */
+goog.db.KeyRange.only = function(key) {
+  return new goog.db.KeyRange(goog.db.KeyRange.IDB_KEY_RANGE_.only(key));
+};
+
+
+/**
+ * Creates a key range with upper and lower bounds.
+ *
+ * @param {IDBKeyType} lower The value of the lower bound.
+ * @param {IDBKeyType} upper The value of the upper bound.
+ * @param {boolean=} opt_lowerOpen If true, the range excludes the lower bound
+ *     value.
+ * @param {boolean=} opt_upperOpen If true, the range excludes the upper bound
+ *     value.
+ * @return {!goog.db.KeyRange} The key range.
+ */
+goog.db.KeyRange.bound = function(lower, upper, opt_lowerOpen, opt_upperOpen) {
+  return new goog.db.KeyRange(goog.db.KeyRange.IDB_KEY_RANGE_.bound(
+      lower, upper, opt_lowerOpen, opt_upperOpen));
+};
+
+
+/**
+ * Creates a key range with a lower bound only, finishes at the last record.
+ *
+ * @param {IDBKeyType} lower The value of the lower bound.
+ * @param {boolean=} opt_lowerOpen If true, the range excludes the lower bound
+ *     value.
+ * @return {!goog.db.KeyRange} The key range.
+ */
+goog.db.KeyRange.lowerBound = function(lower, opt_lowerOpen) {
+  return new goog.db.KeyRange(goog.db.KeyRange.IDB_KEY_RANGE_.lowerBound(
+      lower, opt_lowerOpen));
+};
+
+
+/**
+ * Creates a key range with a upper bound only, starts at the first record.
+ *
+ * @param {IDBKeyType} upper The value of the upper bound.
+ * @param {boolean=} opt_upperOpen If true, the range excludes the upper bound
+ *     value.
+ * @return {!goog.db.KeyRange} The key range.
+ */
+goog.db.KeyRange.upperBound = function(upper, opt_upperOpen) {
+  return new goog.db.KeyRange(goog.db.KeyRange.IDB_KEY_RANGE_.upperBound(
+      upper, opt_upperOpen));
+};
+
+
+/**
+ * Returns underlying key range object. This is used in ObjectStore's openCursor
+ * and count methods.
+ * @return {!IDBKeyRange}
+ */
+goog.db.KeyRange.prototype.range = function() {
+  return this.range_;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/db/objectstore.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/db/objectstore.js b/externs/GCL/externs/goog/db/objectstore.js
new file mode 100644
index 0000000..dbaae37
--- /dev/null
+++ b/externs/GCL/externs/goog/db/objectstore.js
@@ -0,0 +1,400 @@
+// Copyright 2011 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 Wrapper for an IndexedDB object store.
+ *
+ */
+
+
+goog.provide('goog.db.ObjectStore');
+
+goog.require('goog.async.Deferred');
+goog.require('goog.db.Cursor');
+goog.require('goog.db.Error');
+goog.require('goog.db.Index');
+goog.require('goog.debug');
+goog.require('goog.events');
+
+
+
+/**
+ * Creates an IDBObjectStore wrapper object. Object stores have methods for
+ * storing and retrieving records, and are accessed through a transaction
+ * object. They also have methods for creating indexes associated with the
+ * object store. They can only be created when setting the version of the
+ * database. Should not be created directly, access object stores through
+ * transactions.
+ * @see goog.db.IndexedDb#setVersion
+ * @see goog.db.Transaction#objectStore
+ *
+ * @param {!IDBObjectStore} store The backing IndexedDb object.
+ * @constructor
+ *
+ * TODO(arthurhsu): revisit msg in exception and errors in this class. In newer
+ *     Chrome (v22+) the error/request come with a DOM error string that is
+ *     already very descriptive.
+ * @final
+ */
+goog.db.ObjectStore = function(store) {
+  /**
+   * Underlying IndexedDB object store object.
+   *
+   * @type {!IDBObjectStore}
+   * @private
+   */
+  this.store_ = store;
+};
+
+
+/**
+ * @return {string} The name of the object store.
+ */
+goog.db.ObjectStore.prototype.getName = function() {
+  return this.store_.name;
+};
+
+
+/**
+ * Helper function for put and add.
+ *
+ * @param {string} fn Function name to call on the object store.
+ * @param {string} msg Message to give to the error.
+ * @param {*} value Value to insert into the object store.
+ * @param {IDBKeyType=} opt_key The key to use.
+ * @return {!goog.async.Deferred} The resulting deferred request.
+ * @private
+ */
+goog.db.ObjectStore.prototype.insert_ = function(fn, msg, value, opt_key) {
+  // TODO(user): refactor wrapping an IndexedDB request in a Deferred by
+  // creating a higher-level abstraction for it (mostly affects here and
+  // goog.db.Index)
+  var d = new goog.async.Deferred();
+  var request;
+  try {
+    // put or add with (value, undefined) throws an error, so we need to check
+    // for undefined ourselves
+    if (opt_key) {
+      request = this.store_[fn](value, opt_key);
+    } else {
+      request = this.store_[fn](value);
+    }
+  } catch (ex) {
+    msg += goog.debug.deepExpose(value);
+    if (opt_key) {
+      msg += ', with key ' + goog.debug.deepExpose(opt_key);
+    }
+    d.errback(goog.db.Error.fromException(ex, msg));
+    return d;
+  }
+  request.onsuccess = function(ev) {
+    d.callback();
+  };
+  request.onerror = function(ev) {
+    msg += goog.debug.deepExpose(value);
+    if (opt_key) {
+      msg += ', with key ' + goog.debug.deepExpose(opt_key);
+    }
+    d.errback(goog.db.Error.fromRequest(ev.target, msg));
+  };
+  return d;
+};
+
+
+/**
+ * Adds an object to the object store. Replaces existing objects with the
+ * same key.
+ *
+ * @param {*} value The value to put.
+ * @param {IDBKeyType=} opt_key The key to use. Cannot be used if the
+ *     keyPath was specified for the object store. If the keyPath was not
+ *     specified but autoIncrement was not enabled, it must be used.
+ * @return {!goog.async.Deferred} The deferred put request.
+ */
+goog.db.ObjectStore.prototype.put = function(value, opt_key) {
+  return this.insert_(
+      'put',
+      'putting into ' + this.getName() + ' with value',
+      value,
+      opt_key);
+};
+
+
+/**
+ * Adds an object to the object store. Requires that there is no object with
+ * the same key already present.
+ *
+ * @param {*} value The value to add.
+ * @param {IDBKeyType=} opt_key The key to use. Cannot be used if the
+ *     keyPath was specified for the object store. If the keyPath was not
+ *     specified but autoIncrement was not enabled, it must be used.
+ * @return {!goog.async.Deferred} The deferred add request.
+ */
+goog.db.ObjectStore.prototype.add = function(value, opt_key) {
+  return this.insert_(
+      'add',
+      'adding into ' + this.getName() + ' with value ',
+      value,
+      opt_key);
+};
+
+
+/**
+ * Removes an object from the store. No-op if there is no object present with
+ * the given key.
+ *
+ * @param {IDBKeyType} key The key to remove objects under.
+ * @return {!goog.async.Deferred} The deferred remove request.
+ */
+goog.db.ObjectStore.prototype.remove = function(key) {
+  var d = new goog.async.Deferred();
+  var request;
+  try {
+    request = this.store_['delete'](key);
+  } catch (err) {
+    var msg = 'removing from ' + this.getName() + ' with key ' +
+        goog.debug.deepExpose(key);
+    d.errback(goog.db.Error.fromException(err, msg));
+    return d;
+  }
+  request.onsuccess = function(ev) {
+    d.callback();
+  };
+  var self = this;
+  request.onerror = function(ev) {
+    var msg = 'removing from ' + self.getName() + ' with key ' +
+        goog.debug.deepExpose(key);
+    d.errback(goog.db.Error.fromRequest(ev.target, msg));
+  };
+  return d;
+};
+
+
+/**
+ * Gets an object from the store. If no object is present with that key
+ * the result is {@code undefined}.
+ *
+ * @param {IDBKeyType} key The key to look up.
+ * @return {!goog.async.Deferred} The deferred get request.
+ */
+goog.db.ObjectStore.prototype.get = function(key) {
+  var d = new goog.async.Deferred();
+  var request;
+  try {
+    request = this.store_.get(key);
+  } catch (err) {
+    var msg = 'getting from ' + this.getName() + ' with key ' +
+        goog.debug.deepExpose(key);
+    d.errback(goog.db.Error.fromException(err, msg));
+    return d;
+  }
+  request.onsuccess = function(ev) {
+    d.callback(ev.target.result);
+  };
+  var self = this;
+  request.onerror = function(ev) {
+    var msg = 'getting from ' + self.getName() + ' with key ' +
+        goog.debug.deepExpose(key);
+    d.errback(goog.db.Error.fromRequest(ev.target, msg));
+  };
+  return d;
+};
+
+
+/**
+ * Gets all objects from the store and returns them as an array.
+ *
+ * @param {!goog.db.KeyRange=} opt_range The key range. If undefined iterates
+ *     over the whole object store.
+ * @param {!goog.db.Cursor.Direction=} opt_direction The direction. If undefined
+ *     moves in a forward direction with duplicates.
+ * @return {!goog.async.Deferred} The deferred getAll request.
+ */
+goog.db.ObjectStore.prototype.getAll = function(opt_range, opt_direction) {
+  var d = new goog.async.Deferred();
+  var cursor;
+  try {
+    cursor = this.openCursor(opt_range, opt_direction);
+  } catch (err) {
+    d.errback(err);
+    return d;
+  }
+
+  var result = [];
+  var key = goog.events.listen(
+      cursor, goog.db.Cursor.EventType.NEW_DATA, function() {
+        result.push(cursor.getValue());
+        cursor.next();
+      });
+
+  goog.events.listenOnce(cursor, [
+    goog.db.Cursor.EventType.ERROR,
+    goog.db.Cursor.EventType.COMPLETE
+  ], function(evt) {
+    cursor.dispose();
+    if (evt.type == goog.db.Cursor.EventType.COMPLETE) {
+      d.callback(result);
+    } else {
+      d.errback();
+    }
+  });
+  return d;
+};
+
+
+/**
+ * Opens a cursor over the specified key range. Returns a cursor object which is
+ * able to iterate over the given range.
+ *
+ * Example usage:
+ *
+ * <code>
+ *  var cursor = objectStore.openCursor(goog.db.Range.bound('a', 'c'));
+ *
+ *  var key = goog.events.listen(
+ *      cursor, goog.db.Cursor.EventType.NEW_DATA, function() {
+ *    // Do something with data.
+ *    cursor.next();
+ *  });
+ *
+ *  goog.events.listenOnce(
+ *      cursor, goog.db.Cursor.EventType.COMPLETE, function() {
+ *    // Clean up listener, and perform a finishing operation on the data.
+ *    goog.events.unlistenByKey(key);
+ *  });
+ * </code>
+ *
+ * @param {!goog.db.KeyRange=} opt_range The key range. If undefined iterates
+ *     over the whole object store.
+ * @param {!goog.db.Cursor.Direction=} opt_direction The direction. If undefined
+ *     moves in a forward direction with duplicates.
+ * @return {!goog.db.Cursor} The cursor.
+ * @throws {goog.db.Error} If there was a problem opening the cursor.
+ */
+goog.db.ObjectStore.prototype.openCursor = function(opt_range, opt_direction) {
+  return goog.db.Cursor.openCursor(this.store_, opt_range, opt_direction);
+};
+
+
+/**
+ * Deletes all objects from the store.
+ *
+ * @return {!goog.async.Deferred} The deferred clear request.
+ */
+goog.db.ObjectStore.prototype.clear = function() {
+  var msg = 'clearing store ' + this.getName();
+  var d = new goog.async.Deferred();
+  var request;
+  try {
+    request = this.store_.clear();
+  } catch (err) {
+    d.errback(goog.db.Error.fromException(err, msg));
+    return d;
+  }
+  request.onsuccess = function(ev) {
+    d.callback();
+  };
+  request.onerror = function(ev) {
+    d.errback(goog.db.Error.fromRequest(ev.target, msg));
+  };
+  return d;
+};
+
+
+/**
+ * Creates an index in this object store. Can only be called inside the callback
+ * for the Deferred returned from goog.db.IndexedDb#setVersion.
+ *
+ * @param {string} name Name of the index to create.
+ * @param {string} keyPath Attribute to index on.
+ * @param {!Object=} opt_parameters Optional parameters object. The only
+ *     available option is unique, which defaults to false. If unique is true,
+ *     the index will enforce that there is only ever one object in the object
+ *     store for each unique value it indexes on.
+ * @return {!goog.db.Index} The newly created, wrapped index.
+ * @throws {goog.db.Error} In case of an error creating the index.
+ */
+goog.db.ObjectStore.prototype.createIndex = function(
+    name, keyPath, opt_parameters) {
+  try {
+    return new goog.db.Index(this.store_.createIndex(
+        name, keyPath, opt_parameters));
+  } catch (ex) {
+    var msg = 'creating new index ' + name + ' with key path ' + keyPath;
+    throw goog.db.Error.fromException(ex, msg);
+  }
+};
+
+
+/**
+ * Gets an index.
+ *
+ * @param {string} name Name of the index to fetch.
+ * @return {!goog.db.Index} The requested wrapped index.
+ * @throws {goog.db.Error} In case of an error getting the index.
+ */
+goog.db.ObjectStore.prototype.getIndex = function(name) {
+  try {
+    return new goog.db.Index(this.store_.index(name));
+  } catch (ex) {
+    var msg = 'getting index ' + name;
+    throw goog.db.Error.fromException(ex, msg);
+  }
+};
+
+
+/**
+ * Deletes an index from the object store. Can only be called inside the
+ * callback for the Deferred returned from goog.db.IndexedDb#setVersion.
+ *
+ * @param {string} name Name of the index to delete.
+ * @throws {goog.db.Error} In case of an error deleting the index.
+ */
+goog.db.ObjectStore.prototype.deleteIndex = function(name) {
+  try {
+    this.store_.deleteIndex(name);
+  } catch (ex) {
+    var msg = 'deleting index ' + name;
+    throw goog.db.Error.fromException(ex, msg);
+  }
+};
+
+
+/**
+ * Gets number of records within a key range.
+ *
+ * @param {!goog.db.KeyRange=} opt_range The key range. If undefined, this will
+ *     count all records in the object store.
+ * @return {!goog.async.Deferred} The deferred number of records.
+ */
+goog.db.ObjectStore.prototype.count = function(opt_range) {
+  var d = new goog.async.Deferred();
+
+  try {
+    var range = opt_range ? opt_range.range() : null;
+    var request = this.store_.count(range);
+    request.onsuccess = function(ev) {
+      d.callback(ev.target.result);
+    };
+    var self = this;
+    request.onerror = function(ev) {
+      d.errback(goog.db.Error.fromRequest(ev.target, self.getName()));
+    };
+  } catch (ex) {
+    d.errback(goog.db.Error.fromException(ex, this.getName()));
+  }
+
+  return d;
+};
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/db/transaction.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/db/transaction.js b/externs/GCL/externs/goog/db/transaction.js
new file mode 100644
index 0000000..8206a25
--- /dev/null
+++ b/externs/GCL/externs/goog/db/transaction.js
@@ -0,0 +1,223 @@
+// Copyright 2011 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 Wrapper for an IndexedDB transaction.
+ *
+ */
+
+
+goog.provide('goog.db.Transaction');
+goog.provide('goog.db.Transaction.TransactionMode');
+
+goog.require('goog.async.Deferred');
+goog.require('goog.db.Error');
+goog.require('goog.db.ObjectStore');
+goog.require('goog.events');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+
+
+
+/**
+ * Creates a new transaction. Transactions contain methods for accessing object
+ * stores and are created from the database object. Should not be created
+ * directly, open a database and call createTransaction on it.
+ * @see goog.db.IndexedDb#createTransaction
+ *
+ * @param {!IDBTransaction} tx IndexedDB transaction to back this wrapper.
+ * @param {!goog.db.IndexedDb} db The database that this transaction modifies.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ * @final
+ */
+goog.db.Transaction = function(tx, db) {
+  goog.db.Transaction.base(this, 'constructor');
+
+  /**
+   * Underlying IndexedDB transaction object.
+   *
+   * @type {!IDBTransaction}
+   * @private
+   */
+  this.tx_ = tx;
+
+  /**
+   * The database that this transaction modifies.
+   *
+   * @type {!goog.db.IndexedDb}
+   * @private
+   */
+  this.db_ = db;
+
+  /**
+   * Event handler for this transaction.
+   *
+   * @type {!goog.events.EventHandler<!goog.db.Transaction>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+  // TODO(user): remove these casts once the externs file is updated to
+  // correctly reflect that IDBTransaction extends EventTarget
+  this.eventHandler_.listen(
+      /** @type {!EventTarget} */ (this.tx_),
+      'complete',
+      goog.bind(
+          this.dispatchEvent,
+          this,
+          goog.db.Transaction.EventTypes.COMPLETE));
+  this.eventHandler_.listen(
+      /** @type {!EventTarget} */ (this.tx_),
+      'abort',
+      goog.bind(
+          this.dispatchEvent,
+          this,
+          goog.db.Transaction.EventTypes.ABORT));
+  this.eventHandler_.listen(
+      /** @type {!EventTarget} */ (this.tx_),
+      'error',
+      this.dispatchError_);
+};
+goog.inherits(goog.db.Transaction, goog.events.EventTarget);
+
+
+/**
+ * Dispatches an error event based on the given event, wrapping the error
+ * if necessary.
+ *
+ * @param {Event} ev The error event given to the underlying IDBTransaction.
+ * @private
+ */
+goog.db.Transaction.prototype.dispatchError_ = function(ev) {
+  if (ev.target instanceof goog.db.Error) {
+    this.dispatchEvent({
+      type: goog.db.Transaction.EventTypes.ERROR,
+      target: ev.target
+    });
+  } else {
+    this.dispatchEvent({
+      type: goog.db.Transaction.EventTypes.ERROR,
+      target: goog.db.Error.fromRequest(
+          /** @type {!IDBRequest} */ (ev.target), 'in transaction')
+    });
+  }
+};
+
+
+/**
+ * Event types the Transaction can dispatch. COMPLETE events are dispatched
+ * when the transaction is committed. If a transaction is aborted it dispatches
+ * both an ABORT event and an ERROR event with the ABORT_ERR code. Error events
+ * are dispatched on any error.
+ *
+ * @enum {string}
+ */
+goog.db.Transaction.EventTypes = {
+  COMPLETE: 'complete',
+  ABORT: 'abort',
+  ERROR: 'error'
+};
+
+
+/**
+ * @return {goog.db.Transaction.TransactionMode} The transaction's mode.
+ */
+goog.db.Transaction.prototype.getMode = function() {
+  return /** @type {goog.db.Transaction.TransactionMode} */ (this.tx_.mode);
+};
+
+
+/**
+ * @return {!goog.db.IndexedDb} The database that this transaction modifies.
+ */
+goog.db.Transaction.prototype.getDatabase = function() {
+  return this.db_;
+};
+
+
+/**
+ * Opens an object store to do operations on in this transaction. The requested
+ * object store must be one that is in this transaction's scope.
+ * @see goog.db.IndexedDb#createTransaction
+ *
+ * @param {string} name The name of the requested object store.
+ * @return {!goog.db.ObjectStore} The wrapped object store.
+ * @throws {goog.db.Error} In case of error getting the object store.
+ */
+goog.db.Transaction.prototype.objectStore = function(name) {
+  try {
+    return new goog.db.ObjectStore(this.tx_.objectStore(name));
+  } catch (ex) {
+    throw goog.db.Error.fromException(ex, 'getting object store ' + name);
+  }
+};
+
+
+/**
+ * @return {!goog.async.Deferred} A deferred that will fire once the
+ *     transaction is complete. It fires the errback chain if an error occurs
+ *     in the transaction, or if it is aborted.
+ */
+goog.db.Transaction.prototype.wait = function() {
+  var d = new goog.async.Deferred();
+  goog.events.listenOnce(
+      this, goog.db.Transaction.EventTypes.COMPLETE, goog.bind(d.callback, d));
+  var errorKey;
+  var abortKey = goog.events.listenOnce(
+      this, goog.db.Transaction.EventTypes.ABORT, function() {
+        goog.events.unlistenByKey(errorKey);
+        d.errback(new goog.db.Error(goog.db.Error.ErrorCode.ABORT_ERR,
+            'waiting for transaction to complete'));
+      });
+  errorKey = goog.events.listenOnce(
+      this, goog.db.Transaction.EventTypes.ERROR, function(e) {
+        goog.events.unlistenByKey(abortKey);
+        d.errback(e.target);
+      });
+
+  var db = this.getDatabase();
+  return d.addCallback(function() {
+    return db;
+  });
+};
+
+
+/**
+ * Aborts this transaction. No pending operations will be applied to the
+ * database. Dispatches an ABORT event.
+ */
+goog.db.Transaction.prototype.abort = function() {
+  this.tx_.abort();
+};
+
+
+/** @override */
+goog.db.Transaction.prototype.disposeInternal = function() {
+  goog.db.Transaction.base(this, 'disposeInternal');
+  this.eventHandler_.dispose();
+};
+
+
+/**
+ * The three possible transaction modes.
+ * @see http://www.w3.org/TR/IndexedDB/#idl-def-IDBTransaction
+ *
+ * @enum {string}
+ */
+goog.db.Transaction.TransactionMode = {
+  READ_ONLY: 'readonly',
+  READ_WRITE: 'readwrite',
+  VERSION_CHANGE: 'versionchange'
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/debug/console.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/debug/console.js b/externs/GCL/externs/goog/debug/console.js
new file mode 100644
index 0000000..89c6cce
--- /dev/null
+++ b/externs/GCL/externs/goog/debug/console.js
@@ -0,0 +1,207 @@
+// 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 Simple logger that logs to the window console if available.
+ *
+ * Has an autoInstall option which can be put into initialization code, which
+ * will start logging if "Debug=true" is in document.location.href
+ *
+ */
+
+goog.provide('goog.debug.Console');
+
+goog.require('goog.debug.LogManager');
+goog.require('goog.debug.Logger');
+goog.require('goog.debug.TextFormatter');
+
+
+
+/**
+ * Create and install a log handler that logs to window.console if available
+ * @constructor
+ */
+goog.debug.Console = function() {
+  this.publishHandler_ = goog.bind(this.addLogRecord, this);
+
+  /**
+   * Formatter for formatted output.
+   * @type {!goog.debug.TextFormatter}
+   * @private
+   */
+  this.formatter_ = new goog.debug.TextFormatter();
+  this.formatter_.showAbsoluteTime = false;
+  this.formatter_.showExceptionText = false;
+  // The console logging methods automatically append a newline.
+  this.formatter_.appendNewline = false;
+
+  this.isCapturing_ = false;
+  this.logBuffer_ = '';
+
+  /**
+   * Loggers that we shouldn't output.
+   * @type {!Object<boolean>}
+   * @private
+   */
+  this.filteredLoggers_ = {};
+};
+
+
+/**
+ * Returns the text formatter used by this console
+ * @return {!goog.debug.TextFormatter} The text formatter.
+ */
+goog.debug.Console.prototype.getFormatter = function() {
+  return this.formatter_;
+};
+
+
+/**
+ * Sets whether we are currently capturing logger output.
+ * @param {boolean} capturing Whether to capture logger output.
+ */
+goog.debug.Console.prototype.setCapturing = function(capturing) {
+  if (capturing == this.isCapturing_) {
+    return;
+  }
+
+  // attach or detach handler from the root logger
+  var rootLogger = goog.debug.LogManager.getRoot();
+  if (capturing) {
+    rootLogger.addHandler(this.publishHandler_);
+  } else {
+    rootLogger.removeHandler(this.publishHandler_);
+    this.logBuffer = '';
+  }
+  this.isCapturing_ = capturing;
+};
+
+
+/**
+ * Adds a log record.
+ * @param {goog.debug.LogRecord} logRecord The log entry.
+ */
+goog.debug.Console.prototype.addLogRecord = function(logRecord) {
+
+  // Check to see if the log record is filtered or not.
+  if (this.filteredLoggers_[logRecord.getLoggerName()]) {
+    return;
+  }
+
+  var record = this.formatter_.formatRecord(logRecord);
+  var console = goog.debug.Console.console_;
+  if (console) {
+    switch (logRecord.getLevel()) {
+      case goog.debug.Logger.Level.SHOUT:
+        goog.debug.Console.logToConsole_(console, 'info', record);
+        break;
+      case goog.debug.Logger.Level.SEVERE:
+        goog.debug.Console.logToConsole_(console, 'error', record);
+        break;
+      case goog.debug.Logger.Level.WARNING:
+        goog.debug.Console.logToConsole_(console, 'warn', record);
+        break;
+      default:
+        goog.debug.Console.logToConsole_(console, 'debug', record);
+        break;
+    }
+  } else {
+    this.logBuffer_ += record;
+  }
+};
+
+
+/**
+ * Adds a logger name to be filtered.
+ * @param {string} loggerName the logger name to add.
+ */
+goog.debug.Console.prototype.addFilter = function(loggerName) {
+  this.filteredLoggers_[loggerName] = true;
+};
+
+
+/**
+ * Removes a logger name to be filtered.
+ * @param {string} loggerName the logger name to remove.
+ */
+goog.debug.Console.prototype.removeFilter = function(loggerName) {
+  delete this.filteredLoggers_[loggerName];
+};
+
+
+/**
+ * Global console logger instance
+ * @type {goog.debug.Console}
+ */
+goog.debug.Console.instance = null;
+
+
+/**
+ * The console to which to log.  This is a property so it can be mocked out in
+ * this unit test for goog.debug.Console. Using goog.global, as console might be
+ * used in window-less contexts.
+ * @type {Object}
+ * @private
+ */
+goog.debug.Console.console_ = goog.global['console'];
+
+
+/**
+ * Sets the console to which to log.
+ * @param {!Object} console The console to which to log.
+ */
+goog.debug.Console.setConsole = function(console) {
+  goog.debug.Console.console_ = console;
+};
+
+
+/**
+ * Install the console and start capturing if "Debug=true" is in the page URL
+ */
+goog.debug.Console.autoInstall = function() {
+  if (!goog.debug.Console.instance) {
+    goog.debug.Console.instance = new goog.debug.Console();
+  }
+
+  if (goog.global.location &&
+      goog.global.location.href.indexOf('Debug=true') != -1) {
+    goog.debug.Console.instance.setCapturing(true);
+  }
+};
+
+
+/**
+ * Show an alert with all of the captured debug information.
+ * Information is only captured if console is not available
+ */
+goog.debug.Console.show = function() {
+  alert(goog.debug.Console.instance.logBuffer_);
+};
+
+
+/**
+ * Logs the record to the console using the given function.  If the function is
+ * not available on the console object, the log function is used instead.
+ * @param {!Object} console The console object.
+ * @param {string} fnName The name of the function to use.
+ * @param {string} record The record to log.
+ * @private
+ */
+goog.debug.Console.logToConsole_ = function(console, fnName, record) {
+  if (console[fnName]) {
+    console[fnName](record);
+  } else {
+    console.log(record);
+  }
+};


[06/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/i18n/bidiformatter.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/i18n/bidiformatter.js b/externs/GCL/externs/goog/i18n/bidiformatter.js
new file mode 100644
index 0000000..0583f5b
--- /dev/null
+++ b/externs/GCL/externs/goog/i18n/bidiformatter.js
@@ -0,0 +1,596 @@
+// 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 Utility for formatting text for display in a potentially
+ * opposite-directionality context without garbling.
+ * Mostly a port of http://go/formatter.cc.
+ */
+
+
+goog.provide('goog.i18n.BidiFormatter');
+
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.legacyconversions');
+goog.require('goog.i18n.bidi');
+goog.require('goog.i18n.bidi.Dir');
+goog.require('goog.i18n.bidi.Format');
+
+
+
+/**
+ * Utility class for formatting text for display in a potentially
+ * opposite-directionality context without garbling. Provides the following
+ * functionality:
+ *
+ * 1. BiDi Wrapping
+ * When text in one language is mixed into a document in another, opposite-
+ * directionality language, e.g. when an English business name is embedded in a
+ * Hebrew web page, both the inserted string and the text following it may be
+ * displayed incorrectly unless the inserted string is explicitly separated
+ * from the surrounding text in a "wrapper" that declares its directionality at
+ * the start and then resets it back at the end. This wrapping can be done in
+ * HTML mark-up (e.g. a 'span dir="rtl"' tag) or - only in contexts where
+ * mark-up can not be used - in Unicode BiDi formatting codes (LRE|RLE and PDF).
+ * Providing such wrapping services is the basic purpose of the BiDi formatter.
+ *
+ * 2. Directionality estimation
+ * How does one know whether a string about to be inserted into surrounding
+ * text has the same directionality? Well, in many cases, one knows that this
+ * must be the case when writing the code doing the insertion, e.g. when a
+ * localized message is inserted into a localized page. In such cases there is
+ * no need to involve the BiDi formatter at all. In the remaining cases, e.g.
+ * when the string is user-entered or comes from a database, the language of
+ * the string (and thus its directionality) is not known a priori, and must be
+ * estimated at run-time. The BiDi formatter does this automatically.
+ *
+ * 3. Escaping
+ * When wrapping plain text - i.e. text that is not already HTML or HTML-
+ * escaped - in HTML mark-up, the text must first be HTML-escaped to prevent XSS
+ * attacks and other nasty business. This of course is always true, but the
+ * escaping can not be done after the string has already been wrapped in
+ * mark-up, so the BiDi formatter also serves as a last chance and includes
+ * escaping services.
+ *
+ * Thus, in a single call, the formatter will escape the input string as
+ * specified, determine its directionality, and wrap it as necessary. It is
+ * then up to the caller to insert the return value in the output.
+ *
+ * See http://wiki/Main/TemplatesAndBiDi for more information.
+ *
+ * @param {goog.i18n.bidi.Dir|number|boolean|null} contextDir The context
+ *     directionality, in one of the following formats:
+ *     1. A goog.i18n.bidi.Dir constant. NEUTRAL is treated the same as null,
+ *        i.e. unknown, for backward compatibility with legacy calls.
+ *     2. A number (positive = LTR, negative = RTL, 0 = unknown).
+ *     3. A boolean (true = RTL, false = LTR).
+ *     4. A null for unknown directionality.
+ * @param {boolean=} opt_alwaysSpan Whether {@link #spanWrap} should always
+ *     use a 'span' tag, even when the input directionality is neutral or
+ *     matches the context, so that the DOM structure of the output does not
+ *     depend on the combination of directionalities. Default: false.
+ * @constructor
+ * @final
+ */
+goog.i18n.BidiFormatter = function(contextDir, opt_alwaysSpan) {
+  /**
+   * The overall directionality of the context in which the formatter is being
+   * used.
+   * @type {?goog.i18n.bidi.Dir}
+   * @private
+   */
+  this.contextDir_ = goog.i18n.bidi.toDir(contextDir, true /* opt_noNeutral */);
+
+  /**
+   * Whether {@link #spanWrap} and similar methods should always use the same
+   * span structure, regardless of the combination of directionalities, for a
+   * stable DOM structure.
+   * @type {boolean}
+   * @private
+   */
+  this.alwaysSpan_ = !!opt_alwaysSpan;
+};
+
+
+/**
+ * @return {?goog.i18n.bidi.Dir} The context directionality.
+ */
+goog.i18n.BidiFormatter.prototype.getContextDir = function() {
+  return this.contextDir_;
+};
+
+
+/**
+ * @return {boolean} Whether alwaysSpan is set.
+ */
+goog.i18n.BidiFormatter.prototype.getAlwaysSpan = function() {
+  return this.alwaysSpan_;
+};
+
+
+/**
+ * @param {goog.i18n.bidi.Dir|number|boolean|null} contextDir The context
+ *     directionality, in one of the following formats:
+ *     1. A goog.i18n.bidi.Dir constant. NEUTRAL is treated the same as null,
+ *        i.e. unknown.
+ *     2. A number (positive = LTR, negative = RTL, 0 = unknown).
+ *     3. A boolean (true = RTL, false = LTR).
+ *     4. A null for unknown directionality.
+ */
+goog.i18n.BidiFormatter.prototype.setContextDir = function(contextDir) {
+  this.contextDir_ = goog.i18n.bidi.toDir(contextDir, true /* opt_noNeutral */);
+};
+
+
+/**
+ * @param {boolean} alwaysSpan Whether {@link #spanWrap} should always use a
+ *     'span' tag, even when the input directionality is neutral or matches the
+ *     context, so that the DOM structure of the output does not depend on the
+ *     combination of directionalities.
+ */
+goog.i18n.BidiFormatter.prototype.setAlwaysSpan = function(alwaysSpan) {
+  this.alwaysSpan_ = alwaysSpan;
+};
+
+
+/**
+ * Returns the directionality of input argument {@code str}.
+ * Identical to {@link goog.i18n.bidi.estimateDirection}.
+ *
+ * @param {string} str The input text.
+ * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {goog.i18n.bidi.Dir} Estimated overall directionality of {@code str}.
+ */
+goog.i18n.BidiFormatter.prototype.estimateDirection =
+    goog.i18n.bidi.estimateDirection;
+
+
+/**
+ * Returns true if two given directionalities are opposite.
+ * Note: the implementation is based on the numeric values of the Dir enum.
+ *
+ * @param {?goog.i18n.bidi.Dir} dir1 1st directionality.
+ * @param {?goog.i18n.bidi.Dir} dir2 2nd directionality.
+ * @return {boolean} Whether the directionalities are opposite.
+ * @private
+ */
+goog.i18n.BidiFormatter.prototype.areDirectionalitiesOpposite_ = function(dir1,
+    dir2) {
+  return dir1 * dir2 < 0;
+};
+
+
+/**
+ * Returns a unicode BiDi mark matching the context directionality (LRM or
+ * RLM) if {@code opt_dirReset}, and if either the directionality or the exit
+ * directionality of {@code str} is opposite to the context directionality.
+ * Otherwise returns the empty string.
+ *
+ * @param {string} str The input text.
+ * @param {goog.i18n.bidi.Dir} dir {@code str}'s overall directionality.
+ * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
+ *     Default: false.
+ * @param {boolean=} opt_dirReset Whether to perform the reset. Default: false.
+ * @return {string} A unicode BiDi mark or the empty string.
+ * @private
+ */
+goog.i18n.BidiFormatter.prototype.dirResetIfNeeded_ = function(str, dir,
+    opt_isHtml, opt_dirReset) {
+  // endsWithRtl and endsWithLtr are called only if needed (short-circuit).
+  if (opt_dirReset &&
+      (this.areDirectionalitiesOpposite_(dir, this.contextDir_) ||
+       (this.contextDir_ == goog.i18n.bidi.Dir.LTR &&
+        goog.i18n.bidi.endsWithRtl(str, opt_isHtml)) ||
+       (this.contextDir_ == goog.i18n.bidi.Dir.RTL &&
+        goog.i18n.bidi.endsWithLtr(str, opt_isHtml)))) {
+    return this.contextDir_ == goog.i18n.bidi.Dir.LTR ?
+        goog.i18n.bidi.Format.LRM : goog.i18n.bidi.Format.RLM;
+  } else {
+    return '';
+  }
+};
+
+
+/**
+ * Returns "rtl" if {@code str}'s estimated directionality is RTL, and "ltr" if
+ * it is LTR. In case it's NEUTRAL, returns "rtl" if the context directionality
+ * is RTL, and "ltr" otherwise.
+ * Needed for GXP, which can't handle dirAttr.
+ * Example use case:
+ * &lt;td expr:dir='bidiFormatter.dirAttrValue(foo)'&gt;
+ *   &lt;gxp:eval expr='foo'&gt;
+ * &lt;/td&gt;
+ *
+ * @param {string} str Text whose directionality is to be estimated.
+ * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {string} "rtl" or "ltr", according to the logic described above.
+ */
+goog.i18n.BidiFormatter.prototype.dirAttrValue = function(str, opt_isHtml) {
+  return this.knownDirAttrValue(this.estimateDirection(str, opt_isHtml));
+};
+
+
+/**
+ * Returns "rtl" if the given directionality is RTL, and "ltr" if it is LTR. In
+ * case it's NEUTRAL, returns "rtl" if the context directionality is RTL, and
+ * "ltr" otherwise.
+ *
+ * @param {goog.i18n.bidi.Dir} dir A directionality.
+ * @return {string} "rtl" or "ltr", according to the logic described above.
+ */
+goog.i18n.BidiFormatter.prototype.knownDirAttrValue = function(dir) {
+  var resolvedDir = dir == goog.i18n.bidi.Dir.NEUTRAL ? this.contextDir_ : dir;
+  return resolvedDir == goog.i18n.bidi.Dir.RTL ? 'rtl' : 'ltr';
+};
+
+
+/**
+ * Returns 'dir="ltr"' or 'dir="rtl"', depending on {@code str}'s estimated
+ * directionality, if it is not the same as the context directionality.
+ * Otherwise, returns the empty string.
+ *
+ * @param {string} str Text whose directionality is to be estimated.
+ * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {string} 'dir="rtl"' for RTL text in non-RTL context; 'dir="ltr"' for
+ *     LTR text in non-LTR context; else, the empty string.
+ */
+goog.i18n.BidiFormatter.prototype.dirAttr = function(str, opt_isHtml) {
+  return this.knownDirAttr(this.estimateDirection(str, opt_isHtml));
+};
+
+
+/**
+ * Returns 'dir="ltr"' or 'dir="rtl"', depending on the given directionality, if
+ * it is not the same as the context directionality. Otherwise, returns the
+ * empty string.
+ *
+ * @param {goog.i18n.bidi.Dir} dir A directionality.
+ * @return {string} 'dir="rtl"' for RTL text in non-RTL context; 'dir="ltr"' for
+ *     LTR text in non-LTR context; else, the empty string.
+ */
+goog.i18n.BidiFormatter.prototype.knownDirAttr = function(dir) {
+  if (dir != this.contextDir_) {
+    return dir == goog.i18n.bidi.Dir.RTL ? 'dir="rtl"' :
+        dir == goog.i18n.bidi.Dir.LTR ? 'dir="ltr"' : '';
+  }
+  return '';
+};
+
+
+/**
+ * Formats a string of unknown directionality for use in HTML output of the
+ * context directionality, so an opposite-directionality string is neither
+ * garbled nor garbles what follows it.
+ * The algorithm: estimates the directionality of input argument {@code html}.
+ * In case its directionality doesn't match the context directionality, wraps it
+ * with a 'span' tag and adds a "dir" attribute (either 'dir="rtl"' or
+ * 'dir="ltr"'). If setAlwaysSpan(true) was used, the input is always wrapped
+ * with 'span', skipping just the dir attribute when it's not needed.
+ *
+ * If {@code opt_dirReset}, and if the overall directionality or the exit
+ * directionality of {@code str} are opposite to the context directionality, a
+ * trailing unicode BiDi mark matching the context directionality is appened
+ * (LRM or RLM).
+ *
+ * @param {!goog.html.SafeHtml} html The input HTML.
+ * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
+ *     matching the context directionality, when needed, to prevent the possible
+ *     garbling of whatever may follow {@code html}. Default: true.
+ * @return {!goog.html.SafeHtml} Input text after applying the processing.
+ */
+goog.i18n.BidiFormatter.prototype.spanWrapSafeHtml = function(html,
+    opt_dirReset) {
+  return this.spanWrapSafeHtmlWithKnownDir(null, html, opt_dirReset);
+};
+
+
+/**
+ * String version of {@link #spanWrapSafeHtml}.
+ *
+ * If !{@code opt_isHtml}, HTML-escapes {@code str} regardless of wrapping.
+ *
+ * @param {string} str The input text.
+ * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
+ *     Default: false.
+ * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
+ *     matching the context directionality, when needed, to prevent the possible
+ *     garbling of whatever may follow {@code str}. Default: true.
+ * @return {string} Input text after applying the above processing.
+ */
+goog.i18n.BidiFormatter.prototype.spanWrap = function(str, opt_isHtml,
+    opt_dirReset) {
+  return this.spanWrapWithKnownDir(null, str, opt_isHtml, opt_dirReset);
+};
+
+
+/**
+ * Formats a string of given directionality for use in HTML output of the
+ * context directionality, so an opposite-directionality string is neither
+ * garbled nor garbles what follows it.
+ * The algorithm: If {@code dir} doesn't match the context directionality, wraps
+ * {@code html} with a 'span' tag and adds a "dir" attribute (either 'dir="rtl"'
+ * or 'dir="ltr"'). If setAlwaysSpan(true) was used, the input is always wrapped
+ * with 'span', skipping just the dir attribute when it's not needed.
+ *
+ * If {@code opt_dirReset}, and if {@code dir} or the exit directionality of
+ * {@code html} are opposite to the context directionality, a trailing unicode
+ * BiDi mark matching the context directionality is appened (LRM or RLM).
+ *
+ * @param {?goog.i18n.bidi.Dir} dir {@code html}'s overall directionality, or
+ *     null if unknown and needs to be estimated.
+ * @param {!goog.html.SafeHtml} html The input HTML.
+ * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
+ *     matching the context directionality, when needed, to prevent the possible
+ *     garbling of whatever may follow {@code html}. Default: true.
+ * @return {!goog.html.SafeHtml} Input text after applying the processing.
+ */
+goog.i18n.BidiFormatter.prototype.spanWrapSafeHtmlWithKnownDir = function(dir,
+    html, opt_dirReset) {
+  if (dir == null) {
+    dir = this.estimateDirection(goog.html.SafeHtml.unwrap(html), true);
+  }
+  return this.spanWrapWithKnownDir_(dir, html, opt_dirReset);
+};
+
+
+/**
+ * String version of {@link #spanWrapSafeHtmlWithKnownDir}.
+ *
+ * If !{@code opt_isHtml}, HTML-escapes {@code str} regardless of wrapping.
+ *
+ * @param {?goog.i18n.bidi.Dir} dir {@code str}'s overall directionality, or
+ *     null if unknown and needs to be estimated.
+ * @param {string} str The input text.
+ * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
+ *     Default: false.
+ * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
+ *     matching the context directionality, when needed, to prevent the possible
+ *     garbling of whatever may follow {@code str}. Default: true.
+ * @return {string} Input text after applying the above processing.
+ */
+goog.i18n.BidiFormatter.prototype.spanWrapWithKnownDir = function(dir, str,
+    opt_isHtml, opt_dirReset) {
+  // We're calling legacy conversions, but quickly unwrapping it.
+  var html = opt_isHtml ? goog.html.legacyconversions.safeHtmlFromString(str) :
+      goog.html.SafeHtml.htmlEscape(str);
+  return goog.html.SafeHtml.unwrap(
+      this.spanWrapSafeHtmlWithKnownDir(dir, html, opt_dirReset));
+};
+
+
+/**
+ * The internal implementation of spanWrapSafeHtmlWithKnownDir for non-null dir,
+ * to help the compiler optimize.
+ *
+ * @param {goog.i18n.bidi.Dir} dir {@code str}'s overall directionality.
+ * @param {!goog.html.SafeHtml} html The input HTML.
+ * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
+ *     matching the context directionality, when needed, to prevent the possible
+ *     garbling of whatever may follow {@code str}. Default: true.
+ * @return {!goog.html.SafeHtml} Input text after applying the above processing.
+ * @private
+ */
+goog.i18n.BidiFormatter.prototype.spanWrapWithKnownDir_ = function(dir, html,
+    opt_dirReset) {
+  opt_dirReset = opt_dirReset || (opt_dirReset == undefined);
+
+  var result;
+  // Whether to add the "dir" attribute.
+  var dirCondition =
+      dir != goog.i18n.bidi.Dir.NEUTRAL && dir != this.contextDir_;
+  if (this.alwaysSpan_ || dirCondition) {  // Wrap is needed
+    var dirAttribute;
+    if (dirCondition) {
+      dirAttribute = dir == goog.i18n.bidi.Dir.RTL ? 'rtl' : 'ltr';
+    }
+    result = goog.html.SafeHtml.create('span', {'dir': dirAttribute}, html);
+  } else {
+    result = html;
+  }
+  var str = goog.html.SafeHtml.unwrap(html);
+  result = goog.html.SafeHtml.concatWithDir(goog.i18n.bidi.Dir.NEUTRAL, result,
+      this.dirResetIfNeeded_(str, dir, true, opt_dirReset));
+  return result;
+};
+
+
+/**
+ * Formats a string of unknown directionality for use in plain-text output of
+ * the context directionality, so an opposite-directionality string is neither
+ * garbled nor garbles what follows it.
+ * As opposed to {@link #spanWrap}, this makes use of unicode BiDi formatting
+ * characters. In HTML, its *only* valid use is inside of elements that do not
+ * allow mark-up, e.g. an 'option' tag.
+ * The algorithm: estimates the directionality of input argument {@code str}.
+ * In case it doesn't match  the context directionality, wraps it with Unicode
+ * BiDi formatting characters: RLE{@code str}PDF for RTL text, and
+ * LRE{@code str}PDF for LTR text.
+ *
+ * If {@code opt_dirReset}, and if the overall directionality or the exit
+ * directionality of {@code str} are opposite to the context directionality, a
+ * trailing unicode BiDi mark matching the context directionality is appended
+ * (LRM or RLM).
+ *
+ * Does *not* do HTML-escaping regardless of the value of {@code opt_isHtml}.
+ * The return value can be HTML-escaped as necessary.
+ *
+ * @param {string} str The input text.
+ * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
+ *     Default: false.
+ * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
+ *     matching the context directionality, when needed, to prevent the possible
+ *     garbling of whatever may follow {@code str}. Default: true.
+ * @return {string} Input text after applying the above processing.
+ */
+goog.i18n.BidiFormatter.prototype.unicodeWrap = function(str, opt_isHtml,
+    opt_dirReset) {
+  return this.unicodeWrapWithKnownDir(null, str, opt_isHtml, opt_dirReset);
+};
+
+
+/**
+ * Formats a string of given directionality for use in plain-text output of the
+ * context directionality, so an opposite-directionality string is neither
+ * garbled nor garbles what follows it.
+ * As opposed to {@link #spanWrapWithKnownDir}, makes use of unicode BiDi
+ * formatting characters. In HTML, its *only* valid use is inside of elements
+ * that do not allow mark-up, e.g. an 'option' tag.
+ * The algorithm: If {@code dir} doesn't match the context directionality, wraps
+ * {@code str} with Unicode BiDi formatting characters: RLE{@code str}PDF for
+ * RTL text, and LRE{@code str}PDF for LTR text.
+ *
+ * If {@code opt_dirReset}, and if the overall directionality or the exit
+ * directionality of {@code str} are opposite to the context directionality, a
+ * trailing unicode BiDi mark matching the context directionality is appended
+ * (LRM or RLM).
+ *
+ * Does *not* do HTML-escaping regardless of the value of {@code opt_isHtml}.
+ * The return value can be HTML-escaped as necessary.
+ *
+ * @param {?goog.i18n.bidi.Dir} dir {@code str}'s overall directionality, or
+ *     null if unknown and needs to be estimated.
+ * @param {string} str The input text.
+ * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
+ *     Default: false.
+ * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
+ *     matching the context directionality, when needed, to prevent the possible
+ *     garbling of whatever may follow {@code str}. Default: true.
+ * @return {string} Input text after applying the above processing.
+ */
+goog.i18n.BidiFormatter.prototype.unicodeWrapWithKnownDir = function(dir, str,
+    opt_isHtml, opt_dirReset) {
+  if (dir == null) {
+    dir = this.estimateDirection(str, opt_isHtml);
+  }
+  return this.unicodeWrapWithKnownDir_(dir, str, opt_isHtml, opt_dirReset);
+};
+
+
+/**
+ * The internal implementation of unicodeWrapWithKnownDir for non-null dir, to
+ * help the compiler optimize.
+ *
+ * @param {goog.i18n.bidi.Dir} dir {@code str}'s overall directionality.
+ * @param {string} str The input text.
+ * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
+ *     Default: false.
+ * @param {boolean=} opt_dirReset Whether to append a trailing unicode bidi mark
+ *     matching the context directionality, when needed, to prevent the possible
+ *     garbling of whatever may follow {@code str}. Default: true.
+ * @return {string} Input text after applying the above processing.
+ * @private
+ */
+goog.i18n.BidiFormatter.prototype.unicodeWrapWithKnownDir_ = function(dir, str,
+    opt_isHtml, opt_dirReset) {
+  opt_dirReset = opt_dirReset || (opt_dirReset == undefined);
+  var result = [];
+  if (dir != goog.i18n.bidi.Dir.NEUTRAL && dir != this.contextDir_) {
+    result.push(dir == goog.i18n.bidi.Dir.RTL ? goog.i18n.bidi.Format.RLE :
+                                                goog.i18n.bidi.Format.LRE);
+    result.push(str);
+    result.push(goog.i18n.bidi.Format.PDF);
+  } else {
+    result.push(str);
+  }
+
+  result.push(this.dirResetIfNeeded_(str, dir, opt_isHtml, opt_dirReset));
+  return result.join('');
+};
+
+
+/**
+ * Returns a Unicode BiDi mark matching the context directionality (LRM or RLM)
+ * if the directionality or the exit directionality of {@code str} are opposite
+ * to the context directionality. Otherwise returns the empty string.
+ *
+ * @param {string} str The input text.
+ * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {string} A Unicode bidi mark matching the global directionality or
+ *     the empty string.
+ */
+goog.i18n.BidiFormatter.prototype.markAfter = function(str, opt_isHtml) {
+  return this.markAfterKnownDir(null, str, opt_isHtml);
+};
+
+
+/**
+ * Returns a Unicode BiDi mark matching the context directionality (LRM or RLM)
+ * if the given directionality or the exit directionality of {@code str} are
+ * opposite to the context directionality. Otherwise returns the empty string.
+ *
+ * @param {?goog.i18n.bidi.Dir} dir {@code str}'s overall directionality, or
+ *     null if unknown and needs to be estimated.
+ * @param {string} str The input text.
+ * @param {boolean=} opt_isHtml Whether {@code str} is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {string} A Unicode bidi mark matching the global directionality or
+ *     the empty string.
+ */
+goog.i18n.BidiFormatter.prototype.markAfterKnownDir = function(
+    dir, str, opt_isHtml) {
+  if (dir == null) {
+    dir = this.estimateDirection(str, opt_isHtml);
+  }
+  return this.dirResetIfNeeded_(str, dir, opt_isHtml, true);
+};
+
+
+/**
+ * Returns the Unicode BiDi mark matching the context directionality (LRM for
+ * LTR context directionality, RLM for RTL context directionality), or the
+ * empty string for neutral / unknown context directionality.
+ *
+ * @return {string} LRM for LTR context directionality and RLM for RTL context
+ *     directionality.
+ */
+goog.i18n.BidiFormatter.prototype.mark = function() {
+  switch (this.contextDir_) {
+    case (goog.i18n.bidi.Dir.LTR):
+      return goog.i18n.bidi.Format.LRM;
+    case (goog.i18n.bidi.Dir.RTL):
+      return goog.i18n.bidi.Format.RLM;
+    default:
+      return '';
+  }
+};
+
+
+/**
+ * Returns 'right' for RTL context directionality. Otherwise (LTR or neutral /
+ * unknown context directionality) returns 'left'.
+ *
+ * @return {string} 'right' for RTL context directionality and 'left' for other
+ *     context directionality.
+ */
+goog.i18n.BidiFormatter.prototype.startEdge = function() {
+  return this.contextDir_ == goog.i18n.bidi.Dir.RTL ?
+      goog.i18n.bidi.RIGHT : goog.i18n.bidi.LEFT;
+};
+
+
+/**
+ * Returns 'left' for RTL context directionality. Otherwise (LTR or neutral /
+ * unknown context directionality) returns 'right'.
+ *
+ * @return {string} 'left' for RTL context directionality and 'right' for other
+ *     context directionality.
+ */
+goog.i18n.BidiFormatter.prototype.endEdge = function() {
+  return this.contextDir_ == goog.i18n.bidi.Dir.RTL ?
+      goog.i18n.bidi.LEFT : goog.i18n.bidi.RIGHT;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/i18n/charlistdecompressor.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/i18n/charlistdecompressor.js b/externs/GCL/externs/goog/i18n/charlistdecompressor.js
new file mode 100644
index 0000000..48fae13
--- /dev/null
+++ b/externs/GCL/externs/goog/i18n/charlistdecompressor.js
@@ -0,0 +1,158 @@
+// 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 The decompressor for Base88 compressed character lists.
+ *
+ * The compression is by base 88 encoding the delta between two adjacent
+ * characters in ths list. The deltas can be positive or negative. Also, there
+ * would be character ranges. These three types of values
+ * are given enum values 0, 1 and 2 respectively. Initial 3 bits are used for
+ * encoding the type and total length of the encoded value. Length enums 0, 1
+ * and 2 represents lengths 1, 2 and 4. So (value * 8 + type * 3 + length enum)
+ * is encoded in base 88 by following characters for numbers from 0 to 87:
+ * 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ (continued in next line)
+ * abcdefghijklmnopqrstuvwxyz!#$%()*+,-.:;<=>?@[]^_`{|}~
+ *
+ * Value uses 0 based counting. That is value for the range [a, b] is 0 and
+ * that of [a, c] is 1. Simillarly, the delta of "ab" is 0.
+ *
+ * Following python script can be used to compress character lists taken
+ * standard input: http://go/charlistcompressor.py
+ *
+ */
+
+goog.provide('goog.i18n.CharListDecompressor');
+
+goog.require('goog.array');
+goog.require('goog.i18n.uChar');
+
+
+
+/**
+ * Class to decompress base88 compressed character list.
+ * @constructor
+ * @final
+ */
+goog.i18n.CharListDecompressor = function() {
+  this.buildCharMap_('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqr' +
+      'stuvwxyz!#$%()*+,-.:;<=>?@[]^_`{|}~');
+};
+
+
+/**
+ * 1-1 mapping from ascii characters used in encoding to an integer in the
+ * range 0 to 87.
+ * @type {Object}
+ * @private
+ */
+goog.i18n.CharListDecompressor.prototype.charMap_ = null;
+
+
+/**
+ * Builds the map from ascii characters used for the base88 scheme to number
+ * each character represents.
+ * @param {string} str The string of characters used in base88 scheme.
+ * @private
+ */
+goog.i18n.CharListDecompressor.prototype.buildCharMap_ = function(str) {
+  if (!this.charMap_) {
+    this.charMap_ = {};
+    for (var i = 0; i < str.length; i++) {
+      this.charMap_[str.charAt(i)] = i;
+    }
+  }
+};
+
+
+/**
+ * Gets the number encoded in base88 scheme by a substring of given length
+ * and placed at the a given position of the string.
+ * @param {string} str String containing sequence of characters encoding a
+ *     number in base 88 scheme.
+ * @param {number} start Starting position of substring encoding the number.
+ * @param {number} leng Length of the substring encoding the number.
+ * @return {number} The encoded number.
+ * @private
+ */
+goog.i18n.CharListDecompressor.prototype.getCodeAt_ = function(str, start,
+    leng) {
+  var result = 0;
+  for (var i = 0; i < leng; i++) {
+    var c = this.charMap_[str.charAt(start + i)];
+    result += c * Math.pow(88, i);
+  }
+  return result;
+};
+
+
+/**
+ * Add character(s) specified by the value and type to given list and return
+ * the next character in the sequence.
+ * @param {Array<string>} list The list of characters to which the specified
+ *     characters are appended.
+ * @param {number} lastcode The last codepoint that was added to the list.
+ * @param {number} value The value component that representing the delta or
+ *      range.
+ * @param {number} type The type component that representing whether the value
+ *      is a positive or negative delta or range.
+ * @return {number} Last codepoint that is added to the list.
+ * @private
+ */
+goog.i18n.CharListDecompressor.prototype.addChars_ = function(list, lastcode,
+    value, type) {
+   if (type == 0) {
+     lastcode += value + 1;
+     goog.array.extend(list, goog.i18n.uChar.fromCharCode(lastcode));
+   } else if (type == 1) {
+     lastcode -= value + 1;
+     goog.array.extend(list, goog.i18n.uChar.fromCharCode(lastcode));
+   } else if (type == 2) {
+     for (var i = 0; i <= value; i++) {
+       lastcode++;
+       goog.array.extend(list, goog.i18n.uChar.fromCharCode(lastcode));
+     }
+   }
+  return lastcode;
+};
+
+
+/**
+ * Gets the list of characters specified in the given string by base 88 scheme.
+ * @param {string} str The string encoding character list.
+ * @return {!Array<string>} The list of characters specified by the given
+ *     string in base 88 scheme.
+ */
+goog.i18n.CharListDecompressor.prototype.toCharList = function(str) {
+  var metasize = 8;
+  var result = [];
+  var lastcode = 0;
+  var i = 0;
+  while (i < str.length) {
+    var c = this.charMap_[str.charAt(i)];
+    var meta = c % metasize;
+    var type = Math.floor(meta / 3);
+    var leng = (meta % 3) + 1;
+    if (leng == 3) {
+      leng++;
+    }
+    var code = this.getCodeAt_(str, i, leng);
+    var value = Math.floor(code / metasize);
+    lastcode = this.addChars_(result, lastcode, value, type);
+
+    i += leng;
+  }
+  return result;
+};
+


[33/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/samplecomponent.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/samplecomponent.js b/externs/GCL/externs/goog/demos/samplecomponent.js
new file mode 100644
index 0000000..14d3a15
--- /dev/null
+++ b/externs/GCL/externs/goog/demos/samplecomponent.js
@@ -0,0 +1,189 @@
+// 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 A simple, sample component.
+ *
+ */
+goog.provide('goog.demos.SampleComponent');
+
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.classlist');
+goog.require('goog.events.EventType');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.events.KeyHandler');
+goog.require('goog.ui.Component');
+
+
+
+/**
+ * A simple box that changes colour when clicked. This class demonstrates the
+ * goog.ui.Component API, and is keyboard accessible, as per
+ * http://wiki/Main/ClosureKeyboardAccessible
+ *
+ * @param {string=} opt_label A label to display. Defaults to "Click Me" if none
+ *     provided.
+ * @param {goog.dom.DomHelper=} opt_domHelper DOM helper to use.
+ *
+ * @extends {goog.ui.Component}
+ * @constructor
+ * @final
+ */
+goog.demos.SampleComponent = function(opt_label, opt_domHelper) {
+  goog.demos.SampleComponent.base(this, 'constructor', opt_domHelper);
+
+  /**
+   * The label to display.
+   * @type {string}
+   * @private
+   */
+  this.initialLabel_ = opt_label || 'Click Me';
+
+  /**
+   * The current color.
+   * @type {string}
+   * @private
+   */
+  this.color_ = 'red';
+
+  /**
+   * Keyboard handler for this object. This object is created once the
+   * component's DOM element is known.
+   *
+   * @type {goog.events.KeyHandler?}
+   * @private
+   */
+  this.kh_ = null;
+};
+goog.inherits(goog.demos.SampleComponent, goog.ui.Component);
+
+
+/**
+ * Changes the color of the element.
+ * @private
+ */
+goog.demos.SampleComponent.prototype.changeColor_ = function() {
+  if (this.color_ == 'red') {
+    this.color_ = 'green';
+  } else if (this.color_ == 'green') {
+    this.color_ = 'blue';
+  } else {
+    this.color_ = 'red';
+  }
+  this.getElement().style.backgroundColor = this.color_;
+};
+
+
+/**
+ * Creates an initial DOM representation for the component.
+ * @override
+ */
+goog.demos.SampleComponent.prototype.createDom = function() {
+  this.decorateInternal(this.dom_.createElement(goog.dom.TagName.DIV));
+};
+
+
+/**
+ * Decorates an existing HTML DIV element as a SampleComponent.
+ *
+ * @param {Element} element The DIV element to decorate. The element's
+ *    text, if any will be used as the component's label.
+ * @override
+ */
+goog.demos.SampleComponent.prototype.decorateInternal = function(element) {
+  goog.demos.SampleComponent.base(this, 'decorateInternal', element);
+  if (!this.getLabelText()) {
+    this.setLabelText(this.initialLabel_);
+  }
+
+  var elem = this.getElement();
+  goog.dom.classlist.add(elem, goog.getCssName('goog-sample-component'));
+  elem.style.backgroundColor = this.color_;
+  elem.tabIndex = 0;
+
+  this.kh_ = new goog.events.KeyHandler(elem);
+  this.getHandler().listen(this.kh_, goog.events.KeyHandler.EventType.KEY,
+      this.onKey_);
+};
+
+
+/** @override */
+goog.demos.SampleComponent.prototype.disposeInternal = function() {
+  goog.demos.SampleComponent.base(this, 'disposeInternal');
+  if (this.kh_) {
+    this.kh_.dispose();
+  }
+};
+
+
+/**
+ * Called when component's element is known to be in the document.
+ * @override
+ */
+goog.demos.SampleComponent.prototype.enterDocument = function() {
+  goog.demos.SampleComponent.base(this, 'enterDocument');
+  this.getHandler().listen(this.getElement(), goog.events.EventType.CLICK,
+      this.onDivClicked_);
+};
+
+
+/**
+ * Gets the current label text.
+ *
+ * @return {string} The current text set into the label, or empty string if
+ *     none set.
+ */
+goog.demos.SampleComponent.prototype.getLabelText = function() {
+  if (!this.getElement()) {
+    return '';
+  }
+  return goog.dom.getTextContent(this.getElement());
+};
+
+
+/**
+ * Handles DIV element clicks, causing the DIV's colour to change.
+ * @param {goog.events.Event} event The click event.
+ * @private
+ */
+goog.demos.SampleComponent.prototype.onDivClicked_ = function(event) {
+  this.changeColor_();
+};
+
+
+/**
+ * Fired when user presses a key while the DIV has focus. If the user presses
+ * space or enter, the color will be changed.
+ * @param {goog.events.Event} event The key event.
+ * @private
+ */
+goog.demos.SampleComponent.prototype.onKey_ = function(event) {
+  var keyCodes = goog.events.KeyCodes;
+  if (event.keyCode == keyCodes.SPACE || event.keyCode == keyCodes.ENTER) {
+    this.changeColor_();
+  }
+};
+
+
+/**
+ * Sets the current label text. Has no effect if component is not rendered.
+ *
+ * @param {string} text The text to set as the label.
+ */
+goog.demos.SampleComponent.prototype.setLabelText = function(text) {
+  if (this.getElement()) {
+    goog.dom.setTextContent(this.getElement(), text);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/demos/xpc/xpcdemo.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/demos/xpc/xpcdemo.js b/externs/GCL/externs/goog/demos/xpc/xpcdemo.js
new file mode 100644
index 0000000..1e403ee
--- /dev/null
+++ b/externs/GCL/externs/goog/demos/xpc/xpcdemo.js
@@ -0,0 +1,308 @@
+// 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 Contains application code for the XPC demo.
+ * This script is used in both the container page and the iframe.
+ *
+ */
+
+goog.require('goog.Uri');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.events');
+goog.require('goog.events.EventType');
+goog.require('goog.json');
+goog.require('goog.log');
+goog.require('goog.log.Level');
+goog.require('goog.net.xpc.CfgFields');
+goog.require('goog.net.xpc.CrossPageChannel');
+
+
+/**
+ * Namespace for the demo. We don't use goog.provide here because it's not a
+ * real module (cannot be required).
+ */
+var xpcdemo = {};
+
+
+/**
+ * Global function to kick off initialization in the containing document.
+ */
+goog.global.initOuter = function() {
+  goog.events.listen(window, 'load', function() { xpcdemo.initOuter(); });
+};
+
+
+/**
+ * Global function to kick off initialization in the iframe.
+ */
+goog.global.initInner = function() {
+  goog.events.listen(window, 'load', function() { xpcdemo.initInner(); });
+};
+
+
+/**
+ * Initializes XPC in the containing page.
+ */
+xpcdemo.initOuter = function() {
+  // Build the configuration object.
+  var cfg = {};
+
+  var ownUri = new goog.Uri(window.location.href);
+  var relayUri = ownUri.resolve(new goog.Uri('relay.html'));
+  var pollUri = ownUri.resolve(new goog.Uri('blank.html'));
+
+  // Determine the peer domain. Uses the value of the URI-parameter
+  // 'peerdomain'. If that parameter is not present, it falls back to
+  // the own domain so that the demo will work out of the box (but
+  // communication will of course not cross domain-boundaries).  For
+  // real cross-domain communication, the easiest way is to point two
+  // different host-names to the same webserver and then hit the
+  // following URI:
+  // http://host1.com/path/to/closure/demos/xpc/index.html?peerdomain=host2.com
+  var peerDomain = ownUri.getParameterValue('peerdomain') || ownUri.getDomain();
+
+  cfg[goog.net.xpc.CfgFields.LOCAL_RELAY_URI] = relayUri.toString();
+  cfg[goog.net.xpc.CfgFields.PEER_RELAY_URI] =
+      relayUri.setDomain(peerDomain).toString();
+
+  cfg[goog.net.xpc.CfgFields.LOCAL_POLL_URI] = pollUri.toString();
+  cfg[goog.net.xpc.CfgFields.PEER_POLL_URI] =
+      pollUri.setDomain(peerDomain).toString();
+
+
+  // Force transport to be used if tp-parameter is set.
+  var tp = ownUri.getParameterValue('tp');
+  if (tp) {
+    cfg[goog.net.xpc.CfgFields.TRANSPORT] = parseInt(tp, 10);
+  }
+
+
+  // Construct the URI of the peer page.
+
+  var peerUri = ownUri.resolve(
+      new goog.Uri('inner.html')).setDomain(peerDomain);
+  // Passthrough of verbose and compiled flags.
+  if (goog.isDef(ownUri.getParameterValue('verbose'))) {
+    peerUri.setParameterValue('verbose', '');
+  }
+  if (goog.isDef(ownUri.getParameterValue('compiled'))) {
+    peerUri.setParameterValue('compiled', '');
+  }
+
+  cfg[goog.net.xpc.CfgFields.PEER_URI] = peerUri;
+
+  // Instantiate the channel.
+  xpcdemo.channel = new goog.net.xpc.CrossPageChannel(cfg);
+
+  // Create the peer iframe.
+  xpcdemo.peerIframe = xpcdemo.channel.createPeerIframe(
+      goog.dom.getElement('iframeContainer'));
+
+  xpcdemo.initCommon_();
+
+  goog.dom.getElement('inactive').style.display = 'none';
+  goog.dom.getElement('active').style.display = '';
+};
+
+
+/**
+ * Initialization in the iframe.
+ */
+xpcdemo.initInner = function() {
+  // Get the channel configuration passed by the containing document.
+  var cfg = goog.json.parse(
+      (new goog.Uri(window.location.href)).getParameterValue('xpc'));
+
+  xpcdemo.channel = new goog.net.xpc.CrossPageChannel(cfg);
+
+  xpcdemo.initCommon_();
+};
+
+
+/**
+ * Initializes the demo.
+ * Registers service-handlers and connects the channel.
+ * @private
+ */
+xpcdemo.initCommon_ = function() {
+  var xpcLogger = goog.log.getLogger('goog.net.xpc');
+  goog.log.addHandler(xpcLogger, function(logRecord) {
+    xpcdemo.log('[XPC] ' + logRecord.getMessage());
+  });
+  xpcLogger.setLevel(window.location.href.match(/verbose/) ?
+      goog.log.Level.ALL : goog.log.Level.INFO);
+
+  // Register services.
+  xpcdemo.channel.registerService('log', xpcdemo.log);
+  xpcdemo.channel.registerService('ping', xpcdemo.pingHandler_);
+  xpcdemo.channel.registerService('events', xpcdemo.eventsMsgHandler_);
+
+  // Connect the channel.
+  xpcdemo.channel.connect(function() {
+    xpcdemo.channel.send('log', 'Hi from ' + window.location.host);
+    goog.events.listen(goog.dom.getElement('clickfwd'),
+                       'click', xpcdemo.mouseEventHandler_);
+  });
+};
+
+
+/**
+ * Kills the peer iframe and the disposes the channel.
+ */
+xpcdemo.teardown = function() {
+  goog.events.unlisten(goog.dom.getElement('clickfwd'),
+                       goog.events.EventType.CLICK, xpcdemo.mouseEventHandler_);
+
+  xpcdemo.channel.dispose();
+  delete xpcdemo.channel;
+
+  goog.dom.removeNode(xpcdemo.peerIframe);
+  xpcdemo.peerIframe = null;
+
+  goog.dom.getElement('inactive').style.display = '';
+  goog.dom.getElement('active').style.display = 'none';
+};
+
+
+/**
+ * Logging function. Inserts log-message into element with it id 'console'.
+ * @param {string} msgString The log-message.
+ */
+xpcdemo.log = function(msgString) {
+  xpcdemo.consoleElm || (xpcdemo.consoleElm = goog.dom.getElement('console'));
+  var msgElm = goog.dom.createDom(goog.dom.TagName.DIV);
+  msgElm.innerHTML = msgString;
+  xpcdemo.consoleElm.insertBefore(msgElm, xpcdemo.consoleElm.firstChild);
+};
+
+
+/**
+ * Sends a ping request to the peer.
+ */
+xpcdemo.ping = function() {
+  // send current time
+  xpcdemo.channel.send('ping', goog.now() + '');
+};
+
+
+/**
+ * The handler function for incoming pings (messages sent to the service
+ * called 'ping');
+ * @param {string} payload The message payload.
+ * @private
+ */
+xpcdemo.pingHandler_ = function(payload) {
+  // is the incoming message a response to a ping we sent?
+  if (payload.charAt(0) == '#') {
+    // calculate roundtrip time and log
+    var dt = goog.now() - parseInt(payload.substring(1), 10);
+    xpcdemo.log('roundtrip: ' + dt + 'ms');
+  } else {
+    // incoming message is a ping initiated from peer
+    // -> prepend with '#' and send back
+    xpcdemo.channel.send('ping', '#' + payload);
+    xpcdemo.log('ping reply sent');
+  }
+};
+
+
+/**
+ * Counter for mousemove events.
+ * @type {number}
+ * @private
+ */
+xpcdemo.mmCount_ = 0;
+
+
+/**
+ * Holds timestamp when the last mousemove rate has been logged.
+ * @type {number}
+ * @private
+ */
+xpcdemo.mmLastRateOutput_ = 0;
+
+
+/**
+ * Start mousemove event forwarding. Registers a listener on the document which
+ * sends them over the channel.
+ */
+xpcdemo.startMousemoveForwarding = function() {
+  goog.events.listen(document, goog.events.EventType.MOUSEMOVE,
+                     xpcdemo.mouseEventHandler_);
+  xpcdemo.mmLastRateOutput_ = goog.now();
+};
+
+
+/**
+ * Stop mousemove event forwarding.
+ */
+xpcdemo.stopMousemoveForwarding = function() {
+  goog.events.unlisten(document, goog.events.EventType.MOUSEMOVE,
+                       xpcdemo.mouseEventHandler_);
+};
+
+
+/**
+ * Function to be used as handler for mouse-events.
+ * @param {goog.events.BrowserEvent} e The mouse event.
+ * @private
+ */
+xpcdemo.mouseEventHandler_ = function(e) {
+  xpcdemo.channel.send('events',
+      [e.type, e.clientX, e.clientY, goog.now()].join(','));
+};
+
+
+/**
+ * Handler for the 'events' service.
+ * @param {string} payload The string returned from the xpcdemo.
+ * @private
+ */
+xpcdemo.eventsMsgHandler_ = function(payload) {
+  var now = goog.now();
+  var args = payload.split(',');
+  var type = args[0];
+  var pageX = args[1];
+  var pageY = args[2];
+  var time = parseInt(args[3], 10);
+
+  var msg = type + ': (' + pageX + ',' + pageY + '), latency: ' + (now - time);
+  xpcdemo.log(msg);
+
+  if (type == goog.events.EventType.MOUSEMOVE) {
+    xpcdemo.mmCount_++;
+    var dt = now - xpcdemo.mmLastRateOutput_;
+    if (dt > 1000) {
+      msg = 'RATE (mousemove/s): ' + (1000 * xpcdemo.mmCount_ / dt);
+      xpcdemo.log(msg);
+      xpcdemo.mmLastRateOutput_ = now;
+      xpcdemo.mmCount_ = 0;
+    }
+  }
+};
+
+
+/**
+ * Send multiple messages.
+ * @param {number} n The number of messages to send.
+ */
+xpcdemo.sendN = function(n) {
+  xpcdemo.count_ || (xpcdemo.count_ = 1);
+
+  for (var i = 0; i < n; i++) {
+    xpcdemo.channel.send('log', '' + xpcdemo.count_++);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/disposable/disposable.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/disposable/disposable.js b/externs/GCL/externs/goog/disposable/disposable.js
new file mode 100644
index 0000000..d9c89d9
--- /dev/null
+++ b/externs/GCL/externs/goog/disposable/disposable.js
@@ -0,0 +1,307 @@
+// Copyright 2005 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 Implements the disposable interface. The dispose method is used
+ * to clean up references and resources.
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+goog.provide('goog.Disposable');
+/** @suppress {extraProvide} */
+goog.provide('goog.dispose');
+/** @suppress {extraProvide} */
+goog.provide('goog.disposeAll');
+
+goog.require('goog.disposable.IDisposable');
+
+
+
+/**
+ * Class that provides the basic implementation for disposable objects. If your
+ * class holds one or more references to COM objects, DOM nodes, or other
+ * disposable objects, it should extend this class or implement the disposable
+ * interface (defined in goog.disposable.IDisposable).
+ * @constructor
+ * @implements {goog.disposable.IDisposable}
+ */
+goog.Disposable = function() {
+  if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {
+    if (goog.Disposable.INCLUDE_STACK_ON_CREATION) {
+      this.creationStack = new Error().stack;
+    }
+    goog.Disposable.instances_[goog.getUid(this)] = this;
+  }
+  // Support sealing
+  this.disposed_ = this.disposed_;
+  this.onDisposeCallbacks_ = this.onDisposeCallbacks_;
+};
+
+
+/**
+ * @enum {number} Different monitoring modes for Disposable.
+ */
+goog.Disposable.MonitoringMode = {
+  /**
+   * No monitoring.
+   */
+  OFF: 0,
+  /**
+   * Creating and disposing the goog.Disposable instances is monitored. All
+   * disposable objects need to call the {@code goog.Disposable} base
+   * constructor. The PERMANENT mode must be switched on before creating any
+   * goog.Disposable instances.
+   */
+  PERMANENT: 1,
+  /**
+   * INTERACTIVE mode can be switched on and off on the fly without producing
+   * errors. It also doesn't warn if the disposable objects don't call the
+   * {@code goog.Disposable} base constructor.
+   */
+  INTERACTIVE: 2
+};
+
+
+/**
+ * @define {number} The monitoring mode of the goog.Disposable
+ *     instances. Default is OFF. Switching on the monitoring is only
+ *     recommended for debugging because it has a significant impact on
+ *     performance and memory usage. If switched off, the monitoring code
+ *     compiles down to 0 bytes.
+ */
+goog.define('goog.Disposable.MONITORING_MODE', 0);
+
+
+/**
+ * @define {boolean} Whether to attach creation stack to each created disposable
+ *     instance; This is only relevant for when MonitoringMode != OFF.
+ */
+goog.define('goog.Disposable.INCLUDE_STACK_ON_CREATION', true);
+
+
+/**
+ * Maps the unique ID of every undisposed {@code goog.Disposable} object to
+ * the object itself.
+ * @type {!Object<number, !goog.Disposable>}
+ * @private
+ */
+goog.Disposable.instances_ = {};
+
+
+/**
+ * @return {!Array<!goog.Disposable>} All {@code goog.Disposable} objects that
+ *     haven't been disposed of.
+ */
+goog.Disposable.getUndisposedObjects = function() {
+  var ret = [];
+  for (var id in goog.Disposable.instances_) {
+    if (goog.Disposable.instances_.hasOwnProperty(id)) {
+      ret.push(goog.Disposable.instances_[Number(id)]);
+    }
+  }
+  return ret;
+};
+
+
+/**
+ * Clears the registry of undisposed objects but doesn't dispose of them.
+ */
+goog.Disposable.clearUndisposedObjects = function() {
+  goog.Disposable.instances_ = {};
+};
+
+
+/**
+ * Whether the object has been disposed of.
+ * @type {boolean}
+ * @private
+ */
+goog.Disposable.prototype.disposed_ = false;
+
+
+/**
+ * Callbacks to invoke when this object is disposed.
+ * @type {Array<!Function>}
+ * @private
+ */
+goog.Disposable.prototype.onDisposeCallbacks_;
+
+
+/**
+ * If monitoring the goog.Disposable instances is enabled, stores the creation
+ * stack trace of the Disposable instance.
+ * @const {string}
+ */
+goog.Disposable.prototype.creationStack;
+
+
+/**
+ * @return {boolean} Whether the object has been disposed of.
+ * @override
+ */
+goog.Disposable.prototype.isDisposed = function() {
+  return this.disposed_;
+};
+
+
+/**
+ * @return {boolean} Whether the object has been disposed of.
+ * @deprecated Use {@link #isDisposed} instead.
+ */
+goog.Disposable.prototype.getDisposed = goog.Disposable.prototype.isDisposed;
+
+
+/**
+ * Disposes of the object. If the object hasn't already been disposed of, calls
+ * {@link #disposeInternal}. Classes that extend {@code goog.Disposable} should
+ * override {@link #disposeInternal} in order to delete references to COM
+ * objects, DOM nodes, and other disposable objects. Reentrant.
+ *
+ * @return {void} Nothing.
+ * @override
+ */
+goog.Disposable.prototype.dispose = function() {
+  if (!this.disposed_) {
+    // Set disposed_ to true first, in case during the chain of disposal this
+    // gets disposed recursively.
+    this.disposed_ = true;
+    this.disposeInternal();
+    if (goog.Disposable.MONITORING_MODE != goog.Disposable.MonitoringMode.OFF) {
+      var uid = goog.getUid(this);
+      if (goog.Disposable.MONITORING_MODE ==
+          goog.Disposable.MonitoringMode.PERMANENT &&
+          !goog.Disposable.instances_.hasOwnProperty(uid)) {
+        throw Error(this + ' did not call the goog.Disposable base ' +
+            'constructor or was disposed of after a clearUndisposedObjects ' +
+            'call');
+      }
+      delete goog.Disposable.instances_[uid];
+    }
+  }
+};
+
+
+/**
+ * Associates a disposable object with this object so that they will be disposed
+ * together.
+ * @param {goog.disposable.IDisposable} disposable that will be disposed when
+ *     this object is disposed.
+ */
+goog.Disposable.prototype.registerDisposable = function(disposable) {
+  this.addOnDisposeCallback(goog.partial(goog.dispose, disposable));
+};
+
+
+/**
+ * Invokes a callback function when this object is disposed. Callbacks are
+ * invoked in the order in which they were added. If a callback is added to
+ * an already disposed Disposable, it will be called immediately.
+ * @param {function(this:T):?} callback The callback function.
+ * @param {T=} opt_scope An optional scope to call the callback in.
+ * @template T
+ */
+goog.Disposable.prototype.addOnDisposeCallback = function(callback, opt_scope) {
+  if (this.disposed_) {
+    callback.call(opt_scope);
+    return;
+  }
+  if (!this.onDisposeCallbacks_) {
+    this.onDisposeCallbacks_ = [];
+  }
+
+  this.onDisposeCallbacks_.push(
+      goog.isDef(opt_scope) ? goog.bind(callback, opt_scope) : callback);
+};
+
+
+/**
+ * Deletes or nulls out any references to COM objects, DOM nodes, or other
+ * disposable objects. Classes that extend {@code goog.Disposable} should
+ * override this method.
+ * Not reentrant. To avoid calling it twice, it must only be called from the
+ * subclass' {@code disposeInternal} method. Everywhere else the public
+ * {@code dispose} method must be used.
+ * For example:
+ * <pre>
+ *   mypackage.MyClass = function() {
+ *     mypackage.MyClass.base(this, 'constructor');
+ *     // Constructor logic specific to MyClass.
+ *     ...
+ *   };
+ *   goog.inherits(mypackage.MyClass, goog.Disposable);
+ *
+ *   mypackage.MyClass.prototype.disposeInternal = function() {
+ *     // Dispose logic specific to MyClass.
+ *     ...
+ *     // Call superclass's disposeInternal at the end of the subclass's, like
+ *     // in C++, to avoid hard-to-catch issues.
+ *     mypackage.MyClass.base(this, 'disposeInternal');
+ *   };
+ * </pre>
+ * @protected
+ */
+goog.Disposable.prototype.disposeInternal = function() {
+  if (this.onDisposeCallbacks_) {
+    while (this.onDisposeCallbacks_.length) {
+      this.onDisposeCallbacks_.shift()();
+    }
+  }
+};
+
+
+/**
+ * Returns True if we can verify the object is disposed.
+ * Calls {@code isDisposed} on the argument if it supports it.  If obj
+ * is not an object with an isDisposed() method, return false.
+ * @param {*} obj The object to investigate.
+ * @return {boolean} True if we can verify the object is disposed.
+ */
+goog.Disposable.isDisposed = function(obj) {
+  if (obj && typeof obj.isDisposed == 'function') {
+    return obj.isDisposed();
+  }
+  return false;
+};
+
+
+/**
+ * Calls {@code dispose} on the argument if it supports it. If obj is not an
+ *     object with a dispose() method, this is a no-op.
+ * @param {*} obj The object to dispose of.
+ */
+goog.dispose = function(obj) {
+  if (obj && typeof obj.dispose == 'function') {
+    obj.dispose();
+  }
+};
+
+
+/**
+ * Calls {@code dispose} on each member of the list that supports it. (If the
+ * member is an ArrayLike, then {@code goog.disposeAll()} will be called
+ * recursively on each of its members.) If the member is not an object with a
+ * {@code dispose()} method, then it is ignored.
+ * @param {...*} var_args The list.
+ */
+goog.disposeAll = function(var_args) {
+  for (var i = 0, len = arguments.length; i < len; ++i) {
+    var disposable = arguments[i];
+    if (goog.isArrayLike(disposable)) {
+      goog.disposeAll.apply(null, disposable);
+    } else {
+      goog.dispose(disposable);
+    }
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/disposable/idisposable.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/disposable/idisposable.js b/externs/GCL/externs/goog/disposable/idisposable.js
new file mode 100644
index 0000000..917d17e
--- /dev/null
+++ b/externs/GCL/externs/goog/disposable/idisposable.js
@@ -0,0 +1,45 @@
+// Copyright 2011 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 disposable interface.  A disposable object
+ * has a dispose method to to clean up references and resources.
+ * @author nnaze@google.com (Nathan Naze)
+ */
+
+
+goog.provide('goog.disposable.IDisposable');
+
+
+
+/**
+ * Interface for a disposable object.  If a instance requires cleanup
+ * (references COM objects, DOM notes, or other disposable objects), it should
+ * implement this interface (it may subclass goog.Disposable).
+ * @interface
+ */
+goog.disposable.IDisposable = function() {};
+
+
+/**
+ * Disposes of the object and its resources.
+ * @return {void} Nothing.
+ */
+goog.disposable.IDisposable.prototype.dispose = goog.abstractMethod;
+
+
+/**
+ * @return {boolean} Whether the object has been disposed of.
+ */
+goog.disposable.IDisposable.prototype.isDisposed = goog.abstractMethod;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/abstractmultirange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/abstractmultirange.js b/externs/GCL/externs/goog/dom/abstractmultirange.js
new file mode 100644
index 0000000..d45d38d
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/abstractmultirange.js
@@ -0,0 +1,76 @@
+// Copyright 2008 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 working with ranges comprised of multiple
+ * sub-ranges.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.AbstractMultiRange');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.AbstractRange');
+
+
+
+/**
+ * Creates a new multi range with no properties.  Do not use this
+ * constructor: use one of the goog.dom.Range.createFrom* methods instead.
+ * @constructor
+ * @extends {goog.dom.AbstractRange}
+ */
+goog.dom.AbstractMultiRange = function() {
+};
+goog.inherits(goog.dom.AbstractMultiRange, goog.dom.AbstractRange);
+
+
+/** @override */
+goog.dom.AbstractMultiRange.prototype.containsRange = function(
+    otherRange, opt_allowPartial) {
+  // TODO(user): This will incorrectly return false if two (or more) adjacent
+  // elements are both in the control range, and are also in the text range
+  // being compared to.
+  var ranges = this.getTextRanges();
+  var otherRanges = otherRange.getTextRanges();
+
+  var fn = opt_allowPartial ? goog.array.some : goog.array.every;
+  return fn(otherRanges, function(otherRange) {
+    return goog.array.some(ranges, function(range) {
+      return range.containsRange(otherRange, opt_allowPartial);
+    });
+  });
+};
+
+
+/** @override */
+goog.dom.AbstractMultiRange.prototype.insertNode = function(node, before) {
+  if (before) {
+    goog.dom.insertSiblingBefore(node, this.getStartNode());
+  } else {
+    goog.dom.insertSiblingAfter(node, this.getEndNode());
+  }
+  return node;
+};
+
+
+/** @override */
+goog.dom.AbstractMultiRange.prototype.surroundWithNodes = function(startNode,
+    endNode) {
+  this.insertNode(startNode, true);
+  this.insertNode(endNode, false);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/abstractrange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/abstractrange.js b/externs/GCL/externs/goog/dom/abstractrange.js
new file mode 100644
index 0000000..7d66bfb
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/abstractrange.js
@@ -0,0 +1,529 @@
+// 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 Interface definitions for working with ranges
+ * in HTML documents.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.AbstractRange');
+goog.provide('goog.dom.RangeIterator');
+goog.provide('goog.dom.RangeType');
+
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.SavedCaretRange');
+goog.require('goog.dom.TagIterator');
+goog.require('goog.userAgent');
+
+
+/**
+ * Types of ranges.
+ * @enum {string}
+ */
+goog.dom.RangeType = {
+  TEXT: 'text',
+  CONTROL: 'control',
+  MULTI: 'mutli'
+};
+
+
+
+/**
+ * Creates a new selection with no properties.  Do not use this constructor -
+ * use one of the goog.dom.Range.from* methods instead.
+ * @constructor
+ */
+goog.dom.AbstractRange = function() {
+};
+
+
+/**
+ * Gets the browser native selection object from the given window.
+ * @param {Window} win The window to get the selection object from.
+ * @return {Object} The browser native selection object, or null if it could
+ *     not be retrieved.
+ */
+goog.dom.AbstractRange.getBrowserSelectionForWindow = function(win) {
+  if (win.getSelection) {
+    // W3C
+    return win.getSelection();
+  } else {
+    // IE
+    var doc = win.document;
+    var sel = doc.selection;
+    if (sel) {
+      // IE has a bug where it sometimes returns a selection from the wrong
+      // document. Catching these cases now helps us avoid problems later.
+      try {
+        var range = sel.createRange();
+        // Only TextRanges have a parentElement method.
+        if (range.parentElement) {
+          if (range.parentElement().document != doc) {
+            return null;
+          }
+        } else if (!range.length ||
+            /** @type {ControlRange} */ (range).item(0).document != doc) {
+          // For ControlRanges, check that the range has items, and that
+          // the first item in the range is in the correct document.
+          return null;
+        }
+      } catch (e) {
+        // If the selection is in the wrong document, and the wrong document is
+        // in a different domain, IE will throw an exception.
+        return null;
+      }
+      // TODO(user|robbyw) Sometimes IE 6 returns a selection instance
+      // when there is no selection.  This object has a 'type' property equals
+      // to 'None' and a typeDetail property bound to undefined. Ideally this
+      // function should not return this instance.
+      return sel;
+    }
+    return null;
+  }
+};
+
+
+/**
+ * Tests if the given Object is a controlRange.
+ * @param {Object} range The range object to test.
+ * @return {boolean} Whether the given Object is a controlRange.
+ */
+goog.dom.AbstractRange.isNativeControlRange = function(range) {
+  // For now, tests for presence of a control range function.
+  return !!range && !!range.addElement;
+};
+
+
+/**
+ * @return {!goog.dom.AbstractRange} A clone of this range.
+ */
+goog.dom.AbstractRange.prototype.clone = goog.abstractMethod;
+
+
+/**
+ * @return {goog.dom.RangeType} The type of range represented by this object.
+ */
+goog.dom.AbstractRange.prototype.getType = goog.abstractMethod;
+
+
+/**
+ * @return {Range|TextRange} The native browser range object.
+ */
+goog.dom.AbstractRange.prototype.getBrowserRangeObject = goog.abstractMethod;
+
+
+/**
+ * Sets the native browser range object, overwriting any state this range was
+ * storing.
+ * @param {Range|TextRange} nativeRange The native browser range object.
+ * @return {boolean} Whether the given range was accepted.  If not, the caller
+ *     will need to call goog.dom.Range.createFromBrowserRange to create a new
+ *     range object.
+ */
+goog.dom.AbstractRange.prototype.setBrowserRangeObject = function(nativeRange) {
+  return false;
+};
+
+
+/**
+ * @return {number} The number of text ranges in this range.
+ */
+goog.dom.AbstractRange.prototype.getTextRangeCount = goog.abstractMethod;
+
+
+/**
+ * Get the i-th text range in this range.  The behavior is undefined if
+ * i >= getTextRangeCount or i < 0.
+ * @param {number} i The range number to retrieve.
+ * @return {goog.dom.TextRange} The i-th text range.
+ */
+goog.dom.AbstractRange.prototype.getTextRange = goog.abstractMethod;
+
+
+/**
+ * Gets an array of all text ranges this range is comprised of.  For non-multi
+ * ranges, returns a single element array containing this.
+ * @return {!Array<goog.dom.TextRange>} Array of text ranges.
+ */
+goog.dom.AbstractRange.prototype.getTextRanges = function() {
+  var output = [];
+  for (var i = 0, len = this.getTextRangeCount(); i < len; i++) {
+    output.push(this.getTextRange(i));
+  }
+  return output;
+};
+
+
+/**
+ * @return {Node} The deepest node that contains the entire range.
+ */
+goog.dom.AbstractRange.prototype.getContainer = goog.abstractMethod;
+
+
+/**
+ * Returns the deepest element in the tree that contains the entire range.
+ * @return {Element} The deepest element that contains the entire range.
+ */
+goog.dom.AbstractRange.prototype.getContainerElement = function() {
+  var node = this.getContainer();
+  return /** @type {Element} */ (
+      node.nodeType == goog.dom.NodeType.ELEMENT ? node : node.parentNode);
+};
+
+
+/**
+ * @return {Node} The element or text node the range starts in.  For text
+ *     ranges, the range comprises all text between the start and end position.
+ *     For other types of range, start and end give bounds of the range but
+ *     do not imply all nodes in those bounds are selected.
+ */
+goog.dom.AbstractRange.prototype.getStartNode = goog.abstractMethod;
+
+
+/**
+ * @return {number} The offset into the node the range starts in.  For text
+ *     nodes, this is an offset into the node value.  For elements, this is
+ *     an offset into the childNodes array.
+ */
+goog.dom.AbstractRange.prototype.getStartOffset = goog.abstractMethod;
+
+
+/**
+ * @return {goog.math.Coordinate} The coordinate of the selection start node
+ *     and offset.
+ */
+goog.dom.AbstractRange.prototype.getStartPosition = goog.abstractMethod;
+
+
+/**
+ * @return {Node} The element or text node the range ends in.
+ */
+goog.dom.AbstractRange.prototype.getEndNode = goog.abstractMethod;
+
+
+/**
+ * @return {number} The offset into the node the range ends in.  For text
+ *     nodes, this is an offset into the node value.  For elements, this is
+ *     an offset into the childNodes array.
+ */
+goog.dom.AbstractRange.prototype.getEndOffset = goog.abstractMethod;
+
+
+/**
+ * @return {goog.math.Coordinate} The coordinate of the selection end
+ *     node and offset.
+ */
+goog.dom.AbstractRange.prototype.getEndPosition = goog.abstractMethod;
+
+
+/**
+ * @return {Node} The element or text node the range is anchored at.
+ */
+goog.dom.AbstractRange.prototype.getAnchorNode = function() {
+  return this.isReversed() ? this.getEndNode() : this.getStartNode();
+};
+
+
+/**
+ * @return {number} The offset into the node the range is anchored at.  For
+ *     text nodes, this is an offset into the node value.  For elements, this
+ *     is an offset into the childNodes array.
+ */
+goog.dom.AbstractRange.prototype.getAnchorOffset = function() {
+  return this.isReversed() ? this.getEndOffset() : this.getStartOffset();
+};
+
+
+/**
+ * @return {Node} The element or text node the range is focused at - i.e. where
+ *     the cursor is.
+ */
+goog.dom.AbstractRange.prototype.getFocusNode = function() {
+  return this.isReversed() ? this.getStartNode() : this.getEndNode();
+};
+
+
+/**
+ * @return {number} The offset into the node the range is focused at - i.e.
+ *     where the cursor is.  For text nodes, this is an offset into the node
+ *     value.  For elements, this is an offset into the childNodes array.
+ */
+goog.dom.AbstractRange.prototype.getFocusOffset = function() {
+  return this.isReversed() ? this.getStartOffset() : this.getEndOffset();
+};
+
+
+/**
+ * @return {boolean} Whether the selection is reversed.
+ */
+goog.dom.AbstractRange.prototype.isReversed = function() {
+  return false;
+};
+
+
+/**
+ * @return {!Document} The document this selection is a part of.
+ */
+goog.dom.AbstractRange.prototype.getDocument = function() {
+  // Using start node in IE was crashing the browser in some cases so use
+  // getContainer for that browser. It's also faster for IE, but still slower
+  // than start node for other browsers so we continue to use getStartNode when
+  // it is not problematic. See bug 1687309.
+  return goog.dom.getOwnerDocument(goog.userAgent.IE ?
+      this.getContainer() : this.getStartNode());
+};
+
+
+/**
+ * @return {!Window} The window this selection is a part of.
+ */
+goog.dom.AbstractRange.prototype.getWindow = function() {
+  return goog.dom.getWindow(this.getDocument());
+};
+
+
+/**
+ * Tests if this range contains the given range.
+ * @param {goog.dom.AbstractRange} range The range to test.
+ * @param {boolean=} opt_allowPartial If true, the range can be partially
+ *     contained in the selection, otherwise the range must be entirely
+ *     contained.
+ * @return {boolean} Whether this range contains the given range.
+ */
+goog.dom.AbstractRange.prototype.containsRange = goog.abstractMethod;
+
+
+/**
+ * Tests if this range contains the given node.
+ * @param {Node} node The node to test for.
+ * @param {boolean=} opt_allowPartial If not set or false, the node must be
+ *     entirely contained in the selection for this function to return true.
+ * @return {boolean} Whether this range contains the given node.
+ */
+goog.dom.AbstractRange.prototype.containsNode = function(node,
+    opt_allowPartial) {
+  return this.containsRange(goog.dom.Range.createFromNodeContents(node),
+      opt_allowPartial);
+};
+
+
+/**
+ * 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.AbstractRange.prototype.isRangeInDocument = goog.abstractMethod;
+
+
+/**
+ * @return {boolean} Whether the range is collapsed.
+ */
+goog.dom.AbstractRange.prototype.isCollapsed = goog.abstractMethod;
+
+
+/**
+ * @return {string} The text content of the range.
+ */
+goog.dom.AbstractRange.prototype.getText = goog.abstractMethod;
+
+
+/**
+ * Returns the HTML fragment this range selects.  This is slow on all browsers.
+ * The HTML fragment may not be valid HTML, for instance if the user selects
+ * from a to b inclusively in the following html:
+ *
+ * &gt;div&lt;a&gt;/div&lt;b
+ *
+ * This method will return
+ *
+ * a&lt;/div&gt;b
+ *
+ * If you need valid HTML, use {@link #getValidHtml} instead.
+ *
+ * @return {string} HTML fragment of the range, does not include context
+ *     containing elements.
+ */
+goog.dom.AbstractRange.prototype.getHtmlFragment = goog.abstractMethod;
+
+
+/**
+ * Returns valid HTML for this range.  This is fast on IE, and semi-fast on
+ * other browsers.
+ * @return {string} Valid HTML of the range, including context containing
+ *     elements.
+ */
+goog.dom.AbstractRange.prototype.getValidHtml = goog.abstractMethod;
+
+
+/**
+ * Returns pastable HTML for this range.  This guarantees that any child items
+ * that must have specific ancestors will have them, for instance all TDs will
+ * be contained in a TR in a TBODY in a TABLE and all LIs will be contained in
+ * a UL or OL as appropriate.  This is semi-fast on all browsers.
+ * @return {string} Pastable HTML of the range, including context containing
+ *     elements.
+ */
+goog.dom.AbstractRange.prototype.getPastableHtml = goog.abstractMethod;
+
+
+/**
+ * Returns a RangeIterator over the contents of the range.  Regardless of the
+ * direction of the range, the iterator will move in document order.
+ * @param {boolean=} opt_keys Unused for this iterator.
+ * @return {!goog.dom.RangeIterator} An iterator over tags in the range.
+ */
+goog.dom.AbstractRange.prototype.__iterator__ = goog.abstractMethod;
+
+
+// RANGE ACTIONS
+
+
+/**
+ * Sets this range as the selection in its window.
+ */
+goog.dom.AbstractRange.prototype.select = goog.abstractMethod;
+
+
+/**
+ * Removes the contents of the range from the document.
+ */
+goog.dom.AbstractRange.prototype.removeContents = goog.abstractMethod;
+
+
+/**
+ * Inserts a node before (or after) the range.  The range may be disrupted
+ * beyond recovery because of the way this splits nodes.
+ * @param {Node} node The node to insert.
+ * @param {boolean} before True to insert before, false to insert after.
+ * @return {Node} The node added to the document.  This may be different
+ *     than the node parameter because on IE we have to clone it.
+ */
+goog.dom.AbstractRange.prototype.insertNode = goog.abstractMethod;
+
+
+/**
+ * Replaces the range contents with (possibly a copy of) the given node.  The
+ * range may be disrupted beyond recovery because of the way this splits nodes.
+ * @param {Node} node The node to insert.
+ * @return {Node} The node added to the document.  This may be different
+ *     than the node parameter because on IE we have to clone it.
+ */
+goog.dom.AbstractRange.prototype.replaceContentsWithNode = function(node) {
+  if (!this.isCollapsed()) {
+    this.removeContents();
+  }
+
+  return this.insertNode(node, true);
+};
+
+
+/**
+ * Surrounds this range with the two given nodes.  The range may be disrupted
+ * beyond recovery because of the way this splits nodes.
+ * @param {Element} startNode The node to insert at the start.
+ * @param {Element} endNode The node to insert at the end.
+ */
+goog.dom.AbstractRange.prototype.surroundWithNodes = goog.abstractMethod;
+
+
+// SAVE/RESTORE
+
+
+/**
+ * Saves the range so that if the start and end nodes are left alone, it can
+ * be restored.
+ * @return {!goog.dom.SavedRange} A range representation that can be restored
+ *     as long as the endpoint nodes of the selection are not modified.
+ */
+goog.dom.AbstractRange.prototype.saveUsingDom = goog.abstractMethod;
+
+
+/**
+ * Saves the range using HTML carets. As long as the carets remained in the
+ * HTML, the range can be restored...even when the HTML is copied across
+ * documents.
+ * @return {goog.dom.SavedCaretRange?} A range representation that can be
+ *     restored as long as carets are not removed. Returns null if carets
+ *     could not be created.
+ */
+goog.dom.AbstractRange.prototype.saveUsingCarets = function() {
+  return (this.getStartNode() && this.getEndNode()) ?
+      new goog.dom.SavedCaretRange(this) : null;
+};
+
+
+// RANGE MODIFICATION
+
+
+/**
+ * Collapses the range to one of its boundary points.
+ * @param {boolean} toAnchor Whether to collapse to the anchor of the range.
+ */
+goog.dom.AbstractRange.prototype.collapse = goog.abstractMethod;
+
+// RANGE ITERATION
+
+
+
+/**
+ * Subclass of goog.dom.TagIterator that iterates over a DOM range.  It
+ * adds functions to determine the portion of each text node that is selected.
+ * @param {Node} node The node to start traversal at.  When null, creates an
+ *     empty iterator.
+ * @param {boolean=} opt_reverse Whether to traverse nodes in reverse.
+ * @constructor
+ * @extends {goog.dom.TagIterator}
+ */
+goog.dom.RangeIterator = function(node, opt_reverse) {
+  goog.dom.TagIterator.call(this, node, opt_reverse, true);
+};
+goog.inherits(goog.dom.RangeIterator, goog.dom.TagIterator);
+
+
+/**
+ * @return {number} The offset into the current node, or -1 if the current node
+ *     is not a text node.
+ */
+goog.dom.RangeIterator.prototype.getStartTextOffset = goog.abstractMethod;
+
+
+/**
+ * @return {number} The end offset into the current node, or -1 if the current
+ *     node is not a text node.
+ */
+goog.dom.RangeIterator.prototype.getEndTextOffset = goog.abstractMethod;
+
+
+/**
+ * @return {Node} node The iterator's start node.
+ */
+goog.dom.RangeIterator.prototype.getStartNode = goog.abstractMethod;
+
+
+/**
+ * @return {Node} The iterator's end node.
+ */
+goog.dom.RangeIterator.prototype.getEndNode = goog.abstractMethod;
+
+
+/**
+ * @return {boolean} Whether a call to next will fail.
+ */
+goog.dom.RangeIterator.prototype.isLast = goog.abstractMethod;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/animationframe/animationframe.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/animationframe/animationframe.js b/externs/GCL/externs/goog/dom/animationframe/animationframe.js
new file mode 100644
index 0000000..b9bccff
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/animationframe/animationframe.js
@@ -0,0 +1,287 @@
+// Copyright 2014 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 goog.dom.animationFrame permits work to be done in-sync with
+ * the render refresh rate of the browser and to divide work up globally based
+ * on whether the intent is to measure or to mutate the DOM. The latter avoids
+ * repeated style recalculation which can be really slow.
+ *
+ * Goals of the API:
+ * <ul>
+ *   <li>Make it easy to schedule work for the next animation frame.
+ *   <li>Make it easy to only do work once per animation frame, even if two
+ *       events fire that trigger the same work.
+ *   <li>Make it easy to do all work in two phases to avoid repeated style
+ *       recalculation caused by interleaved reads and writes.
+ *   <li>Avoid creating closures per schedule operation.
+ * </ul>
+ *
+ *
+ * Programmatic:
+ * <pre>
+ * var animationTask = goog.dom.animationFrame.createTask({
+ *     measure: function(state) {
+ *       state.width = goog.style.getSize(elem).width;
+ *       this.animationTask();
+ *     },
+ *     mutate: function(state) {
+ *       goog.style.setWidth(elem, Math.floor(state.width / 2));
+ *     }
+ *   }, this);
+ * });
+ * </pre>
+ *
+ * See also
+ * https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame
+ */
+
+goog.provide('goog.dom.animationFrame');
+goog.provide('goog.dom.animationFrame.Spec');
+goog.provide('goog.dom.animationFrame.State');
+
+goog.require('goog.dom.animationFrame.polyfill');
+
+// Install the polyfill.
+goog.dom.animationFrame.polyfill.install();
+
+
+/**
+ * @typedef {{
+ *   id: number,
+ *   fn: !Function,
+ *   context: (!Object|undefined)
+ * }}
+ * @private
+ */
+goog.dom.animationFrame.Task_;
+
+
+/**
+ * @typedef {{
+ *   measureTask: goog.dom.animationFrame.Task_,
+ *   mutateTask: goog.dom.animationFrame.Task_,
+ *   state: (!Object|undefined),
+ *   args: (!Array|undefined),
+ *   isScheduled: boolean
+ * }}
+ * @private
+ */
+goog.dom.animationFrame.TaskSet_;
+
+
+/**
+ * @typedef {{
+ *   measure: (!Function|undefined),
+ *   mutate: (!Function|undefined)
+ * }}
+ */
+goog.dom.animationFrame.Spec;
+
+
+
+/**
+ * A type to represent state. Users may add properties as desired.
+ * @constructor
+ * @final
+ */
+goog.dom.animationFrame.State = function() {};
+
+
+/**
+ * Saves a set of tasks to be executed in the next requestAnimationFrame phase.
+ * This list is initialized once before any event firing occurs. It is not
+ * affected by the fired events or the requestAnimationFrame processing (unless
+ * a new event is created during the processing).
+ * @private {!Array<!Array<goog.dom.animationFrame.TaskSet_>>}
+ */
+goog.dom.animationFrame.tasks_ = [[], []];
+
+
+/**
+ * Values are 0 or 1, for whether the first or second array should be used to
+ * lookup or add tasks.
+ * @private {number}
+ */
+goog.dom.animationFrame.doubleBufferIndex_ = 0;
+
+
+/**
+ * Whether we have already requested an animation frame that hasn't happened
+ * yet.
+ * @private {boolean}
+ */
+goog.dom.animationFrame.requestedFrame_ = false;
+
+
+/**
+ * Counter to generate IDs for tasks.
+ * @private {number}
+ */
+goog.dom.animationFrame.taskId_ = 0;
+
+
+/**
+ * Whether the animationframe runTasks_ loop is currently running.
+ * @private {boolean}
+ */
+goog.dom.animationFrame.running_ = false;
+
+
+/**
+ * Returns a function that schedules the two passed-in functions to be run upon
+ * the next animation frame. Calling the function again during the same
+ * animation frame does nothing.
+ *
+ * The function under the "measure" key will run first and together with all
+ * other functions scheduled under this key and the function under "mutate" will
+ * run after that.
+ *
+ * @param {{
+ *   measure: (function(this:THIS, !goog.dom.animationFrame.State)|undefined),
+ *   mutate: (function(this:THIS, !goog.dom.animationFrame.State)|undefined)
+ * }} spec
+ * @param {THIS=} opt_context Context in which to run the function.
+ * @return {function(...?)}
+ * @template THIS
+ */
+goog.dom.animationFrame.createTask = function(spec, opt_context) {
+  var id = goog.dom.animationFrame.taskId_++;
+  var measureTask = {
+    id: id,
+    fn: spec.measure,
+    context: opt_context
+  };
+  var mutateTask = {
+    id: id,
+    fn: spec.mutate,
+    context: opt_context
+  };
+
+  var taskSet = {
+    measureTask: measureTask,
+    mutateTask: mutateTask,
+    state: {},
+    args: undefined,
+    isScheduled: false
+  };
+
+  return function() {
+    // Default the context to the one that was used to call the tasks scheduler
+    // (this function).
+    if (!opt_context) {
+      measureTask.context = this;
+      mutateTask.context = this;
+    }
+
+    // Save args and state.
+    if (arguments.length > 0) {
+      // The state argument goes last. That is kinda horrible but compatible
+      // with {@see wiz.async.method}.
+      if (!taskSet.args) {
+        taskSet.args = [];
+      }
+      taskSet.args.length = 0;
+      taskSet.args.push.apply(taskSet.args, arguments);
+      taskSet.args.push(taskSet.state);
+    } else {
+      if (!taskSet.args || taskSet.args.length == 0) {
+        taskSet.args = [taskSet.state];
+      } else {
+        taskSet.args[0] = taskSet.state;
+        taskSet.args.length = 1;
+      }
+    }
+    if (!taskSet.isScheduled) {
+      taskSet.isScheduled = true;
+      var tasksArray = goog.dom.animationFrame.tasks_[
+          goog.dom.animationFrame.doubleBufferIndex_];
+      tasksArray.push(taskSet);
+    }
+    goog.dom.animationFrame.requestAnimationFrame_();
+  };
+};
+
+
+/**
+ * Run scheduled tasks.
+ * @private
+ */
+goog.dom.animationFrame.runTasks_ = function() {
+  goog.dom.animationFrame.running_ = true;
+  goog.dom.animationFrame.requestedFrame_ = false;
+  var tasksArray = goog.dom.animationFrame
+                       .tasks_[goog.dom.animationFrame.doubleBufferIndex_];
+  var taskLength = tasksArray.length;
+
+  // During the runTasks_, if there is a recursive call to queue up more
+  // task(s) for the next frame, we use double-buffering for that.
+  goog.dom.animationFrame.doubleBufferIndex_ =
+      (goog.dom.animationFrame.doubleBufferIndex_ + 1) % 2;
+
+  var task;
+
+  // Run all the measure tasks first.
+  for (var i = 0; i < taskLength; ++i) {
+    task = tasksArray[i];
+    var measureTask = task.measureTask;
+    task.isScheduled = false;
+    if (measureTask.fn) {
+      // TODO (perumaal): Handle any exceptions thrown by the lambda.
+      measureTask.fn.apply(measureTask.context, task.args);
+    }
+  }
+
+  // Run the mutate tasks next.
+  for (var i = 0; i < taskLength; ++i) {
+    task = tasksArray[i];
+    var mutateTask = task.mutateTask;
+    task.isScheduled = false;
+    if (mutateTask.fn) {
+      // TODO (perumaal): Handle any exceptions thrown by the lambda.
+      mutateTask.fn.apply(mutateTask.context, task.args);
+    }
+
+    // Clear state for next vsync.
+    task.state = {};
+  }
+
+  // Clear the tasks array as we have finished processing all the tasks.
+  tasksArray.length = 0;
+  goog.dom.animationFrame.running_ = false;
+};
+
+
+/**
+ * @return {boolean} Whether the animationframe is currently running. For use
+ *     by callers who need not to delay tasks scheduled during runTasks_ for an
+ *     additional frame.
+ */
+goog.dom.animationFrame.isRunning = function() {
+  return goog.dom.animationFrame.running_;
+};
+
+
+/**
+ * Request {@see goog.dom.animationFrame.runTasks_} to be called upon the
+ * next animation frame if we haven't done so already.
+ * @private
+ */
+goog.dom.animationFrame.requestAnimationFrame_ = function() {
+  if (goog.dom.animationFrame.requestedFrame_) {
+    return;
+  }
+  goog.dom.animationFrame.requestedFrame_ = true;
+  window.requestAnimationFrame(goog.dom.animationFrame.runTasks_);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/animationframe/polyfill.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/animationframe/polyfill.js b/externs/GCL/externs/goog/dom/animationframe/polyfill.js
new file mode 100644
index 0000000..19e8866
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/animationframe/polyfill.js
@@ -0,0 +1,61 @@
+// Copyright 2014 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 polyfill for window.requestAnimationFrame and
+ * window.cancelAnimationFrame.
+ * Code based on https://gist.github.com/paulirish/1579671
+ */
+
+goog.provide('goog.dom.animationFrame.polyfill');
+
+
+/**
+ * @define {boolean} If true, will install the requestAnimationFrame polyfill.
+ */
+goog.define('goog.dom.animationFrame.polyfill.ENABLED', true);
+
+
+/**
+ * Installs the requestAnimationFrame (and cancelAnimationFrame) polyfill.
+ */
+goog.dom.animationFrame.polyfill.install =
+    goog.dom.animationFrame.polyfill.ENABLED ? function() {
+  var vendors = ['ms', 'moz', 'webkit', 'o'];
+  for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
+    window.requestAnimationFrame = window[vendors[x] +
+        'RequestAnimationFrame'];
+    window.cancelAnimationFrame = window[vendors[x] +
+        'CancelAnimationFrame'] ||
+            window[vendors[x] + 'CancelRequestAnimationFrame'];
+  }
+
+  if (!window.requestAnimationFrame) {
+    var lastTime = 0;
+    window.requestAnimationFrame = function(callback, element) {
+      var currTime = new Date().getTime();
+      var timeToCall = Math.max(0, 16 - (currTime - lastTime));
+      lastTime = currTime + timeToCall;
+      return window.setTimeout(function() {
+        callback(currTime + timeToCall);
+      }, timeToCall);
+    };
+
+    if (!window.cancelAnimationFrame) {
+      window.cancelAnimationFrame = function(id) {
+        clearTimeout(id);
+      };
+    }
+  }
+} : goog.nullFunction;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/annotate.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/annotate.js b/externs/GCL/externs/goog/dom/annotate.js
new file mode 100644
index 0000000..7a772e8
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/annotate.js
@@ -0,0 +1,357 @@
+// 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 Methods for annotating occurrences of query terms in text or
+ *   in a DOM tree. Adapted from Gmail code.
+ *
+ */
+
+goog.provide('goog.dom.annotate');
+goog.provide('goog.dom.annotate.AnnotateFn');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.safe');
+goog.require('goog.html.SafeHtml');
+
+
+/**
+ * A function that takes:
+ *   (1) the number of the term that is "hit",
+ *   (2) the HTML (search term) to be annotated,
+ * and returns the annotated term as an HTML.
+ * @typedef {function(number, !goog.html.SafeHtml): !goog.html.SafeHtml}
+ */
+goog.dom.annotate.AnnotateFn;
+
+
+/**
+ * Calls {@code annotateFn} for each occurrence of a search term in text nodes
+ * under {@code node}. Returns the number of hits.
+ *
+ * @param {Node} node  A DOM node.
+ * @param {Array<!Array<string|boolean>>} terms
+ *   An array of [searchTerm, matchWholeWordOnly] tuples.
+ *   The matchWholeWordOnly value is a per-term attribute because some terms
+ *   may be CJK, while others are not. (For correctness, matchWholeWordOnly
+ *   should always be false for CJK terms.).
+ * @param {goog.dom.annotate.AnnotateFn} annotateFn
+ * @param {*=} opt_ignoreCase  Whether to ignore the case of the query
+ *   terms when looking for matches.
+ * @param {Array<string>=} opt_classesToSkip  Nodes with one of these CSS class
+ *   names (and its descendants) will be skipped.
+ * @param {number=} opt_maxMs  Number of milliseconds after which this function,
+ *   if still annotating, should stop and return.
+ *
+ * @return {boolean} Whether any terms were annotated.
+ */
+goog.dom.annotate.annotateTerms = function(node, terms, annotateFn,
+                                           opt_ignoreCase,
+                                           opt_classesToSkip,
+                                           opt_maxMs) {
+  if (opt_ignoreCase) {
+    terms = goog.dom.annotate.lowercaseTerms_(terms);
+  }
+  var stopTime = opt_maxMs > 0 ? goog.now() + opt_maxMs : 0;
+
+  return goog.dom.annotate.annotateTermsInNode_(
+      node, terms, annotateFn, opt_ignoreCase, opt_classesToSkip || [],
+      stopTime, 0);
+};
+
+
+/**
+ * The maximum recursion depth allowed. Any DOM nodes deeper than this are
+ * ignored.
+ * @type {number}
+ * @private
+ */
+goog.dom.annotate.MAX_RECURSION_ = 200;
+
+
+/**
+ * The node types whose descendants should not be affected by annotation.
+ * @private {Array<string>}
+ */
+goog.dom.annotate.NODES_TO_SKIP_ = [
+  goog.dom.TagName.SCRIPT, goog.dom.TagName.STYLE, goog.dom.TagName.TEXTAREA];
+
+
+/**
+ * Recursive helper function.
+ *
+ * @param {Node} node  A DOM node.
+ * @param {Array<!Array<string|boolean>>} terms
+ *     An array of [searchTerm, matchWholeWordOnly] tuples.
+ *     The matchWholeWordOnly value is a per-term attribute because some terms
+ *     may be CJK, while others are not. (For correctness, matchWholeWordOnly
+ *     should always be false for CJK terms.).
+ * @param {goog.dom.annotate.AnnotateFn} annotateFn
+ * @param {*} ignoreCase  Whether to ignore the case of the query terms
+ *     when looking for matches.
+ * @param {Array<string>} classesToSkip  Nodes with one of these CSS class
+ *     names will be skipped (as will their descendants).
+ * @param {number} stopTime  Deadline for annotation operation (ignored if 0).
+ * @param {number} recursionLevel  How deep this recursive call is; pass the
+ *     value 0 in the initial call.
+ * @return {boolean} Whether any terms were annotated.
+ * @private
+ */
+goog.dom.annotate.annotateTermsInNode_ =
+    function(node, terms, annotateFn, ignoreCase, classesToSkip,
+             stopTime, recursionLevel) {
+  if ((stopTime > 0 && goog.now() >= stopTime) ||
+      recursionLevel > goog.dom.annotate.MAX_RECURSION_) {
+    return false;
+  }
+
+  var annotated = false;
+
+  if (node.nodeType == goog.dom.NodeType.TEXT) {
+    var html = goog.dom.annotate.helpAnnotateText_(node.nodeValue, terms,
+                                                   annotateFn, ignoreCase);
+    if (html != null) {
+      // Replace the text with the annotated html. First we put the html into
+      // a temporary node, to get its DOM structure. To avoid adding a wrapper
+      // element as a side effect, we'll only actually use the temporary node's
+      // children.
+      var tempNode = goog.dom.getOwnerDocument(node).createElement(
+          goog.dom.TagName.SPAN);
+      goog.dom.safe.setInnerHtml(tempNode, html);
+
+      var parentNode = node.parentNode;
+      var nodeToInsert;
+      while ((nodeToInsert = tempNode.firstChild) != null) {
+        // Each parentNode.insertBefore call removes the inserted node from
+        // tempNode's list of children.
+        parentNode.insertBefore(nodeToInsert, node);
+      }
+
+      parentNode.removeChild(node);
+      annotated = true;
+    }
+  } else if (node.hasChildNodes() &&
+             !goog.array.contains(goog.dom.annotate.NODES_TO_SKIP_,
+                 node.tagName)) {
+    var classes = node.className.split(/\s+/);
+    var skip = goog.array.some(classes, function(className) {
+      return goog.array.contains(classesToSkip, className);
+    });
+
+    if (!skip) {
+      ++recursionLevel;
+      var curNode = node.firstChild;
+      while (curNode) {
+        var nextNode = curNode.nextSibling;
+        var curNodeAnnotated = goog.dom.annotate.annotateTermsInNode_(
+            curNode, terms, annotateFn, ignoreCase, classesToSkip,
+            stopTime, recursionLevel);
+        annotated = annotated || curNodeAnnotated;
+        curNode = nextNode;
+      }
+    }
+  }
+
+  return annotated;
+};
+
+
+/**
+ * Regular expression that matches non-word characters.
+ *
+ * Performance note: Testing a one-character string using this regex is as fast
+ * as the equivalent string test ("a-zA-Z0-9_".indexOf(c) < 0), give or take a
+ * few percent. (The regex is about 5% faster in IE 6 and about 4% slower in
+ * Firefox 1.5.) If performance becomes critical, it may be better to convert
+ * the character to a numerical char code and check whether it falls in the
+ * word character ranges. A quick test suggests that could be 33% faster.
+ *
+ * @type {RegExp}
+ * @private
+ */
+goog.dom.annotate.NONWORD_RE_ = /\W/;
+
+
+/**
+ * Annotates occurrences of query terms in plain text. This process consists of
+ * identifying all occurrences of all query terms, calling a provided function
+ * to get the appropriate replacement HTML for each occurrence, and
+ * HTML-escaping all the text.
+ *
+ * @param {string} text  The plain text to be searched.
+ * @param {Array<Array<?>>} terms  An array of
+ *   [{string} searchTerm, {boolean} matchWholeWordOnly] tuples.
+ *   The matchWholeWordOnly value is a per-term attribute because some terms
+ *   may be CJK, while others are not. (For correctness, matchWholeWordOnly
+ *   should always be false for CJK terms.).
+ * @param {goog.dom.annotate.AnnotateFn} annotateFn
+ * @param {*=} opt_ignoreCase  Whether to ignore the case of the query
+ *   terms when looking for matches.
+ * @return {goog.html.SafeHtml} The HTML equivalent of {@code text} with terms
+ *   annotated, or null if the text did not contain any of the terms.
+ */
+goog.dom.annotate.annotateText = function(text, terms, annotateFn,
+                                          opt_ignoreCase) {
+  if (opt_ignoreCase) {
+    terms = goog.dom.annotate.lowercaseTerms_(terms);
+  }
+  return goog.dom.annotate.helpAnnotateText_(text, terms, annotateFn,
+                                             opt_ignoreCase);
+};
+
+
+/**
+ * Annotates occurrences of query terms in plain text. This process consists of
+ * identifying all occurrences of all query terms, calling a provided function
+ * to get the appropriate replacement HTML for each occurrence, and
+ * HTML-escaping all the text.
+ *
+ * @param {string} text  The plain text to be searched.
+ * @param {Array<Array<?>>} terms  An array of
+ *   [{string} searchTerm, {boolean} matchWholeWordOnly] tuples.
+ *   If {@code ignoreCase} is true, each search term must already be lowercase.
+ *   The matchWholeWordOnly value is a per-term attribute because some terms
+ *   may be CJK, while others are not. (For correctness, matchWholeWordOnly
+ *   should always be false for CJK terms.).
+ * @param {goog.dom.annotate.AnnotateFn} annotateFn
+ * @param {*} ignoreCase  Whether to ignore the case of the query terms
+ *   when looking for matches.
+ * @return {goog.html.SafeHtml} The HTML equivalent of {@code text} with terms
+ *   annotated, or null if the text did not contain any of the terms.
+ * @private
+ */
+goog.dom.annotate.helpAnnotateText_ = function(text, terms, annotateFn,
+                                               ignoreCase) {
+  var hit = false;
+  var textToSearch = ignoreCase ? text.toLowerCase() : text;
+  var textLen = textToSearch.length;
+  var numTerms = terms.length;
+
+  // Each element will be an array of hit positions for the term.
+  var termHits = new Array(numTerms);
+
+  // First collect all the hits into allHits.
+  for (var i = 0; i < numTerms; i++) {
+    var term = terms[i];
+    var hits = [];
+    var termText = term[0];
+    if (termText != '') {
+      var matchWholeWordOnly = term[1];
+      var termLen = termText.length;
+      var pos = 0;
+      // Find each hit for term t and append to termHits.
+      while (pos < textLen) {
+        var hitPos = textToSearch.indexOf(termText, pos);
+        if (hitPos == -1) {
+          break;
+        } else {
+          var prevCharPos = hitPos - 1;
+          var nextCharPos = hitPos + termLen;
+          if (!matchWholeWordOnly ||
+              ((prevCharPos < 0 ||
+                goog.dom.annotate.NONWORD_RE_.test(
+                    textToSearch.charAt(prevCharPos))) &&
+               (nextCharPos >= textLen ||
+                goog.dom.annotate.NONWORD_RE_.test(
+                    textToSearch.charAt(nextCharPos))))) {
+            hits.push(hitPos);
+            hit = true;
+          }
+          pos = hitPos + termLen;
+        }
+      }
+    }
+    termHits[i] = hits;
+  }
+
+  if (hit) {
+    var html = [];
+    var pos = 0;
+
+    while (true) {
+      // First determine which of the n terms is the next hit.
+      var termIndexOfNextHit;
+      var posOfNextHit = -1;
+
+      for (var i = 0; i < numTerms; i++) {
+        var hits = termHits[i];
+        // pull off the position of the next hit of term t
+        // (it's always the first in the array because we're shifting
+        // hits off the front of the array as we process them)
+        // this is the next candidate to consider for the next overall hit
+        if (!goog.array.isEmpty(hits)) {
+          var hitPos = hits[0];
+
+          // Discard any hits embedded in the previous hit.
+          while (hitPos >= 0 && hitPos < pos) {
+            hits.shift();
+            hitPos = goog.array.isEmpty(hits) ? -1 : hits[0];
+          }
+
+          if (hitPos >= 0 && (posOfNextHit < 0 || hitPos < posOfNextHit)) {
+            termIndexOfNextHit = i;
+            posOfNextHit = hitPos;
+          }
+        }
+      }
+
+      // Quit if there are no more hits.
+      if (posOfNextHit < 0) break;
+
+      // Remove the next hit from our hit list.
+      termHits[termIndexOfNextHit].shift();
+
+      // Append everything from the end of the last hit up to this one.
+      html.push(text.substr(pos, posOfNextHit - pos));
+
+      // Append the annotated term.
+      var termLen = terms[termIndexOfNextHit][0].length;
+      var termHtml = goog.html.SafeHtml.htmlEscape(
+          text.substr(posOfNextHit, termLen));
+      html.push(
+          annotateFn(goog.asserts.assertNumber(termIndexOfNextHit), termHtml));
+
+      pos = posOfNextHit + termLen;
+    }
+
+    // Append everything after the last hit.
+    html.push(text.substr(pos));
+    return goog.html.SafeHtml.concat(html);
+  } else {
+    return null;
+  }
+};
+
+
+/**
+ * Converts terms to lowercase.
+ *
+ * @param {Array<Array<?>>} terms  An array of
+ *   [{string} searchTerm, {boolean} matchWholeWordOnly] tuples.
+ * @return {!Array<Array<?>>}  An array of
+ *   [{string} searchTerm, {boolean} matchWholeWordOnly] tuples.
+ * @private
+ */
+goog.dom.annotate.lowercaseTerms_ = function(terms) {
+  var lowercaseTerms = [];
+  for (var i = 0; i < terms.length; ++i) {
+    var term = terms[i];
+    lowercaseTerms[i] = [term[0].toLowerCase(), term[1]];
+  }
+  return lowercaseTerms;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/browserfeature1.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/browserfeature1.js b/externs/GCL/externs/goog/dom/browserfeature1.js
new file mode 100644
index 0000000..2c70cda
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/browserfeature1.js
@@ -0,0 +1,72 @@
+// Copyright 2010 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 Browser capability checks for the dom package.
+ *
+ */
+
+
+goog.provide('goog.dom.BrowserFeature');
+
+goog.require('goog.userAgent');
+
+
+/**
+ * Enum of browser capabilities.
+ * @enum {boolean}
+ */
+goog.dom.BrowserFeature = {
+  /**
+   * Whether attributes 'name' and 'type' can be added to an element after it's
+   * created. False in Internet Explorer prior to version 9.
+   */
+  CAN_ADD_NAME_OR_TYPE_ATTRIBUTES: !goog.userAgent.IE ||
+      goog.userAgent.isDocumentModeOrHigher(9),
+
+  /**
+   * Whether we can use element.children to access an element's Element
+   * children. Available since Gecko 1.9.1, IE 9. (IE<9 also includes comment
+   * nodes in the collection.)
+   */
+  CAN_USE_CHILDREN_ATTRIBUTE: !goog.userAgent.GECKO && !goog.userAgent.IE ||
+      goog.userAgent.IE && goog.userAgent.isDocumentModeOrHigher(9) ||
+      goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9.1'),
+
+  /**
+   * Opera, Safari 3, and Internet Explorer 9 all support innerText but they
+   * include text nodes in script and style tags. Not document-mode-dependent.
+   */
+  CAN_USE_INNER_TEXT: (
+      goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9')),
+
+  /**
+   * MSIE, Opera, and Safari>=4 support element.parentElement to access an
+   * element's parent if it is an Element.
+   */
+  CAN_USE_PARENT_ELEMENT_PROPERTY: goog.userAgent.IE || goog.userAgent.OPERA ||
+      goog.userAgent.WEBKIT,
+
+  /**
+   * Whether NoScope elements need a scoped element written before them in
+   * innerHTML.
+   * MSDN: http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx#1
+   */
+  INNER_HTML_NEEDS_SCOPED_ELEMENT: goog.userAgent.IE,
+
+  /**
+   * Whether we use legacy IE range API.
+   */
+  LEGACY_IE_RANGES: goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/browserrange/abstractrange.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/browserrange/abstractrange.js b/externs/GCL/externs/goog/dom/browserrange/abstractrange.js
new file mode 100644
index 0000000..3956f3a
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/browserrange/abstractrange.js
@@ -0,0 +1,350 @@
+// 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 interface.
+ *
+ * DO NOT USE THIS FILE DIRECTLY.  Use goog.dom.Range instead.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+
+goog.provide('goog.dom.browserrange.AbstractRange');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.RangeEndpoint');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.TextRangeIterator');
+goog.require('goog.iter');
+goog.require('goog.math.Coordinate');
+goog.require('goog.string');
+goog.require('goog.string.StringBuffer');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * The constructor for abstract ranges.  Don't call this from subclasses.
+ * @constructor
+ */
+goog.dom.browserrange.AbstractRange = function() {
+};
+
+
+/**
+ * @return {goog.dom.browserrange.AbstractRange} A clone of this range.
+ */
+goog.dom.browserrange.AbstractRange.prototype.clone = goog.abstractMethod;
+
+
+/**
+ * Returns the browser native implementation of the range.  Please refrain from
+ * using this function - if you find you need the range please add wrappers for
+ * the functionality you need rather than just using the native range.
+ * @return {Range|TextRange} The browser native range object.
+ */
+goog.dom.browserrange.AbstractRange.prototype.getBrowserRange =
+    goog.abstractMethod;
+
+
+/**
+ * Returns the deepest node in the tree that contains the entire range.
+ * @return {Node} The deepest node that contains the entire range.
+ */
+goog.dom.browserrange.AbstractRange.prototype.getContainer =
+    goog.abstractMethod;
+
+
+/**
+ * Returns the node the range starts in.
+ * @return {Node} The element or text node the range starts in.
+ */
+goog.dom.browserrange.AbstractRange.prototype.getStartNode =
+    goog.abstractMethod;
+
+
+/**
+ * Returns the offset into the node the range starts in.
+ * @return {number} The offset into the node the range starts in.  For text
+ *     nodes, this is an offset into the node value.  For elements, this is
+ *     an offset into the childNodes array.
+ */
+goog.dom.browserrange.AbstractRange.prototype.getStartOffset =
+    goog.abstractMethod;
+
+
+/**
+ * @return {goog.math.Coordinate} The coordinate of the selection start node
+ *     and offset.
+ */
+goog.dom.browserrange.AbstractRange.prototype.getStartPosition = function() {
+  goog.asserts.assert(this.range_.getClientRects,
+      'Getting selection coordinates is not supported.');
+
+  var rects = this.range_.getClientRects();
+  if (rects.length) {
+    return new goog.math.Coordinate(rects[0]['left'], rects[0]['top']);
+  }
+  return null;
+};
+
+
+/**
+ * Returns the node the range ends in.
+ * @return {Node} The element or text node the range ends in.
+ */
+goog.dom.browserrange.AbstractRange.prototype.getEndNode =
+    goog.abstractMethod;
+
+
+/**
+ * Returns the offset into the node the range ends in.
+ * @return {number} The offset into the node the range ends in.  For text
+ *     nodes, this is an offset into the node value.  For elements, this is
+ *     an offset into the childNodes array.
+ */
+goog.dom.browserrange.AbstractRange.prototype.getEndOffset =
+    goog.abstractMethod;
+
+
+/**
+ * @return {goog.math.Coordinate} The coordinate of the selection end node
+ *     and offset.
+ */
+goog.dom.browserrange.AbstractRange.prototype.getEndPosition = function() {
+  goog.asserts.assert(this.range_.getClientRects,
+      'Getting selection coordinates is not supported.');
+
+  var rects = this.range_.getClientRects();
+  if (rects.length) {
+    var lastRect = goog.array.peek(rects);
+    return new goog.math.Coordinate(lastRect['right'], lastRect['bottom']);
+  }
+  return null;
+};
+
+
+/**
+ * Compares one endpoint of this range with the endpoint of another browser
+ * native range object.
+ * @param {Range|TextRange} range The browser native range 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 other
+ *     range to compare with.
+ * @return {number} 0 if the endpoints are equal, negative if this range
+ *     endpoint comes before the other range endpoint, and positive otherwise.
+ */
+goog.dom.browserrange.AbstractRange.prototype.compareBrowserRangeEndpoints =
+    goog.abstractMethod;
+
+
+/**
+ * Tests if this range contains the given range.
+ * @param {goog.dom.browserrange.AbstractRange} abstractRange The range to test.
+ * @param {boolean=} opt_allowPartial If not set or false, the range must be
+ *     entirely contained in the selection for this function to return true.
+ * @return {boolean} Whether this range contains the given range.
+ */
+goog.dom.browserrange.AbstractRange.prototype.containsRange =
+    function(abstractRange, opt_allowPartial) {
+  // IE sometimes misreports the boundaries for collapsed ranges. So if the
+  // other range is collapsed, make sure the whole range is contained. This is
+  // logically equivalent, and works around IE's bug.
+  var checkPartial = opt_allowPartial && !abstractRange.isCollapsed();
+
+  var range = abstractRange.getBrowserRange();
+  var start = goog.dom.RangeEndpoint.START, end = goog.dom.RangeEndpoint.END;
+  /** @preserveTry */
+  try {
+    if (checkPartial) {
+      // There are two ways to not overlap.  Being before, and being after.
+      // Before is represented by this.end before range.start: comparison < 0.
+      // After is represented by this.start after range.end: comparison > 0.
+      // The below is the negation of not overlapping.
+      return this.compareBrowserRangeEndpoints(range, end, start) >= 0 &&
+             this.compareBrowserRangeEndpoints(range, start, end) <= 0;
+
+    } else {
+      // Return true if this range bounds the parameter range from both sides.
+      return this.compareBrowserRangeEndpoints(range, end, end) >= 0 &&
+          this.compareBrowserRangeEndpoints(range, start, start) <= 0;
+    }
+  } catch (e) {
+    if (!goog.userAgent.IE) {
+      throw e;
+    }
+    // IE sometimes throws exceptions when one range is invalid, i.e. points
+    // to a node that has been removed from the document.  Return false in this
+    // case.
+    return false;
+  }
+};
+
+
+/**
+ * Tests if this range contains the given node.
+ * @param {Node} node The node to test.
+ * @param {boolean=} opt_allowPartial If not set or false, the node must be
+ *     entirely contained in the selection for this function to return true.
+ * @return {boolean} Whether this range contains the given node.
+ */
+goog.dom.browserrange.AbstractRange.prototype.containsNode = function(node,
+    opt_allowPartial) {
+  return this.containsRange(
+      goog.dom.browserrange.createRangeFromNodeContents(node),
+      opt_allowPartial);
+};
+
+
+/**
+ * Tests if the selection is collapsed - i.e. is just a caret.
+ * @return {boolean} Whether the range is collapsed.
+ */
+goog.dom.browserrange.AbstractRange.prototype.isCollapsed =
+    goog.abstractMethod;
+
+
+/**
+ * @return {string} The text content of the range.
+ */
+goog.dom.browserrange.AbstractRange.prototype.getText =
+    goog.abstractMethod;
+
+
+/**
+ * Returns the HTML fragment this range selects.  This is slow on all browsers.
+ * @return {string} HTML fragment of the range, does not include context
+ *     containing elements.
+ */
+goog.dom.browserrange.AbstractRange.prototype.getHtmlFragment = function() {
+  var output = new goog.string.StringBuffer();
+  goog.iter.forEach(this, function(node, ignore, it) {
+    if (node.nodeType == goog.dom.NodeType.TEXT) {
+      output.append(goog.string.htmlEscape(node.nodeValue.substring(
+          it.getStartTextOffset(), it.getEndTextOffset())));
+    } else if (node.nodeType == goog.dom.NodeType.ELEMENT) {
+      if (it.isEndTag()) {
+        if (goog.dom.canHaveChildren(node)) {
+          output.append('</' + node.tagName + '>');
+        }
+      } else {
+        var shallow = node.cloneNode(false);
+        var html = goog.dom.getOuterHtml(shallow);
+        if (goog.userAgent.IE && node.tagName == goog.dom.TagName.LI) {
+          // For an LI, IE just returns "<li>" with no closing tag
+          output.append(html);
+        } else {
+          var index = html.lastIndexOf('<');
+          output.append(index ? html.substr(0, index) : html);
+        }
+      }
+    }
+  }, this);
+
+  return output.toString();
+};
+
+
+/**
+ * Returns valid HTML for this range.  This is fast on IE, and semi-fast on
+ * other browsers.
+ * @return {string} Valid HTML of the range, including context containing
+ *     elements.
+ */
+goog.dom.browserrange.AbstractRange.prototype.getValidHtml =
+    goog.abstractMethod;
+
+
+/**
+ * Returns a RangeIterator over the contents of the range.  Regardless of the
+ * direction of the range, the iterator will move in document order.
+ * @param {boolean=} opt_keys Unused for this iterator.
+ * @return {!goog.dom.RangeIterator} An iterator over tags in the range.
+ */
+goog.dom.browserrange.AbstractRange.prototype.__iterator__ = function(
+    opt_keys) {
+  return new goog.dom.TextRangeIterator(this.getStartNode(),
+      this.getStartOffset(), this.getEndNode(), this.getEndOffset());
+};
+
+
+// SELECTION MODIFICATION
+
+
+/**
+ * Set this range as the selection in its window.
+ * @param {boolean=} opt_reverse Whether to select the range in reverse,
+ *     if possible.
+ */
+goog.dom.browserrange.AbstractRange.prototype.select =
+    goog.abstractMethod;
+
+
+/**
+ * Removes the contents of the range from the document.  As a side effect, the
+ * selection will be collapsed.  The behavior of content removal is normalized
+ * across browsers.  For instance, IE sometimes creates extra text nodes that
+ * a W3C browser does not.  That behavior is corrected for.
+ */
+goog.dom.browserrange.AbstractRange.prototype.removeContents =
+    goog.abstractMethod;
+
+
+/**
+ * Surrounds the text range with the specified element (on Mozilla) or with a
+ * clone of the specified element (on IE).  Returns a reference to the
+ * surrounding element if the operation was successful; returns null if the
+ * operation failed.
+ * @param {Element} element The element with which the selection is to be
+ *    surrounded.
+ * @return {Element} The surrounding element (same as the argument on Mozilla,
+ *    but not on IE), or null if unsuccessful.
+ */
+goog.dom.browserrange.AbstractRange.prototype.surroundContents =
+    goog.abstractMethod;
+
+
+/**
+ * Inserts a node before (or after) the range.  The range may be disrupted
+ * beyond recovery because of the way this splits nodes.
+ * @param {Node} node The node to insert.
+ * @param {boolean} before True to insert before, false to insert after.
+ * @return {Node} The node added to the document.  This may be different
+ *     than the node parameter because on IE we have to clone it.
+ */
+goog.dom.browserrange.AbstractRange.prototype.insertNode =
+    goog.abstractMethod;
+
+
+/**
+ * Surrounds this range with the two given nodes.  The range may be disrupted
+ * beyond recovery because of the way this splits nodes.
+ * @param {Element} startNode The node to insert at the start.
+ * @param {Element} endNode The node to insert at the end.
+ */
+goog.dom.browserrange.AbstractRange.prototype.surroundWithNodes =
+    goog.abstractMethod;
+
+
+/**
+ * Collapses the range to one of its boundary points.
+ * @param {boolean} toStart Whether to collapse to the start of the range.
+ */
+goog.dom.browserrange.AbstractRange.prototype.collapse =
+    goog.abstractMethod;


[25/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/focus.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/focus.js b/externs/GCL/externs/goog/editor/focus.js
new file mode 100644
index 0000000..4253b3c
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/focus.js
@@ -0,0 +1,32 @@
+// 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 Utilties to handle focusing related to rich text editing.
+ *
+ */
+
+goog.provide('goog.editor.focus');
+
+goog.require('goog.dom.selection');
+
+
+/**
+ * Change focus to the given input field and set cursor to end of current text.
+ * @param {Element} inputElem Input DOM element.
+ */
+goog.editor.focus.focusInputField = function(inputElem) {
+  inputElem.focus();
+  goog.dom.selection.setCursorPosition(inputElem, inputElem.value.length);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/icontent.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/icontent.js b/externs/GCL/externs/goog/editor/icontent.js
new file mode 100644
index 0000000..fac433a
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/icontent.js
@@ -0,0 +1,300 @@
+// 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.
+// All Rights Reserved.
+
+/**
+ * @fileoverview Static functions for writing the contents of an iframe-based
+ * editable field. These vary significantly from browser to browser. Uses
+ * strings and document.write instead of DOM manipulation, because
+ * iframe-loading is a performance bottleneck.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.editor.icontent');
+goog.provide('goog.editor.icontent.FieldFormatInfo');
+goog.provide('goog.editor.icontent.FieldStyleInfo');
+
+goog.require('goog.dom');
+goog.require('goog.editor.BrowserFeature');
+goog.require('goog.style');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * A data structure for storing simple rendering info about a field.
+ *
+ * @param {string} fieldId The id of the field.
+ * @param {boolean} standards Whether the field should be rendered in
+ *     standards mode.
+ * @param {boolean} blended Whether the field is in blended mode.
+ * @param {boolean} fixedHeight Whether the field is in fixedHeight mode.
+ * @param {Object=} opt_extraStyles Other style attributes for the field,
+ *     represented as a map of strings.
+ * @constructor
+ * @final
+ */
+goog.editor.icontent.FieldFormatInfo = function(fieldId, standards, blended,
+    fixedHeight, opt_extraStyles) {
+  this.fieldId_ = fieldId;
+  this.standards_ = standards;
+  this.blended_ = blended;
+  this.fixedHeight_ = fixedHeight;
+  this.extraStyles_ = opt_extraStyles || {};
+};
+
+
+
+/**
+ * A data structure for storing simple info about the styles of a field.
+ * Only needed in Firefox/Blended mode.
+ * @param {Element} wrapper The wrapper div around a field.
+ * @param {string} css The css for a field.
+ * @constructor
+ * @final
+ */
+goog.editor.icontent.FieldStyleInfo = function(wrapper, css) {
+  this.wrapper_ = wrapper;
+  this.css_ = css;
+};
+
+
+/**
+ * Whether to always use standards-mode iframes.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.icontent.useStandardsModeIframes_ = false;
+
+
+/**
+ * Sets up goog.editor.icontent to always use standards-mode iframes.
+ */
+goog.editor.icontent.forceStandardsModeIframes = function() {
+  goog.editor.icontent.useStandardsModeIframes_ = true;
+};
+
+
+/**
+ * Generate the initial iframe content.
+ * @param {goog.editor.icontent.FieldFormatInfo} info Formatting info about
+ *     the field.
+ * @param {string} bodyHtml The HTML to insert as the iframe body.
+ * @param {goog.editor.icontent.FieldStyleInfo?} style Style info about
+ *     the field, if needed.
+ * @return {string} The initial IFRAME content HTML.
+ * @private
+ */
+goog.editor.icontent.getInitialIframeContent_ =
+    function(info, bodyHtml, style) {
+  var html = [];
+
+  if (info.blended_ && info.standards_ ||
+      goog.editor.icontent.useStandardsModeIframes_) {
+    html.push('<!DOCTYPE HTML>');
+  }
+
+  // <HTML>
+  // NOTE(user): Override min-widths that may be set for all
+  // HTML/BODY nodes. A similar workaround is below for the <body> tag. This
+  // can happen if the host page includes a rule like this in its CSS:
+  //
+  // html, body {min-width: 500px}
+  //
+  // In this case, the iframe's <html> and/or <body> may be affected. This was
+  // part of the problem observed in http://b/5674613. (The other part of that
+  // problem had to do with the presence of a spurious horizontal scrollbar,
+  // which caused the editor height to be computed incorrectly.)
+  html.push('<html style="background:none transparent;min-width:0;');
+
+  // Make sure that the HTML element's height has the
+  // correct value as the body element's percentage height is made relative
+  // to the HTML element's height.
+  // For fixed-height it should be 100% since we want the body to fill the
+  // whole height. For growing fields it should be auto since we want the
+  // body to size to its content.
+  if (info.blended_) {
+    html.push('height:', info.fixedHeight_ ? '100%' : 'auto');
+  }
+  html.push('">');
+
+  // <HEAD><STYLE>
+
+  // IE/Safari whitebox need styles set only iff the client specifically
+  // requested them.
+  html.push('<head><style>');
+  if (style && style.css_) {
+    html.push(style.css_);
+  }
+
+  // Firefox blended needs to inherit all the css from the original page.
+  // Firefox standards mode needs to set extra style for images.
+  if (goog.userAgent.GECKO && info.standards_) {
+    // Standards mode will collapse broken images.  This means that they
+    // can never be removed from the field.  This style forces the images
+    // to render as a broken image icon, sized based on the width and height
+    // of the image.
+    // TODO(user): Make sure we move this into a contentEditable code
+    // path if there ever is one for FF.
+    html.push(' img {-moz-force-broken-image-icon: 1;}');
+  }
+
+  html.push('</style></head>');
+
+  // <BODY>
+  // Hidefocus is needed to ensure that IE7 doesn't show the dotted, focus
+  // border when you tab into the field.
+  html.push('<body g_editable="true" hidefocus="true" ');
+  if (goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
+    html.push('contentEditable ');
+  }
+
+  html.push('class="editable ');
+
+  // TODO: put the field's original ID on the body and stop using ID as a
+  // way of getting the pointer to the field in the iframe now that it's
+  // always the body.
+  html.push('" id="', info.fieldId_, '" style="min-width:0;');
+
+  if (goog.userAgent.GECKO && info.blended_) {
+    // IMPORTANT: Apply the css from the body then all of the clearing
+    // CSS to make sure the clearing CSS overrides (e.g. if the body
+    // has a 3px margin, we want to make sure to override it with 0px.
+    html.push(
+
+        // margin should not be applied to blended mode because the margin is
+        // outside the iframe
+        // In whitebox mode, we want to leave the margin to the default so
+        // there is a nice margin around the text.
+        ';width:100%;border:0;margin:0;background:none transparent;',
+
+        // In standards-mode, height 100% makes the body size to its
+        // parent html element, but in quirks mode, we want auto because
+        // 100% makes it size to the containing window even if the html
+        // element is smaller.
+        // TODO: Fixed height, standards mode, CSS_WRITING, with margins on the
+        // paragraphs has a scrollbar when it doesn't need it.  Putting the
+        // height to auto seems to fix it.  Figure out if we should always
+        // just use auto?
+        ';height:', info.standards_ ? '100%' : 'auto');
+
+    // Only do this for mozilla. IE6 standards mode has a rendering bug when
+    // there are scrollbars and the body's overflow property is auto
+    if (info.fixedHeight_) {
+      html.push(';overflow:auto');
+    } else {
+      html.push(';overflow-y:hidden;overflow-x:auto');
+    }
+  }
+
+  // Hide the native focus rect in Opera.
+  if (goog.userAgent.OPERA) {
+    html.push(';outline:hidden');
+  }
+
+  for (var key in info.extraStyles_) {
+    html.push(';' + key + ':' + info.extraStyles_[key]);
+  }
+
+  html.push('">', bodyHtml, '</body></html>');
+
+  return html.join('');
+};
+
+
+/**
+ * Write the initial iframe content in normal mode.
+ * @param {goog.editor.icontent.FieldFormatInfo} info Formatting info about
+ *     the field.
+ * @param {string} bodyHtml The HTML to insert as the iframe body.
+ * @param {goog.editor.icontent.FieldStyleInfo?} style Style info about
+ *     the field, if needed.
+ * @param {HTMLIFrameElement} iframe The iframe.
+ */
+goog.editor.icontent.writeNormalInitialBlendedIframe =
+    function(info, bodyHtml, style, iframe) {
+  // Firefox blended needs to inherit all the css from the original page.
+  // Firefox standards mode needs to set extra style for images.
+  if (info.blended_) {
+    var field = style.wrapper_;
+    // If there is padding on the original field, then the iFrame will be
+    // positioned inside the padding by default.  We don't want this, as it
+    // causes the contents to appear to shift, and also causes the
+    // scrollbars to appear inside the padding.
+    //
+    // To compensate, we set the iframe margins to offset the padding.
+    var paddingBox = goog.style.getPaddingBox(field);
+    if (paddingBox.top || paddingBox.left ||
+        paddingBox.right || paddingBox.bottom) {
+      goog.style.setStyle(iframe, 'margin',
+          (-paddingBox.top) + 'px ' +
+          (-paddingBox.right) + 'px ' +
+          (-paddingBox.bottom) + 'px ' +
+          (-paddingBox.left) + 'px');
+    }
+  }
+
+  goog.editor.icontent.writeNormalInitialIframe(
+      info, bodyHtml, style, iframe);
+};
+
+
+/**
+ * Write the initial iframe content in normal mode.
+ * @param {goog.editor.icontent.FieldFormatInfo} info Formatting info about
+ *     the field.
+ * @param {string} bodyHtml The HTML to insert as the iframe body.
+ * @param {goog.editor.icontent.FieldStyleInfo?} style Style info about
+ *     the field, if needed.
+ * @param {HTMLIFrameElement} iframe The iframe.
+ */
+goog.editor.icontent.writeNormalInitialIframe =
+    function(info, bodyHtml, style, iframe) {
+
+  var html = goog.editor.icontent.getInitialIframeContent_(
+      info, bodyHtml, style);
+
+  var doc = goog.dom.getFrameContentDocument(iframe);
+  doc.open();
+  doc.write(html);
+  doc.close();
+};
+
+
+/**
+ * Write the initial iframe content in IE/HTTPS mode.
+ * @param {goog.editor.icontent.FieldFormatInfo} info Formatting info about
+ *     the field.
+ * @param {Document} doc The iframe document.
+ * @param {string} bodyHtml The HTML to insert as the iframe body.
+ */
+goog.editor.icontent.writeHttpsInitialIframe = function(info, doc, bodyHtml) {
+  var body = doc.body;
+
+  // For HTTPS we already have a document with a doc type and a body element
+  // and don't want to create a new history entry which can cause data loss if
+  // the user clicks the back button.
+  if (goog.editor.BrowserFeature.HAS_CONTENT_EDITABLE) {
+    body.contentEditable = true;
+  }
+  body.className = 'editable';
+  body.setAttribute('g_editable', true);
+  body.hideFocus = true;
+  body.id = info.fieldId_;
+
+  goog.style.setStyle(body, info.extraStyles_);
+  body.innerHTML = bodyHtml;
+};
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/link.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/link.js b/externs/GCL/externs/goog/editor/link.js
new file mode 100644
index 0000000..72f6c52
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/link.js
@@ -0,0 +1,390 @@
+// 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 A utility class for managing editable links.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.editor.Link');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.Range');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.BrowserFeature');
+goog.require('goog.editor.Command');
+goog.require('goog.editor.node');
+goog.require('goog.editor.range');
+goog.require('goog.string');
+goog.require('goog.string.Unicode');
+goog.require('goog.uri.utils');
+goog.require('goog.uri.utils.ComponentIndex');
+
+
+
+/**
+ * Wrap an editable link.
+ * @param {HTMLAnchorElement} anchor The anchor element.
+ * @param {boolean} isNew Whether this is a new link.
+ * @constructor
+ * @final
+ */
+goog.editor.Link = function(anchor, isNew) {
+  /**
+   * The link DOM element.
+   * @type {HTMLAnchorElement}
+   * @private
+   */
+  this.anchor_ = anchor;
+
+  /**
+   * Whether this link represents a link just added to the document.
+   * @type {boolean}
+   * @private
+   */
+  this.isNew_ = isNew;
+
+
+  /**
+   * Any extra anchors created by the browser from a selection in the same
+   * operation that created the primary link
+   * @type {!Array<HTMLAnchorElement>}
+   * @private
+   */
+  this.extraAnchors_ = [];
+};
+
+
+/**
+ * @return {HTMLAnchorElement} The anchor element.
+ */
+goog.editor.Link.prototype.getAnchor = function() {
+  return this.anchor_;
+};
+
+
+/**
+ * @return {!Array<HTMLAnchorElement>} The extra anchor elements, if any,
+ *     created by the browser from a selection.
+ */
+goog.editor.Link.prototype.getExtraAnchors = function() {
+  return this.extraAnchors_;
+};
+
+
+/**
+ * @return {string} The inner text for the anchor.
+ */
+goog.editor.Link.prototype.getCurrentText = function() {
+  if (!this.currentText_) {
+    var anchor = this.getAnchor();
+
+    var leaf = goog.editor.node.getLeftMostLeaf(anchor);
+    if (leaf.tagName && leaf.tagName == goog.dom.TagName.IMG) {
+      this.currentText_ = leaf.getAttribute('alt');
+    } else {
+      this.currentText_ = goog.dom.getRawTextContent(this.getAnchor());
+    }
+  }
+  return this.currentText_;
+};
+
+
+/**
+ * @return {boolean} Whether the link is new.
+ */
+goog.editor.Link.prototype.isNew = function() {
+  return this.isNew_;
+};
+
+
+/**
+ * Set the url without affecting the isNew() status of the link.
+ * @param {string} url A URL.
+ */
+goog.editor.Link.prototype.initializeUrl = function(url) {
+  this.getAnchor().href = url;
+};
+
+
+/**
+ * Removes the link, leaving its contents in the document.  Note that this
+ * object will no longer be usable/useful after this call.
+ */
+goog.editor.Link.prototype.removeLink = function() {
+  goog.dom.flattenElement(this.anchor_);
+  this.anchor_ = null;
+  while (this.extraAnchors_.length) {
+    goog.dom.flattenElement(/** @type {Element} */(this.extraAnchors_.pop()));
+  }
+};
+
+
+/**
+ * Change the link.
+ * @param {string} newText New text for the link. If the link contains all its
+ *     text in one descendent, newText will only replace the text in that
+ *     one node. Otherwise, we'll change the innerHTML of the whole
+ *     link to newText.
+ * @param {string} newUrl A new URL.
+ */
+goog.editor.Link.prototype.setTextAndUrl = function(newText, newUrl) {
+  var anchor = this.getAnchor();
+  anchor.href = newUrl;
+
+  // If the text did not change, don't update link text.
+  var currentText = this.getCurrentText();
+  if (newText != currentText) {
+    var leaf = goog.editor.node.getLeftMostLeaf(anchor);
+
+    if (leaf.tagName && leaf.tagName == goog.dom.TagName.IMG) {
+      leaf.setAttribute('alt', newText ? newText : '');
+    } else {
+      if (leaf.nodeType == goog.dom.NodeType.TEXT) {
+        leaf = leaf.parentNode;
+      }
+
+      if (goog.dom.getRawTextContent(leaf) != currentText) {
+        leaf = anchor;
+      }
+
+      goog.dom.removeChildren(leaf);
+      var domHelper = goog.dom.getDomHelper(leaf);
+      goog.dom.appendChild(leaf, domHelper.createTextNode(newText));
+    }
+
+    // The text changed, so force getCurrentText to recompute.
+    this.currentText_ = null;
+  }
+
+  this.isNew_ = false;
+};
+
+
+/**
+ * Places the cursor to the right of the anchor.
+ * Note that this is different from goog.editor.range's placeCursorNextTo
+ * in that it specifically handles the placement of a cursor in browsers
+ * that trap you in links, by adding a space when necessary and placing the
+ * cursor after that space.
+ */
+goog.editor.Link.prototype.placeCursorRightOf = function() {
+  var anchor = this.getAnchor();
+  // If the browser gets stuck in a link if we place the cursor next to it,
+  // we'll place the cursor after a space instead.
+  if (goog.editor.BrowserFeature.GETS_STUCK_IN_LINKS) {
+    var spaceNode;
+    var nextSibling = anchor.nextSibling;
+
+    // Check if there is already a space after the link.  Only handle the
+    // simple case - the next node is a text node that starts with a space.
+    if (nextSibling &&
+        nextSibling.nodeType == goog.dom.NodeType.TEXT &&
+        (goog.string.startsWith(nextSibling.data, goog.string.Unicode.NBSP) ||
+         goog.string.startsWith(nextSibling.data, ' '))) {
+      spaceNode = nextSibling;
+    } else {
+      // If there isn't an obvious space to use, create one after the link.
+      var dh = goog.dom.getDomHelper(anchor);
+      spaceNode = dh.createTextNode(goog.string.Unicode.NBSP);
+      goog.dom.insertSiblingAfter(spaceNode, anchor);
+    }
+
+    // Move the selection after the space.
+    var range = goog.dom.Range.createCaret(spaceNode, 1);
+    range.select();
+  } else {
+    goog.editor.range.placeCursorNextTo(anchor, false);
+  }
+};
+
+
+/**
+ * Updates the cursor position and link bubble for this link.
+ * @param {goog.editor.Field} field The field in which the link is created.
+ * @param {string} url The link url.
+ * @private
+ */
+goog.editor.Link.prototype.updateLinkDisplay_ = function(field, url) {
+  this.initializeUrl(url);
+  this.placeCursorRightOf();
+  field.execCommand(goog.editor.Command.UPDATE_LINK_BUBBLE);
+};
+
+
+/**
+ * @return {string?} The modified string for the link if the link
+ *     text appears to be a valid link. Returns null if this is not
+ *     a valid link address.
+ */
+goog.editor.Link.prototype.getValidLinkFromText = function() {
+  var text = goog.string.trim(this.getCurrentText());
+  if (goog.editor.Link.isLikelyUrl(text)) {
+    if (text.search(/:/) < 0) {
+      return 'http://' + goog.string.trimLeft(text);
+    }
+    return text;
+  } else if (goog.editor.Link.isLikelyEmailAddress(text)) {
+    return 'mailto:' + text;
+  }
+  return null;
+};
+
+
+/**
+ * After link creation, finish creating the link depending on the type
+ * of link being created.
+ * @param {goog.editor.Field} field The field where this link is being created.
+ */
+goog.editor.Link.prototype.finishLinkCreation = function(field) {
+  var linkFromText = this.getValidLinkFromText();
+  if (linkFromText) {
+    this.updateLinkDisplay_(field, linkFromText);
+  } else {
+    field.execCommand(goog.editor.Command.MODAL_LINK_EDITOR, this);
+  }
+};
+
+
+/**
+ * Initialize a new link.
+ * @param {HTMLAnchorElement} anchor The anchor element.
+ * @param {string} url The initial URL.
+ * @param {string=} opt_target The target.
+ * @param {Array<HTMLAnchorElement>=} opt_extraAnchors Extra anchors created
+ *     by the browser when parsing a selection.
+ * @return {!goog.editor.Link} The link.
+ */
+goog.editor.Link.createNewLink = function(anchor, url, opt_target,
+    opt_extraAnchors) {
+  var link = new goog.editor.Link(anchor, true);
+  link.initializeUrl(url);
+
+  if (opt_target) {
+    anchor.target = opt_target;
+  }
+  if (opt_extraAnchors) {
+    link.extraAnchors_ = opt_extraAnchors;
+  }
+
+  return link;
+};
+
+
+/**
+ * Initialize a new link using text in anchor, or empty string if there is no
+ * likely url in the anchor.
+ * @param {HTMLAnchorElement} anchor The anchor element with likely url content.
+ * @param {string=} opt_target The target.
+ * @return {!goog.editor.Link} The link.
+ */
+goog.editor.Link.createNewLinkFromText = function(anchor, opt_target) {
+  var link = new goog.editor.Link(anchor, true);
+  var text = link.getValidLinkFromText();
+  link.initializeUrl(text ? text : '');
+  if (opt_target) {
+    anchor.target = opt_target;
+  }
+  return link;
+};
+
+
+/**
+ * Returns true if str could be a URL, false otherwise
+ *
+ * Ex: TR_Util.isLikelyUrl_("http://www.google.com") == true
+ *     TR_Util.isLikelyUrl_("www.google.com") == true
+ *
+ * @param {string} str String to check if it looks like a URL.
+ * @return {boolean} Whether str could be a URL.
+ */
+goog.editor.Link.isLikelyUrl = function(str) {
+  // Whitespace means this isn't a domain.
+  if (/\s/.test(str)) {
+    return false;
+  }
+
+  if (goog.editor.Link.isLikelyEmailAddress(str)) {
+    return false;
+  }
+
+  // Add a scheme if the url doesn't have one - this helps the parser.
+  var addedScheme = false;
+  if (!/^[^:\/?#.]+:/.test(str)) {
+    str = 'http://' + str;
+    addedScheme = true;
+  }
+
+  // Parse the domain.
+  var parts = goog.uri.utils.split(str);
+
+  // Relax the rules for special schemes.
+  var scheme = parts[goog.uri.utils.ComponentIndex.SCHEME];
+  if (goog.array.indexOf(['mailto', 'aim'], scheme) != -1) {
+    return true;
+  }
+
+  // Require domains to contain a '.', unless the domain is fully qualified and
+  // forbids domains from containing invalid characters.
+  var domain = parts[goog.uri.utils.ComponentIndex.DOMAIN];
+  if (!domain || (addedScheme && domain.indexOf('.') == -1) ||
+      (/[^\w\d\-\u0100-\uffff.%]/.test(domain))) {
+    return false;
+  }
+
+  // Require http and ftp paths to start with '/'.
+  var path = parts[goog.uri.utils.ComponentIndex.PATH];
+  return !path || path.indexOf('/') == 0;
+};
+
+
+/**
+ * Regular expression that matches strings that could be an email address.
+ * @type {RegExp}
+ * @private
+ */
+goog.editor.Link.LIKELY_EMAIL_ADDRESS_ = new RegExp(
+    '^' +                     // Test from start of string
+    '[\\w-]+(\\.[\\w-]+)*' +  // Dot-delimited alphanumerics and dashes (name)
+    '\\@' +                   // @
+    '([\\w-]+\\.)+' +         // Alphanumerics, dashes and dots (domain)
+    '(\\d+|\\w\\w+)$',        // Domain ends in at least one number or 2 letters
+    'i');
+
+
+/**
+ * Returns true if str could be an email address, false otherwise
+ *
+ * Ex: goog.editor.Link.isLikelyEmailAddress_("some word") == false
+ *     goog.editor.Link.isLikelyEmailAddress_("foo@foo.com") == true
+ *
+ * @param {string} str String to test for being email address.
+ * @return {boolean} Whether "str" looks like an email address.
+ */
+goog.editor.Link.isLikelyEmailAddress = function(str) {
+  return goog.editor.Link.LIKELY_EMAIL_ADDRESS_.test(str);
+};
+
+
+/**
+ * Determines whether or not a url is an email link.
+ * @param {string} url A url.
+ * @return {boolean} Whether the url is a mailto link.
+ */
+goog.editor.Link.isMailto = function(url) {
+  return !!url && goog.string.startsWith(url, 'mailto:');
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/node.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/node.js b/externs/GCL/externs/goog/editor/node.js
new file mode 100644
index 0000000..006936d
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/node.js
@@ -0,0 +1,484 @@
+// Copyright 2005 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 Utilties for working with DOM nodes related to rich text
+ * editing.  Many of these are not general enough to go into goog.dom.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.editor.node');
+
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.iter.ChildIterator');
+goog.require('goog.dom.iter.SiblingIterator');
+goog.require('goog.iter');
+goog.require('goog.object');
+goog.require('goog.string');
+goog.require('goog.string.Unicode');
+goog.require('goog.userAgent');
+
+
+/**
+ * Names of all block-level tags
+ * @type {Object}
+ * @private
+ */
+goog.editor.node.BLOCK_TAG_NAMES_ = goog.object.createSet(
+    goog.dom.TagName.ADDRESS,
+    goog.dom.TagName.ARTICLE,
+    goog.dom.TagName.ASIDE,
+    goog.dom.TagName.BLOCKQUOTE,
+    goog.dom.TagName.BODY,
+    goog.dom.TagName.CAPTION,
+    goog.dom.TagName.CENTER,
+    goog.dom.TagName.COL,
+    goog.dom.TagName.COLGROUP,
+    goog.dom.TagName.DETAILS,
+    goog.dom.TagName.DIR,
+    goog.dom.TagName.DIV,
+    goog.dom.TagName.DL,
+    goog.dom.TagName.DD,
+    goog.dom.TagName.DT,
+    goog.dom.TagName.FIELDSET,
+    goog.dom.TagName.FIGCAPTION,
+    goog.dom.TagName.FIGURE,
+    goog.dom.TagName.FOOTER,
+    goog.dom.TagName.FORM,
+    goog.dom.TagName.H1,
+    goog.dom.TagName.H2,
+    goog.dom.TagName.H3,
+    goog.dom.TagName.H4,
+    goog.dom.TagName.H5,
+    goog.dom.TagName.H6,
+    goog.dom.TagName.HEADER,
+    goog.dom.TagName.HGROUP,
+    goog.dom.TagName.HR,
+    goog.dom.TagName.ISINDEX,
+    goog.dom.TagName.OL,
+    goog.dom.TagName.LI,
+    goog.dom.TagName.MAP,
+    goog.dom.TagName.MENU,
+    goog.dom.TagName.NAV,
+    goog.dom.TagName.OPTGROUP,
+    goog.dom.TagName.OPTION,
+    goog.dom.TagName.P,
+    goog.dom.TagName.PRE,
+    goog.dom.TagName.SECTION,
+    goog.dom.TagName.SUMMARY,
+    goog.dom.TagName.TABLE,
+    goog.dom.TagName.TBODY,
+    goog.dom.TagName.TD,
+    goog.dom.TagName.TFOOT,
+    goog.dom.TagName.TH,
+    goog.dom.TagName.THEAD,
+    goog.dom.TagName.TR,
+    goog.dom.TagName.UL);
+
+
+/**
+ * Names of tags that have intrinsic content.
+ * TODO(robbyw): What about object, br, input, textarea, button, isindex,
+ * hr, keygen, select, table, tr, td?
+ * @type {Object}
+ * @private
+ */
+goog.editor.node.NON_EMPTY_TAGS_ = goog.object.createSet(
+    goog.dom.TagName.IMG, goog.dom.TagName.IFRAME, goog.dom.TagName.EMBED);
+
+
+/**
+ * Check if the node is in a standards mode document.
+ * @param {Node} node The node to test.
+ * @return {boolean} Whether the node is in a standards mode document.
+ */
+goog.editor.node.isStandardsMode = function(node) {
+  return goog.dom.getDomHelper(node).isCss1CompatMode();
+};
+
+
+/**
+ * Get the right-most non-ignorable leaf node of the given node.
+ * @param {Node} parent The parent ndoe.
+ * @return {Node} The right-most non-ignorable leaf node.
+ */
+goog.editor.node.getRightMostLeaf = function(parent) {
+  var temp;
+  while (temp = goog.editor.node.getLastChild(parent)) {
+    parent = temp;
+  }
+  return parent;
+};
+
+
+/**
+ * Get the left-most non-ignorable leaf node of the given node.
+ * @param {Node} parent The parent ndoe.
+ * @return {Node} The left-most non-ignorable leaf node.
+ */
+goog.editor.node.getLeftMostLeaf = function(parent) {
+  var temp;
+  while (temp = goog.editor.node.getFirstChild(parent)) {
+    parent = temp;
+  }
+  return parent;
+};
+
+
+/**
+ * Version of firstChild that skips nodes that are entirely
+ * whitespace and comments.
+ * @param {Node} parent The reference node.
+ * @return {Node} The first child of sibling that is important according to
+ *     goog.editor.node.isImportant, or null if no such node exists.
+ */
+goog.editor.node.getFirstChild = function(parent) {
+  return goog.editor.node.getChildHelper_(parent, false);
+};
+
+
+/**
+ * Version of lastChild that skips nodes that are entirely whitespace or
+ * comments.  (Normally lastChild is a property of all DOM nodes that gives the
+ * last of the nodes contained directly in the reference node.)
+ * @param {Node} parent The reference node.
+ * @return {Node} The last child of sibling that is important according to
+ *     goog.editor.node.isImportant, or null if no such node exists.
+ */
+goog.editor.node.getLastChild = function(parent) {
+  return goog.editor.node.getChildHelper_(parent, true);
+};
+
+
+/**
+ * Version of previoussibling that skips nodes that are entirely
+ * whitespace or comments.  (Normally previousSibling is a property
+ * of all DOM nodes that gives the sibling node, the node that is
+ * a child of the same parent, that occurs immediately before the
+ * reference node.)
+ * @param {Node} sibling The reference node.
+ * @return {Node} The closest previous sibling to sibling that is
+ *     important according to goog.editor.node.isImportant, or null if no such
+ *     node exists.
+ */
+goog.editor.node.getPreviousSibling = function(sibling) {
+  return /** @type {Node} */ (goog.editor.node.getFirstValue_(
+      goog.iter.filter(new goog.dom.iter.SiblingIterator(sibling, false, true),
+      goog.editor.node.isImportant)));
+};
+
+
+/**
+ * Version of nextSibling that skips nodes that are entirely whitespace or
+ * comments.
+ * @param {Node} sibling The reference node.
+ * @return {Node} The closest next sibling to sibling that is important
+ *     according to goog.editor.node.isImportant, or null if no
+ *     such node exists.
+ */
+goog.editor.node.getNextSibling = function(sibling) {
+  return /** @type {Node} */ (goog.editor.node.getFirstValue_(
+      goog.iter.filter(new goog.dom.iter.SiblingIterator(sibling),
+      goog.editor.node.isImportant)));
+};
+
+
+/**
+ * Internal helper for lastChild/firstChild that skips nodes that are entirely
+ * whitespace or comments.
+ * @param {Node} parent The reference node.
+ * @param {boolean} isReversed Whether children should be traversed forward
+ *     or backward.
+ * @return {Node} The first/last child of sibling that is important according
+ *     to goog.editor.node.isImportant, or null if no such node exists.
+ * @private
+ */
+goog.editor.node.getChildHelper_ = function(parent, isReversed) {
+  return (!parent || parent.nodeType != goog.dom.NodeType.ELEMENT) ? null :
+      /** @type {Node} */ (goog.editor.node.getFirstValue_(goog.iter.filter(
+          new goog.dom.iter.ChildIterator(
+              /** @type {!Element} */ (parent), isReversed),
+          goog.editor.node.isImportant)));
+};
+
+
+/**
+ * Utility function that returns the first value from an iterator or null if
+ * the iterator is empty.
+ * @param {goog.iter.Iterator} iterator The iterator to get a value from.
+ * @return {*} The first value from the iterator.
+ * @private
+ */
+goog.editor.node.getFirstValue_ = function(iterator) {
+  /** @preserveTry */
+  try {
+    return iterator.next();
+  } catch (e) {
+    return null;
+  }
+};
+
+
+/**
+ * Determine if a node should be returned by the iterator functions.
+ * @param {Node} node An object implementing the DOM1 Node interface.
+ * @return {boolean} Whether the node is an element, or a text node that
+ *     is not all whitespace.
+ */
+goog.editor.node.isImportant = function(node) {
+  // Return true if the node is not either a TextNode or an ElementNode.
+  return node.nodeType == goog.dom.NodeType.ELEMENT ||
+         node.nodeType == goog.dom.NodeType.TEXT &&
+         !goog.editor.node.isAllNonNbspWhiteSpace(node);
+};
+
+
+/**
+ * Determine whether a node's text content is entirely whitespace.
+ * @param {Node} textNode A node implementing the CharacterData interface (i.e.,
+ *     a Text, Comment, or CDATASection node.
+ * @return {boolean} Whether the text content of node is whitespace,
+ *     otherwise false.
+ */
+goog.editor.node.isAllNonNbspWhiteSpace = function(textNode) {
+  return goog.string.isBreakingWhitespace(textNode.nodeValue);
+};
+
+
+/**
+ * Returns true if the node contains only whitespace and is not and does not
+ * contain any images, iframes or embed tags.
+ * @param {Node} node The node to check.
+ * @param {boolean=} opt_prohibitSingleNbsp By default, this function treats a
+ *     single nbsp as empty.  Set this to true to treat this case as non-empty.
+ * @return {boolean} Whether the node contains only whitespace.
+ */
+goog.editor.node.isEmpty = function(node, opt_prohibitSingleNbsp) {
+  var nodeData = goog.dom.getRawTextContent(node);
+
+  if (node.getElementsByTagName) {
+    for (var tag in goog.editor.node.NON_EMPTY_TAGS_) {
+      if (node.tagName == tag || node.getElementsByTagName(tag).length > 0) {
+        return false;
+      }
+    }
+  }
+  return (!opt_prohibitSingleNbsp && nodeData == goog.string.Unicode.NBSP) ||
+      goog.string.isBreakingWhitespace(nodeData);
+};
+
+
+/**
+ * Returns the length of the text in node if it is a text node, or the number
+ * of children of the node, if it is an element. Useful for range-manipulation
+ * code where you need to know the offset for the right side of the node.
+ * @param {Node} node The node to get the length of.
+ * @return {number} The length of the node.
+ */
+goog.editor.node.getLength = function(node) {
+  return node.length || node.childNodes.length;
+};
+
+
+/**
+ * Search child nodes using a predicate function and return the first node that
+ * satisfies the condition.
+ * @param {Node} parent The parent node to search.
+ * @param {function(Node):boolean} hasProperty A function that takes a child
+ *    node as a parameter and returns true if it meets the criteria.
+ * @return {?number} The index of the node found, or null if no node is found.
+ */
+goog.editor.node.findInChildren = function(parent, hasProperty) {
+  for (var i = 0, len = parent.childNodes.length; i < len; i++) {
+    if (hasProperty(parent.childNodes[i])) {
+      return i;
+    }
+  }
+  return null;
+};
+
+
+/**
+ * Search ancestor nodes using a predicate function and returns the topmost
+ * ancestor in the chain of consecutive ancestors that satisfies the condition.
+ *
+ * @param {Node} node The node whose ancestors have to be searched.
+ * @param {function(Node): boolean} hasProperty A function that takes a parent
+ *     node as a parameter and returns true if it meets the criteria.
+ * @return {Node} The topmost ancestor or null if no ancestor satisfies the
+ *     predicate function.
+ */
+goog.editor.node.findHighestMatchingAncestor = function(node, hasProperty) {
+  var parent = node.parentNode;
+  var ancestor = null;
+  while (parent && hasProperty(parent)) {
+    ancestor = parent;
+    parent = parent.parentNode;
+  }
+  return ancestor;
+};
+
+
+/**
+* Checks if node is a block-level html element. The <tt>display</tt> css
+ * property is ignored.
+ * @param {Node} node The node to test.
+ * @return {boolean} Whether the node is a block-level node.
+ */
+goog.editor.node.isBlockTag = function(node) {
+  return !!goog.editor.node.BLOCK_TAG_NAMES_[node.tagName];
+};
+
+
+/**
+ * Skips siblings of a node that are empty text nodes.
+ * @param {Node} node A node. May be null.
+ * @return {Node} The node or the first sibling of the node that is not an
+ *     empty text node. May be null.
+ */
+goog.editor.node.skipEmptyTextNodes = function(node) {
+  while (node && node.nodeType == goog.dom.NodeType.TEXT &&
+      !node.nodeValue) {
+    node = node.nextSibling;
+  }
+  return node;
+};
+
+
+/**
+ * Checks if an element is a top-level editable container (meaning that
+ * it itself is not editable, but all its child nodes are editable).
+ * @param {Node} element The element to test.
+ * @return {boolean} Whether the element is a top-level editable container.
+ */
+goog.editor.node.isEditableContainer = function(element) {
+  return element.getAttribute &&
+      element.getAttribute('g_editable') == 'true';
+};
+
+
+/**
+ * Checks if a node is inside an editable container.
+ * @param {Node} node The node to test.
+ * @return {boolean} Whether the node is in an editable container.
+ */
+goog.editor.node.isEditable = function(node) {
+  return !!goog.dom.getAncestor(node, goog.editor.node.isEditableContainer);
+};
+
+
+/**
+ * Finds the top-most DOM node inside an editable field that is an ancestor
+ * (or self) of a given DOM node and meets the specified criteria.
+ * @param {Node} node The DOM node where the search starts.
+ * @param {function(Node) : boolean} criteria A function that takes a DOM node
+ *     as a parameter and returns a boolean to indicate whether the node meets
+ *     the criteria or not.
+ * @return {Node} The DOM node if found, or null.
+ */
+goog.editor.node.findTopMostEditableAncestor = function(node, criteria) {
+  var targetNode = null;
+  while (node && !goog.editor.node.isEditableContainer(node)) {
+    if (criteria(node)) {
+      targetNode = node;
+    }
+    node = node.parentNode;
+  }
+  return targetNode;
+};
+
+
+/**
+ * Splits off a subtree.
+ * @param {!Node} currentNode The starting splitting point.
+ * @param {Node=} opt_secondHalf The initial leftmost leaf the new subtree.
+ *     If null, siblings after currentNode will be placed in the subtree, but
+ *     no additional node will be.
+ * @param {Node=} opt_root The top of the tree where splitting stops at.
+ * @return {!Node} The new subtree.
+ */
+goog.editor.node.splitDomTreeAt = function(currentNode,
+    opt_secondHalf, opt_root) {
+  var parent;
+  while (currentNode != opt_root && (parent = currentNode.parentNode)) {
+    opt_secondHalf = goog.editor.node.getSecondHalfOfNode_(parent, currentNode,
+        opt_secondHalf);
+    currentNode = parent;
+  }
+  return /** @type {!Node} */(opt_secondHalf);
+};
+
+
+/**
+ * Creates a clone of node, moving all children after startNode to it.
+ * When firstChild is not null or undefined, it is also appended to the clone
+ * as the first child.
+ * @param {!Node} node The node to clone.
+ * @param {!Node} startNode All siblings after this node will be moved to the
+ *     clone.
+ * @param {Node|undefined} firstChild The first child of the new cloned element.
+ * @return {!Node} The cloned node that now contains the children after
+ *     startNode.
+ * @private
+ */
+goog.editor.node.getSecondHalfOfNode_ = function(node, startNode, firstChild) {
+  var secondHalf = /** @type {!Node} */(node.cloneNode(false));
+  while (startNode.nextSibling) {
+    goog.dom.appendChild(secondHalf, startNode.nextSibling);
+  }
+  if (firstChild) {
+    secondHalf.insertBefore(firstChild, secondHalf.firstChild);
+  }
+  return secondHalf;
+};
+
+
+/**
+ * Appends all of oldNode's children to newNode. This removes all children from
+ * oldNode and appends them to newNode. oldNode is left with no children.
+ * @param {!Node} newNode Node to transfer children to.
+ * @param {Node} oldNode Node to transfer children from.
+ * @deprecated Use goog.dom.append directly instead.
+ */
+goog.editor.node.transferChildren = function(newNode, oldNode) {
+  goog.dom.append(newNode, oldNode.childNodes);
+};
+
+
+/**
+ * Replaces the innerHTML of a node.
+ *
+ * IE has serious problems if you try to set innerHTML of an editable node with
+ * any selection. Early versions of IE tear up the old internal tree storage, to
+ * help avoid ref-counting loops. But this sometimes leaves the selection object
+ * in a bad state and leads to segfaults.
+ *
+ * Removing the nodes first prevents IE from tearing them up. This is not
+ * strictly necessary in nodes that do not have the selection. You should always
+ * use this function when setting innerHTML inside of a field.
+ *
+ * @param {Node} node A node.
+ * @param {string} html The innerHTML to set on the node.
+ */
+goog.editor.node.replaceInnerHtml = function(node, html) {
+  // Only do this IE. On gecko, we use element change events, and don't
+  // want to trigger spurious events.
+  if (goog.userAgent.IE) {
+    goog.dom.removeChildren(node);
+  }
+  node.innerHTML = html;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugin.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugin.js b/externs/GCL/externs/goog/editor/plugin.js
new file mode 100644
index 0000000..d823ccb
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugin.js
@@ -0,0 +1,463 @@
+// Copyright 2008 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.
+// All Rights Reserved.
+
+/**
+ * @fileoverview Abstract API for TrogEdit plugins.
+ *
+ * @see ../demos/editor/editor.html
+ */
+
+goog.provide('goog.editor.Plugin');
+
+// TODO(user): Remove the dependency on goog.editor.Command asap. Currently only
+// needed for execCommand issues with links.
+goog.require('goog.events.EventTarget');
+goog.require('goog.functions');
+goog.require('goog.log');
+goog.require('goog.object');
+goog.require('goog.reflect');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Abstract API for trogedit plugins.
+ * @constructor
+ * @extends {goog.events.EventTarget}
+ */
+goog.editor.Plugin = function() {
+  goog.events.EventTarget.call(this);
+
+  /**
+   * Whether this plugin is enabled for the registered field object.
+   * @type {boolean}
+   * @private
+   */
+  this.enabled_ = this.activeOnUneditableFields();
+};
+goog.inherits(goog.editor.Plugin, goog.events.EventTarget);
+
+
+/**
+ * The field object this plugin is attached to.
+ * @type {goog.editor.Field}
+ * @protected
+ * @deprecated Use goog.editor.Plugin.getFieldObject and
+ *     goog.editor.Plugin.setFieldObject.
+ */
+goog.editor.Plugin.prototype.fieldObject = null;
+
+
+/**
+ * @return {goog.dom.DomHelper?} The dom helper object associated with the
+ *     currently active field.
+ */
+goog.editor.Plugin.prototype.getFieldDomHelper = function() {
+  return this.getFieldObject() && this.getFieldObject().getEditableDomHelper();
+};
+
+
+/**
+ * Indicates if this plugin should be automatically disposed when the
+ * registered field is disposed. This should be changed to false for
+ * plugins used as multi-field plugins.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.Plugin.prototype.autoDispose_ = true;
+
+
+/**
+ * The logger for this plugin.
+ * @type {goog.log.Logger}
+ * @protected
+ */
+goog.editor.Plugin.prototype.logger =
+    goog.log.getLogger('goog.editor.Plugin');
+
+
+/**
+ * Sets the field object for use with this plugin.
+ * @return {goog.editor.Field} The editable field object.
+ * @protected
+ * @suppress {deprecated} Until fieldObject can be made private.
+ */
+goog.editor.Plugin.prototype.getFieldObject = function() {
+  return this.fieldObject;
+};
+
+
+/**
+ * Sets the field object for use with this plugin.
+ * @param {goog.editor.Field} fieldObject The editable field object.
+ * @protected
+ * @suppress {deprecated} Until fieldObject can be made private.
+ */
+goog.editor.Plugin.prototype.setFieldObject = function(fieldObject) {
+  this.fieldObject = fieldObject;
+};
+
+
+/**
+ * Registers the field object for use with this plugin.
+ * @param {goog.editor.Field} fieldObject The editable field object.
+ */
+goog.editor.Plugin.prototype.registerFieldObject = function(fieldObject) {
+  this.setFieldObject(fieldObject);
+};
+
+
+/**
+ * Unregisters and disables this plugin for the current field object.
+ * @param {goog.editor.Field} fieldObj The field object. For single-field
+ *     plugins, this parameter is ignored.
+ */
+goog.editor.Plugin.prototype.unregisterFieldObject = function(fieldObj) {
+  if (this.getFieldObject()) {
+    this.disable(this.getFieldObject());
+    this.setFieldObject(null);
+  }
+};
+
+
+/**
+ * Enables this plugin for the specified, registered field object. A field
+ * object should only be enabled when it is loaded.
+ * @param {goog.editor.Field} fieldObject The field object.
+ */
+goog.editor.Plugin.prototype.enable = function(fieldObject) {
+  if (this.getFieldObject() == fieldObject) {
+    this.enabled_ = true;
+  } else {
+    goog.log.error(this.logger, 'Trying to enable an unregistered field with ' +
+        'this plugin.');
+  }
+};
+
+
+/**
+ * Disables this plugin for the specified, registered field object.
+ * @param {goog.editor.Field} fieldObject The field object.
+ */
+goog.editor.Plugin.prototype.disable = function(fieldObject) {
+  if (this.getFieldObject() == fieldObject) {
+    this.enabled_ = false;
+  } else {
+    goog.log.error(this.logger, 'Trying to disable an unregistered field ' +
+        'with this plugin.');
+  }
+};
+
+
+/**
+ * Returns whether this plugin is enabled for the field object.
+ *
+ * @param {goog.editor.Field} fieldObject The field object.
+ * @return {boolean} Whether this plugin is enabled for the field object.
+ */
+goog.editor.Plugin.prototype.isEnabled = function(fieldObject) {
+  return this.getFieldObject() == fieldObject ? this.enabled_ : false;
+};
+
+
+/**
+ * Set if this plugin should automatically be disposed when the registered
+ * field is disposed.
+ * @param {boolean} autoDispose Whether to autoDispose.
+ */
+goog.editor.Plugin.prototype.setAutoDispose = function(autoDispose) {
+  this.autoDispose_ = autoDispose;
+};
+
+
+/**
+ * @return {boolean} Whether or not this plugin should automatically be disposed
+ *     when it's registered field is disposed.
+ */
+goog.editor.Plugin.prototype.isAutoDispose = function() {
+  return this.autoDispose_;
+};
+
+
+/**
+ * @return {boolean} If true, field will not disable the command
+ *     when the field becomes uneditable.
+ */
+goog.editor.Plugin.prototype.activeOnUneditableFields = goog.functions.FALSE;
+
+
+/**
+ * @param {string} command The command to check.
+ * @return {boolean} If true, field will not dispatch change events
+ *     for commands of this type. This is useful for "seamless" plugins like
+ *     dialogs and lorem ipsum.
+ */
+goog.editor.Plugin.prototype.isSilentCommand = goog.functions.FALSE;
+
+
+/** @override */
+goog.editor.Plugin.prototype.disposeInternal = function() {
+  if (this.getFieldObject()) {
+    this.unregisterFieldObject(this.getFieldObject());
+  }
+
+  goog.editor.Plugin.superClass_.disposeInternal.call(this);
+};
+
+
+/**
+ * @return {string} The ID unique to this plugin class. Note that different
+ *     instances off the plugin share the same classId.
+ */
+goog.editor.Plugin.prototype.getTrogClassId;
+
+
+/**
+ * An enum of operations that plugins may support.
+ * @enum {number}
+ */
+goog.editor.Plugin.Op = {
+  KEYDOWN: 1,
+  KEYPRESS: 2,
+  KEYUP: 3,
+  SELECTION: 4,
+  SHORTCUT: 5,
+  EXEC_COMMAND: 6,
+  QUERY_COMMAND: 7,
+  PREPARE_CONTENTS_HTML: 8,
+  CLEAN_CONTENTS_HTML: 10,
+  CLEAN_CONTENTS_DOM: 11
+};
+
+
+/**
+ * A map from plugin operations to the names of the methods that
+ * invoke those operations.
+ */
+goog.editor.Plugin.OPCODE = goog.object.transpose(
+    goog.reflect.object(goog.editor.Plugin, {
+      handleKeyDown: goog.editor.Plugin.Op.KEYDOWN,
+      handleKeyPress: goog.editor.Plugin.Op.KEYPRESS,
+      handleKeyUp: goog.editor.Plugin.Op.KEYUP,
+      handleSelectionChange: goog.editor.Plugin.Op.SELECTION,
+      handleKeyboardShortcut: goog.editor.Plugin.Op.SHORTCUT,
+      execCommand: goog.editor.Plugin.Op.EXEC_COMMAND,
+      queryCommandValue: goog.editor.Plugin.Op.QUERY_COMMAND,
+      prepareContentsHtml: goog.editor.Plugin.Op.PREPARE_CONTENTS_HTML,
+      cleanContentsHtml: goog.editor.Plugin.Op.CLEAN_CONTENTS_HTML,
+      cleanContentsDom: goog.editor.Plugin.Op.CLEAN_CONTENTS_DOM
+    }));
+
+
+/**
+ * A set of op codes that run even on disabled plugins.
+ */
+goog.editor.Plugin.IRREPRESSIBLE_OPS = goog.object.createSet(
+    goog.editor.Plugin.Op.PREPARE_CONTENTS_HTML,
+    goog.editor.Plugin.Op.CLEAN_CONTENTS_HTML,
+    goog.editor.Plugin.Op.CLEAN_CONTENTS_DOM);
+
+
+/**
+ * Handles keydown. It is run before handleKeyboardShortcut and if it returns
+ * true handleKeyboardShortcut will not be called.
+ * @param {!goog.events.BrowserEvent} e The browser event.
+ * @return {boolean} Whether the event was handled and thus should *not* be
+ *     propagated to other plugins or handleKeyboardShortcut.
+ */
+goog.editor.Plugin.prototype.handleKeyDown;
+
+
+/**
+ * Handles keypress. It is run before handleKeyboardShortcut and if it returns
+ * true handleKeyboardShortcut will not be called.
+ * @param {!goog.events.BrowserEvent} e The browser event.
+ * @return {boolean} Whether the event was handled and thus should *not* be
+ *     propagated to other plugins or handleKeyboardShortcut.
+ */
+goog.editor.Plugin.prototype.handleKeyPress;
+
+
+/**
+ * Handles keyup.
+ * @param {!goog.events.BrowserEvent} e The browser event.
+ * @return {boolean} Whether the event was handled and thus should *not* be
+ *     propagated to other plugins.
+ */
+goog.editor.Plugin.prototype.handleKeyUp;
+
+
+/**
+ * Handles selection change.
+ * @param {!goog.events.BrowserEvent=} opt_e The browser event.
+ * @param {!Node=} opt_target The node the selection changed to.
+ * @return {boolean} Whether the event was handled and thus should *not* be
+ *     propagated to other plugins.
+ */
+goog.editor.Plugin.prototype.handleSelectionChange;
+
+
+/**
+ * Handles keyboard shortcuts.  Preferred to using handleKey* as it will use
+ * the proper event based on browser and will be more performant. If
+ * handleKeyPress/handleKeyDown returns true, this will not be called. If the
+ * plugin handles the shortcut, it is responsible for dispatching appropriate
+ * events (change, selection change at the time of this comment). If the plugin
+ * calls execCommand on the editable field, then execCommand already takes care
+ * of dispatching events.
+ * NOTE: For performance reasons this is only called when any key is pressed
+ * in conjunction with ctrl/meta keys OR when a small subset of keys (defined
+ * in goog.editor.Field.POTENTIAL_SHORTCUT_KEYCODES_) are pressed without
+ * ctrl/meta keys. We specifically don't invoke it when altKey is pressed since
+ * alt key is used in many i8n UIs to enter certain characters.
+ * @param {!goog.events.BrowserEvent} e The browser event.
+ * @param {string} key The key pressed.
+ * @param {boolean} isModifierPressed Whether the ctrl/meta key was pressed or
+ *     not.
+ * @return {boolean} Whether the event was handled and thus should *not* be
+ *     propagated to other plugins. We also call preventDefault on the event if
+ *     the return value is true.
+ */
+goog.editor.Plugin.prototype.handleKeyboardShortcut;
+
+
+/**
+ * Handles execCommand. This default implementation handles dispatching
+ * BEFORECHANGE, CHANGE, and SELECTIONCHANGE events, and calls
+ * execCommandInternal to perform the actual command. Plugins that want to
+ * do their own event dispatching should override execCommand, otherwise
+ * it is preferred to only override execCommandInternal.
+ *
+ * This version of execCommand will only work for single field plugins.
+ * Multi-field plugins must override execCommand.
+ *
+ * @param {string} command The command to execute.
+ * @param {...*} var_args Any additional parameters needed to
+ *     execute the command.
+ * @return {*} The result of the execCommand, if any.
+ */
+goog.editor.Plugin.prototype.execCommand = function(command, var_args) {
+  // TODO(user): Replace all uses of isSilentCommand with plugins that just
+  // override this base execCommand method.
+  var silent = this.isSilentCommand(command);
+  if (!silent) {
+    // Stop listening to mutation events in Firefox while text formatting
+    // is happening.  This prevents us from trying to size the field in the
+    // middle of an execCommand, catching the field in a strange intermediary
+    // state where both replacement nodes and original nodes are appended to
+    // the dom.  Note that change events get turned back on by
+    // fieldObj.dispatchChange.
+    if (goog.userAgent.GECKO) {
+      this.getFieldObject().stopChangeEvents(true, true);
+    }
+
+    this.getFieldObject().dispatchBeforeChange();
+  }
+
+  try {
+    var result = this.execCommandInternal.apply(this, arguments);
+  } finally {
+    // If the above execCommandInternal call throws an exception, we still need
+    // to turn change events back on (see http://b/issue?id=1471355).
+    // NOTE: If if you add to or change the methods called in this finally
+    // block, please add them as expected calls to the unit test function
+    // testExecCommandException().
+    if (!silent) {
+      // dispatchChange includes a call to startChangeEvents, which unwinds the
+      // call to stopChangeEvents made before the try block.
+      this.getFieldObject().dispatchChange();
+      this.getFieldObject().dispatchSelectionChangeEvent();
+    }
+  }
+
+  return result;
+};
+
+
+/**
+ * Handles execCommand. This default implementation does nothing, and is
+ * called by execCommand, which handles event dispatching. This method should
+ * be overriden by plugins that don't need to do their own event dispatching.
+ * If custom event dispatching is needed, execCommand shoul be overriden
+ * instead.
+ *
+ * @param {string} command The command to execute.
+ * @param {...*} var_args Any additional parameters needed to
+ *     execute the command.
+ * @return {*} The result of the execCommand, if any.
+ * @protected
+ */
+goog.editor.Plugin.prototype.execCommandInternal;
+
+
+/**
+ * Gets the state of this command if this plugin serves that command.
+ * @param {string} command The command to check.
+ * @return {*} The value of the command.
+ */
+goog.editor.Plugin.prototype.queryCommandValue;
+
+
+/**
+ * Prepares the given HTML for editing. Strips out content that should not
+ * appear in an editor, and normalizes content as appropriate. The inverse
+ * of cleanContentsHtml.
+ *
+ * This op is invoked even on disabled plugins.
+ *
+ * @param {string} originalHtml The original HTML.
+ * @param {Object} styles A map of strings. If the plugin wants to add
+ *     any styles to the field element, it should add them as key-value
+ *     pairs to this object.
+ * @return {string} New HTML that's ok for editing.
+ */
+goog.editor.Plugin.prototype.prepareContentsHtml;
+
+
+/**
+ * Cleans the contents of the node passed to it. The node contents are modified
+ * directly, and the modifications will subsequently be used, for operations
+ * such as saving the innerHTML of the editor etc. Since the plugins act on
+ * the DOM directly, this method can be very expensive.
+ *
+ * This op is invoked even on disabled plugins.
+ *
+ * @param {!Element} fieldCopy The copy of the editable field which
+ *     needs to be cleaned up.
+ */
+goog.editor.Plugin.prototype.cleanContentsDom;
+
+
+/**
+ * Cleans the html contents of Trogedit. Both cleanContentsDom and
+ * and cleanContentsHtml will be called on contents extracted from Trogedit.
+ * The inverse of prepareContentsHtml.
+ *
+ * This op is invoked even on disabled plugins.
+ *
+ * @param {string} originalHtml The trogedit HTML.
+ * @return {string} Cleaned-up HTML.
+ */
+goog.editor.Plugin.prototype.cleanContentsHtml;
+
+
+/**
+ * Whether the string corresponds to a command this plugin handles.
+ * @param {string} command Command string to check.
+ * @return {boolean} Whether the plugin handles this type of command.
+ */
+goog.editor.Plugin.prototype.isSupportedCommand = function(command) {
+  return false;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/abstractbubbleplugin.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/abstractbubbleplugin.js b/externs/GCL/externs/goog/editor/plugins/abstractbubbleplugin.js
new file mode 100644
index 0000000..4951ed6
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/abstractbubbleplugin.js
@@ -0,0 +1,712 @@
+// Copyright 2005 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 Base class for bubble plugins.
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.editor.plugins.AbstractBubblePlugin');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.Range');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.classlist');
+goog.require('goog.editor.Plugin');
+goog.require('goog.editor.style');
+goog.require('goog.events');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventType');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.events.actionEventWrapper');
+goog.require('goog.functions');
+goog.require('goog.string.Unicode');
+goog.require('goog.ui.Component');
+goog.require('goog.ui.editor.Bubble');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Base class for bubble plugins. This is used for to connect user behavior
+ * in the editor to a goog.ui.editor.Bubble UI element that allows
+ * the user to modify the properties of an element on their page (e.g. the alt
+ * text of an image tag).
+ *
+ * Subclasses should override the abstract method getBubbleTargetFromSelection()
+ * with code to determine if the current selection should activate the bubble
+ * type. The other abstract method createBubbleContents() should be overriden
+ * with code to create the inside markup of the bubble.  The base class creates
+ * the rest of the bubble.
+ *
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ */
+goog.editor.plugins.AbstractBubblePlugin = function() {
+  goog.editor.plugins.AbstractBubblePlugin.base(this, 'constructor');
+
+  /**
+   * Place to register events the plugin listens to.
+   * @type {goog.events.EventHandler<
+   *     !goog.editor.plugins.AbstractBubblePlugin>}
+   * @protected
+   */
+  this.eventRegister = new goog.events.EventHandler(this);
+
+  /**
+   * Instance factory function that creates a bubble UI component.  If set to a
+   * non-null value, this function will be used to create a bubble instead of
+   * the global factory function.  It takes as parameters the bubble parent
+   * element and the z index to draw the bubble at.
+   * @type {?function(!Element, number): !goog.ui.editor.Bubble}
+   * @private
+   */
+  this.bubbleFactory_ = null;
+};
+goog.inherits(goog.editor.plugins.AbstractBubblePlugin, goog.editor.Plugin);
+
+
+/**
+ * The css class name of option link elements.
+ * @type {string}
+ * @private
+ */
+goog.editor.plugins.AbstractBubblePlugin.OPTION_LINK_CLASSNAME_ =
+    goog.getCssName('tr_option-link');
+
+
+/**
+ * The css class name of link elements.
+ * @type {string}
+ * @private
+ */
+goog.editor.plugins.AbstractBubblePlugin.LINK_CLASSNAME_ =
+    goog.getCssName('tr_bubble_link');
+
+
+/**
+ * A class name to mark elements that should be reachable by keyboard tabbing.
+ * @type {string}
+ * @private
+ */
+goog.editor.plugins.AbstractBubblePlugin.TABBABLE_CLASSNAME_ =
+    goog.getCssName('tr_bubble_tabbable');
+
+
+/**
+ * The constant string used to separate option links.
+ * @type {string}
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.DASH_NBSP_STRING =
+    goog.string.Unicode.NBSP + '-' + goog.string.Unicode.NBSP;
+
+
+/**
+ * Default factory function for creating a bubble UI component.
+ * @param {!Element} parent The parent element for the bubble.
+ * @param {number} zIndex The z index to draw the bubble at.
+ * @return {!goog.ui.editor.Bubble} The new bubble component.
+ * @private
+ */
+goog.editor.plugins.AbstractBubblePlugin.defaultBubbleFactory_ = function(
+    parent, zIndex) {
+  return new goog.ui.editor.Bubble(parent, zIndex);
+};
+
+
+/**
+ * Global factory function that creates a bubble UI component. It takes as
+ * parameters the bubble parent element and the z index to draw the bubble at.
+ * @type {function(!Element, number): !goog.ui.editor.Bubble}
+ * @private
+ */
+goog.editor.plugins.AbstractBubblePlugin.globalBubbleFactory_ =
+    goog.editor.plugins.AbstractBubblePlugin.defaultBubbleFactory_;
+
+
+/**
+ * Sets the global bubble factory function.
+ * @param {function(!Element, number): !goog.ui.editor.Bubble}
+ *     bubbleFactory Function that creates a bubble for the given bubble parent
+ *     element and z index.
+ */
+goog.editor.plugins.AbstractBubblePlugin.setBubbleFactory = function(
+    bubbleFactory) {
+  goog.editor.plugins.AbstractBubblePlugin.globalBubbleFactory_ = bubbleFactory;
+};
+
+
+/**
+ * Map from field id to shared bubble object.
+ * @type {!Object<goog.ui.editor.Bubble>}
+ * @private
+ */
+goog.editor.plugins.AbstractBubblePlugin.bubbleMap_ = {};
+
+
+/**
+ * The optional parent of the bubble.  If null or not set, we will use the
+ * application document. This is useful when you have an editor embedded in
+ * a scrolling DIV.
+ * @type {Element|undefined}
+ * @private
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.bubbleParent_;
+
+
+/**
+ * The id of the panel this plugin added to the shared bubble.  Null when
+ * this plugin doesn't currently have a panel in a bubble.
+ * @type {string?}
+ * @private
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.panelId_ = null;
+
+
+/**
+ * Whether this bubble should support tabbing through elements. False
+ * by default.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.keyboardNavigationEnabled_ =
+    false;
+
+
+/**
+ * Sets the instance bubble factory function.  If set to a non-null value, this
+ * function will be used to create a bubble instead of the global factory
+ * function.
+ * @param {?function(!Element, number): !goog.ui.editor.Bubble} bubbleFactory
+ *     Function that creates a bubble for the given bubble parent element and z
+ *     index.  Null to reset the factory function.
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.setBubbleFactory = function(
+    bubbleFactory) {
+  this.bubbleFactory_ = bubbleFactory;
+};
+
+
+/**
+ * Sets whether the bubble should support tabbing through elements.
+ * @param {boolean} keyboardNavigationEnabled
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.enableKeyboardNavigation =
+    function(keyboardNavigationEnabled) {
+  this.keyboardNavigationEnabled_ = keyboardNavigationEnabled;
+};
+
+
+/**
+ * Sets the bubble parent.
+ * @param {Element} bubbleParent An element where the bubble will be
+ *     anchored. If null, we will use the application document. This
+ *     is useful when you have an editor embedded in a scrolling div.
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.setBubbleParent = function(
+    bubbleParent) {
+  this.bubbleParent_ = bubbleParent;
+};
+
+
+/**
+ * Returns the bubble map.  Subclasses may override to use a separate map.
+ * @return {!Object<goog.ui.editor.Bubble>}
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.getBubbleMap = function() {
+  return goog.editor.plugins.AbstractBubblePlugin.bubbleMap_;
+};
+
+
+/**
+ * @return {goog.dom.DomHelper} The dom helper for the bubble window.
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.getBubbleDom = function() {
+  return this.dom_;
+};
+
+
+/** @override */
+goog.editor.plugins.AbstractBubblePlugin.prototype.getTrogClassId =
+    goog.functions.constant('AbstractBubblePlugin');
+
+
+/**
+ * Returns the element whose properties the bubble manipulates.
+ * @return {Element} The target element.
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.getTargetElement =
+    function() {
+  return this.targetElement_;
+};
+
+
+/** @override */
+goog.editor.plugins.AbstractBubblePlugin.prototype.handleKeyUp = function(e) {
+  // For example, when an image is selected, pressing any key overwrites
+  // the image and the panel should be hidden.
+  // Therefore we need to track key presses when the bubble is showing.
+  if (this.isVisible()) {
+    this.handleSelectionChange();
+  }
+  return false;
+};
+
+
+/**
+ * Pops up a property bubble for the given selection if appropriate and closes
+ * open property bubbles if no longer needed.  This should not be overridden.
+ * @override
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.handleSelectionChange =
+    function(opt_e, opt_target) {
+  var selectedElement;
+  if (opt_e) {
+    selectedElement = /** @type {Element} */ (opt_e.target);
+  } else if (opt_target) {
+    selectedElement = /** @type {Element} */ (opt_target);
+  } else {
+    var range = this.getFieldObject().getRange();
+    if (range) {
+      var startNode = range.getStartNode();
+      var endNode = range.getEndNode();
+      var startOffset = range.getStartOffset();
+      var endOffset = range.getEndOffset();
+      // Sometimes in IE, the range will be collapsed, but think the end node
+      // and start node are different (although in the same visible position).
+      // In this case, favor the position IE thinks is the start node.
+      if (goog.userAgent.IE && range.isCollapsed() && startNode != endNode) {
+        range = goog.dom.Range.createCaret(startNode, startOffset);
+      }
+      if (startNode.nodeType == goog.dom.NodeType.ELEMENT &&
+          startNode == endNode && startOffset == endOffset - 1) {
+        var element = startNode.childNodes[startOffset];
+        if (element.nodeType == goog.dom.NodeType.ELEMENT) {
+          selectedElement = element;
+        }
+      }
+    }
+    selectedElement = selectedElement || range && range.getContainerElement();
+  }
+  return this.handleSelectionChangeInternal(selectedElement);
+};
+
+
+/**
+ * Pops up a property bubble for the given selection if appropriate and closes
+ * open property bubbles if no longer needed.
+ * @param {Element?} selectedElement The selected element.
+ * @return {boolean} Always false, allowing every bubble plugin to handle the
+ *     event.
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.
+    handleSelectionChangeInternal = function(selectedElement) {
+  if (selectedElement) {
+    var bubbleTarget = this.getBubbleTargetFromSelection(selectedElement);
+    if (bubbleTarget) {
+      if (bubbleTarget != this.targetElement_ || !this.panelId_) {
+        // Make sure any existing panel of the same type is closed before
+        // creating a new one.
+        if (this.panelId_) {
+          this.closeBubble();
+        }
+        this.createBubble(bubbleTarget);
+      }
+      return false;
+    }
+  }
+
+  if (this.panelId_) {
+    this.closeBubble();
+  }
+
+  return false;
+};
+
+
+/**
+ * Should be overriden by subclasses to return the bubble target element or
+ * null if an element of their required type isn't found.
+ * @param {Element} selectedElement The target of the selection change event or
+ *     the parent container of the current entire selection.
+ * @return {Element?} The HTML bubble target element or null if no element of
+ *     the required type is not found.
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.
+    getBubbleTargetFromSelection = goog.abstractMethod;
+
+
+/** @override */
+goog.editor.plugins.AbstractBubblePlugin.prototype.disable = function(field) {
+  // When the field is made uneditable, dispose of the bubble.  We do this
+  // because the next time the field is made editable again it may be in
+  // a different document / iframe.
+  if (field.isUneditable()) {
+    var bubbleMap = this.getBubbleMap();
+    var bubble = bubbleMap[field.id];
+    if (bubble) {
+      if (field == this.getFieldObject()) {
+        this.closeBubble();
+      }
+      bubble.dispose();
+      delete bubbleMap[field.id];
+    }
+  }
+};
+
+
+/**
+ * @return {!goog.ui.editor.Bubble} The shared bubble object for the field this
+ *     plugin is registered on.  Creates it if necessary.
+ * @private
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.getSharedBubble_ =
+    function() {
+  var bubbleParent = /** @type {!Element} */ (this.bubbleParent_ ||
+      this.getFieldObject().getAppWindow().document.body);
+  this.dom_ = goog.dom.getDomHelper(bubbleParent);
+
+  var bubbleMap = this.getBubbleMap();
+  var bubble = bubbleMap[this.getFieldObject().id];
+  if (!bubble) {
+    var factory = this.bubbleFactory_ ||
+        goog.editor.plugins.AbstractBubblePlugin.globalBubbleFactory_;
+    bubble = factory.call(null, bubbleParent,
+        this.getFieldObject().getBaseZindex());
+    bubbleMap[this.getFieldObject().id] = bubble;
+  }
+  return bubble;
+};
+
+
+/**
+ * Creates and shows the property bubble.
+ * @param {Element} targetElement The target element of the bubble.
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.createBubble = function(
+    targetElement) {
+  var bubble = this.getSharedBubble_();
+  if (!bubble.hasPanelOfType(this.getBubbleType())) {
+    this.targetElement_ = targetElement;
+
+    this.panelId_ = bubble.addPanel(this.getBubbleType(), this.getBubbleTitle(),
+        targetElement,
+        goog.bind(this.createBubbleContents, this),
+        this.shouldPreferBubbleAboveElement());
+    this.eventRegister.listen(bubble, goog.ui.Component.EventType.HIDE,
+        this.handlePanelClosed_);
+
+    this.onShow();
+
+    if (this.keyboardNavigationEnabled_) {
+      this.eventRegister.listen(bubble.getContentElement(),
+          goog.events.EventType.KEYDOWN, this.onBubbleKey_);
+    }
+  }
+};
+
+
+/**
+ * @return {string} The type of bubble shown by this plugin.  Usually the tag
+ *     name of the element this bubble targets.
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.getBubbleType = function() {
+  return '';
+};
+
+
+/**
+ * @return {string} The title for bubble shown by this plugin.  Defaults to no
+ *     title.  Should be overridden by subclasses.
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.getBubbleTitle = function() {
+  return '';
+};
+
+
+/**
+ * @return {boolean} Whether the bubble should prefer placement above the
+ *     target element.
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.
+    shouldPreferBubbleAboveElement = goog.functions.FALSE;
+
+
+/**
+ * Should be overriden by subclasses to add the type specific contents to the
+ *     bubble.
+ * @param {Element} bubbleContainer The container element of the bubble to
+ *     which the contents should be added.
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.createBubbleContents =
+    goog.abstractMethod;
+
+
+/**
+ * Register the handler for the target's CLICK event.
+ * @param {Element} target The event source element.
+ * @param {Function} handler The event handler.
+ * @protected
+ * @deprecated Use goog.editor.plugins.AbstractBubblePlugin.
+ *     registerActionHandler to register click and enter events.
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.registerClickHandler =
+    function(target, handler) {
+  this.registerActionHandler(target, handler);
+};
+
+
+/**
+ * Register the handler for the target's CLICK and ENTER key events.
+ * @param {Element} target The event source element.
+ * @param {Function} handler The event handler.
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.registerActionHandler =
+    function(target, handler) {
+  this.eventRegister.listenWithWrapper(target, goog.events.actionEventWrapper,
+      handler);
+};
+
+
+/**
+ * Closes the bubble.
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.closeBubble = function() {
+  if (this.panelId_) {
+    this.getSharedBubble_().removePanel(this.panelId_);
+    this.handlePanelClosed_();
+  }
+};
+
+
+/**
+ * Called after the bubble is shown. The default implementation does nothing.
+ * Override it to provide your own one.
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.onShow = goog.nullFunction;
+
+
+/**
+ * Called when the bubble is closed or hidden. The default implementation does
+ * nothing.
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.cleanOnBubbleClose =
+    goog.nullFunction;
+
+
+/**
+ * Handles when the bubble panel is closed.  Invoked when the entire bubble is
+ * hidden and also directly when the panel is closed manually.
+ * @private
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.handlePanelClosed_ =
+    function() {
+  this.targetElement_ = null;
+  this.panelId_ = null;
+  this.eventRegister.removeAll();
+  this.cleanOnBubbleClose();
+};
+
+
+/**
+ * In case the keyboard navigation is enabled, this will set focus on the first
+ * tabbable element in the bubble when TAB is clicked.
+ * @override
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.handleKeyDown = function(e) {
+  if (this.keyboardNavigationEnabled_ &&
+      this.isVisible() &&
+      e.keyCode == goog.events.KeyCodes.TAB && !e.shiftKey) {
+    var bubbleEl = this.getSharedBubble_().getContentElement();
+    var tabbable = goog.dom.getElementByClass(
+        goog.editor.plugins.AbstractBubblePlugin.TABBABLE_CLASSNAME_, bubbleEl);
+    if (tabbable) {
+      tabbable.focus();
+      e.preventDefault();
+      return true;
+    }
+  }
+  return false;
+};
+
+
+/**
+ * Handles a key event on the bubble. This ensures that the focus loops through
+ * the tabbable elements found in the bubble and then the focus is got by the
+ * field element.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.onBubbleKey_ = function(e) {
+  if (this.isVisible() &&
+      e.keyCode == goog.events.KeyCodes.TAB) {
+    var bubbleEl = this.getSharedBubble_().getContentElement();
+    var tabbables = goog.dom.getElementsByClass(
+        goog.editor.plugins.AbstractBubblePlugin.TABBABLE_CLASSNAME_, bubbleEl);
+    var tabbable = e.shiftKey ? tabbables[0] : goog.array.peek(tabbables);
+    var tabbingOutOfBubble = tabbable == e.target;
+    if (tabbingOutOfBubble) {
+      this.getFieldObject().focus();
+      e.preventDefault();
+    }
+  }
+};
+
+
+/**
+ * @return {boolean} Whether the bubble is visible.
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.isVisible = function() {
+  return !!this.panelId_;
+};
+
+
+/**
+ * Reposition the property bubble.
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.reposition = function() {
+  var bubble = this.getSharedBubble_();
+  if (bubble) {
+    bubble.reposition();
+  }
+};
+
+
+/**
+ * Helper method that creates option links (such as edit, test, remove)
+ * @param {string} id String id for the span id.
+ * @return {Element} The option link element.
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.createLinkOption = function(
+    id) {
+  // Dash plus link are together in a span so we can hide/show them easily
+  return this.dom_.createDom(goog.dom.TagName.SPAN,
+      {
+        id: id,
+        className:
+            goog.editor.plugins.AbstractBubblePlugin.OPTION_LINK_CLASSNAME_
+      },
+      this.dom_.createTextNode(
+          goog.editor.plugins.AbstractBubblePlugin.DASH_NBSP_STRING));
+};
+
+
+/**
+ * Helper method that creates a link with text set to linkText and optionally
+ * wires up a listener for the CLICK event or the link. The link is navigable by
+ * tabs if {@code enableKeyboardNavigation(true)} was called.
+ * @param {string} linkId The id of the link.
+ * @param {string} linkText Text of the link.
+ * @param {Function=} opt_onClick Optional function to call when the link is
+ *     clicked.
+ * @param {Element=} opt_container If specified, location to insert link. If no
+ *     container is specified, the old link is removed and replaced.
+ * @return {Element} The link element.
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.createLink = function(
+    linkId, linkText, opt_onClick, opt_container) {
+  var link = this.createLinkHelper(linkId, linkText, false, opt_container);
+  if (opt_onClick) {
+    this.registerActionHandler(link, opt_onClick);
+  }
+  return link;
+};
+
+
+/**
+ * Helper method to create a link to insert into the bubble. The link is
+ * navigable by tabs if {@code enableKeyboardNavigation(true)} was called.
+ * @param {string} linkId The id of the link.
+ * @param {string} linkText Text of the link.
+ * @param {boolean} isAnchor Set to true to create an actual anchor tag
+ *     instead of a span.  Actual links are right clickable (e.g. to open in
+ *     a new window) and also update window status on hover.
+ * @param {Element=} opt_container If specified, location to insert link. If no
+ *     container is specified, the old link is removed and replaced.
+ * @return {Element} The link element.
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.createLinkHelper = function(
+    linkId, linkText, isAnchor, opt_container) {
+  var link = this.dom_.createDom(
+      isAnchor ? goog.dom.TagName.A : goog.dom.TagName.SPAN,
+      {className: goog.editor.plugins.AbstractBubblePlugin.LINK_CLASSNAME_},
+      linkText);
+  if (this.keyboardNavigationEnabled_) {
+    this.setTabbable(link);
+  }
+  link.setAttribute('role', 'link');
+  this.setupLink(link, linkId, opt_container);
+  goog.editor.style.makeUnselectable(link, this.eventRegister);
+  return link;
+};
+
+
+/**
+ * Makes the given element tabbable.
+ *
+ * <p>Elements created by createLink[Helper] are tabbable even without
+ * calling this method. Call it for other elements if needed.
+ *
+ * <p>If tabindex is not already set in the element, this function sets it to 0.
+ * You'll usually want to also call {@code enableKeyboardNavigation(true)}.
+ *
+ * @param {!Element} element
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.setTabbable =
+    function(element) {
+  if (!element.hasAttribute('tabindex')) {
+    element.setAttribute('tabindex', 0);
+  }
+  goog.dom.classlist.add(element,
+      goog.editor.plugins.AbstractBubblePlugin.TABBABLE_CLASSNAME_);
+};
+
+
+/**
+ * Inserts a link in the given container if it is specified or removes
+ * the old link with this id and replaces it with the new link
+ * @param {Element} link Html element to insert.
+ * @param {string} linkId Id of the link.
+ * @param {Element=} opt_container If specified, location to insert link.
+ * @protected
+ */
+goog.editor.plugins.AbstractBubblePlugin.prototype.setupLink = function(
+    link, linkId, opt_container) {
+  if (opt_container) {
+    opt_container.appendChild(link);
+  } else {
+    var oldLink = this.dom_.getElement(linkId);
+    if (oldLink) {
+      goog.dom.replaceNode(link, oldLink);
+    }
+  }
+
+  link.id = linkId;
+};


[47/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/base.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/base.js b/externs/GCL/externs/goog/base.js
new file mode 100644
index 0000000..bb232f8
--- /dev/null
+++ b/externs/GCL/externs/goog/base.js
@@ -0,0 +1,2547 @@
+// 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 Bootstrap for the Google JS Library (Closure).
+ *
+ * In uncompiled mode base.js will write out Closure's deps file, unless the
+ * global <code>CLOSURE_NO_DEPS</code> is set to true.  This allows projects to
+ * include their own deps file(s) from different locations.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ *
+ * @provideGoog
+ */
+
+
+/**
+ * @define {boolean} Overridden to true by the compiler when --closure_pass
+ *     or --mark_as_compiled is specified.
+ */
+var COMPILED = false;
+
+
+/**
+ * Base namespace for the Closure library.  Checks to see goog is already
+ * defined in the current scope before assigning to prevent clobbering if
+ * base.js is loaded more than once.
+ *
+ * @const
+ */
+var goog = goog || {};
+
+
+/**
+ * Reference to the global context.  In most cases this will be 'window'.
+ */
+goog.global = this;
+
+
+/**
+ * A hook for overriding the define values in uncompiled mode.
+ *
+ * In uncompiled mode, {@code CLOSURE_UNCOMPILED_DEFINES} may be defined before
+ * loading base.js.  If a key is defined in {@code CLOSURE_UNCOMPILED_DEFINES},
+ * {@code goog.define} will use the value instead of the default value.  This
+ * allows flags to be overwritten without compilation (this is normally
+ * accomplished with the compiler's "define" flag).
+ *
+ * Example:
+ * <pre>
+ *   var CLOSURE_UNCOMPILED_DEFINES = {'goog.DEBUG': false};
+ * </pre>
+ *
+ * @type {Object<string, (string|number|boolean)>|undefined}
+ */
+goog.global.CLOSURE_UNCOMPILED_DEFINES;
+
+
+/**
+ * A hook for overriding the define values in uncompiled or compiled mode,
+ * like CLOSURE_UNCOMPILED_DEFINES but effective in compiled code.  In
+ * uncompiled code CLOSURE_UNCOMPILED_DEFINES takes precedence.
+ *
+ * Also unlike CLOSURE_UNCOMPILED_DEFINES the values must be number, boolean or
+ * string literals or the compiler will emit an error.
+ *
+ * While any @define value may be set, only those set with goog.define will be
+ * effective for uncompiled code.
+ *
+ * Example:
+ * <pre>
+ *   var CLOSURE_DEFINES = {'goog.DEBUG': false} ;
+ * </pre>
+ *
+ * @type {Object<string, (string|number|boolean)>|undefined}
+ */
+goog.global.CLOSURE_DEFINES;
+
+
+/**
+ * Returns true if the specified value is not undefined.
+ * WARNING: Do not use this to test if an object has a property. Use the in
+ * operator instead.
+ *
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is defined.
+ */
+goog.isDef = function(val) {
+  // void 0 always evaluates to undefined and hence we do not need to depend on
+  // the definition of the global variable named 'undefined'.
+  return val !== void 0;
+};
+
+
+/**
+ * Builds an object structure for the provided namespace path, ensuring that
+ * names that already exist are not overwritten. For example:
+ * "a.b.c" -> a = {};a.b={};a.b.c={};
+ * Used by goog.provide and goog.exportSymbol.
+ * @param {string} name name of the object that this file defines.
+ * @param {*=} opt_object the object to expose at the end of the path.
+ * @param {Object=} opt_objectToExportTo The object to add the path to; default
+ *     is |goog.global|.
+ * @private
+ */
+goog.exportPath_ = function(name, opt_object, opt_objectToExportTo) {
+  var parts = name.split('.');
+  var cur = opt_objectToExportTo || goog.global;
+
+  // Internet Explorer exhibits strange behavior when throwing errors from
+  // methods externed in this manner.  See the testExportSymbolExceptions in
+  // base_test.html for an example.
+  if (!(parts[0] in cur) && cur.execScript) {
+    cur.execScript('var ' + parts[0]);
+  }
+
+  // Certain browsers cannot parse code in the form for((a in b); c;);
+  // This pattern is produced by the JSCompiler when it collapses the
+  // statement above into the conditional loop below. To prevent this from
+  // happening, use a for-loop and reserve the init logic as below.
+
+  // Parentheses added to eliminate strict JS warning in Firefox.
+  for (var part; parts.length && (part = parts.shift());) {
+    if (!parts.length && goog.isDef(opt_object)) {
+      // last part and we have an object; use it
+      cur[part] = opt_object;
+    } else if (cur[part]) {
+      cur = cur[part];
+    } else {
+      cur = cur[part] = {};
+    }
+  }
+};
+
+
+/**
+ * Defines a named value. In uncompiled mode, the value is retrieved from
+ * CLOSURE_DEFINES or CLOSURE_UNCOMPILED_DEFINES if the object is defined and
+ * has the property specified, and otherwise used the defined defaultValue.
+ * When compiled the default can be overridden using the compiler
+ * options or the value set in the CLOSURE_DEFINES object.
+ *
+ * @param {string} name The distinguished name to provide.
+ * @param {string|number|boolean} defaultValue
+ */
+goog.define = function(name, defaultValue) {
+  var value = defaultValue;
+  if (!COMPILED) {
+    if (goog.global.CLOSURE_UNCOMPILED_DEFINES &&
+        Object.prototype.hasOwnProperty.call(
+            goog.global.CLOSURE_UNCOMPILED_DEFINES, name)) {
+      value = goog.global.CLOSURE_UNCOMPILED_DEFINES[name];
+    } else if (goog.global.CLOSURE_DEFINES &&
+        Object.prototype.hasOwnProperty.call(
+            goog.global.CLOSURE_DEFINES, name)) {
+      value = goog.global.CLOSURE_DEFINES[name];
+    }
+  }
+  goog.exportPath_(name, value);
+};
+
+
+/**
+ * @define {boolean} DEBUG is provided as a convenience so that debugging code
+ * that should not be included in a production js_binary can be easily stripped
+ * by specifying --define goog.DEBUG=false to the JSCompiler. For example, most
+ * toString() methods should be declared inside an "if (goog.DEBUG)" conditional
+ * because they are generally used for debugging purposes and it is difficult
+ * for the JSCompiler to statically determine whether they are used.
+ */
+goog.define('goog.DEBUG', true);
+
+
+/**
+ * @define {string} LOCALE defines the locale being used for compilation. It is
+ * used to select locale specific data to be compiled in js binary. BUILD rule
+ * can specify this value by "--define goog.LOCALE=<locale_name>" as JSCompiler
+ * option.
+ *
+ * Take into account that the locale code format is important. You should use
+ * the canonical Unicode format with hyphen as a delimiter. Language must be
+ * lowercase, Language Script - Capitalized, Region - UPPERCASE.
+ * There are few examples: pt-BR, en, en-US, sr-Latin-BO, zh-Hans-CN.
+ *
+ * See more info about locale codes here:
+ * http://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers
+ *
+ * For language codes you should use values defined by ISO 693-1. See it here
+ * http://www.w3.org/WAI/ER/IG/ert/iso639.htm. There is only one exception from
+ * this rule: the Hebrew language. For legacy reasons the old code (iw) should
+ * be used instead of the new code (he), see http://wiki/Main/IIISynonyms.
+ */
+goog.define('goog.LOCALE', 'en');  // default to en
+
+
+/**
+ * @define {boolean} Whether this code is running on trusted sites.
+ *
+ * On untrusted sites, several native functions can be defined or overridden by
+ * external libraries like Prototype, Datejs, and JQuery and setting this flag
+ * to false forces closure to use its own implementations when possible.
+ *
+ * If your JavaScript can be loaded by a third party site and you are wary about
+ * relying on non-standard implementations, specify
+ * "--define goog.TRUSTED_SITE=false" to the JSCompiler.
+ */
+goog.define('goog.TRUSTED_SITE', true);
+
+
+/**
+ * @define {boolean} Whether a project is expected to be running in strict mode.
+ *
+ * This define can be used to trigger alternate implementations compatible with
+ * running in EcmaScript Strict mode or warn about unavailable functionality.
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/Strict_mode
+ *
+ */
+goog.define('goog.STRICT_MODE_COMPATIBLE', false);
+
+
+/**
+ * @define {boolean} Whether code that calls {@link goog.setTestOnly} should
+ *     be disallowed in the compilation unit.
+ */
+goog.define('goog.DISALLOW_TEST_ONLY_CODE', COMPILED && !goog.DEBUG);
+
+
+/**
+ * @define {boolean} Whether to use a Chrome app CSP-compliant method for
+ *     loading scripts via goog.require. @see appendScriptSrcNode_.
+ */
+goog.define('goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING', false);
+
+
+/**
+ * Defines a namespace in Closure.
+ *
+ * A namespace may only be defined once in a codebase. It may be defined using
+ * goog.provide() or goog.module().
+ *
+ * The presence of one or more goog.provide() calls in a file indicates
+ * that the file defines the given objects/namespaces.
+ * Provided symbols must not be null or undefined.
+ *
+ * In addition, goog.provide() creates the object stubs for a namespace
+ * (for example, goog.provide("goog.foo.bar") will create the object
+ * goog.foo.bar if it does not already exist).
+ *
+ * Build tools also scan for provide/require/module statements
+ * to discern dependencies, build dependency files (see deps.js), etc.
+ *
+ * @see goog.require
+ * @see goog.module
+ * @param {string} name Namespace provided by this file in the form
+ *     "goog.package.part".
+ */
+goog.provide = function(name) {
+  if (!COMPILED) {
+    // Ensure that the same namespace isn't provided twice.
+    // A goog.module/goog.provide maps a goog.require to a specific file
+    if (goog.isProvided_(name)) {
+      throw Error('Namespace "' + name + '" already declared.');
+    }
+  }
+
+  goog.constructNamespace_(name);
+};
+
+
+/**
+ * @param {string} name Namespace provided by this file in the form
+ *     "goog.package.part".
+ * @param {Object=} opt_obj The object to embed in the namespace.
+ * @private
+ */
+goog.constructNamespace_ = function(name, opt_obj) {
+  if (!COMPILED) {
+    delete goog.implicitNamespaces_[name];
+
+    var namespace = name;
+    while ((namespace = namespace.substring(0, namespace.lastIndexOf('.')))) {
+      if (goog.getObjectByName(namespace)) {
+        break;
+      }
+      goog.implicitNamespaces_[namespace] = true;
+    }
+  }
+
+  goog.exportPath_(name, opt_obj);
+};
+
+
+/**
+ * Module identifier validation regexp.
+ * Note: This is a conservative check, it is very possible to be more lenient,
+ *   the primary exclusion here is "/" and "\" and a leading ".", these
+ *   restrictions are intended to leave the door open for using goog.require
+ *   with relative file paths rather than module identifiers.
+ * @private
+ */
+goog.VALID_MODULE_RE_ = /^[a-zA-Z_$][a-zA-Z0-9._$]*$/;
+
+
+/**
+ * Defines a module in Closure.
+ *
+ * Marks that this file must be loaded as a module and claims the namespace.
+ *
+ * A namespace may only be defined once in a codebase. It may be defined using
+ * goog.provide() or goog.module().
+ *
+ * goog.module() has three requirements:
+ * - goog.module may not be used in the same file as goog.provide.
+ * - goog.module must be the first statement in the file.
+ * - only one goog.module is allowed per file.
+ *
+ * When a goog.module annotated file is loaded, it is enclosed in
+ * a strict function closure. This means that:
+ * - any variables declared in a goog.module file are private to the file
+ * (not global), though the compiler is expected to inline the module.
+ * - The code must obey all the rules of "strict" JavaScript.
+ * - the file will be marked as "use strict"
+ *
+ * NOTE: unlike goog.provide, goog.module does not declare any symbols by
+ * itself. If declared symbols are desired, use
+ * goog.module.declareLegacyNamespace().
+ *
+ *
+ * See the public goog.module proposal: http://goo.gl/Va1hin
+ *
+ * @param {string} name Namespace provided by this file in the form
+ *     "goog.package.part", is expected but not required.
+ */
+goog.module = function(name) {
+  if (!goog.isString(name) ||
+      !name ||
+      name.search(goog.VALID_MODULE_RE_) == -1) {
+    throw Error('Invalid module identifier');
+  }
+  if (!goog.isInModuleLoader_()) {
+    throw Error('Module ' + name + ' has been loaded incorrectly.');
+  }
+  if (goog.moduleLoaderState_.moduleName) {
+    throw Error('goog.module may only be called once per module.');
+  }
+
+  // Store the module name for the loader.
+  goog.moduleLoaderState_.moduleName = name;
+  if (!COMPILED) {
+    // Ensure that the same namespace isn't provided twice.
+    // A goog.module/goog.provide maps a goog.require to a specific file
+    if (goog.isProvided_(name)) {
+      throw Error('Namespace "' + name + '" already declared.');
+    }
+    delete goog.implicitNamespaces_[name];
+  }
+};
+
+
+/**
+ * @param {string} name The module identifier.
+ * @return {?} The module exports for an already loaded module or null.
+ *
+ * Note: This is not an alternative to goog.require, it does not
+ * indicate a hard dependency, instead it is used to indicate
+ * an optional dependency or to access the exports of a module
+ * that has already been loaded.
+ * @suppress {missingProvide}
+ */
+goog.module.get = function(name) {
+  return goog.module.getInternal_(name);
+};
+
+
+/**
+ * @param {string} name The module identifier.
+ * @return {?} The module exports for an already loaded module or null.
+ * @private
+ */
+goog.module.getInternal_ = function(name) {
+  if (!COMPILED) {
+    if (goog.isProvided_(name)) {
+      // goog.require only return a value with-in goog.module files.
+      return name in goog.loadedModules_ ?
+          goog.loadedModules_[name] :
+          goog.getObjectByName(name);
+    } else {
+      return null;
+    }
+  }
+};
+
+
+/**
+ * @private {?{
+ *   moduleName: (string|undefined),
+ *   declareTestMethods: boolean
+ * }}
+ */
+goog.moduleLoaderState_ = null;
+
+
+/**
+ * @private
+ * @return {boolean} Whether a goog.module is currently being initialized.
+ */
+goog.isInModuleLoader_ = function() {
+  return goog.moduleLoaderState_ != null;
+};
+
+
+/**
+ * Indicate that a module's exports that are known test methods should
+ * be copied to the global object.  This makes the test methods visible to
+ * test runners that inspect the global object.
+ *
+ * TODO(johnlenz): Make the test framework aware of goog.module so
+ * that this isn't necessary. Alternately combine this with goog.setTestOnly
+ * to minimize boiler plate.
+ * @suppress {missingProvide}
+ * @deprecated This approach does not translate to ES6 module syntax, instead
+ *    use goog.testing.testSuite to declare the test methods.
+ */
+goog.module.declareTestMethods = function() {
+  if (!goog.isInModuleLoader_()) {
+    throw new Error('goog.module.declareTestMethods must be called from ' +
+        'within a goog.module');
+  }
+  goog.moduleLoaderState_.declareTestMethods = true;
+};
+
+
+/**
+ * Provide the module's exports as a globally accessible object under the
+ * module's declared name.  This is intended to ease migration to goog.module
+ * for files that have existing usages.
+ * @suppress {missingProvide}
+ */
+goog.module.declareLegacyNamespace = function() {
+  if (!COMPILED && !goog.isInModuleLoader_()) {
+    throw new Error('goog.module.declareLegacyNamespace must be called from ' +
+        'within a goog.module');
+  }
+  if (!COMPILED && !goog.moduleLoaderState_.moduleName) {
+    throw Error('goog.module must be called prior to ' +
+        'goog.module.declareLegacyNamespace.');
+  }
+  goog.moduleLoaderState_.declareLegacyNamespace = true;
+};
+
+
+/**
+ * Marks that the current file should only be used for testing, and never for
+ * live code in production.
+ *
+ * In the case of unit tests, the message may optionally be an exact namespace
+ * for the test (e.g. 'goog.stringTest'). The linter will then ignore the extra
+ * provide (if not explicitly defined in the code).
+ *
+ * @param {string=} opt_message Optional message to add to the error that's
+ *     raised when used in production code.
+ */
+goog.setTestOnly = function(opt_message) {
+  if (goog.DISALLOW_TEST_ONLY_CODE) {
+    opt_message = opt_message || '';
+    throw Error('Importing test-only code into non-debug environment' +
+                (opt_message ? ': ' + opt_message : '.'));
+  }
+};
+
+
+/**
+ * Forward declares a symbol. This is an indication to the compiler that the
+ * symbol may be used in the source yet is not required and may not be provided
+ * in compilation.
+ *
+ * The most common usage of forward declaration is code that takes a type as a
+ * function parameter but does not need to require it. By forward declaring
+ * instead of requiring, no hard dependency is made, and (if not required
+ * elsewhere) the namespace may never be required and thus, not be pulled
+ * into the JavaScript binary. If it is required elsewhere, it will be type
+ * checked as normal.
+ *
+ *
+ * @param {string} name The namespace to forward declare in the form of
+ *     "goog.package.part".
+ */
+goog.forwardDeclare = function(name) {};
+
+
+if (!COMPILED) {
+
+  /**
+   * Check if the given name has been goog.provided. This will return false for
+   * names that are available only as implicit namespaces.
+   * @param {string} name name of the object to look for.
+   * @return {boolean} Whether the name has been provided.
+   * @private
+   */
+  goog.isProvided_ = function(name) {
+    return (name in goog.loadedModules_) ||
+        (!goog.implicitNamespaces_[name] &&
+            goog.isDefAndNotNull(goog.getObjectByName(name)));
+  };
+
+  /**
+   * Namespaces implicitly defined by goog.provide. For example,
+   * goog.provide('goog.events.Event') implicitly declares that 'goog' and
+   * 'goog.events' must be namespaces.
+   *
+   * @type {!Object<string, (boolean|undefined)>}
+   * @private
+   */
+  goog.implicitNamespaces_ = {'goog.module': true};
+
+  // NOTE: We add goog.module as an implicit namespace as goog.module is defined
+  // here and because the existing module package has not been moved yet out of
+  // the goog.module namespace. This satisifies both the debug loader and
+  // ahead-of-time dependency management.
+}
+
+
+/**
+ * Returns an object based on its fully qualified external name.  The object
+ * is not found if null or undefined.  If you are using a compilation pass that
+ * renames property names beware that using this function will not find renamed
+ * properties.
+ *
+ * @param {string} name The fully qualified name.
+ * @param {Object=} opt_obj The object within which to look; default is
+ *     |goog.global|.
+ * @return {?} The value (object or primitive) or, if not found, null.
+ */
+goog.getObjectByName = function(name, opt_obj) {
+  var parts = name.split('.');
+  var cur = opt_obj || goog.global;
+  for (var part; part = parts.shift(); ) {
+    if (goog.isDefAndNotNull(cur[part])) {
+      cur = cur[part];
+    } else {
+      return null;
+    }
+  }
+  return cur;
+};
+
+
+/**
+ * Globalizes a whole namespace, such as goog or goog.lang.
+ *
+ * @param {!Object} obj The namespace to globalize.
+ * @param {Object=} opt_global The object to add the properties to.
+ * @deprecated Properties may be explicitly exported to the global scope, but
+ *     this should no longer be done in bulk.
+ */
+goog.globalize = function(obj, opt_global) {
+  var global = opt_global || goog.global;
+  for (var x in obj) {
+    global[x] = obj[x];
+  }
+};
+
+
+/**
+ * Adds a dependency from a file to the files it requires.
+ * @param {string} relPath The path to the js file.
+ * @param {!Array<string>} provides An array of strings with
+ *     the names of the objects this file provides.
+ * @param {!Array<string>} requires An array of strings with
+ *     the names of the objects this file requires.
+ * @param {boolean=} opt_isModule Whether this dependency must be loaded as
+ *     a module as declared by goog.module.
+ */
+goog.addDependency = function(relPath, provides, requires, opt_isModule) {
+  if (goog.DEPENDENCIES_ENABLED) {
+    var provide, require;
+    var path = relPath.replace(/\\/g, '/');
+    var deps = goog.dependencies_;
+    for (var i = 0; provide = provides[i]; i++) {
+      deps.nameToPath[provide] = path;
+      deps.pathIsModule[path] = !!opt_isModule;
+    }
+    for (var j = 0; require = requires[j]; j++) {
+      if (!(path in deps.requires)) {
+        deps.requires[path] = {};
+      }
+      deps.requires[path][require] = true;
+    }
+  }
+};
+
+
+
+
+// NOTE(nnaze): The debug DOM loader was included in base.js as an original way
+// to do "debug-mode" development.  The dependency system can sometimes be
+// confusing, as can the debug DOM loader's asynchronous nature.
+//
+// With the DOM loader, a call to goog.require() is not blocking -- the script
+// will not load until some point after the current script.  If a namespace is
+// needed at runtime, it needs to be defined in a previous script, or loaded via
+// require() with its registered dependencies.
+// User-defined namespaces may need their own deps file.  See http://go/js_deps,
+// http://go/genjsdeps, or, externally, DepsWriter.
+// https://developers.google.com/closure/library/docs/depswriter
+//
+// Because of legacy clients, the DOM loader can't be easily removed from
+// base.js.  Work is being done to make it disableable or replaceable for
+// different environments (DOM-less JavaScript interpreters like Rhino or V8,
+// for example). See bootstrap/ for more information.
+
+
+/**
+ * @define {boolean} Whether to enable the debug loader.
+ *
+ * If enabled, a call to goog.require() will attempt to load the namespace by
+ * appending a script tag to the DOM (if the namespace has been registered).
+ *
+ * If disabled, goog.require() will simply assert that the namespace has been
+ * provided (and depend on the fact that some outside tool correctly ordered
+ * the script).
+ */
+goog.define('goog.ENABLE_DEBUG_LOADER', true);
+
+
+/**
+ * @param {string} msg
+ * @private
+ */
+goog.logToConsole_ = function(msg) {
+  if (goog.global.console) {
+    goog.global.console['error'](msg);
+  }
+};
+
+
+/**
+ * Implements a system for the dynamic resolution of dependencies that works in
+ * parallel with the BUILD system. Note that all calls to goog.require will be
+ * stripped by the JSCompiler when the --closure_pass option is used.
+ * @see goog.provide
+ * @param {string} name Namespace to include (as was given in goog.provide()) in
+ *     the form "goog.package.part".
+ * @return {?} If called within a goog.module file, the associated namespace or
+ *     module otherwise null.
+ */
+goog.require = function(name) {
+
+  // If the object already exists we do not need do do anything.
+  if (!COMPILED) {
+    if (goog.ENABLE_DEBUG_LOADER && goog.IS_OLD_IE_) {
+      goog.maybeProcessDeferredDep_(name);
+    }
+
+    if (goog.isProvided_(name)) {
+      if (goog.isInModuleLoader_()) {
+        return goog.module.getInternal_(name);
+      } else {
+        return null;
+      }
+    }
+
+    if (goog.ENABLE_DEBUG_LOADER) {
+      var path = goog.getPathFromDeps_(name);
+      if (path) {
+        goog.included_[path] = true;
+        goog.writeScripts_();
+        return null;
+      }
+    }
+
+    var errorMessage = 'goog.require could not find: ' + name;
+    goog.logToConsole_(errorMessage);
+
+    throw Error(errorMessage);
+  }
+};
+
+
+/**
+ * Path for included scripts.
+ * @type {string}
+ */
+goog.basePath = '';
+
+
+/**
+ * A hook for overriding the base path.
+ * @type {string|undefined}
+ */
+goog.global.CLOSURE_BASE_PATH;
+
+
+/**
+ * Whether to write out Closure's deps file. By default, the deps are written.
+ * @type {boolean|undefined}
+ */
+goog.global.CLOSURE_NO_DEPS;
+
+
+/**
+ * A function to import a single script. This is meant to be overridden when
+ * Closure is being run in non-HTML contexts, such as web workers. It's defined
+ * in the global scope so that it can be set before base.js is loaded, which
+ * allows deps.js to be imported properly.
+ *
+ * The function is passed the script source, which is a relative URI. It should
+ * return true if the script was imported, false otherwise.
+ * @type {(function(string): boolean)|undefined}
+ */
+goog.global.CLOSURE_IMPORT_SCRIPT;
+
+
+/**
+ * Null function used for default values of callbacks, etc.
+ * @return {void} Nothing.
+ */
+goog.nullFunction = function() {};
+
+
+
+/**
+ * When defining a class Foo with an abstract method bar(), you can do:
+ * Foo.prototype.bar = goog.abstractMethod
+ *
+ * Now if a subclass of Foo fails to override bar(), an error will be thrown
+ * when bar() is invoked.
+ *
+ * Note: This does not take the name of the function to override as an argument
+ * because that would make it more difficult to obfuscate our JavaScript code.
+ *
+ * @type {!Function}
+ * @throws {Error} when invoked to indicate the method should be overridden.
+ */
+goog.abstractMethod = function() {
+  throw Error('unimplemented abstract method');
+};
+
+
+/**
+ * Adds a {@code getInstance} static method that always returns the same
+ * instance object.
+ * @param {!Function} ctor The constructor for the class to add the static
+ *     method to.
+ */
+goog.addSingletonGetter = function(ctor) {
+  ctor.getInstance = function() {
+    if (ctor.instance_) {
+      return ctor.instance_;
+    }
+    if (goog.DEBUG) {
+      // NOTE: JSCompiler can't optimize away Array#push.
+      goog.instantiatedSingletons_[goog.instantiatedSingletons_.length] = ctor;
+    }
+    return ctor.instance_ = new ctor;
+  };
+};
+
+
+/**
+ * All singleton classes that have been instantiated, for testing. Don't read
+ * it directly, use the {@code goog.testing.singleton} module. The compiler
+ * removes this variable if unused.
+ * @type {!Array<!Function>}
+ * @private
+ */
+goog.instantiatedSingletons_ = [];
+
+
+/**
+ * @define {boolean} Whether to load goog.modules using {@code eval} when using
+ * the debug loader.  This provides a better debugging experience as the
+ * source is unmodified and can be edited using Chrome Workspaces or similar.
+ * However in some environments the use of {@code eval} is banned
+ * so we provide an alternative.
+ */
+goog.define('goog.LOAD_MODULE_USING_EVAL', true);
+
+
+/**
+ * @define {boolean} Whether the exports of goog.modules should be sealed when
+ * possible.
+ */
+goog.define('goog.SEAL_MODULE_EXPORTS', goog.DEBUG);
+
+
+/**
+ * The registry of initialized modules:
+ * the module identifier to module exports map.
+ * @private @const {!Object<string, ?>}
+ */
+goog.loadedModules_ = {};
+
+
+/**
+ * True if goog.dependencies_ is available.
+ * @const {boolean}
+ */
+goog.DEPENDENCIES_ENABLED = !COMPILED && goog.ENABLE_DEBUG_LOADER;
+
+
+if (goog.DEPENDENCIES_ENABLED) {
+  /**
+   * Object used to keep track of urls that have already been added. This record
+   * allows the prevention of circular dependencies.
+   * @private {!Object<string, boolean>}
+   */
+  goog.included_ = {};
+
+
+  /**
+   * This object is used to keep track of dependencies and other data that is
+   * used for loading scripts.
+   * @private
+   * @type {{
+   *   pathIsModule: !Object<string, boolean>,
+   *   nameToPath: !Object<string, string>,
+   *   requires: !Object<string, !Object<string, boolean>>,
+   *   visited: !Object<string, boolean>,
+   *   written: !Object<string, boolean>,
+   *   deferred: !Object<string, string>
+   * }}
+   */
+  goog.dependencies_ = {
+    pathIsModule: {}, // 1 to 1
+
+    nameToPath: {}, // 1 to 1
+
+    requires: {}, // 1 to many
+
+    // Used when resolving dependencies to prevent us from visiting file twice.
+    visited: {},
+
+    written: {}, // Used to keep track of script files we have written.
+
+    deferred: {} // Used to track deferred module evaluations in old IEs
+  };
+
+
+  /**
+   * Tries to detect whether is in the context of an HTML document.
+   * @return {boolean} True if it looks like HTML document.
+   * @private
+   */
+  goog.inHtmlDocument_ = function() {
+    var doc = goog.global.document;
+    return typeof doc != 'undefined' &&
+           'write' in doc;  // XULDocument misses write.
+  };
+
+
+  /**
+   * Tries to detect the base path of base.js script that bootstraps Closure.
+   * @private
+   */
+  goog.findBasePath_ = function() {
+    if (goog.global.CLOSURE_BASE_PATH) {
+      goog.basePath = goog.global.CLOSURE_BASE_PATH;
+      return;
+    } else if (!goog.inHtmlDocument_()) {
+      return;
+    }
+    var doc = goog.global.document;
+    var scripts = doc.getElementsByTagName('SCRIPT');
+    // Search backwards since the current script is in almost all cases the one
+    // that has base.js.
+    for (var i = scripts.length - 1; i >= 0; --i) {
+      var script = /** @type {!HTMLScriptElement} */ (scripts[i]);
+      var src = script.src;
+      var qmark = src.lastIndexOf('?');
+      var l = qmark == -1 ? src.length : qmark;
+      if (src.substr(l - 7, 7) == 'base.js') {
+        goog.basePath = src.substr(0, l - 7);
+        return;
+      }
+    }
+  };
+
+
+  /**
+   * Imports a script if, and only if, that script hasn't already been imported.
+   * (Must be called at execution time)
+   * @param {string} src Script source.
+   * @param {string=} opt_sourceText The optionally source text to evaluate
+   * @private
+   */
+  goog.importScript_ = function(src, opt_sourceText) {
+    var importScript = goog.global.CLOSURE_IMPORT_SCRIPT ||
+        goog.writeScriptTag_;
+    if (importScript(src, opt_sourceText)) {
+      goog.dependencies_.written[src] = true;
+    }
+  };
+
+
+  /** @const @private {boolean} */
+  goog.IS_OLD_IE_ = !goog.global.atob && goog.global.document &&
+      goog.global.document.all;
+
+
+  /**
+   * Given a URL initiate retrieval and execution of the module.
+   * @param {string} src Script source URL.
+   * @private
+   */
+  goog.importModule_ = function(src) {
+    // In an attempt to keep browsers from timing out loading scripts using
+    // synchronous XHRs, put each load in its own script block.
+    var bootstrap = 'goog.retrieveAndExecModule_("' + src + '");';
+
+    if (goog.importScript_('', bootstrap)) {
+      goog.dependencies_.written[src] = true;
+    }
+  };
+
+
+  /** @private {!Array<string>} */
+  goog.queuedModules_ = [];
+
+
+  /**
+   * Return an appropriate module text. Suitable to insert into
+   * a script tag (that is unescaped).
+   * @param {string} srcUrl
+   * @param {string} scriptText
+   * @return {string}
+   * @private
+   */
+  goog.wrapModule_ = function(srcUrl, scriptText) {
+    if (!goog.LOAD_MODULE_USING_EVAL || !goog.isDef(goog.global.JSON)) {
+      return '' +
+          'goog.loadModule(function(exports) {' +
+          '"use strict";' +
+          scriptText +
+          '\n' + // terminate any trailing single line comment.
+          ';return exports' +
+          '});' +
+          '\n//# sourceURL=' + srcUrl + '\n';
+    } else {
+      return '' +
+          'goog.loadModule(' +
+          goog.global.JSON.stringify(
+              scriptText + '\n//# sourceURL=' + srcUrl + '\n') +
+          ');';
+    }
+  };
+
+  // On IE9 and earlier, it is necessary to handle
+  // deferred module loads. In later browsers, the
+  // code to be evaluated is simply inserted as a script
+  // block in the correct order. To eval deferred
+  // code at the right time, we piggy back on goog.require to call
+  // goog.maybeProcessDeferredDep_.
+  //
+  // The goog.requires are used both to bootstrap
+  // the loading process (when no deps are available) and
+  // declare that they should be available.
+  //
+  // Here we eval the sources, if all the deps are available
+  // either already eval'd or goog.require'd.  This will
+  // be the case when all the dependencies have already
+  // been loaded, and the dependent module is loaded.
+  //
+  // But this alone isn't sufficient because it is also
+  // necessary to handle the case where there is no root
+  // that is not deferred.  For that there we register for an event
+  // and trigger goog.loadQueuedModules_ handle any remaining deferred
+  // evaluations.
+
+  /**
+   * Handle any remaining deferred goog.module evals.
+   * @private
+   */
+  goog.loadQueuedModules_ = function() {
+    var count = goog.queuedModules_.length;
+    if (count > 0) {
+      var queue = goog.queuedModules_;
+      goog.queuedModules_ = [];
+      for (var i = 0; i < count; i++) {
+        var path = queue[i];
+        goog.maybeProcessDeferredPath_(path);
+      }
+    }
+  };
+
+
+  /**
+   * Eval the named module if its dependencies are
+   * available.
+   * @param {string} name The module to load.
+   * @private
+   */
+  goog.maybeProcessDeferredDep_ = function(name) {
+    if (goog.isDeferredModule_(name) &&
+        goog.allDepsAreAvailable_(name)) {
+      var path = goog.getPathFromDeps_(name);
+      goog.maybeProcessDeferredPath_(goog.basePath + path);
+    }
+  };
+
+  /**
+   * @param {string} name The module to check.
+   * @return {boolean} Whether the name represents a
+   *     module whose evaluation has been deferred.
+   * @private
+   */
+  goog.isDeferredModule_ = function(name) {
+    var path = goog.getPathFromDeps_(name);
+    if (path && goog.dependencies_.pathIsModule[path]) {
+      var abspath = goog.basePath + path;
+      return (abspath) in goog.dependencies_.deferred;
+    }
+    return false;
+  };
+
+  /**
+   * @param {string} name The module to check.
+   * @return {boolean} Whether the name represents a
+   *     module whose declared dependencies have all been loaded
+   *     (eval'd or a deferred module load)
+   * @private
+   */
+  goog.allDepsAreAvailable_ = function(name) {
+    var path = goog.getPathFromDeps_(name);
+    if (path && (path in goog.dependencies_.requires)) {
+      for (var requireName in goog.dependencies_.requires[path]) {
+        if (!goog.isProvided_(requireName) &&
+            !goog.isDeferredModule_(requireName)) {
+          return false;
+        }
+      }
+    }
+    return true;
+  };
+
+
+  /**
+   * @param {string} abspath
+   * @private
+   */
+  goog.maybeProcessDeferredPath_ = function(abspath) {
+    if (abspath in goog.dependencies_.deferred) {
+      var src = goog.dependencies_.deferred[abspath];
+      delete goog.dependencies_.deferred[abspath];
+      goog.globalEval(src);
+    }
+  };
+
+
+  /**
+   * @param {function(?):?|string} moduleDef The module definition.
+   */
+  goog.loadModule = function(moduleDef) {
+    // NOTE: we allow function definitions to be either in the from
+    // of a string to eval (which keeps the original source intact) or
+    // in a eval forbidden environment (CSP) we allow a function definition
+    // which in its body must call {@code goog.module}, and return the exports
+    // of the module.
+    var previousState = goog.moduleLoaderState_;
+    try {
+      goog.moduleLoaderState_ = {
+        moduleName: undefined, declareTestMethods: false};
+      var exports;
+      if (goog.isFunction(moduleDef)) {
+        exports = moduleDef.call(goog.global, {});
+      } else if (goog.isString(moduleDef)) {
+        exports = goog.loadModuleFromSource_.call(goog.global, moduleDef);
+      } else {
+        throw Error('Invalid module definition');
+      }
+
+      var moduleName = goog.moduleLoaderState_.moduleName;
+      if (!goog.isString(moduleName) || !moduleName) {
+        throw Error('Invalid module name \"' + moduleName + '\"');
+      }
+
+      // Don't seal legacy namespaces as they may be uses as a parent of
+      // another namespace
+      if (goog.moduleLoaderState_.declareLegacyNamespace) {
+        goog.constructNamespace_(moduleName, exports);
+      } else if (goog.SEAL_MODULE_EXPORTS && Object.seal) {
+        Object.seal(exports);
+      }
+
+      goog.loadedModules_[moduleName] = exports;
+      if (goog.moduleLoaderState_.declareTestMethods) {
+        for (var entry in exports) {
+          if (entry.indexOf('test', 0) === 0 ||
+              entry == 'tearDown' ||
+              entry == 'setUp' ||
+              entry == 'setUpPage' ||
+              entry == 'tearDownPage') {
+            goog.global[entry] = exports[entry];
+          }
+        }
+      }
+    } finally {
+      goog.moduleLoaderState_ = previousState;
+    }
+  };
+
+
+  /**
+   * @param {string} source
+   * @return {!Object}
+   * @private
+   */
+  goog.loadModuleFromSource_ = function(source) {
+    // NOTE: we avoid declaring parameters or local variables here to avoid
+    // masking globals or leaking values into the module definition.
+    'use strict';
+    var exports = {};
+    eval(arguments[0]);
+    return exports;
+  };
+
+
+  /**
+   * Writes a new script pointing to {@code src} directly into the DOM.
+   *
+   * NOTE: This method is not CSP-compliant. @see goog.appendScriptSrcNode_ for
+   * the fallback mechanism.
+   *
+   * @param {string} src The script URL.
+   * @private
+   */
+  goog.writeScriptSrcNode_ = function(src) {
+    goog.global.document.write(
+        '<script type="text/javascript" src="' + src + '"></' + 'script>');
+  };
+
+
+  /**
+   * Appends a new script node to the DOM using a CSP-compliant mechanism. This
+   * method exists as a fallback for document.write (which is not allowed in a
+   * strict CSP context, e.g., Chrome apps).
+   *
+   * NOTE: This method is not analogous to using document.write to insert a
+   * <script> tag; specifically, the user agent will execute a script added by
+   * document.write immediately after the current script block finishes
+   * executing, whereas the DOM-appended script node will not be executed until
+   * the entire document is parsed and executed. That is to say, this script is
+   * added to the end of the script execution queue.
+   *
+   * The page must not attempt to call goog.required entities until after the
+   * document has loaded, e.g., in or after the window.onload callback.
+   *
+   * @param {string} src The script URL.
+   * @private
+   */
+  goog.appendScriptSrcNode_ = function(src) {
+    var doc = goog.global.document;
+    var scriptEl = doc.createElement('script');
+    scriptEl.type = 'text/javascript';
+    scriptEl.src = src;
+    scriptEl.defer = false;
+    scriptEl.async = false;
+    doc.head.appendChild(scriptEl);
+  };
+
+
+  /**
+   * The default implementation of the import function. Writes a script tag to
+   * import the script.
+   *
+   * @param {string} src The script url.
+   * @param {string=} opt_sourceText The optionally source text to evaluate
+   * @return {boolean} True if the script was imported, false otherwise.
+   * @private
+   */
+  goog.writeScriptTag_ = function(src, opt_sourceText) {
+    if (goog.inHtmlDocument_()) {
+      var doc = goog.global.document;
+
+      // If the user tries to require a new symbol after document load,
+      // something has gone terribly wrong. Doing a document.write would
+      // wipe out the page. This does not apply to the CSP-compliant method
+      // of writing script tags.
+      if (!goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING &&
+          doc.readyState == 'complete') {
+        // Certain test frameworks load base.js multiple times, which tries
+        // to write deps.js each time. If that happens, just fail silently.
+        // These frameworks wipe the page between each load of base.js, so this
+        // is OK.
+        var isDeps = /\bdeps.js$/.test(src);
+        if (isDeps) {
+          return false;
+        } else {
+          throw Error('Cannot write "' + src + '" after document load');
+        }
+      }
+
+      var isOldIE = goog.IS_OLD_IE_;
+
+      if (opt_sourceText === undefined) {
+        if (!isOldIE) {
+          if (goog.ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING) {
+            goog.appendScriptSrcNode_(src);
+          } else {
+            goog.writeScriptSrcNode_(src);
+          }
+        } else {
+          var state = " onreadystatechange='goog.onScriptLoad_(this, " +
+              ++goog.lastNonModuleScriptIndex_ + ")' ";
+          doc.write(
+              '<script type="text/javascript" src="' +
+                  src + '"' + state + '></' + 'script>');
+        }
+      } else {
+        doc.write(
+            '<script type="text/javascript">' +
+            opt_sourceText +
+            '</' + 'script>');
+      }
+      return true;
+    } else {
+      return false;
+    }
+  };
+
+
+  /** @private {number} */
+  goog.lastNonModuleScriptIndex_ = 0;
+
+
+  /**
+   * A readystatechange handler for legacy IE
+   * @param {!HTMLScriptElement} script
+   * @param {number} scriptIndex
+   * @return {boolean}
+   * @private
+   */
+  goog.onScriptLoad_ = function(script, scriptIndex) {
+    // for now load the modules when we reach the last script,
+    // later allow more inter-mingling.
+    if (script.readyState == 'complete' &&
+        goog.lastNonModuleScriptIndex_ == scriptIndex) {
+      goog.loadQueuedModules_();
+    }
+    return true;
+  };
+
+  /**
+   * Resolves dependencies based on the dependencies added using addDependency
+   * and calls importScript_ in the correct order.
+   * @private
+   */
+  goog.writeScripts_ = function() {
+    /** @type {!Array<string>} The scripts we need to write this time. */
+    var scripts = [];
+    var seenScript = {};
+    var deps = goog.dependencies_;
+
+    /** @param {string} path */
+    function visitNode(path) {
+      if (path in deps.written) {
+        return;
+      }
+
+      // We have already visited this one. We can get here if we have cyclic
+      // dependencies.
+      if (path in deps.visited) {
+        if (!(path in seenScript)) {
+          seenScript[path] = true;
+          scripts.push(path);
+        }
+        return;
+      }
+
+      deps.visited[path] = true;
+
+      if (path in deps.requires) {
+        for (var requireName in deps.requires[path]) {
+          // If the required name is defined, we assume that it was already
+          // bootstrapped by other means.
+          if (!goog.isProvided_(requireName)) {
+            if (requireName in deps.nameToPath) {
+              visitNode(deps.nameToPath[requireName]);
+            } else {
+              throw Error('Undefined nameToPath for ' + requireName);
+            }
+          }
+        }
+      }
+
+      if (!(path in seenScript)) {
+        seenScript[path] = true;
+        scripts.push(path);
+      }
+    }
+
+    for (var path in goog.included_) {
+      if (!deps.written[path]) {
+        visitNode(path);
+      }
+    }
+
+    // record that we are going to load all these scripts.
+    for (var i = 0; i < scripts.length; i++) {
+      var path = scripts[i];
+      goog.dependencies_.written[path] = true;
+    }
+
+    // If a module is loaded synchronously then we need to
+    // clear the current inModuleLoader value, and restore it when we are
+    // done loading the current "requires".
+    var moduleState = goog.moduleLoaderState_;
+    goog.moduleLoaderState_ = null;
+
+    var loadingModule = false;
+    for (var i = 0; i < scripts.length; i++) {
+      var path = scripts[i];
+      if (path) {
+        if (!deps.pathIsModule[path]) {
+          goog.importScript_(goog.basePath + path);
+        } else {
+          loadingModule = true;
+          goog.importModule_(goog.basePath + path);
+        }
+      } else {
+        goog.moduleLoaderState_ = moduleState;
+        throw Error('Undefined script input');
+      }
+    }
+
+    // restore the current "module loading state"
+    goog.moduleLoaderState_ = moduleState;
+  };
+
+
+  /**
+   * Looks at the dependency rules and tries to determine the script file that
+   * fulfills a particular rule.
+   * @param {string} rule In the form goog.namespace.Class or project.script.
+   * @return {?string} Url corresponding to the rule, or null.
+   * @private
+   */
+  goog.getPathFromDeps_ = function(rule) {
+    if (rule in goog.dependencies_.nameToPath) {
+      return goog.dependencies_.nameToPath[rule];
+    } else {
+      return null;
+    }
+  };
+
+  goog.findBasePath_();
+
+  // Allow projects to manage the deps files themselves.
+  if (!goog.global.CLOSURE_NO_DEPS) {
+    goog.importScript_(goog.basePath + 'deps.js');
+  }
+}
+
+
+/**
+ * Normalize a file path by removing redundant ".." and extraneous "." file
+ * path components.
+ * @param {string} path
+ * @return {string}
+ * @private
+ */
+goog.normalizePath_ = function(path) {
+  var components = path.split('/');
+  var i = 0;
+  while (i < components.length) {
+    if (components[i] == '.') {
+      components.splice(i, 1);
+    } else if (i && components[i] == '..' &&
+        components[i - 1] && components[i - 1] != '..') {
+      components.splice(--i, 2);
+    } else {
+      i++;
+    }
+  }
+  return components.join('/');
+};
+
+
+/**
+ * Loads file by synchronous XHR. Should not be used in production environments.
+ * @param {string} src Source URL.
+ * @return {string} File contents.
+ * @private
+ */
+goog.loadFileSync_ = function(src) {
+  if (goog.global.CLOSURE_LOAD_FILE_SYNC) {
+    return goog.global.CLOSURE_LOAD_FILE_SYNC(src);
+  } else {
+    var xhr = new goog.global['XMLHttpRequest']();
+    xhr.open('get', src, false);
+    xhr.send();
+    return xhr.responseText;
+  }
+};
+
+
+/**
+ * Retrieve and execute a module.
+ * @param {string} src Script source URL.
+ * @private
+ */
+goog.retrieveAndExecModule_ = function(src) {
+  if (!COMPILED) {
+    // The full but non-canonicalized URL for later use.
+    var originalPath = src;
+    // Canonicalize the path, removing any /./ or /../ since Chrome's debugging
+    // console doesn't auto-canonicalize XHR loads as it does <script> srcs.
+    src = goog.normalizePath_(src);
+
+    var importScript = goog.global.CLOSURE_IMPORT_SCRIPT ||
+        goog.writeScriptTag_;
+
+    var scriptText = goog.loadFileSync_(src);
+
+    if (scriptText != null) {
+      var execModuleScript = goog.wrapModule_(src, scriptText);
+      var isOldIE = goog.IS_OLD_IE_;
+      if (isOldIE) {
+        goog.dependencies_.deferred[originalPath] = execModuleScript;
+        goog.queuedModules_.push(originalPath);
+      } else {
+        importScript(src, execModuleScript);
+      }
+    } else {
+      throw new Error('load of ' + src + 'failed');
+    }
+  }
+};
+
+
+//==============================================================================
+// Language Enhancements
+//==============================================================================
+
+
+/**
+ * This is a "fixed" version of the typeof operator.  It differs from the typeof
+ * operator in such a way that null returns 'null' and arrays return 'array'.
+ * @param {*} value The value to get the type of.
+ * @return {string} The name of the type.
+ */
+goog.typeOf = function(value) {
+  var s = typeof value;
+  if (s == 'object') {
+    if (value) {
+      // Check these first, so we can avoid calling Object.prototype.toString if
+      // possible.
+      //
+      // IE improperly marshals tyepof across execution contexts, but a
+      // cross-context object will still return false for "instanceof Object".
+      if (value instanceof Array) {
+        return 'array';
+      } else if (value instanceof Object) {
+        return s;
+      }
+
+      // HACK: In order to use an Object prototype method on the arbitrary
+      //   value, the compiler requires the value be cast to type Object,
+      //   even though the ECMA spec explicitly allows it.
+      var className = Object.prototype.toString.call(
+          /** @type {Object} */ (value));
+      // In Firefox 3.6, attempting to access iframe window objects' length
+      // property throws an NS_ERROR_FAILURE, so we need to special-case it
+      // here.
+      if (className == '[object Window]') {
+        return 'object';
+      }
+
+      // We cannot always use constructor == Array or instanceof Array because
+      // different frames have different Array objects. In IE6, if the iframe
+      // where the array was created is destroyed, the array loses its
+      // prototype. Then dereferencing val.splice here throws an exception, so
+      // we can't use goog.isFunction. Calling typeof directly returns 'unknown'
+      // so that will work. In this case, this function will return false and
+      // most array functions will still work because the array is still
+      // array-like (supports length and []) even though it has lost its
+      // prototype.
+      // Mark Miller noticed that Object.prototype.toString
+      // allows access to the unforgeable [[Class]] property.
+      //  15.2.4.2 Object.prototype.toString ( )
+      //  When the toString method is called, the following steps are taken:
+      //      1. Get the [[Class]] property of this object.
+      //      2. Compute a string value by concatenating the three strings
+      //         "[object ", Result(1), and "]".
+      //      3. Return Result(2).
+      // and this behavior survives the destruction of the execution context.
+      if ((className == '[object Array]' ||
+           // In IE all non value types are wrapped as objects across window
+           // boundaries (not iframe though) so we have to do object detection
+           // for this edge case.
+           typeof value.length == 'number' &&
+           typeof value.splice != 'undefined' &&
+           typeof value.propertyIsEnumerable != 'undefined' &&
+           !value.propertyIsEnumerable('splice')
+
+          )) {
+        return 'array';
+      }
+      // HACK: There is still an array case that fails.
+      //     function ArrayImpostor() {}
+      //     ArrayImpostor.prototype = [];
+      //     var impostor = new ArrayImpostor;
+      // this can be fixed by getting rid of the fast path
+      // (value instanceof Array) and solely relying on
+      // (value && Object.prototype.toString.vall(value) === '[object Array]')
+      // but that would require many more function calls and is not warranted
+      // unless closure code is receiving objects from untrusted sources.
+
+      // IE in cross-window calls does not correctly marshal the function type
+      // (it appears just as an object) so we cannot use just typeof val ==
+      // 'function'. However, if the object has a call property, it is a
+      // function.
+      if ((className == '[object Function]' ||
+          typeof value.call != 'undefined' &&
+          typeof value.propertyIsEnumerable != 'undefined' &&
+          !value.propertyIsEnumerable('call'))) {
+        return 'function';
+      }
+
+    } else {
+      return 'null';
+    }
+
+  } else if (s == 'function' && typeof value.call == 'undefined') {
+    // In Safari typeof nodeList returns 'function', and on Firefox typeof
+    // behaves similarly for HTML{Applet,Embed,Object}, Elements and RegExps. We
+    // would like to return object for those and we can detect an invalid
+    // function by making sure that the function object has a call method.
+    return 'object';
+  }
+  return s;
+};
+
+
+/**
+ * Returns true if the specified value is null.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is null.
+ */
+goog.isNull = function(val) {
+  return val === null;
+};
+
+
+/**
+ * Returns true if the specified value is defined and not null.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is defined and not null.
+ */
+goog.isDefAndNotNull = function(val) {
+  // Note that undefined == null.
+  return val != null;
+};
+
+
+/**
+ * Returns true if the specified value is an array.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is an array.
+ */
+goog.isArray = function(val) {
+  return goog.typeOf(val) == 'array';
+};
+
+
+/**
+ * Returns true if the object looks like an array. To qualify as array like
+ * the value needs to be either a NodeList or an object with a Number length
+ * property. As a special case, a function value is not array like, because its
+ * length property is fixed to correspond to the number of expected arguments.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is an array.
+ */
+goog.isArrayLike = function(val) {
+  var type = goog.typeOf(val);
+  // We do not use goog.isObject here in order to exclude function values.
+  return type == 'array' || type == 'object' && typeof val.length == 'number';
+};
+
+
+/**
+ * Returns true if the object looks like a Date. To qualify as Date-like the
+ * value needs to be an object and have a getFullYear() function.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is a like a Date.
+ */
+goog.isDateLike = function(val) {
+  return goog.isObject(val) && typeof val.getFullYear == 'function';
+};
+
+
+/**
+ * Returns true if the specified value is a string.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is a string.
+ */
+goog.isString = function(val) {
+  return typeof val == 'string';
+};
+
+
+/**
+ * Returns true if the specified value is a boolean.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is boolean.
+ */
+goog.isBoolean = function(val) {
+  return typeof val == 'boolean';
+};
+
+
+/**
+ * Returns true if the specified value is a number.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is a number.
+ */
+goog.isNumber = function(val) {
+  return typeof val == 'number';
+};
+
+
+/**
+ * Returns true if the specified value is a function.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is a function.
+ */
+goog.isFunction = function(val) {
+  return goog.typeOf(val) == 'function';
+};
+
+
+/**
+ * Returns true if the specified value is an object.  This includes arrays and
+ * functions.
+ * @param {?} val Variable to test.
+ * @return {boolean} Whether variable is an object.
+ */
+goog.isObject = function(val) {
+  var type = typeof val;
+  return type == 'object' && val != null || type == 'function';
+  // return Object(val) === val also works, but is slower, especially if val is
+  // not an object.
+};
+
+
+/**
+ * Gets a unique ID for an object. This mutates the object so that further calls
+ * with the same object as a parameter returns the same value. The unique ID is
+ * guaranteed to be unique across the current session amongst objects that are
+ * passed into {@code getUid}. There is no guarantee that the ID is unique or
+ * consistent across sessions. It is unsafe to generate unique ID for function
+ * prototypes.
+ *
+ * @param {Object} obj The object to get the unique ID for.
+ * @return {number} The unique ID for the object.
+ */
+goog.getUid = function(obj) {
+  // TODO(arv): Make the type stricter, do not accept null.
+
+  // In Opera window.hasOwnProperty exists but always returns false so we avoid
+  // using it. As a consequence the unique ID generated for BaseClass.prototype
+  // and SubClass.prototype will be the same.
+  return obj[goog.UID_PROPERTY_] ||
+      (obj[goog.UID_PROPERTY_] = ++goog.uidCounter_);
+};
+
+
+/**
+ * Whether the given object is already assigned a unique ID.
+ *
+ * This does not modify the object.
+ *
+ * @param {!Object} obj The object to check.
+ * @return {boolean} Whether there is an assigned unique id for the object.
+ */
+goog.hasUid = function(obj) {
+  return !!obj[goog.UID_PROPERTY_];
+};
+
+
+/**
+ * Removes the unique ID from an object. This is useful if the object was
+ * previously mutated using {@code goog.getUid} in which case the mutation is
+ * undone.
+ * @param {Object} obj The object to remove the unique ID field from.
+ */
+goog.removeUid = function(obj) {
+  // TODO(arv): Make the type stricter, do not accept null.
+
+  // In IE, DOM nodes are not instances of Object and throw an exception if we
+  // try to delete.  Instead we try to use removeAttribute.
+  if ('removeAttribute' in obj) {
+    obj.removeAttribute(goog.UID_PROPERTY_);
+  }
+  /** @preserveTry */
+  try {
+    delete obj[goog.UID_PROPERTY_];
+  } catch (ex) {
+  }
+};
+
+
+/**
+ * Name for unique ID property. Initialized in a way to help avoid collisions
+ * with other closure JavaScript on the same page.
+ * @type {string}
+ * @private
+ */
+goog.UID_PROPERTY_ = 'closure_uid_' + ((Math.random() * 1e9) >>> 0);
+
+
+/**
+ * Counter for UID.
+ * @type {number}
+ * @private
+ */
+goog.uidCounter_ = 0;
+
+
+/**
+ * Adds a hash code field to an object. The hash code is unique for the
+ * given object.
+ * @param {Object} obj The object to get the hash code for.
+ * @return {number} The hash code for the object.
+ * @deprecated Use goog.getUid instead.
+ */
+goog.getHashCode = goog.getUid;
+
+
+/**
+ * Removes the hash code field from an object.
+ * @param {Object} obj The object to remove the field from.
+ * @deprecated Use goog.removeUid instead.
+ */
+goog.removeHashCode = goog.removeUid;
+
+
+/**
+ * Clones a value. The input may be an Object, Array, or basic type. Objects and
+ * arrays will be cloned recursively.
+ *
+ * WARNINGS:
+ * <code>goog.cloneObject</code> does not detect reference loops. Objects that
+ * refer to themselves will cause infinite recursion.
+ *
+ * <code>goog.cloneObject</code> is unaware of unique identifiers, and copies
+ * UIDs created by <code>getUid</code> into cloned results.
+ *
+ * @param {*} obj The value to clone.
+ * @return {*} A clone of the input value.
+ * @deprecated goog.cloneObject is unsafe. Prefer the goog.object methods.
+ */
+goog.cloneObject = function(obj) {
+  var type = goog.typeOf(obj);
+  if (type == 'object' || type == 'array') {
+    if (obj.clone) {
+      return obj.clone();
+    }
+    var clone = type == 'array' ? [] : {};
+    for (var key in obj) {
+      clone[key] = goog.cloneObject(obj[key]);
+    }
+    return clone;
+  }
+
+  return obj;
+};
+
+
+/**
+ * A native implementation of goog.bind.
+ * @param {Function} fn A function to partially apply.
+ * @param {Object|undefined} selfObj Specifies the object which this should
+ *     point to when the function is run.
+ * @param {...*} var_args Additional arguments that are partially applied to the
+ *     function.
+ * @return {!Function} A partially-applied form of the function bind() was
+ *     invoked as a method of.
+ * @private
+ * @suppress {deprecated} The compiler thinks that Function.prototype.bind is
+ *     deprecated because some people have declared a pure-JS version.
+ *     Only the pure-JS version is truly deprecated.
+ */
+goog.bindNative_ = function(fn, selfObj, var_args) {
+  return /** @type {!Function} */ (fn.call.apply(fn.bind, arguments));
+};
+
+
+/**
+ * A pure-JS implementation of goog.bind.
+ * @param {Function} fn A function to partially apply.
+ * @param {Object|undefined} selfObj Specifies the object which this should
+ *     point to when the function is run.
+ * @param {...*} var_args Additional arguments that are partially applied to the
+ *     function.
+ * @return {!Function} A partially-applied form of the function bind() was
+ *     invoked as a method of.
+ * @private
+ */
+goog.bindJs_ = function(fn, selfObj, var_args) {
+  if (!fn) {
+    throw new Error();
+  }
+
+  if (arguments.length > 2) {
+    var boundArgs = Array.prototype.slice.call(arguments, 2);
+    return function() {
+      // Prepend the bound arguments to the current arguments.
+      var newArgs = Array.prototype.slice.call(arguments);
+      Array.prototype.unshift.apply(newArgs, boundArgs);
+      return fn.apply(selfObj, newArgs);
+    };
+
+  } else {
+    return function() {
+      return fn.apply(selfObj, arguments);
+    };
+  }
+};
+
+
+/**
+ * Partially applies this function to a particular 'this object' and zero or
+ * more arguments. The result is a new function with some arguments of the first
+ * function pre-filled and the value of this 'pre-specified'.
+ *
+ * Remaining arguments specified at call-time are appended to the pre-specified
+ * ones.
+ *
+ * Also see: {@link #partial}.
+ *
+ * Usage:
+ * <pre>var barMethBound = bind(myFunction, myObj, 'arg1', 'arg2');
+ * barMethBound('arg3', 'arg4');</pre>
+ *
+ * @param {?function(this:T, ...)} fn A function to partially apply.
+ * @param {T} selfObj Specifies the object which this should point to when the
+ *     function is run.
+ * @param {...*} var_args Additional arguments that are partially applied to the
+ *     function.
+ * @return {!Function} A partially-applied form of the function bind() was
+ *     invoked as a method of.
+ * @template T
+ * @suppress {deprecated} See above.
+ */
+goog.bind = function(fn, selfObj, var_args) {
+  // TODO(nicksantos): narrow the type signature.
+  if (Function.prototype.bind &&
+      // NOTE(nicksantos): Somebody pulled base.js into the default Chrome
+      // extension environment. This means that for Chrome extensions, they get
+      // the implementation of Function.prototype.bind that calls goog.bind
+      // instead of the native one. Even worse, we don't want to introduce a
+      // circular dependency between goog.bind and Function.prototype.bind, so
+      // we have to hack this to make sure it works correctly.
+      Function.prototype.bind.toString().indexOf('native code') != -1) {
+    goog.bind = goog.bindNative_;
+  } else {
+    goog.bind = goog.bindJs_;
+  }
+  return goog.bind.apply(null, arguments);
+};
+
+
+/**
+ * Like bind(), except that a 'this object' is not required. Useful when the
+ * target function is already bound.
+ *
+ * Usage:
+ * var g = partial(f, arg1, arg2);
+ * g(arg3, arg4);
+ *
+ * @param {Function} fn A function to partially apply.
+ * @param {...*} var_args Additional arguments that are partially applied to fn.
+ * @return {!Function} A partially-applied form of the function bind() was
+ *     invoked as a method of.
+ */
+goog.partial = function(fn, var_args) {
+  var args = Array.prototype.slice.call(arguments, 1);
+  return function() {
+    // Clone the array (with slice()) and append additional arguments
+    // to the existing arguments.
+    var newArgs = args.slice();
+    newArgs.push.apply(newArgs, arguments);
+    return fn.apply(this, newArgs);
+  };
+};
+
+
+/**
+ * Copies all the members of a source object to a target object. This method
+ * does not work on all browsers for all objects that contain keys such as
+ * toString or hasOwnProperty. Use goog.object.extend for this purpose.
+ * @param {Object} target Target.
+ * @param {Object} source Source.
+ */
+goog.mixin = function(target, source) {
+  for (var x in source) {
+    target[x] = source[x];
+  }
+
+  // For IE7 or lower, the for-in-loop does not contain any properties that are
+  // not enumerable on the prototype object (for example, isPrototypeOf from
+  // Object.prototype) but also it will not include 'replace' on objects that
+  // extend String and change 'replace' (not that it is common for anyone to
+  // extend anything except Object).
+};
+
+
+/**
+ * @return {number} An integer value representing the number of milliseconds
+ *     between midnight, January 1, 1970 and the current time.
+ */
+goog.now = (goog.TRUSTED_SITE && Date.now) || (function() {
+  // Unary plus operator converts its operand to a number which in the case of
+  // a date is done by calling getTime().
+  return +new Date();
+});
+
+
+/**
+ * Evals JavaScript in the global scope.  In IE this uses execScript, other
+ * browsers use goog.global.eval. If goog.global.eval does not evaluate in the
+ * global scope (for example, in Safari), appends a script tag instead.
+ * Throws an exception if neither execScript or eval is defined.
+ * @param {string} script JavaScript string.
+ */
+goog.globalEval = function(script) {
+  if (goog.global.execScript) {
+    goog.global.execScript(script, 'JavaScript');
+  } else if (goog.global.eval) {
+    // Test to see if eval works
+    if (goog.evalWorksForGlobals_ == null) {
+      goog.global.eval('var _et_ = 1;');
+      if (typeof goog.global['_et_'] != 'undefined') {
+        delete goog.global['_et_'];
+        goog.evalWorksForGlobals_ = true;
+      } else {
+        goog.evalWorksForGlobals_ = false;
+      }
+    }
+
+    if (goog.evalWorksForGlobals_) {
+      goog.global.eval(script);
+    } else {
+      var doc = goog.global.document;
+      var scriptElt = doc.createElement('SCRIPT');
+      scriptElt.type = 'text/javascript';
+      scriptElt.defer = false;
+      // Note(user): can't use .innerHTML since "t('<test>')" will fail and
+      // .text doesn't work in Safari 2.  Therefore we append a text node.
+      scriptElt.appendChild(doc.createTextNode(script));
+      doc.body.appendChild(scriptElt);
+      doc.body.removeChild(scriptElt);
+    }
+  } else {
+    throw Error('goog.globalEval not available');
+  }
+};
+
+
+/**
+ * Indicates whether or not we can call 'eval' directly to eval code in the
+ * global scope. Set to a Boolean by the first call to goog.globalEval (which
+ * empirically tests whether eval works for globals). @see goog.globalEval
+ * @type {?boolean}
+ * @private
+ */
+goog.evalWorksForGlobals_ = null;
+
+
+/**
+ * Optional map of CSS class names to obfuscated names used with
+ * goog.getCssName().
+ * @private {!Object<string, string>|undefined}
+ * @see goog.setCssNameMapping
+ */
+goog.cssNameMapping_;
+
+
+/**
+ * Optional obfuscation style for CSS class names. Should be set to either
+ * 'BY_WHOLE' or 'BY_PART' if defined.
+ * @type {string|undefined}
+ * @private
+ * @see goog.setCssNameMapping
+ */
+goog.cssNameMappingStyle_;
+
+
+/**
+ * Handles strings that are intended to be used as CSS class names.
+ *
+ * This function works in tandem with @see goog.setCssNameMapping.
+ *
+ * Without any mapping set, the arguments are simple joined with a hyphen and
+ * passed through unaltered.
+ *
+ * When there is a mapping, there are two possible styles in which these
+ * mappings are used. In the BY_PART style, each part (i.e. in between hyphens)
+ * of the passed in css name is rewritten according to the map. In the BY_WHOLE
+ * style, the full css name is looked up in the map directly. If a rewrite is
+ * not specified by the map, the compiler will output a warning.
+ *
+ * When the mapping is passed to the compiler, it will replace calls to
+ * goog.getCssName with the strings from the mapping, e.g.
+ *     var x = goog.getCssName('foo');
+ *     var y = goog.getCssName(this.baseClass, 'active');
+ *  becomes:
+ *     var x= 'foo';
+ *     var y = this.baseClass + '-active';
+ *
+ * If one argument is passed it will be processed, if two are passed only the
+ * modifier will be processed, as it is assumed the first argument was generated
+ * as a result of calling goog.getCssName.
+ *
+ * @param {string} className The class name.
+ * @param {string=} opt_modifier A modifier to be appended to the class name.
+ * @return {string} The class name or the concatenation of the class name and
+ *     the modifier.
+ */
+goog.getCssName = function(className, opt_modifier) {
+  var getMapping = function(cssName) {
+    return goog.cssNameMapping_[cssName] || cssName;
+  };
+
+  var renameByParts = function(cssName) {
+    // Remap all the parts individually.
+    var parts = cssName.split('-');
+    var mapped = [];
+    for (var i = 0; i < parts.length; i++) {
+      mapped.push(getMapping(parts[i]));
+    }
+    return mapped.join('-');
+  };
+
+  var rename;
+  if (goog.cssNameMapping_) {
+    rename = goog.cssNameMappingStyle_ == 'BY_WHOLE' ?
+        getMapping : renameByParts;
+  } else {
+    rename = function(a) {
+      return a;
+    };
+  }
+
+  if (opt_modifier) {
+    return className + '-' + rename(opt_modifier);
+  } else {
+    return rename(className);
+  }
+};
+
+
+/**
+ * Sets the map to check when returning a value from goog.getCssName(). Example:
+ * <pre>
+ * goog.setCssNameMapping({
+ *   "goog": "a",
+ *   "disabled": "b",
+ * });
+ *
+ * var x = goog.getCssName('goog');
+ * // The following evaluates to: "a a-b".
+ * goog.getCssName('goog') + ' ' + goog.getCssName(x, 'disabled')
+ * </pre>
+ * When declared as a map of string literals to string literals, the JSCompiler
+ * will replace all calls to goog.getCssName() using the supplied map if the
+ * --closure_pass flag is set.
+ *
+ * @param {!Object} mapping A map of strings to strings where keys are possible
+ *     arguments to goog.getCssName() and values are the corresponding values
+ *     that should be returned.
+ * @param {string=} opt_style The style of css name mapping. There are two valid
+ *     options: 'BY_PART', and 'BY_WHOLE'.
+ * @see goog.getCssName for a description.
+ */
+goog.setCssNameMapping = function(mapping, opt_style) {
+  goog.cssNameMapping_ = mapping;
+  goog.cssNameMappingStyle_ = opt_style;
+};
+
+
+/**
+ * To use CSS renaming in compiled mode, one of the input files should have a
+ * call to goog.setCssNameMapping() with an object literal that the JSCompiler
+ * can extract and use to replace all calls to goog.getCssName(). In uncompiled
+ * mode, JavaScript code should be loaded before this base.js file that declares
+ * a global variable, CLOSURE_CSS_NAME_MAPPING, which is used below. This is
+ * to ensure that the mapping is loaded before any calls to goog.getCssName()
+ * are made in uncompiled mode.
+ *
+ * A hook for overriding the CSS name mapping.
+ * @type {!Object<string, string>|undefined}
+ */
+goog.global.CLOSURE_CSS_NAME_MAPPING;
+
+
+if (!COMPILED && goog.global.CLOSURE_CSS_NAME_MAPPING) {
+  // This does not call goog.setCssNameMapping() because the JSCompiler
+  // requires that goog.setCssNameMapping() be called with an object literal.
+  goog.cssNameMapping_ = goog.global.CLOSURE_CSS_NAME_MAPPING;
+}
+
+
+/**
+ * Gets a localized message.
+ *
+ * This function is a compiler primitive. If you give the compiler a localized
+ * message bundle, it will replace the string at compile-time with a localized
+ * version, and expand goog.getMsg call to a concatenated string.
+ *
+ * Messages must be initialized in the form:
+ * <code>
+ * var MSG_NAME = goog.getMsg('Hello {$placeholder}', {'placeholder': 'world'});
+ * </code>
+ *
+ * @param {string} str Translatable string, places holders in the form {$foo}.
+ * @param {Object<string, string>=} opt_values Maps place holder name to value.
+ * @return {string} message with placeholders filled.
+ */
+goog.getMsg = function(str, opt_values) {
+  if (opt_values) {
+    str = str.replace(/\{\$([^}]+)}/g, function(match, key) {
+      return key in opt_values ? opt_values[key] : match;
+    });
+  }
+  return str;
+};
+
+
+/**
+ * Gets a localized message. If the message does not have a translation, gives a
+ * fallback message.
+ *
+ * This is useful when introducing a new message that has not yet been
+ * translated into all languages.
+ *
+ * This function is a compiler primitive. Must be used in the form:
+ * <code>var x = goog.getMsgWithFallback(MSG_A, MSG_B);</code>
+ * where MSG_A and MSG_B were initialized with goog.getMsg.
+ *
+ * @param {string} a The preferred message.
+ * @param {string} b The fallback message.
+ * @return {string} The best translated message.
+ */
+goog.getMsgWithFallback = function(a, b) {
+  return a;
+};
+
+
+/**
+ * Exposes an unobfuscated global namespace path for the given object.
+ * Note that fields of the exported object *will* be obfuscated, unless they are
+ * exported in turn via this function or goog.exportProperty.
+ *
+ * Also handy for making public items that are defined in anonymous closures.
+ *
+ * ex. goog.exportSymbol('public.path.Foo', Foo);
+ *
+ * ex. goog.exportSymbol('public.path.Foo.staticFunction', Foo.staticFunction);
+ *     public.path.Foo.staticFunction();
+ *
+ * ex. goog.exportSymbol('public.path.Foo.prototype.myMethod',
+ *                       Foo.prototype.myMethod);
+ *     new public.path.Foo().myMethod();
+ *
+ * @param {string} publicPath Unobfuscated name to export.
+ * @param {*} object Object the name should point to.
+ * @param {Object=} opt_objectToExportTo The object to add the path to; default
+ *     is goog.global.
+ */
+goog.exportSymbol = function(publicPath, object, opt_objectToExportTo) {
+  goog.exportPath_(publicPath, object, opt_objectToExportTo);
+};
+
+
+/**
+ * Exports a property unobfuscated into the object's namespace.
+ * ex. goog.exportProperty(Foo, 'staticFunction', Foo.staticFunction);
+ * ex. goog.exportProperty(Foo.prototype, 'myMethod', Foo.prototype.myMethod);
+ * @param {Object} object Object whose static property is being exported.
+ * @param {string} publicName Unobfuscated name to export.
+ * @param {*} symbol Object the name should point to.
+ */
+goog.exportProperty = function(object, publicName, symbol) {
+  object[publicName] = symbol;
+};
+
+
+/**
+ * Inherit the prototype methods from one constructor into another.
+ *
+ * Usage:
+ * <pre>
+ * function ParentClass(a, b) { }
+ * ParentClass.prototype.foo = function(a) { };
+ *
+ * function ChildClass(a, b, c) {
+ *   ChildClass.base(this, 'constructor', a, b);
+ * }
+ * goog.inherits(ChildClass, ParentClass);
+ *
+ * var child = new ChildClass('a', 'b', 'see');
+ * child.foo(); // This works.
+ * </pre>
+ *
+ * @param {Function} childCtor Child class.
+ * @param {Function} parentCtor Parent class.
+ */
+goog.inherits = function(childCtor, parentCtor) {
+  /** @constructor */
+  function tempCtor() {};
+  tempCtor.prototype = parentCtor.prototype;
+  childCtor.superClass_ = parentCtor.prototype;
+  childCtor.prototype = new tempCtor();
+  /** @override */
+  childCtor.prototype.constructor = childCtor;
+
+  /**
+   * Calls superclass constructor/method.
+   *
+   * This function is only available if you use goog.inherits to
+   * express inheritance relationships between classes.
+   *
+   * NOTE: This is a replacement for goog.base and for superClass_
+   * property defined in childCtor.
+   *
+   * @param {!Object} me Should always be "this".
+   * @param {string} methodName The method name to call. Calling
+   *     superclass constructor can be done with the special string
+   *     'constructor'.
+   * @param {...*} var_args The arguments to pass to superclass
+   *     method/constructor.
+   * @return {*} The return value of the superclass method/constructor.
+   */
+  childCtor.base = function(me, methodName, var_args) {
+    // Copying using loop to avoid deop due to passing arguments object to
+    // function. This is faster in many JS engines as of late 2014.
+    var args = new Array(arguments.length - 2);
+    for (var i = 2; i < arguments.length; i++) {
+      args[i - 2] = arguments[i];
+    }
+    return parentCtor.prototype[methodName].apply(me, args);
+  };
+};
+
+
+/**
+ * Call up to the superclass.
+ *
+ * If this is called from a constructor, then this calls the superclass
+ * constructor with arguments 1-N.
+ *
+ * If this is called from a prototype method, then you must pass the name of the
+ * method as the second argument to this function. If you do not, you will get a
+ * runtime error. This calls the superclass' method with arguments 2-N.
+ *
+ * This function only works if you use goog.inherits to express inheritance
+ * relationships between your classes.
+ *
+ * This function is a compiler primitive. At compile-time, the compiler will do
+ * macro expansion to remove a lot of the extra overhead that this function
+ * introduces. The compiler will also enforce a lot of the assumptions that this
+ * function makes, and treat it as a compiler error if you break them.
+ *
+ * @param {!Object} me Should always be "this".
+ * @param {*=} opt_methodName The method name if calling a super method.
+ * @param {...*} var_args The rest of the arguments.
+ * @return {*} The return value of the superclass method.
+ * @suppress {es5Strict} This method can not be used in strict mode, but
+ *     all Closure Library consumers must depend on this file.
+ */
+goog.base = function(me, opt_methodName, var_args) {
+  var caller = arguments.callee.caller;
+
+  if (goog.STRICT_MODE_COMPATIBLE || (goog.DEBUG && !caller)) {
+    throw Error('arguments.caller not defined.  goog.base() cannot be used ' +
+                'with strict mode code. See ' +
+                'http://www.ecma-international.org/ecma-262/5.1/#sec-C');
+  }
+
+  if (caller.superClass_) {
+    // Copying using loop to avoid deop due to passing arguments object to
+    // function. This is faster in many JS engines as of late 2014.
+    var ctorArgs = new Array(arguments.length - 1);
+    for (var i = 1; i < arguments.length; i++) {
+      ctorArgs[i - 1] = arguments[i];
+    }
+    // This is a constructor. Call the superclass constructor.
+    return caller.superClass_.constructor.apply(me, ctorArgs);
+  }
+
+  // Copying using loop to avoid deop due to passing arguments object to
+  // function. This is faster in many JS engines as of late 2014.
+  var args = new Array(arguments.length - 2);
+  for (var i = 2; i < arguments.length; i++) {
+    args[i - 2] = arguments[i];
+  }
+  var foundCaller = false;
+  for (var ctor = me.constructor;
+       ctor; ctor = ctor.superClass_ && ctor.superClass_.constructor) {
+    if (ctor.prototype[opt_methodName] === caller) {
+      foundCaller = true;
+    } else if (foundCaller) {
+      return ctor.prototype[opt_methodName].apply(me, args);
+    }
+  }
+
+  // If we did not find the caller in the prototype chain, then one of two
+  // things happened:
+  // 1) The caller is an instance method.
+  // 2) This method was not called by the right caller.
+  if (me[opt_methodName] === caller) {
+    return me.constructor.prototype[opt_methodName].apply(me, args);
+  } else {
+    throw Error(
+        'goog.base called from a method of one name ' +
+        'to a method of a different name');
+  }
+};
+
+
+/**
+ * Allow for aliasing within scope functions.  This function exists for
+ * uncompiled code - in compiled code the calls will be inlined and the aliases
+ * applied.  In uncompiled code the function is simply run since the aliases as
+ * written are valid JavaScript.
+ *
+ *
+ * @param {function()} fn Function to call.  This function can contain aliases
+ *     to namespaces (e.g. "var dom = goog.dom") or classes
+ *     (e.g. "var Timer = goog.Timer").
+ */
+goog.scope = function(fn) {
+  fn.call(goog.global);
+};
+
+
+/*
+ * To support uncompiled, strict mode bundles that use eval to divide source
+ * like so:
+ *    eval('someSource;//# sourceUrl sourcefile.js');
+ * We need to export the globally defined symbols "goog" and "COMPILED".
+ * Exporting "goog" breaks the compiler optimizations, so we required that
+ * be defined externally.
+ * NOTE: We don't use goog.exportSymbol here because we don't want to trigger
+ * extern generation when that compiler option is enabled.
+ */
+if (!COMPILED) {
+  goog.global['COMPILED'] = COMPILED;
+}
+
+
+
+//==============================================================================
+// goog.defineClass implementation
+//==============================================================================
+
+
+/**
+ * Creates a restricted form of a Closure "class":
+ *   - from the compiler's perspective, the instance returned from the
+ *     constructor is sealed (no new properties may be added).  This enables
+ *     better checks.
+ *   - the compiler will rewrite this definition to a form that is optimal
+ *     for type checking and optimization (initially this will be a more
+ *     traditional form).
+ *
+ * @param {Function} superClass The superclass, Object or null.
+ * @param {goog.defineClass.ClassDescriptor} def
+ *     An object literal describing
+ *     the class.  It may have the following properties:
+ *     "constructor": the constructor function
+ *     "statics": an object literal containing methods to add to the constructor
+ *        as "static" methods or a function that will receive the constructor
+ *        function as its only parameter to which static properties can
+ *        be added.
+ *     all other properties are added to the prototype.
+ * @return {!Function} The class constructor.
+ */
+goog.defineClass = function(superClass, def) {
+  // TODO(johnlenz): consider making the superClass an optional parameter.
+  var constructor = def.constructor;
+  var statics = def.statics;
+  // Wrap the constructor prior to setting up the prototype and static methods.
+  if (!constructor || constructor == Object.prototype.constructor) {
+    constructor = function() {
+      throw Error('cannot instantiate an interface (no constructor defined).');
+    };
+  }
+
+  var cls = goog.defineClass.createSealingConstructor_(constructor, superClass);
+  if (superClass) {
+    goog.inherits(cls, superClass);
+  }
+
+  // Remove all the properties that should not be copied to the prototype.
+  delete def.constructor;
+  delete def.statics;
+
+  goog.defineClass.applyProperties_(cls.prototype, def);
+  if (statics != null) {
+    if (statics instanceof Function) {
+      statics(cls);
+    } else {
+      goog.defineClass.applyProperties_(cls, statics);
+    }
+  }
+
+  return cls;
+};
+
+
+/**
+ * @typedef {
+ *     !Object|
+ *     {constructor:!Function}|
+ *     {constructor:!Function, statics:(Object|function(Function):void)}}
+ * @suppress {missingProvide}
+ */
+goog.defineClass.ClassDescriptor;
+
+
+/**
+ * @define {boolean} Whether the instances returned by
+ * goog.defineClass should be sealed when possible.
+ */
+goog.define('goog.defineClass.SEAL_CLASS_INSTANCES', goog.DEBUG);
+
+
+/**
+ * If goog.defineClass.SEAL_CLASS_INSTANCES is enabled and Object.seal is
+ * defined, this function will wrap the constructor in a function that seals the
+ * results of the provided constructor function.
+ *
+ * @param {!Function} ctr The constructor whose results maybe be sealed.
+ * @param {Function} superClass The superclass constructor.
+ * @return {!Function} The replacement constructor.
+ * @private
+ */
+goog.defineClass.createSealingConstructor_ = function(ctr, superClass) {
+  if (goog.defineClass.SEAL_CLASS_INSTANCES &&
+      Object.seal instanceof Function) {
+    // Don't seal subclasses of unsealable-tagged legacy classes.
+    if (superClass && superClass.prototype &&
+        superClass.prototype[goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_]) {
+      return ctr;
+    }
+    /**
+     * @this {Object}
+     * @return {?}
+     */
+    var wrappedCtr = function() {
+      // Don't seal an instance of a subclass when it calls the constructor of
+      // its super class as there is most likely still setup to do.
+      var instance = ctr.apply(this, arguments) || this;
+      instance[goog.UID_PROPERTY_] = instance[goog.UID_PROPERTY_];
+      if (this.constructor === wrappedCtr) {
+        Object.seal(instance);
+      }
+      return instance;
+    };
+    return wrappedCtr;
+  }
+  return ctr;
+};
+
+
+// TODO(johnlenz): share these values with the goog.object
+/**
+ * The names of the fields that are defined on Object.prototype.
+ * @type {!Array<string>}
+ * @private
+ * @const
+ */
+goog.defineClass.OBJECT_PROTOTYPE_FIELDS_ = [
+  'constructor',
+  'hasOwnProperty',
+  'isPrototypeOf',
+  'propertyIsEnumerable',
+  'toLocaleString',
+  'toString',
+  'valueOf'
+];
+
+
+// TODO(johnlenz): share this function with the goog.object
+/**
+ * @param {!Object} target The object to add properties to.
+ * @param {!Object} source The object to copy properties from.
+ * @private
+ */
+goog.defineClass.applyProperties_ = function(target, source) {
+  // TODO(johnlenz): update this to support ES5 getters/setters
+
+  var key;
+  for (key in source) {
+    if (Object.prototype.hasOwnProperty.call(source, key)) {
+      target[key] = source[key];
+    }
+  }
+
+  // For IE the for-in-loop does not contain any properties that are not
+  // enumerable on the prototype object (for example isPrototypeOf from
+  // Object.prototype) and it will also not include 'replace' on objects that
+  // extend String and change 'replace' (not that it is common for anyone to
+  // extend anything except Object).
+  for (var i = 0; i < goog.defineClass.OBJECT_PROTOTYPE_FIELDS_.length; i++) {
+    key = goog.defineClass.OBJECT_PROTOTYPE_FIELDS_[i];
+    if (Object.prototype.hasOwnProperty.call(source, key)) {
+      target[key] = source[key];
+    }
+  }
+};
+
+
+/**
+ * Sealing classes breaks the older idiom of assigning properties on the
+ * prototype rather than in the constructor.  As such, goog.defineClass
+ * must not seal subclasses of these old-style classes until they are fixed.
+ * Until then, this marks a class as "broken", instructing defineClass
+ * not to seal subclasses.
+ * @param {!Function} ctr The legacy constructor to tag as unsealable.
+ */
+goog.tagUnsealableClass = function(ctr) {
+  if (!COMPILED && goog.defineClass.SEAL_CLASS_INSTANCES) {
+    ctr.prototype[goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_] = true;
+  }
+};
+
+
+/**
+ * Name for unsealable tag property.
+ * @const @private {string}
+ */
+goog.UNSEALABLE_CONSTRUCTOR_PROPERTY_ = 'goog_defineClass_legacy_unsealable';

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/bootstrap/nodejs.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/bootstrap/nodejs.js b/externs/GCL/externs/goog/bootstrap/nodejs.js
new file mode 100644
index 0000000..bde163d
--- /dev/null
+++ b/externs/GCL/externs/goog/bootstrap/nodejs.js
@@ -0,0 +1,110 @@
+// Copyright 2013 The Closure Library Authors.
+//
+// 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 nodejs script for dynamically requiring Closure within
+ * nodejs.
+ *
+ * Example of usage:
+ * <code>
+ * require('./bootstrap/nodejs')
+ * goog.require('goog.ui.Component')
+ * </code>
+ *
+ * This loads goog.ui.Component in the global scope.
+ *
+ * If you want to load custom libraries, you can require the custom deps file
+ * directly. If your custom libraries introduce new globals, you may
+ * need to run goog.nodeGlobalRequire to get them to load correctly.
+ *
+ * <code>
+ * require('./path/to/my/deps.js')
+ * goog.bootstrap.nodeJs.nodeGlobalRequire('./path/to/my/base.js')
+ * goog.require('my.Class')
+ * </code>
+ *
+ * @author nick@medium.com (Nick Santos)
+ *
+ * @nocompile
+ */
+
+
+var fs = require('fs');
+var path = require('path');
+var vm = require('vm');
+
+
+/**
+ * The goog namespace in the global scope.
+ */
+global.goog = {};
+
+
+/**
+ * Imports a script using Node's require() API.
+ *
+ * @param {string} src The script source.
+ * @param {string=} opt_sourceText The optional source text to evaluate.
+ * @return {boolean} True if the script was imported, false otherwise.
+ */
+global.CLOSURE_IMPORT_SCRIPT = function(src, opt_sourceText) {
+  // Sources are always expressed relative to closure's base.js, but
+  // require() is always relative to the current source.
+  if (opt_sourceText === undefined) {
+      require('./../' + src);
+  } else {
+      eval(opt_sourceText);
+  }
+  return true;
+};
+
+
+/**
+ * Loads a file when using Closure's goog.require() API with goog.modules.
+ *
+ * @param {string} src The file source.
+ * @return {string} The file contents.
+ */
+
+global.CLOSURE_LOAD_FILE_SYNC = function(src) {
+  return fs.readFileSync(
+      path.resolve(__dirname, '..', src), { encoding: 'utf-8' });
+};
+
+
+// Declared here so it can be used to require base.js
+function nodeGlobalRequire(file) {
+  vm.runInThisContext.call(
+      global, fs.readFileSync(file), file);
+}
+
+
+// Load Closure's base.js into memory.  It is assumed base.js is in the
+// directory above this directory given this script's location in
+// bootstrap/nodejs.js.
+nodeGlobalRequire(path.resolve(__dirname, '..', 'base.js'));
+
+
+/**
+ * Bootstraps a file into the global scope.
+ *
+ * This is strictly for cases where normal require() won't work,
+ * because the file declares global symbols with 'var' that need to
+ * be added to the global scope.
+ * @suppress {missingProvide}
+ *
+ * @param {string} file The path to the file.
+ */
+goog.nodeGlobalRequire = nodeGlobalRequire;
+


[07/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/html/safestylesheet.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/html/safestylesheet.js b/externs/GCL/externs/goog/html/safestylesheet.js
new file mode 100644
index 0000000..79e8b51
--- /dev/null
+++ b/externs/GCL/externs/goog/html/safestylesheet.js
@@ -0,0 +1,276 @@
+// Copyright 2014 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 The SafeStyleSheet type and its builders.
+ *
+ * TODO(user): Link to document stating type contract.
+ */
+
+goog.provide('goog.html.SafeStyleSheet');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.string');
+goog.require('goog.string.Const');
+goog.require('goog.string.TypedString');
+
+
+
+/**
+ * A string-like object which represents a CSS style sheet and that carries the
+ * security type contract that its value, as a string, will not cause untrusted
+ * script execution (XSS) when evaluated as CSS in a browser.
+ *
+ * Instances of this type must be created via the factory method
+ * {@code goog.html.SafeStyleSheet.fromConstant} and not by invoking its
+ * constructor. The constructor intentionally takes no parameters and the type
+ * is immutable; hence only a default instance corresponding to the empty string
+ * can be obtained via constructor invocation.
+ *
+ * A SafeStyleSheet's string representation can safely be interpolated as the
+ * content of a style element within HTML. The SafeStyleSheet string should
+ * not be escaped before interpolation.
+ *
+ * Values of this type must be composable, i.e. for any two values
+ * {@code styleSheet1} and {@code styleSheet2} of this type,
+ * {@code goog.html.SafeStyleSheet.unwrap(styleSheet1) +
+ * goog.html.SafeStyleSheet.unwrap(styleSheet2)} must itself be a value that
+ * satisfies the SafeStyleSheet type constraint. This requirement implies that
+ * for any value {@code styleSheet} of this type,
+ * {@code goog.html.SafeStyleSheet.unwrap(styleSheet1)} must end in
+ * "beginning of rule" context.
+
+ * A SafeStyleSheet can be constructed via security-reviewed unchecked
+ * conversions. In this case producers of SafeStyleSheet must ensure themselves
+ * that the SafeStyleSheet does not contain unsafe script. Note in particular
+ * that {@code &lt;} is dangerous, even when inside CSS strings, and so should
+ * always be forbidden or CSS-escaped in user controlled input. For example, if
+ * {@code &lt;/style&gt;&lt;script&gt;evil&lt;/script&gt;"} were interpolated
+ * inside a CSS string, it would break out of the context of the original
+ * style element and {@code evil} would execute. Also note that within an HTML
+ * style (raw text) element, HTML character references, such as
+ * {@code &amp;lt;}, are not allowed. See
+ * http://www.w3.org/TR/html5/scripting-1.html#restrictions-for-contents-of-script-elements
+ * (similar considerations apply to the style element).
+ *
+ * @see goog.html.SafeStyleSheet#fromConstant
+ * @constructor
+ * @final
+ * @struct
+ * @implements {goog.string.TypedString}
+ */
+goog.html.SafeStyleSheet = function() {
+  /**
+   * The contained value of this SafeStyleSheet.  The field has a purposely
+   * ugly name to make (non-compiled) code that attempts to directly access this
+   * field stand out.
+   * @private {string}
+   */
+  this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ = '';
+
+  /**
+   * A type marker used to implement additional run-time type checking.
+   * @see goog.html.SafeStyleSheet#unwrap
+   * @const
+   * @private
+   */
+  this.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
+      goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
+};
+
+
+/**
+ * @override
+ * @const
+ */
+goog.html.SafeStyleSheet.prototype.implementsGoogStringTypedString = true;
+
+
+/**
+ * Type marker for the SafeStyleSheet type, used to implement additional
+ * run-time type checking.
+ * @const
+ * @private
+ */
+goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
+
+
+/**
+ * Creates a new SafeStyleSheet object by concatenating values.
+ * @param {...(!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>)}
+ *     var_args Values to concatenate.
+ * @return {!goog.html.SafeStyleSheet}
+ */
+goog.html.SafeStyleSheet.concat = function(var_args) {
+  var result = '';
+
+  /**
+   * @param {!goog.html.SafeStyleSheet|!Array<!goog.html.SafeStyleSheet>}
+   *     argument
+   */
+  var addArgument = function(argument) {
+    if (goog.isArray(argument)) {
+      goog.array.forEach(argument, addArgument);
+    } else {
+      result += goog.html.SafeStyleSheet.unwrap(argument);
+    }
+  };
+
+  goog.array.forEach(arguments, addArgument);
+  return goog.html.SafeStyleSheet
+      .createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(result);
+};
+
+
+/**
+ * Creates a SafeStyleSheet object from a compile-time constant string.
+ *
+ * {@code styleSheet} must not have any &lt; characters in it, so that
+ * the syntactic structure of the surrounding HTML is not affected.
+ *
+ * @param {!goog.string.Const} styleSheet A compile-time-constant string from
+ *     which to create a SafeStyleSheet.
+ * @return {!goog.html.SafeStyleSheet} A SafeStyleSheet object initialized to
+ *     {@code styleSheet}.
+ */
+goog.html.SafeStyleSheet.fromConstant = function(styleSheet) {
+  var styleSheetString = goog.string.Const.unwrap(styleSheet);
+  if (styleSheetString.length === 0) {
+    return goog.html.SafeStyleSheet.EMPTY;
+  }
+  // > is a valid character in CSS selectors and there's no strict need to
+  // block it if we already block <.
+  goog.asserts.assert(!goog.string.contains(styleSheetString, '<'),
+      "Forbidden '<' character in style sheet string: " + styleSheetString);
+  return goog.html.SafeStyleSheet.
+      createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheetString);
+};
+
+
+/**
+ * Returns this SafeStyleSheet's value as a string.
+ *
+ * IMPORTANT: In code where it is security relevant that an object's type is
+ * indeed {@code SafeStyleSheet}, use {@code goog.html.SafeStyleSheet.unwrap}
+ * instead of this method. If in doubt, assume that it's security relevant. In
+ * particular, note that goog.html functions which return a goog.html type do
+ * not guarantee the returned instance is of the right type. For example:
+ *
+ * <pre>
+ * var fakeSafeHtml = new String('fake');
+ * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
+ * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
+ * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
+ * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml
+ * // instanceof goog.html.SafeHtml.
+ * </pre>
+ *
+ * @see goog.html.SafeStyleSheet#unwrap
+ * @override
+ */
+goog.html.SafeStyleSheet.prototype.getTypedStringValue = function() {
+  return this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_;
+};
+
+
+if (goog.DEBUG) {
+  /**
+   * Returns a debug string-representation of this value.
+   *
+   * To obtain the actual string value wrapped in a SafeStyleSheet, use
+   * {@code goog.html.SafeStyleSheet.unwrap}.
+   *
+   * @see goog.html.SafeStyleSheet#unwrap
+   * @override
+   */
+  goog.html.SafeStyleSheet.prototype.toString = function() {
+    return 'SafeStyleSheet{' +
+        this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ + '}';
+  };
+}
+
+
+/**
+ * Performs a runtime check that the provided object is indeed a
+ * SafeStyleSheet object, and returns its value.
+ *
+ * @param {!goog.html.SafeStyleSheet} safeStyleSheet The object to extract from.
+ * @return {string} The safeStyleSheet object's contained string, unless
+ *     the run-time type check fails. In that case, {@code unwrap} returns an
+ *     innocuous string, or, if assertions are enabled, throws
+ *     {@code goog.asserts.AssertionError}.
+ */
+goog.html.SafeStyleSheet.unwrap = function(safeStyleSheet) {
+  // Perform additional Run-time type-checking to ensure that
+  // safeStyleSheet is indeed an instance of the expected type.  This
+  // provides some additional protection against security bugs due to
+  // application code that disables type checks.
+  // Specifically, the following checks are performed:
+  // 1. The object is an instance of the expected type.
+  // 2. The object is not an instance of a subclass.
+  // 3. The object carries a type marker for the expected type. "Faking" an
+  // object requires a reference to the type marker, which has names intended
+  // to stand out in code reviews.
+  if (safeStyleSheet instanceof goog.html.SafeStyleSheet &&
+      safeStyleSheet.constructor === goog.html.SafeStyleSheet &&
+      safeStyleSheet.SAFE_SCRIPT_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
+          goog.html.SafeStyleSheet.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
+    return safeStyleSheet.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_;
+  } else {
+    goog.asserts.fail(
+        "expected object of type SafeStyleSheet, got '" + safeStyleSheet +
+        "'");
+    return 'type_error:SafeStyleSheet';
+  }
+};
+
+
+/**
+ * Package-internal utility method to create SafeStyleSheet instances.
+ *
+ * @param {string} styleSheet The string to initialize the SafeStyleSheet
+ *     object with.
+ * @return {!goog.html.SafeStyleSheet} The initialized SafeStyleSheet object.
+ * @package
+ */
+goog.html.SafeStyleSheet.createSafeStyleSheetSecurityPrivateDoNotAccessOrElse =
+    function(styleSheet) {
+  return new goog.html.SafeStyleSheet().initSecurityPrivateDoNotAccessOrElse_(
+      styleSheet);
+};
+
+
+/**
+ * Called from createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(). This
+ * method exists only so that the compiler can dead code eliminate static
+ * fields (like EMPTY) when they're not accessed.
+ * @param {string} styleSheet
+ * @return {!goog.html.SafeStyleSheet}
+ * @private
+ */
+goog.html.SafeStyleSheet.prototype.initSecurityPrivateDoNotAccessOrElse_ =
+    function(styleSheet) {
+  this.privateDoNotAccessOrElseSafeStyleSheetWrappedValue_ = styleSheet;
+  return this;
+};
+
+
+/**
+ * A SafeStyleSheet instance corresponding to the empty string.
+ * @const {!goog.html.SafeStyleSheet}
+ */
+goog.html.SafeStyleSheet.EMPTY =
+    goog.html.SafeStyleSheet.
+        createSafeStyleSheetSecurityPrivateDoNotAccessOrElse('');

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/html/safeurl.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/html/safeurl.js b/externs/GCL/externs/goog/html/safeurl.js
new file mode 100644
index 0000000..6d2f871
--- /dev/null
+++ b/externs/GCL/externs/goog/html/safeurl.js
@@ -0,0 +1,431 @@
+// Copyright 2013 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 The SafeUrl type and its builders.
+ *
+ * TODO(user): Link to document stating type contract.
+ */
+
+goog.provide('goog.html.SafeUrl');
+
+goog.require('goog.asserts');
+goog.require('goog.fs.url');
+goog.require('goog.i18n.bidi.Dir');
+goog.require('goog.i18n.bidi.DirectionalString');
+goog.require('goog.string.Const');
+goog.require('goog.string.TypedString');
+
+
+
+/**
+ * A string that is safe to use in URL context in DOM APIs and HTML documents.
+ *
+ * A SafeUrl is a string-like object that carries the security type contract
+ * that its value as a string will not cause untrusted script execution
+ * when evaluated as a hyperlink URL in a browser.
+ *
+ * Values of this type are guaranteed to be safe to use in URL/hyperlink
+ * contexts, such as, assignment to URL-valued DOM properties, or
+ * interpolation into a HTML template in URL context (e.g., inside a href
+ * attribute), in the sense that the use will not result in a
+ * Cross-Site-Scripting vulnerability.
+ *
+ * Note that, as documented in {@code goog.html.SafeUrl.unwrap}, this type's
+ * contract does not guarantee that instances are safe to interpolate into HTML
+ * without appropriate escaping.
+ *
+ * Note also that this type's contract does not imply any guarantees regarding
+ * the resource the URL refers to.  In particular, SafeUrls are <b>not</b>
+ * safe to use in a context where the referred-to resource is interpreted as
+ * trusted code, e.g., as the src of a script tag.
+ *
+ * Instances of this type must be created via the factory methods
+ * ({@code goog.html.SafeUrl.fromConstant}, {@code goog.html.SafeUrl.sanitize}),
+ * etc and not by invoking its constructor.  The constructor intentionally
+ * takes no parameters and the type is immutable; hence only a default instance
+ * corresponding to the empty string can be obtained via constructor invocation.
+ *
+ * @see goog.html.SafeUrl#fromConstant
+ * @see goog.html.SafeUrl#from
+ * @see goog.html.SafeUrl#sanitize
+ * @constructor
+ * @final
+ * @struct
+ * @implements {goog.i18n.bidi.DirectionalString}
+ * @implements {goog.string.TypedString}
+ */
+goog.html.SafeUrl = function() {
+  /**
+   * The contained value of this SafeUrl.  The field has a purposely ugly
+   * name to make (non-compiled) code that attempts to directly access this
+   * field stand out.
+   * @private {string}
+   */
+  this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = '';
+
+  /**
+   * A type marker used to implement additional run-time type checking.
+   * @see goog.html.SafeUrl#unwrap
+   * @const
+   * @private
+   */
+  this.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
+      goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
+};
+
+
+/**
+ * The innocuous string generated by goog.html.SafeUrl.sanitize when passed
+ * an unsafe URL.
+ *
+ * about:invalid is registered in
+ * http://www.w3.org/TR/css3-values/#about-invalid.
+ * http://tools.ietf.org/html/rfc6694#section-2.2.1 permits about URLs to
+ * contain a fragment, which is not to be considered when determining if an
+ * about URL is well-known.
+ *
+ * Using about:invalid seems preferable to using a fixed data URL, since
+ * browsers might choose to not report CSP violations on it, as legitimate
+ * CSS function calls to attr() can result in this URL being produced. It is
+ * also a standard URL which matches exactly the semantics we need:
+ * "The about:invalid URI references a non-existent document with a generic
+ * error condition. It can be used when a URI is necessary, but the default
+ * value shouldn't be resolveable as any type of document".
+ *
+ * @const {string}
+ */
+goog.html.SafeUrl.INNOCUOUS_STRING = 'about:invalid#zClosurez';
+
+
+/**
+ * @override
+ * @const
+ */
+goog.html.SafeUrl.prototype.implementsGoogStringTypedString = true;
+
+
+/**
+ * Returns this SafeUrl's value a string.
+ *
+ * IMPORTANT: In code where it is security relevant that an object's type is
+ * indeed {@code SafeUrl}, use {@code goog.html.SafeUrl.unwrap} instead of this
+ * method. If in doubt, assume that it's security relevant. In particular, note
+ * that goog.html functions which return a goog.html type do not guarantee that
+ * the returned instance is of the right type. For example:
+ *
+ * <pre>
+ * var fakeSafeHtml = new String('fake');
+ * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
+ * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
+ * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
+ * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml instanceof
+ * // goog.html.SafeHtml.
+ * </pre>
+ *
+ * IMPORTANT: The guarantees of the SafeUrl type contract only extend to the
+ * behavior of browsers when interpreting URLs. Values of SafeUrl objects MUST
+ * be appropriately escaped before embedding in a HTML document. Note that the
+ * required escaping is context-sensitive (e.g. a different escaping is
+ * required for embedding a URL in a style property within a style
+ * attribute, as opposed to embedding in a href attribute).
+ *
+ * @see goog.html.SafeUrl#unwrap
+ * @override
+ */
+goog.html.SafeUrl.prototype.getTypedStringValue = function() {
+  return this.privateDoNotAccessOrElseSafeHtmlWrappedValue_;
+};
+
+
+/**
+ * @override
+ * @const
+ */
+goog.html.SafeUrl.prototype.implementsGoogI18nBidiDirectionalString = true;
+
+
+/**
+ * Returns this URLs directionality, which is always {@code LTR}.
+ * @override
+ */
+goog.html.SafeUrl.prototype.getDirection = function() {
+  return goog.i18n.bidi.Dir.LTR;
+};
+
+
+if (goog.DEBUG) {
+  /**
+   * Returns a debug string-representation of this value.
+   *
+   * To obtain the actual string value wrapped in a SafeUrl, use
+   * {@code goog.html.SafeUrl.unwrap}.
+   *
+   * @see goog.html.SafeUrl#unwrap
+   * @override
+   */
+  goog.html.SafeUrl.prototype.toString = function() {
+    return 'SafeUrl{' + this.privateDoNotAccessOrElseSafeHtmlWrappedValue_ +
+        '}';
+  };
+}
+
+
+/**
+ * Performs a runtime check that the provided object is indeed a SafeUrl
+ * object, and returns its value.
+ *
+ * IMPORTANT: The guarantees of the SafeUrl type contract only extend to the
+ * behavior of  browsers when interpreting URLs. Values of SafeUrl objects MUST
+ * be appropriately escaped before embedding in a HTML document. Note that the
+ * required escaping is context-sensitive (e.g. a different escaping is
+ * required for embedding a URL in a style property within a style
+ * attribute, as opposed to embedding in a href attribute).
+ *
+ * Note that the returned value does not necessarily correspond to the string
+ * with which the SafeUrl was constructed, since goog.html.SafeUrl.sanitize
+ * will percent-encode many characters.
+ *
+ * @param {!goog.html.SafeUrl} safeUrl The object to extract from.
+ * @return {string} The SafeUrl object's contained string, unless the run-time
+ *     type check fails. In that case, {@code unwrap} returns an innocuous
+ *     string, or, if assertions are enabled, throws
+ *     {@code goog.asserts.AssertionError}.
+ */
+goog.html.SafeUrl.unwrap = function(safeUrl) {
+  // Perform additional Run-time type-checking to ensure that safeUrl is indeed
+  // an instance of the expected type.  This provides some additional protection
+  // against security bugs due to application code that disables type checks.
+  // Specifically, the following checks are performed:
+  // 1. The object is an instance of the expected type.
+  // 2. The object is not an instance of a subclass.
+  // 3. The object carries a type marker for the expected type. "Faking" an
+  // object requires a reference to the type marker, which has names intended
+  // to stand out in code reviews.
+  if (safeUrl instanceof goog.html.SafeUrl &&
+      safeUrl.constructor === goog.html.SafeUrl &&
+      safeUrl.SAFE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
+          goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
+    return safeUrl.privateDoNotAccessOrElseSafeHtmlWrappedValue_;
+  } else {
+    goog.asserts.fail('expected object of type SafeUrl, got \'' +
+                      safeUrl + '\'');
+    return 'type_error:SafeUrl';
+
+  }
+};
+
+
+/**
+ * Creates a SafeUrl object from a compile-time constant string.
+ *
+ * Compile-time constant strings are inherently program-controlled and hence
+ * trusted.
+ *
+ * @param {!goog.string.Const} url A compile-time-constant string from which to
+ *         create a SafeUrl.
+ * @return {!goog.html.SafeUrl} A SafeUrl object initialized to {@code url}.
+ */
+goog.html.SafeUrl.fromConstant = function(url) {
+  return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(
+      goog.string.Const.unwrap(url));
+};
+
+
+/**
+ * A pattern that matches Blob types that can have SafeUrls created from
+ * URL.createObjectURL(blob). Only matches image types, currently.
+ * @const
+ * @private
+ */
+goog.html.SAFE_BLOB_TYPE_PATTERN_ =
+    /^image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)$/i;
+
+
+/**
+ * Creates a SafeUrl wrapping a blob URL for the given {@code blob}. The
+ * blob URL is created with {@code URL.createObjectURL}. If the MIME type
+ * for {@code blob} is not of a known safe image MIME type, then the
+ * SafeUrl will wrap {@link #INNOCUOUS_STRING}.
+ * @see http://www.w3.org/TR/FileAPI/#url
+ * @param {!Blob} blob
+ * @return {!goog.html.SafeUrl} The blob URL, or an innocuous string wrapped
+ *   as a SafeUrl.
+ */
+goog.html.SafeUrl.fromBlob = function(blob) {
+  var url = goog.html.SAFE_BLOB_TYPE_PATTERN_.test(blob.type) ?
+      goog.fs.url.createObjectUrl(blob) : goog.html.SafeUrl.INNOCUOUS_STRING;
+  return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
+};
+
+
+/**
+ * A pattern that recognizes a commonly useful subset of URLs that satisfy
+ * the SafeUrl contract.
+ *
+ * This regular expression matches a subset of URLs that will not cause script
+ * execution if used in URL context within a HTML document. Specifically, this
+ * regular expression matches if (comment from here on and regex copied from
+ * Soy's EscapingConventions):
+ * (1) Either a protocol in a whitelist (http, https, mailto or ftp).
+ * (2) or no protocol.  A protocol must be followed by a colon. The below
+ *     allows that by allowing colons only after one of the characters [/?#].
+ *     A colon after a hash (#) must be in the fragment.
+ *     Otherwise, a colon after a (?) must be in a query.
+ *     Otherwise, a colon after a single solidus (/) must be in a path.
+ *     Otherwise, a colon after a double solidus (//) must be in the authority
+ *     (before port).
+ *
+ * The pattern disallows &, used in HTML entity declarations before
+ * one of the characters in [/?#]. This disallows HTML entities used in the
+ * protocol name, which should never happen, e.g. "h&#116;tp" for "http".
+ * It also disallows HTML entities in the first path part of a relative path,
+ * e.g. "foo&lt;bar/baz".  Our existing escaping functions should not produce
+ * that. More importantly, it disallows masking of a colon,
+ * e.g. "javascript&#58;...".
+ *
+ * @private
+ * @const {!RegExp}
+ */
+goog.html.SAFE_URL_PATTERN_ =
+    /^(?:(?:https?|mailto|ftp):|[^&:/?#]*(?:[/?#]|$))/i;
+
+
+/**
+ * Creates a SafeUrl object from {@code url}. If {@code url} is a
+ * goog.html.SafeUrl then it is simply returned. Otherwise the input string is
+ * validated to match a pattern of commonly used safe URLs. The string is
+ * converted to UTF-8 and non-whitelisted characters are percent-encoded. The
+ * string wrapped by the created SafeUrl will thus contain only ASCII printable
+ * characters.
+ *
+ * {@code url} may be a URL with the http, https, mailto or ftp scheme,
+ * or a relative URL (i.e., a URL without a scheme; specifically, a
+ * scheme-relative, absolute-path-relative, or path-relative URL).
+ *
+ * {@code url} is converted to UTF-8 and non-whitelisted characters are
+ * percent-encoded. Whitelisted characters are '%' and, from RFC 3986,
+ * unreserved characters and reserved characters, with the exception of '\'',
+ * '(' and ')'. This ensures the the SafeUrl contains only ASCII-printable
+ * characters and reduces the chance of security bugs were it to be
+ * interpolated into a specific context without the necessary escaping.
+ *
+ * If {@code url} fails validation or does not UTF-16 decode correctly
+ * (JavaScript strings are UTF-16 encoded), this function returns a SafeUrl
+ * object containing an innocuous string, goog.html.SafeUrl.INNOCUOUS_STRING.
+ *
+ * @see http://url.spec.whatwg.org/#concept-relative-url
+ * @param {string|!goog.string.TypedString} url The URL to validate.
+ * @return {!goog.html.SafeUrl} The validated URL, wrapped as a SafeUrl.
+ */
+goog.html.SafeUrl.sanitize = function(url) {
+  if (url instanceof goog.html.SafeUrl) {
+    return url;
+  }
+  else if (url.implementsGoogStringTypedString) {
+    url = url.getTypedStringValue();
+  } else {
+    url = String(url);
+  }
+  if (!goog.html.SAFE_URL_PATTERN_.test(url)) {
+    url = goog.html.SafeUrl.INNOCUOUS_STRING;
+  } else {
+    url = goog.html.SafeUrl.normalize_(url);
+  }
+  return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
+};
+
+
+/**
+ * Normalizes {@code url} the UTF-8 encoding of url, using a whitelist of
+ * characters. Whitelisted characters are not percent-encoded.
+ * @param {string} url The URL to normalize.
+ * @return {string} The normalized URL.
+ * @private
+ */
+goog.html.SafeUrl.normalize_ = function(url) {
+  try {
+    var normalized = encodeURI(url);
+  } catch (e) {  // Happens if url contains invalid surrogate sequences.
+    return goog.html.SafeUrl.INNOCUOUS_STRING;
+  }
+
+  return normalized.replace(
+      goog.html.SafeUrl.NORMALIZE_MATCHER_,
+      function(match) {
+        return goog.html.SafeUrl.NORMALIZE_REPLACER_MAP_[match];
+      });
+};
+
+
+/**
+ * Matches characters and strings which need to be replaced in the string
+ * generated by encodeURI. Specifically:
+ *
+ * - '\'', '(' and ')' are not encoded. They are part of the reserved
+ *   characters group in RFC 3986 but only appear in the obsolete mark
+ *   production in Appendix D.2 of RFC 3986, so they can be encoded without
+ *   changing semantics.
+ * - '[' and ']' are encoded by encodeURI, despite being reserved characters
+ *   which can be used to represent IPv6 addresses. So they need to be decoded.
+ * - '%' is encoded by encodeURI. However, encoding '%' characters that are
+ *   already part of a valid percent-encoded sequence changes the semantics of a
+ *   URL, and hence we need to preserve them. Note that this may allow
+ *   non-encoded '%' characters to remain in the URL (i.e., occurrences of '%'
+ *   that are not part of a valid percent-encoded sequence, for example,
+ *   'ab%xy').
+ *
+ * @const {!RegExp}
+ * @private
+ */
+goog.html.SafeUrl.NORMALIZE_MATCHER_ = /[()']|%5B|%5D|%25/g;
+
+
+/**
+ * Map of replacements to be done in string generated by encodeURI.
+ * @const {!Object<string, string>}
+ * @private
+ */
+goog.html.SafeUrl.NORMALIZE_REPLACER_MAP_ = {
+  '\'': '%27',
+  '(': '%28',
+  ')': '%29',
+  '%5B': '[',
+  '%5D': ']',
+  '%25': '%'
+};
+
+
+/**
+ * Type marker for the SafeUrl type, used to implement additional run-time
+ * type checking.
+ * @const
+ * @private
+ */
+goog.html.SafeUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
+
+
+/**
+ * Package-internal utility method to create SafeUrl instances.
+ *
+ * @param {string} url The string to initialize the SafeUrl object with.
+ * @return {!goog.html.SafeUrl} The initialized SafeUrl object.
+ * @package
+ */
+goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse = function(
+    url) {
+  var safeUrl = new goog.html.SafeUrl();
+  safeUrl.privateDoNotAccessOrElseSafeHtmlWrappedValue_ = url;
+  return safeUrl;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/html/silverlight.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/html/silverlight.js b/externs/GCL/externs/goog/html/silverlight.js
new file mode 100644
index 0000000..6aed4e2
--- /dev/null
+++ b/externs/GCL/externs/goog/html/silverlight.js
@@ -0,0 +1,92 @@
+// Copyright 2014 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 SafeHtml factory methods for creating object tags for
+ * loading Silverlight files.
+ */
+
+goog.provide('goog.html.silverlight');
+
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.TrustedResourceUrl');
+goog.require('goog.html.flash');
+goog.require('goog.string.Const');
+
+
+/**
+ * Attributes and param tag name attributes not allowed to be overriden
+ * when calling createObjectForSilverlight().
+ *
+ * While values that should be specified as params are probably not
+ * recognized as attributes, we block them anyway just to be sure.
+ * @const {!Array<string>}
+ * @private
+ */
+goog.html.silverlight.FORBIDDEN_ATTRS_AND_PARAMS_ON_SILVERLIGHT_ = [
+  'data',  // Always set to a fixed value.
+  'source',  // Specifies the URL for the Silverlight file.
+  'type',  // Always set to a fixed value.
+  'typemustmatch'  // Always set to a fixed value.
+];
+
+
+/**
+ * Creates a SafeHtml representing an object tag, for loading Silverlight files.
+ *
+ * The following attributes are set to these fixed values:
+ * - data: data:application/x-silverlight-2,
+ * - type: application/x-silverlight-2
+ * - typemustmatch: "" (the empty string, meaning true for a boolean attribute)
+ *
+ * @param {!goog.html.TrustedResourceUrl} source The value of the source param.
+ * @param {!Object<string, string>=} opt_params Mapping used to generate child
+ *     param tags. Each tag has a name and value attribute, as defined in
+ *     mapping. Only names consisting of [a-zA-Z0-9-] are allowed. Value of
+ *     null or undefined causes the param tag to be omitted.
+ * @param {!Object<string, goog.html.SafeHtml.AttributeValue_>=}
+ *     opt_attributes Mapping from other attribute names to their values. Only
+ *     attribute names consisting of [a-zA-Z0-9-] are allowed. Value of null or
+ *     undefined causes the attribute to be omitted.
+ * @return {!goog.html.SafeHtml} The SafeHtml content with the object tag.
+ * @throws {Error} If invalid attribute or param name, or attribute or param
+ *     value is provided. Also if opt_attributes or opt_params contains any of
+ *     the attributes set to fixed values, documented above, or contains source.
+ *
+ */
+goog.html.silverlight.createObject = function(
+    source, opt_params, opt_attributes) {
+  goog.html.flash.verifyKeysNotInMaps(
+      goog.html.silverlight.FORBIDDEN_ATTRS_AND_PARAMS_ON_SILVERLIGHT_,
+      opt_attributes,
+      opt_params);
+
+  // We don't set default for Silverlight's EnableHtmlAccess and
+  // AllowHtmlPopupwindow because their default changes depending on whether
+  // a file loaded from the same domain.
+  var paramTags = goog.html.flash.combineParams(
+      {'source': source}, opt_params);
+  var fixedAttributes = {
+    'data': goog.html.TrustedResourceUrl.fromConstant(
+        goog.string.Const.from('data:application/x-silverlight-2,')),
+    'type': 'application/x-silverlight-2',
+    'typemustmatch': ''
+  };
+  var attributes = goog.html.SafeHtml.combineAttributes(
+      fixedAttributes, {}, opt_attributes);
+
+  return goog.html.SafeHtml.createSafeHtmlTagSecurityPrivateDoNotAccessOrElse(
+      'object', attributes, paramTags);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/html/trustedresourceurl.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/html/trustedresourceurl.js b/externs/GCL/externs/goog/html/trustedresourceurl.js
new file mode 100644
index 0000000..e7c7bf5
--- /dev/null
+++ b/externs/GCL/externs/goog/html/trustedresourceurl.js
@@ -0,0 +1,224 @@
+// Copyright 2013 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 The TrustedResourceUrl type and its builders.
+ *
+ * TODO(user): Link to document stating type contract.
+ */
+
+goog.provide('goog.html.TrustedResourceUrl');
+
+goog.require('goog.asserts');
+goog.require('goog.i18n.bidi.Dir');
+goog.require('goog.i18n.bidi.DirectionalString');
+goog.require('goog.string.Const');
+goog.require('goog.string.TypedString');
+
+
+
+/**
+ * A URL which is under application control and from which script, CSS, and
+ * other resources that represent executable code, can be fetched.
+ *
+ * Given that the URL can only be constructed from strings under application
+ * control and is used to load resources, bugs resulting in a malformed URL
+ * should not have a security impact and are likely to be easily detectable
+ * during testing. Given the wide number of non-RFC compliant URLs in use,
+ * stricter validation could prevent some applications from being able to use
+ * this type.
+ *
+ * Instances of this type must be created via the factory method,
+ * ({@code goog.html.TrustedResourceUrl.fromConstant}), and not by invoking its
+ * constructor. The constructor intentionally takes no parameters and the type
+ * is immutable; hence only a default instance corresponding to the empty
+ * string can be obtained via constructor invocation.
+ *
+ * @see goog.html.TrustedResourceUrl#fromConstant
+ * @constructor
+ * @final
+ * @struct
+ * @implements {goog.i18n.bidi.DirectionalString}
+ * @implements {goog.string.TypedString}
+ */
+goog.html.TrustedResourceUrl = function() {
+  /**
+   * The contained value of this TrustedResourceUrl.  The field has a purposely
+   * ugly name to make (non-compiled) code that attempts to directly access this
+   * field stand out.
+   * @private {string}
+   */
+  this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ = '';
+
+  /**
+   * A type marker used to implement additional run-time type checking.
+   * @see goog.html.TrustedResourceUrl#unwrap
+   * @const
+   * @private
+   */
+  this.TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ =
+      goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_;
+};
+
+
+/**
+ * @override
+ * @const
+ */
+goog.html.TrustedResourceUrl.prototype.implementsGoogStringTypedString = true;
+
+
+/**
+ * Returns this TrustedResourceUrl's value as a string.
+ *
+ * IMPORTANT: In code where it is security relevant that an object's type is
+ * indeed {@code TrustedResourceUrl}, use
+ * {@code goog.html.TrustedResourceUrl.unwrap} instead of this method. If in
+ * doubt, assume that it's security relevant. In particular, note that
+ * goog.html functions which return a goog.html type do not guarantee that
+ * the returned instance is of the right type. For example:
+ *
+ * <pre>
+ * var fakeSafeHtml = new String('fake');
+ * fakeSafeHtml.__proto__ = goog.html.SafeHtml.prototype;
+ * var newSafeHtml = goog.html.SafeHtml.htmlEscape(fakeSafeHtml);
+ * // newSafeHtml is just an alias for fakeSafeHtml, it's passed through by
+ * // goog.html.SafeHtml.htmlEscape() as fakeSafeHtml instanceof
+ * // goog.html.SafeHtml.
+ * </pre>
+ *
+ * @see goog.html.TrustedResourceUrl#unwrap
+ * @override
+ */
+goog.html.TrustedResourceUrl.prototype.getTypedStringValue = function() {
+  return this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_;
+};
+
+
+/**
+ * @override
+ * @const
+ */
+goog.html.TrustedResourceUrl.prototype.implementsGoogI18nBidiDirectionalString =
+    true;
+
+
+/**
+ * Returns this URLs directionality, which is always {@code LTR}.
+ * @override
+ */
+goog.html.TrustedResourceUrl.prototype.getDirection = function() {
+  return goog.i18n.bidi.Dir.LTR;
+};
+
+
+if (goog.DEBUG) {
+  /**
+   * Returns a debug string-representation of this value.
+   *
+   * To obtain the actual string value wrapped in a TrustedResourceUrl, use
+   * {@code goog.html.TrustedResourceUrl.unwrap}.
+   *
+   * @see goog.html.TrustedResourceUrl#unwrap
+   * @override
+   */
+  goog.html.TrustedResourceUrl.prototype.toString = function() {
+    return 'TrustedResourceUrl{' +
+        this.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ + '}';
+  };
+}
+
+
+/**
+ * Performs a runtime check that the provided object is indeed a
+ * TrustedResourceUrl object, and returns its value.
+ *
+ * @param {!goog.html.TrustedResourceUrl} trustedResourceUrl The object to
+ *     extract from.
+ * @return {string} The trustedResourceUrl object's contained string, unless
+ *     the run-time type check fails. In that case, {@code unwrap} returns an
+ *     innocuous string, or, if assertions are enabled, throws
+ *     {@code goog.asserts.AssertionError}.
+ */
+goog.html.TrustedResourceUrl.unwrap = function(trustedResourceUrl) {
+  // Perform additional Run-time type-checking to ensure that
+  // trustedResourceUrl is indeed an instance of the expected type.  This
+  // provides some additional protection against security bugs due to
+  // application code that disables type checks.
+  // Specifically, the following checks are performed:
+  // 1. The object is an instance of the expected type.
+  // 2. The object is not an instance of a subclass.
+  // 3. The object carries a type marker for the expected type. "Faking" an
+  // object requires a reference to the type marker, which has names intended
+  // to stand out in code reviews.
+  if (trustedResourceUrl instanceof goog.html.TrustedResourceUrl &&
+      trustedResourceUrl.constructor === goog.html.TrustedResourceUrl &&
+      trustedResourceUrl
+          .TRUSTED_RESOURCE_URL_TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ ===
+              goog.html.TrustedResourceUrl
+                  .TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_) {
+    return trustedResourceUrl
+        .privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_;
+  } else {
+    goog.asserts.fail('expected object of type TrustedResourceUrl, got \'' +
+                      trustedResourceUrl + '\'');
+    return 'type_error:TrustedResourceUrl';
+
+  }
+};
+
+
+/**
+ * Creates a TrustedResourceUrl object from a compile-time constant string.
+ *
+ * Compile-time constant strings are inherently program-controlled and hence
+ * trusted.
+ *
+ * @param {!goog.string.Const} url A compile-time-constant string from which to
+ *     create a TrustedResourceUrl.
+ * @return {!goog.html.TrustedResourceUrl} A TrustedResourceUrl object
+ *     initialized to {@code url}.
+ */
+goog.html.TrustedResourceUrl.fromConstant = function(url) {
+  return goog.html.TrustedResourceUrl
+      .createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(
+          goog.string.Const.unwrap(url));
+};
+
+
+/**
+ * Type marker for the TrustedResourceUrl type, used to implement additional
+ * run-time type checking.
+ * @const
+ * @private
+ */
+goog.html.TrustedResourceUrl.TYPE_MARKER_GOOG_HTML_SECURITY_PRIVATE_ = {};
+
+
+/**
+ * Package-internal utility method to create TrustedResourceUrl instances.
+ *
+ * @param {string} url The string to initialize the TrustedResourceUrl object
+ *     with.
+ * @return {!goog.html.TrustedResourceUrl} The initialized TrustedResourceUrl
+ *     object.
+ * @package
+ */
+goog.html.TrustedResourceUrl.
+    createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse = function(url) {
+  var trustedResourceUrl = new goog.html.TrustedResourceUrl();
+  trustedResourceUrl.privateDoNotAccessOrElseTrustedResourceUrlWrappedValue_ =
+      url;
+  return trustedResourceUrl;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/html/uncheckedconversions.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/html/uncheckedconversions.js b/externs/GCL/externs/goog/html/uncheckedconversions.js
new file mode 100644
index 0000000..a1a5a9a
--- /dev/null
+++ b/externs/GCL/externs/goog/html/uncheckedconversions.js
@@ -0,0 +1,231 @@
+// Copyright 2013 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 Unchecked conversions to create values of goog.html types from
+ * plain strings.  Use of these functions could potentially result in instances
+ * of goog.html types that violate their type contracts, and hence result in
+ * security vulnerabilties.
+ *
+ * Therefore, all uses of the methods herein must be carefully security
+ * reviewed.  Avoid use of the methods in this file whenever possible; instead
+ * prefer to create instances of goog.html types using inherently safe builders
+ * or template systems.
+ *
+ *
+ * @visibility {//closure/goog/html:approved_for_unchecked_conversion}
+ * @visibility {//closure/goog/bin/sizetests:__pkg__}
+ */
+
+
+goog.provide('goog.html.uncheckedconversions');
+
+goog.require('goog.asserts');
+goog.require('goog.html.SafeHtml');
+goog.require('goog.html.SafeScript');
+goog.require('goog.html.SafeStyle');
+goog.require('goog.html.SafeStyleSheet');
+goog.require('goog.html.SafeUrl');
+goog.require('goog.html.TrustedResourceUrl');
+goog.require('goog.string');
+goog.require('goog.string.Const');
+
+
+/**
+ * Performs an "unchecked conversion" to SafeHtml from a plain string that is
+ * known to satisfy the SafeHtml type contract.
+ *
+ * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
+ * that the value of {@code html} satisfies the SafeHtml type contract in all
+ * possible program states.
+ *
+ *
+ * @param {!goog.string.Const} justification A constant string explaining why
+ *     this use of this method is safe. May include a security review ticket
+ *     number.
+ * @param {string} html A string that is claimed to adhere to the SafeHtml
+ *     contract.
+ * @param {?goog.i18n.bidi.Dir=} opt_dir The optional directionality of the
+ *     SafeHtml to be constructed. A null or undefined value signifies an
+ *     unknown directionality.
+ * @return {!goog.html.SafeHtml} The value of html, wrapped in a SafeHtml
+ *     object.
+ * @suppress {visibility} For access to SafeHtml.create...  Note that this
+ *     use is appropriate since this method is intended to be "package private"
+ *     withing goog.html.  DO NOT call SafeHtml.create... from outside this
+ *     package; use appropriate wrappers instead.
+ */
+goog.html.uncheckedconversions.safeHtmlFromStringKnownToSatisfyTypeContract =
+    function(justification, html, opt_dir) {
+  // unwrap() called inside an assert so that justification can be optimized
+  // away in production code.
+  goog.asserts.assertString(goog.string.Const.unwrap(justification),
+                            'must provide justification');
+  goog.asserts.assert(
+      !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)),
+      'must provide non-empty justification');
+  return goog.html.SafeHtml.createSafeHtmlSecurityPrivateDoNotAccessOrElse(
+      html, opt_dir || null);
+};
+
+
+/**
+ * Performs an "unchecked conversion" to SafeScript from a plain string that is
+ * known to satisfy the SafeScript type contract.
+ *
+ * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
+ * that the value of {@code script} satisfies the SafeScript type contract in
+ * all possible program states.
+ *
+ *
+ * @param {!goog.string.Const} justification A constant string explaining why
+ *     this use of this method is safe. May include a security review ticket
+ *     number.
+ * @param {string} script The string to wrap as a SafeScript.
+ * @return {!goog.html.SafeScript} The value of {@code script}, wrapped in a
+ *     SafeScript object.
+ */
+goog.html.uncheckedconversions.safeScriptFromStringKnownToSatisfyTypeContract =
+    function(justification, script) {
+  // unwrap() called inside an assert so that justification can be optimized
+  // away in production code.
+  goog.asserts.assertString(goog.string.Const.unwrap(justification),
+                            'must provide justification');
+  goog.asserts.assert(
+      !goog.string.isEmpty(goog.string.Const.unwrap(justification)),
+      'must provide non-empty justification');
+  return goog.html.SafeScript.createSafeScriptSecurityPrivateDoNotAccessOrElse(
+      script);
+};
+
+
+/**
+ * Performs an "unchecked conversion" to SafeStyle from a plain string that is
+ * known to satisfy the SafeStyle type contract.
+ *
+ * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
+ * that the value of {@code style} satisfies the SafeUrl type contract in all
+ * possible program states.
+ *
+ *
+ * @param {!goog.string.Const} justification A constant string explaining why
+ *     this use of this method is safe. May include a security review ticket
+ *     number.
+ * @param {string} style The string to wrap as a SafeStyle.
+ * @return {!goog.html.SafeStyle} The value of {@code style}, wrapped in a
+ *     SafeStyle object.
+ */
+goog.html.uncheckedconversions.safeStyleFromStringKnownToSatisfyTypeContract =
+    function(justification, style) {
+  // unwrap() called inside an assert so that justification can be optimized
+  // away in production code.
+  goog.asserts.assertString(goog.string.Const.unwrap(justification),
+                            'must provide justification');
+  goog.asserts.assert(
+      !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)),
+      'must provide non-empty justification');
+  return goog.html.SafeStyle.createSafeStyleSecurityPrivateDoNotAccessOrElse(
+      style);
+};
+
+
+/**
+ * Performs an "unchecked conversion" to SafeStyleSheet from a plain string
+ * that is known to satisfy the SafeStyleSheet type contract.
+ *
+ * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
+ * that the value of {@code styleSheet} satisfies the SafeUrl type contract in
+ * all possible program states.
+ *
+ *
+ * @param {!goog.string.Const} justification A constant string explaining why
+ *     this use of this method is safe. May include a security review ticket
+ *     number.
+ * @param {string} styleSheet The string to wrap as a SafeStyleSheet.
+ * @return {!goog.html.SafeStyleSheet} The value of {@code styleSheet}, wrapped
+ *     in a SafeStyleSheet object.
+ */
+goog.html.uncheckedconversions.
+    safeStyleSheetFromStringKnownToSatisfyTypeContract =
+    function(justification, styleSheet) {
+  // unwrap() called inside an assert so that justification can be optimized
+  // away in production code.
+  goog.asserts.assertString(goog.string.Const.unwrap(justification),
+                            'must provide justification');
+  goog.asserts.assert(
+      !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)),
+      'must provide non-empty justification');
+  return goog.html.SafeStyleSheet.
+      createSafeStyleSheetSecurityPrivateDoNotAccessOrElse(styleSheet);
+};
+
+
+/**
+ * Performs an "unchecked conversion" to SafeUrl from a plain string that is
+ * known to satisfy the SafeUrl type contract.
+ *
+ * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
+ * that the value of {@code url} satisfies the SafeUrl type contract in all
+ * possible program states.
+ *
+ *
+ * @param {!goog.string.Const} justification A constant string explaining why
+ *     this use of this method is safe. May include a security review ticket
+ *     number.
+ * @param {string} url The string to wrap as a SafeUrl.
+ * @return {!goog.html.SafeUrl} The value of {@code url}, wrapped in a SafeUrl
+ *     object.
+ */
+goog.html.uncheckedconversions.safeUrlFromStringKnownToSatisfyTypeContract =
+    function(justification, url) {
+  // unwrap() called inside an assert so that justification can be optimized
+  // away in production code.
+  goog.asserts.assertString(goog.string.Const.unwrap(justification),
+                            'must provide justification');
+  goog.asserts.assert(
+      !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)),
+      'must provide non-empty justification');
+  return goog.html.SafeUrl.createSafeUrlSecurityPrivateDoNotAccessOrElse(url);
+};
+
+
+/**
+ * Performs an "unchecked conversion" to TrustedResourceUrl from a plain string
+ * that is known to satisfy the TrustedResourceUrl type contract.
+ *
+ * IMPORTANT: Uses of this method must be carefully security-reviewed to ensure
+ * that the value of {@code url} satisfies the TrustedResourceUrl type contract
+ * in all possible program states.
+ *
+ *
+ * @param {!goog.string.Const} justification A constant string explaining why
+ *     this use of this method is safe. May include a security review ticket
+ *     number.
+ * @param {string} url The string to wrap as a TrustedResourceUrl.
+ * @return {!goog.html.TrustedResourceUrl} The value of {@code url}, wrapped in
+ *     a TrustedResourceUrl object.
+ */
+goog.html.uncheckedconversions.
+    trustedResourceUrlFromStringKnownToSatisfyTypeContract =
+    function(justification, url) {
+  // unwrap() called inside an assert so that justification can be optimized
+  // away in production code.
+  goog.asserts.assertString(goog.string.Const.unwrap(justification),
+                            'must provide justification');
+  goog.asserts.assert(
+      !goog.string.isEmptyOrWhitespace(goog.string.Const.unwrap(justification)),
+      'must provide non-empty justification');
+  return goog.html.TrustedResourceUrl.
+      createTrustedResourceUrlSecurityPrivateDoNotAccessOrElse(url);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/html/utils.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/html/utils.js b/externs/GCL/externs/goog/html/utils.js
new file mode 100644
index 0000000..c54381b
--- /dev/null
+++ b/externs/GCL/externs/goog/html/utils.js
@@ -0,0 +1,67 @@
+// Copyright 2013 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 HTML processing utilities for HTML in string form.
+ */
+
+goog.provide('goog.html.utils');
+
+goog.require('goog.string');
+
+
+/**
+ * Extracts plain text from HTML.
+ *
+ * This behaves similarly to extracting textContent from a hypothetical DOM
+ * element containing the specified HTML.  Block-level elements such as div are
+ * surrounded with whitespace, but inline elements are not.  Span is treated as
+ * a block level element because it is often used as a container.  Breaking
+ * spaces are compressed and trimmed.
+ *
+ * @param {string} value The input HTML to have tags removed.
+ * @return {string} The plain text of value without tags, HTML comments, or
+ *     other non-text content.  Does NOT return safe HTML!
+ */
+goog.html.utils.stripHtmlTags = function(value) {
+  // TODO(user): Make a version that extracts text attributes such as alt.
+  return goog.string.unescapeEntities(goog.string.trim(value.replace(
+      goog.html.utils.HTML_TAG_REGEX_, function(fullMatch, tagName) {
+        return goog.html.utils.INLINE_HTML_TAG_REGEX_.test(tagName) ? '' : ' ';
+      }).
+      replace(/[\t\n ]+/g, ' ')));
+};
+
+
+/**
+ * Matches all tags that do not require extra space.
+ *
+ * @const
+ * @private {RegExp}
+ */
+goog.html.utils.INLINE_HTML_TAG_REGEX_ =
+    /^(?:abbr|acronym|address|b|em|i|small|strong|su[bp]|u)$/i;
+
+
+/**
+ * Matches all tags, HTML comments, and DOCTYPEs in tag soup HTML.
+ * By removing these, and replacing any '<' or '>' characters with
+ * entities we guarantee that the result can be embedded into
+ * an attribute without introducing a tag boundary.
+ *
+ * @private {RegExp}
+ * @const
+ */
+goog.html.utils.HTML_TAG_REGEX_ = /<[!\/]?([a-z0-9]+)([\/ ][^>]*)?>/gi;

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/i18n/bidi.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/i18n/bidi.js b/externs/GCL/externs/goog/i18n/bidi.js
new file mode 100644
index 0000000..0f85cc2
--- /dev/null
+++ b/externs/GCL/externs/goog/i18n/bidi.js
@@ -0,0 +1,897 @@
+// 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 Utility functions for supporting Bidi issues.
+ */
+
+
+/**
+ * Namespace for bidi supporting functions.
+ */
+goog.provide('goog.i18n.bidi');
+goog.provide('goog.i18n.bidi.Dir');
+goog.provide('goog.i18n.bidi.DirectionalString');
+goog.provide('goog.i18n.bidi.Format');
+
+
+/**
+ * @define {boolean} FORCE_RTL forces the {@link goog.i18n.bidi.IS_RTL} constant
+ * to say that the current locale is a RTL locale.  This should only be used
+ * if you want to override the default behavior for deciding whether the
+ * current locale is RTL or not.
+ *
+ * {@see goog.i18n.bidi.IS_RTL}
+ */
+goog.define('goog.i18n.bidi.FORCE_RTL', false);
+
+
+/**
+ * Constant that defines whether or not the current locale is a RTL locale.
+ * If {@link goog.i18n.bidi.FORCE_RTL} is not true, this constant will default
+ * to check that {@link goog.LOCALE} is one of a few major RTL locales.
+ *
+ * <p>This is designed to be a maximally efficient compile-time constant. For
+ * example, for the default goog.LOCALE, compiling
+ * "if (goog.i18n.bidi.IS_RTL) alert('rtl') else {}" should produce no code. It
+ * is this design consideration that limits the implementation to only
+ * supporting a few major RTL locales, as opposed to the broader repertoire of
+ * something like goog.i18n.bidi.isRtlLanguage.
+ *
+ * <p>Since this constant refers to the directionality of the locale, it is up
+ * to the caller to determine if this constant should also be used for the
+ * direction of the UI.
+ *
+ * {@see goog.LOCALE}
+ *
+ * @type {boolean}
+ *
+ * TODO(user): write a test that checks that this is a compile-time constant.
+ */
+goog.i18n.bidi.IS_RTL = goog.i18n.bidi.FORCE_RTL ||
+    (
+        (goog.LOCALE.substring(0, 2).toLowerCase() == 'ar' ||
+         goog.LOCALE.substring(0, 2).toLowerCase() == 'fa' ||
+         goog.LOCALE.substring(0, 2).toLowerCase() == 'he' ||
+         goog.LOCALE.substring(0, 2).toLowerCase() == 'iw' ||
+         goog.LOCALE.substring(0, 2).toLowerCase() == 'ps' ||
+         goog.LOCALE.substring(0, 2).toLowerCase() == 'sd' ||
+         goog.LOCALE.substring(0, 2).toLowerCase() == 'ug' ||
+         goog.LOCALE.substring(0, 2).toLowerCase() == 'ur' ||
+         goog.LOCALE.substring(0, 2).toLowerCase() == 'yi') &&
+        (goog.LOCALE.length == 2 ||
+         goog.LOCALE.substring(2, 3) == '-' ||
+         goog.LOCALE.substring(2, 3) == '_')
+    ) || (
+        goog.LOCALE.length >= 3 &&
+        goog.LOCALE.substring(0, 3).toLowerCase() == 'ckb' &&
+        (goog.LOCALE.length == 3 ||
+         goog.LOCALE.substring(3, 4) == '-' ||
+         goog.LOCALE.substring(3, 4) == '_')
+    );
+
+
+/**
+ * Unicode formatting characters and directionality string constants.
+ * @enum {string}
+ */
+goog.i18n.bidi.Format = {
+  /** Unicode "Left-To-Right Embedding" (LRE) character. */
+  LRE: '\u202A',
+  /** Unicode "Right-To-Left Embedding" (RLE) character. */
+  RLE: '\u202B',
+  /** Unicode "Pop Directional Formatting" (PDF) character. */
+  PDF: '\u202C',
+  /** Unicode "Left-To-Right Mark" (LRM) character. */
+  LRM: '\u200E',
+  /** Unicode "Right-To-Left Mark" (RLM) character. */
+  RLM: '\u200F'
+};
+
+
+/**
+ * Directionality enum.
+ * @enum {number}
+ */
+goog.i18n.bidi.Dir = {
+  /**
+   * Left-to-right.
+   */
+  LTR: 1,
+
+  /**
+   * Right-to-left.
+   */
+  RTL: -1,
+
+  /**
+   * Neither left-to-right nor right-to-left.
+   */
+  NEUTRAL: 0
+};
+
+
+/**
+ * 'right' string constant.
+ * @type {string}
+ */
+goog.i18n.bidi.RIGHT = 'right';
+
+
+/**
+ * 'left' string constant.
+ * @type {string}
+ */
+goog.i18n.bidi.LEFT = 'left';
+
+
+/**
+ * 'left' if locale is RTL, 'right' if not.
+ * @type {string}
+ */
+goog.i18n.bidi.I18N_RIGHT = goog.i18n.bidi.IS_RTL ? goog.i18n.bidi.LEFT :
+    goog.i18n.bidi.RIGHT;
+
+
+/**
+ * 'right' if locale is RTL, 'left' if not.
+ * @type {string}
+ */
+goog.i18n.bidi.I18N_LEFT = goog.i18n.bidi.IS_RTL ? goog.i18n.bidi.RIGHT :
+    goog.i18n.bidi.LEFT;
+
+
+/**
+ * Convert a directionality given in various formats to a goog.i18n.bidi.Dir
+ * constant. Useful for interaction with different standards of directionality
+ * representation.
+ *
+ * @param {goog.i18n.bidi.Dir|number|boolean|null} givenDir Directionality given
+ *     in one of the following formats:
+ *     1. A goog.i18n.bidi.Dir constant.
+ *     2. A number (positive = LTR, negative = RTL, 0 = neutral).
+ *     3. A boolean (true = RTL, false = LTR).
+ *     4. A null for unknown directionality.
+ * @param {boolean=} opt_noNeutral Whether a givenDir of zero or
+ *     goog.i18n.bidi.Dir.NEUTRAL should be treated as null, i.e. unknown, in
+ *     order to preserve legacy behavior.
+ * @return {?goog.i18n.bidi.Dir} A goog.i18n.bidi.Dir constant matching the
+ *     given directionality. If given null, returns null (i.e. unknown).
+ */
+goog.i18n.bidi.toDir = function(givenDir, opt_noNeutral) {
+  if (typeof givenDir == 'number') {
+    // This includes the non-null goog.i18n.bidi.Dir case.
+    return givenDir > 0 ? goog.i18n.bidi.Dir.LTR :
+        givenDir < 0 ? goog.i18n.bidi.Dir.RTL :
+        opt_noNeutral ? null : goog.i18n.bidi.Dir.NEUTRAL;
+  } else if (givenDir == null) {
+    return null;
+  } else {
+    // Must be typeof givenDir == 'boolean'.
+    return givenDir ? goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR;
+  }
+};
+
+
+/**
+ * A practical pattern to identify strong LTR characters. This pattern is not
+ * theoretically correct according to the Unicode standard. It is simplified for
+ * performance and small code size.
+ * @type {string}
+ * @private
+ */
+goog.i18n.bidi.ltrChars_ =
+    'A-Za-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF' +
+    '\u200E\u2C00-\uFB1C\uFE00-\uFE6F\uFEFD-\uFFFF';
+
+
+/**
+ * A practical pattern to identify strong RTL character. This pattern is not
+ * theoretically correct according to the Unicode standard. It is simplified
+ * for performance and small code size.
+ * @type {string}
+ * @private
+ */
+goog.i18n.bidi.rtlChars_ = '\u0591-\u07FF\u200F\uFB1D-\uFDFF\uFE70-\uFEFC';
+
+
+/**
+ * Simplified regular expression for an HTML tag (opening or closing) or an HTML
+ * escape. We might want to skip over such expressions when estimating the text
+ * directionality.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.htmlSkipReg_ = /<[^>]*>|&[^;]+;/g;
+
+
+/**
+ * Returns the input text with spaces instead of HTML tags or HTML escapes, if
+ * opt_isStripNeeded is true. Else returns the input as is.
+ * Useful for text directionality estimation.
+ * Note: the function should not be used in other contexts; it is not 100%
+ * correct, but rather a good-enough implementation for directionality
+ * estimation purposes.
+ * @param {string} str The given string.
+ * @param {boolean=} opt_isStripNeeded Whether to perform the stripping.
+ *     Default: false (to retain consistency with calling functions).
+ * @return {string} The given string cleaned of HTML tags / escapes.
+ * @private
+ */
+goog.i18n.bidi.stripHtmlIfNeeded_ = function(str, opt_isStripNeeded) {
+  return opt_isStripNeeded ? str.replace(goog.i18n.bidi.htmlSkipReg_, '') :
+      str;
+};
+
+
+/**
+ * Regular expression to check for RTL characters.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.rtlCharReg_ = new RegExp('[' + goog.i18n.bidi.rtlChars_ + ']');
+
+
+/**
+ * Regular expression to check for LTR characters.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.ltrCharReg_ = new RegExp('[' + goog.i18n.bidi.ltrChars_ + ']');
+
+
+/**
+ * Test whether the given string has any RTL characters in it.
+ * @param {string} str The given string that need to be tested.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {boolean} Whether the string contains RTL characters.
+ */
+goog.i18n.bidi.hasAnyRtl = function(str, opt_isHtml) {
+  return goog.i18n.bidi.rtlCharReg_.test(goog.i18n.bidi.stripHtmlIfNeeded_(
+      str, opt_isHtml));
+};
+
+
+/**
+ * Test whether the given string has any RTL characters in it.
+ * @param {string} str The given string that need to be tested.
+ * @return {boolean} Whether the string contains RTL characters.
+ * @deprecated Use hasAnyRtl.
+ */
+goog.i18n.bidi.hasRtlChar = goog.i18n.bidi.hasAnyRtl;
+
+
+/**
+ * Test whether the given string has any LTR characters in it.
+ * @param {string} str The given string that need to be tested.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {boolean} Whether the string contains LTR characters.
+ */
+goog.i18n.bidi.hasAnyLtr = function(str, opt_isHtml) {
+  return goog.i18n.bidi.ltrCharReg_.test(goog.i18n.bidi.stripHtmlIfNeeded_(
+      str, opt_isHtml));
+};
+
+
+/**
+ * Regular expression pattern to check if the first character in the string
+ * is LTR.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.ltrRe_ = new RegExp('^[' + goog.i18n.bidi.ltrChars_ + ']');
+
+
+/**
+ * Regular expression pattern to check if the first character in the string
+ * is RTL.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.rtlRe_ = new RegExp('^[' + goog.i18n.bidi.rtlChars_ + ']');
+
+
+/**
+ * Check if the first character in the string is RTL or not.
+ * @param {string} str The given string that need to be tested.
+ * @return {boolean} Whether the first character in str is an RTL char.
+ */
+goog.i18n.bidi.isRtlChar = function(str) {
+  return goog.i18n.bidi.rtlRe_.test(str);
+};
+
+
+/**
+ * Check if the first character in the string is LTR or not.
+ * @param {string} str The given string that need to be tested.
+ * @return {boolean} Whether the first character in str is an LTR char.
+ */
+goog.i18n.bidi.isLtrChar = function(str) {
+  return goog.i18n.bidi.ltrRe_.test(str);
+};
+
+
+/**
+ * Check if the first character in the string is neutral or not.
+ * @param {string} str The given string that need to be tested.
+ * @return {boolean} Whether the first character in str is a neutral char.
+ */
+goog.i18n.bidi.isNeutralChar = function(str) {
+  return !goog.i18n.bidi.isLtrChar(str) && !goog.i18n.bidi.isRtlChar(str);
+};
+
+
+/**
+ * Regular expressions to check if a piece of text is of LTR directionality
+ * on first character with strong directionality.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.ltrDirCheckRe_ = new RegExp(
+    '^[^' + goog.i18n.bidi.rtlChars_ + ']*[' + goog.i18n.bidi.ltrChars_ + ']');
+
+
+/**
+ * Regular expressions to check if a piece of text is of RTL directionality
+ * on first character with strong directionality.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.rtlDirCheckRe_ = new RegExp(
+    '^[^' + goog.i18n.bidi.ltrChars_ + ']*[' + goog.i18n.bidi.rtlChars_ + ']');
+
+
+/**
+ * Check whether the first strongly directional character (if any) is RTL.
+ * @param {string} str String being checked.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {boolean} Whether RTL directionality is detected using the first
+ *     strongly-directional character method.
+ */
+goog.i18n.bidi.startsWithRtl = function(str, opt_isHtml) {
+  return goog.i18n.bidi.rtlDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(
+      str, opt_isHtml));
+};
+
+
+/**
+ * Check whether the first strongly directional character (if any) is RTL.
+ * @param {string} str String being checked.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {boolean} Whether RTL directionality is detected using the first
+ *     strongly-directional character method.
+ * @deprecated Use startsWithRtl.
+ */
+goog.i18n.bidi.isRtlText = goog.i18n.bidi.startsWithRtl;
+
+
+/**
+ * Check whether the first strongly directional character (if any) is LTR.
+ * @param {string} str String being checked.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {boolean} Whether LTR directionality is detected using the first
+ *     strongly-directional character method.
+ */
+goog.i18n.bidi.startsWithLtr = function(str, opt_isHtml) {
+  return goog.i18n.bidi.ltrDirCheckRe_.test(goog.i18n.bidi.stripHtmlIfNeeded_(
+      str, opt_isHtml));
+};
+
+
+/**
+ * Check whether the first strongly directional character (if any) is LTR.
+ * @param {string} str String being checked.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {boolean} Whether LTR directionality is detected using the first
+ *     strongly-directional character method.
+ * @deprecated Use startsWithLtr.
+ */
+goog.i18n.bidi.isLtrText = goog.i18n.bidi.startsWithLtr;
+
+
+/**
+ * Regular expression to check if a string looks like something that must
+ * always be LTR even in RTL text, e.g. a URL. When estimating the
+ * directionality of text containing these, we treat these as weakly LTR,
+ * like numbers.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.isRequiredLtrRe_ = /^http:\/\/.*/;
+
+
+/**
+ * Check whether the input string either contains no strongly directional
+ * characters or looks like a url.
+ * @param {string} str String being checked.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {boolean} Whether neutral directionality is detected.
+ */
+goog.i18n.bidi.isNeutralText = function(str, opt_isHtml) {
+  str = goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml);
+  return goog.i18n.bidi.isRequiredLtrRe_.test(str) ||
+      !goog.i18n.bidi.hasAnyLtr(str) && !goog.i18n.bidi.hasAnyRtl(str);
+};
+
+
+/**
+ * Regular expressions to check if the last strongly-directional character in a
+ * piece of text is LTR.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.ltrExitDirCheckRe_ = new RegExp(
+    '[' + goog.i18n.bidi.ltrChars_ + '][^' + goog.i18n.bidi.rtlChars_ + ']*$');
+
+
+/**
+ * Regular expressions to check if the last strongly-directional character in a
+ * piece of text is RTL.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.rtlExitDirCheckRe_ = new RegExp(
+    '[' + goog.i18n.bidi.rtlChars_ + '][^' + goog.i18n.bidi.ltrChars_ + ']*$');
+
+
+/**
+ * Check if the exit directionality a piece of text is LTR, i.e. if the last
+ * strongly-directional character in the string is LTR.
+ * @param {string} str String being checked.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {boolean} Whether LTR exit directionality was detected.
+ */
+goog.i18n.bidi.endsWithLtr = function(str, opt_isHtml) {
+  return goog.i18n.bidi.ltrExitDirCheckRe_.test(
+      goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
+};
+
+
+/**
+ * Check if the exit directionality a piece of text is LTR, i.e. if the last
+ * strongly-directional character in the string is LTR.
+ * @param {string} str String being checked.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {boolean} Whether LTR exit directionality was detected.
+ * @deprecated Use endsWithLtr.
+ */
+goog.i18n.bidi.isLtrExitText = goog.i18n.bidi.endsWithLtr;
+
+
+/**
+ * Check if the exit directionality a piece of text is RTL, i.e. if the last
+ * strongly-directional character in the string is RTL.
+ * @param {string} str String being checked.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {boolean} Whether RTL exit directionality was detected.
+ */
+goog.i18n.bidi.endsWithRtl = function(str, opt_isHtml) {
+  return goog.i18n.bidi.rtlExitDirCheckRe_.test(
+      goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml));
+};
+
+
+/**
+ * Check if the exit directionality a piece of text is RTL, i.e. if the last
+ * strongly-directional character in the string is RTL.
+ * @param {string} str String being checked.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {boolean} Whether RTL exit directionality was detected.
+ * @deprecated Use endsWithRtl.
+ */
+goog.i18n.bidi.isRtlExitText = goog.i18n.bidi.endsWithRtl;
+
+
+/**
+ * A regular expression for matching right-to-left language codes.
+ * See {@link #isRtlLanguage} for the design.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.rtlLocalesRe_ = new RegExp(
+    '^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|' +
+    '.*[-_](Arab|Hebr|Thaa|Nkoo|Tfng))' +
+    '(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)',
+    'i');
+
+
+/**
+ * Check if a BCP 47 / III language code indicates an RTL language, i.e. either:
+ * - a language code explicitly specifying one of the right-to-left scripts,
+ *   e.g. "az-Arab", or<p>
+ * - a language code specifying one of the languages normally written in a
+ *   right-to-left script, e.g. "fa" (Farsi), except ones explicitly specifying
+ *   Latin or Cyrillic script (which are the usual LTR alternatives).<p>
+ * The list of right-to-left scripts appears in the 100-199 range in
+ * http://www.unicode.org/iso15924/iso15924-num.html, of which Arabic and
+ * Hebrew are by far the most widely used. We also recognize Thaana, N'Ko, and
+ * Tifinagh, which also have significant modern usage. The rest (Syriac,
+ * Samaritan, Mandaic, etc.) seem to have extremely limited or no modern usage
+ * and are not recognized to save on code size.
+ * The languages usually written in a right-to-left script are taken as those
+ * with Suppress-Script: Hebr|Arab|Thaa|Nkoo|Tfng  in
+ * http://www.iana.org/assignments/language-subtag-registry,
+ * as well as Central (or Sorani) Kurdish (ckb), Sindhi (sd) and Uyghur (ug).
+ * Other subtags of the language code, e.g. regions like EG (Egypt), are
+ * ignored.
+ * @param {string} lang BCP 47 (a.k.a III) language code.
+ * @return {boolean} Whether the language code is an RTL language.
+ */
+goog.i18n.bidi.isRtlLanguage = function(lang) {
+  return goog.i18n.bidi.rtlLocalesRe_.test(lang);
+};
+
+
+/**
+ * Regular expression for bracket guard replacement in html.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.bracketGuardHtmlRe_ =
+    /(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(&lt;.*?(&gt;)+)/g;
+
+
+/**
+ * Regular expression for bracket guard replacement in text.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.bracketGuardTextRe_ =
+    /(\(.*?\)+)|(\[.*?\]+)|(\{.*?\}+)|(<.*?>+)/g;
+
+
+/**
+ * Apply bracket guard using html span tag. This is to address the problem of
+ * messy bracket display frequently happens in RTL layout.
+ * @param {string} s The string that need to be processed.
+ * @param {boolean=} opt_isRtlContext specifies default direction (usually
+ *     direction of the UI).
+ * @return {string} The processed string, with all bracket guarded.
+ */
+goog.i18n.bidi.guardBracketInHtml = function(s, opt_isRtlContext) {
+  var useRtl = opt_isRtlContext === undefined ?
+      goog.i18n.bidi.hasAnyRtl(s) : opt_isRtlContext;
+  if (useRtl) {
+    return s.replace(goog.i18n.bidi.bracketGuardHtmlRe_,
+        '<span dir=rtl>$&</span>');
+  }
+  return s.replace(goog.i18n.bidi.bracketGuardHtmlRe_,
+      '<span dir=ltr>$&</span>');
+};
+
+
+/**
+ * Apply bracket guard using LRM and RLM. This is to address the problem of
+ * messy bracket display frequently happens in RTL layout.
+ * This version works for both plain text and html. But it does not work as
+ * good as guardBracketInHtml in some cases.
+ * @param {string} s The string that need to be processed.
+ * @param {boolean=} opt_isRtlContext specifies default direction (usually
+ *     direction of the UI).
+ * @return {string} The processed string, with all bracket guarded.
+ */
+goog.i18n.bidi.guardBracketInText = function(s, opt_isRtlContext) {
+  var useRtl = opt_isRtlContext === undefined ?
+      goog.i18n.bidi.hasAnyRtl(s) : opt_isRtlContext;
+  var mark = useRtl ? goog.i18n.bidi.Format.RLM : goog.i18n.bidi.Format.LRM;
+  return s.replace(goog.i18n.bidi.bracketGuardTextRe_, mark + '$&' + mark);
+};
+
+
+/**
+ * Enforce the html snippet in RTL directionality regardless overall context.
+ * If the html piece was enclosed by tag, dir will be applied to existing
+ * tag, otherwise a span tag will be added as wrapper. For this reason, if
+ * html snippet start with with tag, this tag must enclose the whole piece. If
+ * the tag already has a dir specified, this new one will override existing
+ * one in behavior (tested on FF and IE).
+ * @param {string} html The string that need to be processed.
+ * @return {string} The processed string, with directionality enforced to RTL.
+ */
+goog.i18n.bidi.enforceRtlInHtml = function(html) {
+  if (html.charAt(0) == '<') {
+    return html.replace(/<\w+/, '$& dir=rtl');
+  }
+  // '\n' is important for FF so that it won't incorrectly merge span groups
+  return '\n<span dir=rtl>' + html + '</span>';
+};
+
+
+/**
+ * Enforce RTL on both end of the given text piece using unicode BiDi formatting
+ * characters RLE and PDF.
+ * @param {string} text The piece of text that need to be wrapped.
+ * @return {string} The wrapped string after process.
+ */
+goog.i18n.bidi.enforceRtlInText = function(text) {
+  return goog.i18n.bidi.Format.RLE + text + goog.i18n.bidi.Format.PDF;
+};
+
+
+/**
+ * Enforce the html snippet in RTL directionality regardless overall context.
+ * If the html piece was enclosed by tag, dir will be applied to existing
+ * tag, otherwise a span tag will be added as wrapper. For this reason, if
+ * html snippet start with with tag, this tag must enclose the whole piece. If
+ * the tag already has a dir specified, this new one will override existing
+ * one in behavior (tested on FF and IE).
+ * @param {string} html The string that need to be processed.
+ * @return {string} The processed string, with directionality enforced to RTL.
+ */
+goog.i18n.bidi.enforceLtrInHtml = function(html) {
+  if (html.charAt(0) == '<') {
+    return html.replace(/<\w+/, '$& dir=ltr');
+  }
+  // '\n' is important for FF so that it won't incorrectly merge span groups
+  return '\n<span dir=ltr>' + html + '</span>';
+};
+
+
+/**
+ * Enforce LTR on both end of the given text piece using unicode BiDi formatting
+ * characters LRE and PDF.
+ * @param {string} text The piece of text that need to be wrapped.
+ * @return {string} The wrapped string after process.
+ */
+goog.i18n.bidi.enforceLtrInText = function(text) {
+  return goog.i18n.bidi.Format.LRE + text + goog.i18n.bidi.Format.PDF;
+};
+
+
+/**
+ * Regular expression to find dimensions such as "padding: .3 0.4ex 5px 6;"
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.dimensionsRe_ =
+    /:\s*([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)\s+([.\d][.\w]*)/g;
+
+
+/**
+ * Regular expression for left.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.leftRe_ = /left/gi;
+
+
+/**
+ * Regular expression for right.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.rightRe_ = /right/gi;
+
+
+/**
+ * Placeholder regular expression for swapping.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.tempRe_ = /%%%%/g;
+
+
+/**
+ * Swap location parameters and 'left'/'right' in CSS specification. The
+ * processed string will be suited for RTL layout. Though this function can
+ * cover most cases, there are always exceptions. It is suggested to put
+ * those exceptions in separate group of CSS string.
+ * @param {string} cssStr CSS spefication string.
+ * @return {string} Processed CSS specification string.
+ */
+goog.i18n.bidi.mirrorCSS = function(cssStr) {
+  return cssStr.
+      // reverse dimensions
+      replace(goog.i18n.bidi.dimensionsRe_, ':$1 $4 $3 $2').
+      replace(goog.i18n.bidi.leftRe_, '%%%%').          // swap left and right
+      replace(goog.i18n.bidi.rightRe_, goog.i18n.bidi.LEFT).
+      replace(goog.i18n.bidi.tempRe_, goog.i18n.bidi.RIGHT);
+};
+
+
+/**
+ * Regular expression for hebrew double quote substitution, finding quote
+ * directly after hebrew characters.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.doubleQuoteSubstituteRe_ = /([\u0591-\u05f2])"/g;
+
+
+/**
+ * Regular expression for hebrew single quote substitution, finding quote
+ * directly after hebrew characters.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.singleQuoteSubstituteRe_ = /([\u0591-\u05f2])'/g;
+
+
+/**
+ * Replace the double and single quote directly after a Hebrew character with
+ * GERESH and GERSHAYIM. In such case, most likely that's user intention.
+ * @param {string} str String that need to be processed.
+ * @return {string} Processed string with double/single quote replaced.
+ */
+goog.i18n.bidi.normalizeHebrewQuote = function(str) {
+  return str.
+      replace(goog.i18n.bidi.doubleQuoteSubstituteRe_, '$1\u05f4').
+      replace(goog.i18n.bidi.singleQuoteSubstituteRe_, '$1\u05f3');
+};
+
+
+/**
+ * Regular expression to split a string into "words" for directionality
+ * estimation based on relative word counts.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.wordSeparatorRe_ = /\s+/;
+
+
+/**
+ * Regular expression to check if a string contains any numerals. Used to
+ * differentiate between completely neutral strings and those containing
+ * numbers, which are weakly LTR.
+ * @type {RegExp}
+ * @private
+ */
+goog.i18n.bidi.hasNumeralsRe_ = /\d/;
+
+
+/**
+ * This constant controls threshold of RTL directionality.
+ * @type {number}
+ * @private
+ */
+goog.i18n.bidi.rtlDetectionThreshold_ = 0.40;
+
+
+/**
+ * Estimates the directionality of a string based on relative word counts.
+ * If the number of RTL words is above a certain percentage of the total number
+ * of strongly directional words, returns RTL.
+ * Otherwise, if any words are strongly or weakly LTR, returns LTR.
+ * Otherwise, returns UNKNOWN, which is used to mean "neutral".
+ * Numbers are counted as weakly LTR.
+ * @param {string} str The string to be checked.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {goog.i18n.bidi.Dir} Estimated overall directionality of {@code str}.
+ */
+goog.i18n.bidi.estimateDirection = function(str, opt_isHtml) {
+  var rtlCount = 0;
+  var totalCount = 0;
+  var hasWeaklyLtr = false;
+  var tokens = goog.i18n.bidi.stripHtmlIfNeeded_(str, opt_isHtml).
+      split(goog.i18n.bidi.wordSeparatorRe_);
+  for (var i = 0; i < tokens.length; i++) {
+    var token = tokens[i];
+    if (goog.i18n.bidi.startsWithRtl(token)) {
+      rtlCount++;
+      totalCount++;
+    } else if (goog.i18n.bidi.isRequiredLtrRe_.test(token)) {
+      hasWeaklyLtr = true;
+    } else if (goog.i18n.bidi.hasAnyLtr(token)) {
+      totalCount++;
+    } else if (goog.i18n.bidi.hasNumeralsRe_.test(token)) {
+      hasWeaklyLtr = true;
+    }
+  }
+
+  return totalCount == 0 ?
+      (hasWeaklyLtr ? goog.i18n.bidi.Dir.LTR : goog.i18n.bidi.Dir.NEUTRAL) :
+      (rtlCount / totalCount > goog.i18n.bidi.rtlDetectionThreshold_ ?
+          goog.i18n.bidi.Dir.RTL : goog.i18n.bidi.Dir.LTR);
+};
+
+
+/**
+ * Check the directionality of a piece of text, return true if the piece of
+ * text should be laid out in RTL direction.
+ * @param {string} str The piece of text that need to be detected.
+ * @param {boolean=} opt_isHtml Whether str is HTML / HTML-escaped.
+ *     Default: false.
+ * @return {boolean} Whether this piece of text should be laid out in RTL.
+ */
+goog.i18n.bidi.detectRtlDirectionality = function(str, opt_isHtml) {
+  return goog.i18n.bidi.estimateDirection(str, opt_isHtml) ==
+      goog.i18n.bidi.Dir.RTL;
+};
+
+
+/**
+ * Sets text input element's directionality and text alignment based on a
+ * given directionality. Does nothing if the given directionality is unknown or
+ * neutral.
+ * @param {Element} element Input field element to set directionality to.
+ * @param {goog.i18n.bidi.Dir|number|boolean|null} dir Desired directionality,
+ *     given in one of the following formats:
+ *     1. A goog.i18n.bidi.Dir constant.
+ *     2. A number (positive = LRT, negative = RTL, 0 = neutral).
+ *     3. A boolean (true = RTL, false = LTR).
+ *     4. A null for unknown directionality.
+ */
+goog.i18n.bidi.setElementDirAndAlign = function(element, dir) {
+  if (element) {
+    dir = goog.i18n.bidi.toDir(dir);
+    if (dir) {
+      element.style.textAlign =
+          dir == goog.i18n.bidi.Dir.RTL ?
+          goog.i18n.bidi.RIGHT : goog.i18n.bidi.LEFT;
+      element.dir = dir == goog.i18n.bidi.Dir.RTL ? 'rtl' : 'ltr';
+    }
+  }
+};
+
+
+/**
+ * Sets element dir based on estimated directionality of the given text.
+ * @param {!Element} element
+ * @param {string} text
+ */
+goog.i18n.bidi.setElementDirByTextDirectionality = function(element, text) {
+  switch (goog.i18n.bidi.estimateDirection(text)) {
+    case (goog.i18n.bidi.Dir.LTR):
+      element.dir = 'ltr';
+      break;
+    case (goog.i18n.bidi.Dir.RTL):
+      element.dir = 'rtl';
+      break;
+    default:
+      // Default for no direction, inherit from document.
+      element.removeAttribute('dir');
+  }
+};
+
+
+
+/**
+ * Strings that have an (optional) known direction.
+ *
+ * Implementations of this interface are string-like objects that carry an
+ * attached direction, if known.
+ * @interface
+ */
+goog.i18n.bidi.DirectionalString = function() {};
+
+
+/**
+ * Interface marker of the DirectionalString interface.
+ *
+ * This property can be used to determine at runtime whether or not an object
+ * implements this interface.  All implementations of this interface set this
+ * property to {@code true}.
+ * @type {boolean}
+ */
+goog.i18n.bidi.DirectionalString.prototype.
+    implementsGoogI18nBidiDirectionalString;
+
+
+/**
+ * Retrieves this object's known direction (if any).
+ * @return {?goog.i18n.bidi.Dir} The known direction. Null if unknown.
+ */
+goog.i18n.bidi.DirectionalString.prototype.getDirection;


[30/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/dom/dom.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/dom/dom.js b/externs/GCL/externs/goog/dom/dom.js
new file mode 100644
index 0000000..ad4f430
--- /dev/null
+++ b/externs/GCL/externs/goog/dom/dom.js
@@ -0,0 +1,2990 @@
+// 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 manipulating the browser's Document Object Model
+ * Inspiration taken *heavily* from mochikit (http://mochikit.com/).
+ *
+ * You can use {@link goog.dom.DomHelper} to create new dom helpers that refer
+ * to a different document object.  This is useful if you are working with
+ * frames or multiple windows.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+
+// TODO(arv): Rename/refactor getTextContent and getRawTextContent. The problem
+// is that getTextContent should mimic the DOM3 textContent. We should add a
+// getInnerText (or getText) which tries to return the visible text, innerText.
+
+
+goog.provide('goog.dom');
+goog.provide('goog.dom.Appendable');
+goog.provide('goog.dom.DomHelper');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.dom.BrowserFeature');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.safe');
+goog.require('goog.html.SafeHtml');
+goog.require('goog.math.Coordinate');
+goog.require('goog.math.Size');
+goog.require('goog.object');
+goog.require('goog.string');
+goog.require('goog.string.Unicode');
+goog.require('goog.userAgent');
+
+
+/**
+ * @define {boolean} Whether we know at compile time that the browser is in
+ * quirks mode.
+ */
+goog.define('goog.dom.ASSUME_QUIRKS_MODE', false);
+
+
+/**
+ * @define {boolean} Whether we know at compile time that the browser is in
+ * standards compliance mode.
+ */
+goog.define('goog.dom.ASSUME_STANDARDS_MODE', false);
+
+
+/**
+ * Whether we know the compatibility mode at compile time.
+ * @type {boolean}
+ * @private
+ */
+goog.dom.COMPAT_MODE_KNOWN_ =
+    goog.dom.ASSUME_QUIRKS_MODE || goog.dom.ASSUME_STANDARDS_MODE;
+
+
+/**
+ * Gets the DomHelper object for the document where the element resides.
+ * @param {(Node|Window)=} opt_element If present, gets the DomHelper for this
+ *     element.
+ * @return {!goog.dom.DomHelper} The DomHelper.
+ */
+goog.dom.getDomHelper = function(opt_element) {
+  return opt_element ?
+      new goog.dom.DomHelper(goog.dom.getOwnerDocument(opt_element)) :
+      (goog.dom.defaultDomHelper_ ||
+          (goog.dom.defaultDomHelper_ = new goog.dom.DomHelper()));
+};
+
+
+/**
+ * Cached default DOM helper.
+ * @type {goog.dom.DomHelper}
+ * @private
+ */
+goog.dom.defaultDomHelper_;
+
+
+/**
+ * Gets the document object being used by the dom library.
+ * @return {!Document} Document object.
+ */
+goog.dom.getDocument = function() {
+  return document;
+};
+
+
+/**
+ * Gets an element from the current document by element id.
+ *
+ * If an Element is passed in, it is returned.
+ *
+ * @param {string|Element} element Element ID or a DOM node.
+ * @return {Element} The element with the given ID, or the node passed in.
+ */
+goog.dom.getElement = function(element) {
+  return goog.dom.getElementHelper_(document, element);
+};
+
+
+/**
+ * Gets an element by id from the given document (if present).
+ * If an element is given, it is returned.
+ * @param {!Document} doc
+ * @param {string|Element} element Element ID or a DOM node.
+ * @return {Element} The resulting element.
+ * @private
+ */
+goog.dom.getElementHelper_ = function(doc, element) {
+  return goog.isString(element) ?
+      doc.getElementById(element) :
+      element;
+};
+
+
+/**
+ * Gets an element by id, asserting that the element is found.
+ *
+ * This is used when an element is expected to exist, and should fail with
+ * an assertion error if it does not (if assertions are enabled).
+ *
+ * @param {string} id Element ID.
+ * @return {!Element} The element with the given ID, if it exists.
+ */
+goog.dom.getRequiredElement = function(id) {
+  return goog.dom.getRequiredElementHelper_(document, id);
+};
+
+
+/**
+ * Helper function for getRequiredElementHelper functions, both static and
+ * on DomHelper.  Asserts the element with the given id exists.
+ * @param {!Document} doc
+ * @param {string} id
+ * @return {!Element} The element with the given ID, if it exists.
+ * @private
+ */
+goog.dom.getRequiredElementHelper_ = function(doc, id) {
+  // To prevent users passing in Elements as is permitted in getElement().
+  goog.asserts.assertString(id);
+  var element = goog.dom.getElementHelper_(doc, id);
+  element = goog.asserts.assertElement(element,
+      'No element found with id: ' + id);
+  return element;
+};
+
+
+/**
+ * Alias for getElement.
+ * @param {string|Element} element Element ID or a DOM node.
+ * @return {Element} The element with the given ID, or the node passed in.
+ * @deprecated Use {@link goog.dom.getElement} instead.
+ */
+goog.dom.$ = goog.dom.getElement;
+
+
+/**
+ * Looks up elements by both tag and class name, using browser native functions
+ * ({@code querySelectorAll}, {@code getElementsByTagName} or
+ * {@code getElementsByClassName}) where possible. This function
+ * is a useful, if limited, way of collecting a list of DOM elements
+ * with certain characteristics.  {@code goog.dom.query} offers a
+ * more powerful and general solution which allows matching on CSS3
+ * selector expressions, but at increased cost in code size. If all you
+ * need is particular tags belonging to a single class, this function
+ * is fast and sleek.
+ *
+ * Note that tag names are case sensitive in the SVG namespace, and this
+ * function converts opt_tag to uppercase for comparisons. For queries in the
+ * SVG namespace you should use querySelector or querySelectorAll instead.
+ * https://bugzilla.mozilla.org/show_bug.cgi?id=963870
+ * https://bugs.webkit.org/show_bug.cgi?id=83438
+ *
+ * @see {goog.dom.query}
+ *
+ * @param {?string=} opt_tag Element tag name.
+ * @param {?string=} opt_class Optional class name.
+ * @param {(Document|Element)=} opt_el Optional element to look in.
+ * @return { {length: number} } Array-like list of elements (only a length
+ *     property and numerical indices are guaranteed to exist).
+ */
+goog.dom.getElementsByTagNameAndClass = function(opt_tag, opt_class, opt_el) {
+  return goog.dom.getElementsByTagNameAndClass_(document, opt_tag, opt_class,
+                                                opt_el);
+};
+
+
+/**
+ * Returns a static, array-like list of the elements with the provided
+ * className.
+ * @see {goog.dom.query}
+ * @param {string} className the name of the class to look for.
+ * @param {(Document|Element)=} opt_el Optional element to look in.
+ * @return { {length: number} } The items found with the class name provided.
+ */
+goog.dom.getElementsByClass = function(className, opt_el) {
+  var parent = opt_el || document;
+  if (goog.dom.canUseQuerySelector_(parent)) {
+    return parent.querySelectorAll('.' + className);
+  }
+  return goog.dom.getElementsByTagNameAndClass_(
+      document, '*', className, opt_el);
+};
+
+
+/**
+ * Returns the first element with the provided className.
+ * @see {goog.dom.query}
+ * @param {string} className the name of the class to look for.
+ * @param {Element|Document=} opt_el Optional element to look in.
+ * @return {Element} The first item with the class name provided.
+ */
+goog.dom.getElementByClass = function(className, opt_el) {
+  var parent = opt_el || document;
+  var retVal = null;
+  if (parent.getElementsByClassName) {
+    retVal = parent.getElementsByClassName(className)[0];
+  } else if (goog.dom.canUseQuerySelector_(parent)) {
+    retVal = parent.querySelector('.' + className);
+  } else {
+    retVal = goog.dom.getElementsByTagNameAndClass_(
+        document, '*', className, opt_el)[0];
+  }
+  return retVal || null;
+};
+
+
+/**
+ * Ensures an element with the given className exists, and then returns the
+ * first element with the provided className.
+ * @see {goog.dom.query}
+ * @param {string} className the name of the class to look for.
+ * @param {!Element|!Document=} opt_root Optional element or document to look
+ *     in.
+ * @return {!Element} The first item with the class name provided.
+ * @throws {goog.asserts.AssertionError} Thrown if no element is found.
+ */
+goog.dom.getRequiredElementByClass = function(className, opt_root) {
+  var retValue = goog.dom.getElementByClass(className, opt_root);
+  return goog.asserts.assert(retValue,
+      'No element found with className: ' + className);
+};
+
+
+/**
+ * Prefer the standardized (http://www.w3.org/TR/selectors-api/), native and
+ * fast W3C Selectors API.
+ * @param {!(Element|Document)} parent The parent document object.
+ * @return {boolean} whether or not we can use parent.querySelector* APIs.
+ * @private
+ */
+goog.dom.canUseQuerySelector_ = function(parent) {
+  return !!(parent.querySelectorAll && parent.querySelector);
+};
+
+
+/**
+ * Helper for {@code getElementsByTagNameAndClass}.
+ * @param {!Document} doc The document to get the elements in.
+ * @param {?string=} opt_tag Element tag name.
+ * @param {?string=} opt_class Optional class name.
+ * @param {(Document|Element)=} opt_el Optional element to look in.
+ * @return { {length: number} } Array-like list of elements (only a length
+ *     property and numerical indices are guaranteed to exist).
+ * @private
+ */
+goog.dom.getElementsByTagNameAndClass_ = function(doc, opt_tag, opt_class,
+                                                  opt_el) {
+  var parent = opt_el || doc;
+  var tagName = (opt_tag && opt_tag != '*') ? opt_tag.toUpperCase() : '';
+
+  if (goog.dom.canUseQuerySelector_(parent) &&
+      (tagName || opt_class)) {
+    var query = tagName + (opt_class ? '.' + opt_class : '');
+    return parent.querySelectorAll(query);
+  }
+
+  // Use the native getElementsByClassName if available, under the assumption
+  // that even when the tag name is specified, there will be fewer elements to
+  // filter through when going by class than by tag name
+  if (opt_class && parent.getElementsByClassName) {
+    var els = parent.getElementsByClassName(opt_class);
+
+    if (tagName) {
+      var arrayLike = {};
+      var len = 0;
+
+      // Filter for specific tags if requested.
+      for (var i = 0, el; el = els[i]; i++) {
+        if (tagName == el.nodeName) {
+          arrayLike[len++] = el;
+        }
+      }
+      arrayLike.length = len;
+
+      return arrayLike;
+    } else {
+      return els;
+    }
+  }
+
+  var els = parent.getElementsByTagName(tagName || '*');
+
+  if (opt_class) {
+    var arrayLike = {};
+    var len = 0;
+    for (var i = 0, el; el = els[i]; i++) {
+      var className = el.className;
+      // Check if className has a split function since SVG className does not.
+      if (typeof className.split == 'function' &&
+          goog.array.contains(className.split(/\s+/), opt_class)) {
+        arrayLike[len++] = el;
+      }
+    }
+    arrayLike.length = len;
+    return arrayLike;
+  } else {
+    return els;
+  }
+};
+
+
+/**
+ * Alias for {@code getElementsByTagNameAndClass}.
+ * @param {?string=} opt_tag Element tag name.
+ * @param {?string=} opt_class Optional class name.
+ * @param {Element=} opt_el Optional element to look in.
+ * @return { {length: number} } Array-like list of elements (only a length
+ *     property and numerical indices are guaranteed to exist).
+ * @deprecated Use {@link goog.dom.getElementsByTagNameAndClass} instead.
+ */
+goog.dom.$$ = goog.dom.getElementsByTagNameAndClass;
+
+
+/**
+ * Sets multiple properties on a node.
+ * @param {Element} element DOM node to set properties on.
+ * @param {Object} properties Hash of property:value pairs.
+ */
+goog.dom.setProperties = function(element, properties) {
+  goog.object.forEach(properties, function(val, key) {
+    if (key == 'style') {
+      element.style.cssText = val;
+    } else if (key == 'class') {
+      element.className = val;
+    } else if (key == 'for') {
+      element.htmlFor = val;
+    } else if (key in goog.dom.DIRECT_ATTRIBUTE_MAP_) {
+      element.setAttribute(goog.dom.DIRECT_ATTRIBUTE_MAP_[key], val);
+    } else if (goog.string.startsWith(key, 'aria-') ||
+        goog.string.startsWith(key, 'data-')) {
+      element.setAttribute(key, val);
+    } else {
+      element[key] = val;
+    }
+  });
+};
+
+
+/**
+ * Map of attributes that should be set using
+ * element.setAttribute(key, val) instead of element[key] = val.  Used
+ * by goog.dom.setProperties.
+ *
+ * @private {!Object<string, string>}
+ * @const
+ */
+goog.dom.DIRECT_ATTRIBUTE_MAP_ = {
+  'cellpadding': 'cellPadding',
+  'cellspacing': 'cellSpacing',
+  'colspan': 'colSpan',
+  'frameborder': 'frameBorder',
+  'height': 'height',
+  'maxlength': 'maxLength',
+  'role': 'role',
+  'rowspan': 'rowSpan',
+  'type': 'type',
+  'usemap': 'useMap',
+  'valign': 'vAlign',
+  'width': 'width'
+};
+
+
+/**
+ * Gets the dimensions of the viewport.
+ *
+ * Gecko Standards mode:
+ * docEl.clientWidth  Width of viewport excluding scrollbar.
+ * win.innerWidth     Width of viewport including scrollbar.
+ * body.clientWidth   Width of body element.
+ *
+ * docEl.clientHeight Height of viewport excluding scrollbar.
+ * win.innerHeight    Height of viewport including scrollbar.
+ * body.clientHeight  Height of document.
+ *
+ * Gecko Backwards compatible mode:
+ * docEl.clientWidth  Width of viewport excluding scrollbar.
+ * win.innerWidth     Width of viewport including scrollbar.
+ * body.clientWidth   Width of viewport excluding scrollbar.
+ *
+ * docEl.clientHeight Height of document.
+ * win.innerHeight    Height of viewport including scrollbar.
+ * body.clientHeight  Height of viewport excluding scrollbar.
+ *
+ * IE6/7 Standards mode:
+ * docEl.clientWidth  Width of viewport excluding scrollbar.
+ * win.innerWidth     Undefined.
+ * body.clientWidth   Width of body element.
+ *
+ * docEl.clientHeight Height of viewport excluding scrollbar.
+ * win.innerHeight    Undefined.
+ * body.clientHeight  Height of document element.
+ *
+ * IE5 + IE6/7 Backwards compatible mode:
+ * docEl.clientWidth  0.
+ * win.innerWidth     Undefined.
+ * body.clientWidth   Width of viewport excluding scrollbar.
+ *
+ * docEl.clientHeight 0.
+ * win.innerHeight    Undefined.
+ * body.clientHeight  Height of viewport excluding scrollbar.
+ *
+ * Opera 9 Standards and backwards compatible mode:
+ * docEl.clientWidth  Width of viewport excluding scrollbar.
+ * win.innerWidth     Width of viewport including scrollbar.
+ * body.clientWidth   Width of viewport excluding scrollbar.
+ *
+ * docEl.clientHeight Height of document.
+ * win.innerHeight    Height of viewport including scrollbar.
+ * body.clientHeight  Height of viewport excluding scrollbar.
+ *
+ * WebKit:
+ * Safari 2
+ * docEl.clientHeight Same as scrollHeight.
+ * docEl.clientWidth  Same as innerWidth.
+ * win.innerWidth     Width of viewport excluding scrollbar.
+ * win.innerHeight    Height of the viewport including scrollbar.
+ * frame.innerHeight  Height of the viewport exluding scrollbar.
+ *
+ * Safari 3 (tested in 522)
+ *
+ * docEl.clientWidth  Width of viewport excluding scrollbar.
+ * docEl.clientHeight Height of viewport excluding scrollbar in strict mode.
+ * body.clientHeight  Height of viewport excluding scrollbar in quirks mode.
+ *
+ * @param {Window=} opt_window Optional window element to test.
+ * @return {!goog.math.Size} Object with values 'width' and 'height'.
+ */
+goog.dom.getViewportSize = function(opt_window) {
+  // TODO(arv): This should not take an argument
+  return goog.dom.getViewportSize_(opt_window || window);
+};
+
+
+/**
+ * Helper for {@code getViewportSize}.
+ * @param {Window} win The window to get the view port size for.
+ * @return {!goog.math.Size} Object with values 'width' and 'height'.
+ * @private
+ */
+goog.dom.getViewportSize_ = function(win) {
+  var doc = win.document;
+  var el = goog.dom.isCss1CompatMode_(doc) ? doc.documentElement : doc.body;
+  return new goog.math.Size(el.clientWidth, el.clientHeight);
+};
+
+
+/**
+ * Calculates the height of the document.
+ *
+ * @return {number} The height of the current document.
+ */
+goog.dom.getDocumentHeight = function() {
+  return goog.dom.getDocumentHeight_(window);
+};
+
+
+/**
+ * Calculates the height of the document of the given window.
+ *
+ * Function code copied from the opensocial gadget api:
+ *   gadgets.window.adjustHeight(opt_height)
+ *
+ * @private
+ * @param {!Window} win The window whose document height to retrieve.
+ * @return {number} The height of the document of the given window.
+ */
+goog.dom.getDocumentHeight_ = function(win) {
+  // NOTE(eae): This method will return the window size rather than the document
+  // size in webkit quirks mode.
+  var doc = win.document;
+  var height = 0;
+
+  if (doc) {
+    // Calculating inner content height is hard and different between
+    // browsers rendering in Strict vs. Quirks mode.  We use a combination of
+    // three properties within document.body and document.documentElement:
+    // - scrollHeight
+    // - offsetHeight
+    // - clientHeight
+    // These values differ significantly between browsers and rendering modes.
+    // But there are patterns.  It just takes a lot of time and persistence
+    // to figure out.
+
+    var body = doc.body;
+    var docEl = doc.documentElement;
+    if (!(docEl && body)) {
+      return 0;
+    }
+
+    // Get the height of the viewport
+    var vh = goog.dom.getViewportSize_(win).height;
+    if (goog.dom.isCss1CompatMode_(doc) && docEl.scrollHeight) {
+      // In Strict mode:
+      // The inner content height is contained in either:
+      //    document.documentElement.scrollHeight
+      //    document.documentElement.offsetHeight
+      // Based on studying the values output by different browsers,
+      // use the value that's NOT equal to the viewport height found above.
+      height = docEl.scrollHeight != vh ?
+          docEl.scrollHeight : docEl.offsetHeight;
+    } else {
+      // In Quirks mode:
+      // documentElement.clientHeight is equal to documentElement.offsetHeight
+      // except in IE.  In most browsers, document.documentElement can be used
+      // to calculate the inner content height.
+      // However, in other browsers (e.g. IE), document.body must be used
+      // instead.  How do we know which one to use?
+      // If document.documentElement.clientHeight does NOT equal
+      // document.documentElement.offsetHeight, then use document.body.
+      var sh = docEl.scrollHeight;
+      var oh = docEl.offsetHeight;
+      if (docEl.clientHeight != oh) {
+        sh = body.scrollHeight;
+        oh = body.offsetHeight;
+      }
+
+      // Detect whether the inner content height is bigger or smaller
+      // than the bounding box (viewport).  If bigger, take the larger
+      // value.  If smaller, take the smaller value.
+      if (sh > vh) {
+        // Content is larger
+        height = sh > oh ? sh : oh;
+      } else {
+        // Content is smaller
+        height = sh < oh ? sh : oh;
+      }
+    }
+  }
+
+  return height;
+};
+
+
+/**
+ * Gets the page scroll distance as a coordinate object.
+ *
+ * @param {Window=} opt_window Optional window element to test.
+ * @return {!goog.math.Coordinate} Object with values 'x' and 'y'.
+ * @deprecated Use {@link goog.dom.getDocumentScroll} instead.
+ */
+goog.dom.getPageScroll = function(opt_window) {
+  var win = opt_window || goog.global || window;
+  return goog.dom.getDomHelper(win.document).getDocumentScroll();
+};
+
+
+/**
+ * Gets the document scroll distance as a coordinate object.
+ *
+ * @return {!goog.math.Coordinate} Object with values 'x' and 'y'.
+ */
+goog.dom.getDocumentScroll = function() {
+  return goog.dom.getDocumentScroll_(document);
+};
+
+
+/**
+ * Helper for {@code getDocumentScroll}.
+ *
+ * @param {!Document} doc The document to get the scroll for.
+ * @return {!goog.math.Coordinate} Object with values 'x' and 'y'.
+ * @private
+ */
+goog.dom.getDocumentScroll_ = function(doc) {
+  var el = goog.dom.getDocumentScrollElement_(doc);
+  var win = goog.dom.getWindow_(doc);
+  if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('10') &&
+      win.pageYOffset != el.scrollTop) {
+    // The keyboard on IE10 touch devices shifts the page using the pageYOffset
+    // without modifying scrollTop. For this case, we want the body scroll
+    // offsets.
+    return new goog.math.Coordinate(el.scrollLeft, el.scrollTop);
+  }
+  return new goog.math.Coordinate(win.pageXOffset || el.scrollLeft,
+      win.pageYOffset || el.scrollTop);
+};
+
+
+/**
+ * Gets the document scroll element.
+ * @return {!Element} Scrolling element.
+ */
+goog.dom.getDocumentScrollElement = function() {
+  return goog.dom.getDocumentScrollElement_(document);
+};
+
+
+/**
+ * Helper for {@code getDocumentScrollElement}.
+ * @param {!Document} doc The document to get the scroll element for.
+ * @return {!Element} Scrolling element.
+ * @private
+ */
+goog.dom.getDocumentScrollElement_ = function(doc) {
+  // WebKit needs body.scrollLeft in both quirks mode and strict mode. We also
+  // default to the documentElement if the document does not have a body (e.g.
+  // a SVG document).
+  if (!goog.userAgent.WEBKIT && goog.dom.isCss1CompatMode_(doc)) {
+    return doc.documentElement;
+  }
+  return doc.body || doc.documentElement;
+};
+
+
+/**
+ * Gets the window object associated with the given document.
+ *
+ * @param {Document=} opt_doc  Document object to get window for.
+ * @return {!Window} The window associated with the given document.
+ */
+goog.dom.getWindow = function(opt_doc) {
+  // TODO(arv): This should not take an argument.
+  return opt_doc ? goog.dom.getWindow_(opt_doc) : window;
+};
+
+
+/**
+ * Helper for {@code getWindow}.
+ *
+ * @param {!Document} doc  Document object to get window for.
+ * @return {!Window} The window associated with the given document.
+ * @private
+ */
+goog.dom.getWindow_ = function(doc) {
+  return doc.parentWindow || doc.defaultView;
+};
+
+
+/**
+ * Returns a dom node with a set of attributes.  This function accepts varargs
+ * for subsequent nodes to be added.  Subsequent nodes will be added to the
+ * first node as childNodes.
+ *
+ * So:
+ * <code>createDom('div', null, createDom('p'), createDom('p'));</code>
+ * would return a div with two child paragraphs
+ *
+ * @param {string} tagName Tag to create.
+ * @param {(Object|Array<string>|string)=} opt_attributes If object, then a map
+ *     of name-value pairs for attributes. If a string, then this is the
+ *     className of the new element. If an array, the elements will be joined
+ *     together as the className of the new element.
+ * @param {...(Object|string|Array|NodeList)} var_args Further DOM nodes or
+ *     strings for text nodes. If one of the var_args is an array or NodeList,i
+ *     its elements will be added as childNodes instead.
+ * @return {!Element} Reference to a DOM node.
+ */
+goog.dom.createDom = function(tagName, opt_attributes, var_args) {
+  return goog.dom.createDom_(document, arguments);
+};
+
+
+/**
+ * Helper for {@code createDom}.
+ * @param {!Document} doc The document to create the DOM in.
+ * @param {!Arguments} args Argument object passed from the callers. See
+ *     {@code goog.dom.createDom} for details.
+ * @return {!Element} Reference to a DOM node.
+ * @private
+ */
+goog.dom.createDom_ = function(doc, args) {
+  var tagName = args[0];
+  var attributes = args[1];
+
+  // Internet Explorer is dumb: http://msdn.microsoft.com/workshop/author/
+  //                            dhtml/reference/properties/name_2.asp
+  // Also does not allow setting of 'type' attribute on 'input' or 'button'.
+  if (!goog.dom.BrowserFeature.CAN_ADD_NAME_OR_TYPE_ATTRIBUTES && attributes &&
+      (attributes.name || attributes.type)) {
+    var tagNameArr = ['<', tagName];
+    if (attributes.name) {
+      tagNameArr.push(' name="', goog.string.htmlEscape(attributes.name),
+                      '"');
+    }
+    if (attributes.type) {
+      tagNameArr.push(' type="', goog.string.htmlEscape(attributes.type),
+                      '"');
+
+      // Clone attributes map to remove 'type' without mutating the input.
+      var clone = {};
+      goog.object.extend(clone, attributes);
+
+      // JSCompiler can't see how goog.object.extend added this property,
+      // because it was essentially added by reflection.
+      // So it needs to be quoted.
+      delete clone['type'];
+
+      attributes = clone;
+    }
+    tagNameArr.push('>');
+    tagName = tagNameArr.join('');
+  }
+
+  var element = doc.createElement(tagName);
+
+  if (attributes) {
+    if (goog.isString(attributes)) {
+      element.className = attributes;
+    } else if (goog.isArray(attributes)) {
+      element.className = attributes.join(' ');
+    } else {
+      goog.dom.setProperties(element, attributes);
+    }
+  }
+
+  if (args.length > 2) {
+    goog.dom.append_(doc, element, args, 2);
+  }
+
+  return element;
+};
+
+
+/**
+ * Appends a node with text or other nodes.
+ * @param {!Document} doc The document to create new nodes in.
+ * @param {!Node} parent The node to append nodes to.
+ * @param {!Arguments} args The values to add. See {@code goog.dom.append}.
+ * @param {number} startIndex The index of the array to start from.
+ * @private
+ */
+goog.dom.append_ = function(doc, parent, args, startIndex) {
+  function childHandler(child) {
+    // TODO(user): More coercion, ala MochiKit?
+    if (child) {
+      parent.appendChild(goog.isString(child) ?
+          doc.createTextNode(child) : child);
+    }
+  }
+
+  for (var i = startIndex; i < args.length; i++) {
+    var arg = args[i];
+    // TODO(attila): Fix isArrayLike to return false for a text node.
+    if (goog.isArrayLike(arg) && !goog.dom.isNodeLike(arg)) {
+      // If the argument is a node list, not a real array, use a clone,
+      // because forEach can't be used to mutate a NodeList.
+      goog.array.forEach(goog.dom.isNodeList(arg) ?
+          goog.array.toArray(arg) : arg,
+          childHandler);
+    } else {
+      childHandler(arg);
+    }
+  }
+};
+
+
+/**
+ * Alias for {@code createDom}.
+ * @param {string} tagName Tag to create.
+ * @param {(string|Object)=} opt_attributes If object, then a map of name-value
+ *     pairs for attributes. If a string, then this is the className of the new
+ *     element.
+ * @param {...(Object|string|Array|NodeList)} var_args Further DOM nodes or
+ *     strings for text nodes. If one of the var_args is an array, its
+ *     children will be added as childNodes instead.
+ * @return {!Element} Reference to a DOM node.
+ * @deprecated Use {@link goog.dom.createDom} instead.
+ */
+goog.dom.$dom = goog.dom.createDom;
+
+
+/**
+ * Creates a new element.
+ * @param {string} name Tag name.
+ * @return {!Element} The new element.
+ */
+goog.dom.createElement = function(name) {
+  return document.createElement(name);
+};
+
+
+/**
+ * Creates a new text node.
+ * @param {number|string} content Content.
+ * @return {!Text} The new text node.
+ */
+goog.dom.createTextNode = function(content) {
+  return document.createTextNode(String(content));
+};
+
+
+/**
+ * Create a table.
+ * @param {number} rows The number of rows in the table.  Must be >= 1.
+ * @param {number} columns The number of columns in the table.  Must be >= 1.
+ * @param {boolean=} opt_fillWithNbsp If true, fills table entries with
+ *     {@code goog.string.Unicode.NBSP} characters.
+ * @return {!Element} The created table.
+ */
+goog.dom.createTable = function(rows, columns, opt_fillWithNbsp) {
+  // TODO(user): Return HTMLTableElement, also in prototype function.
+  // Callers need to be updated to e.g. not assign numbers to table.cellSpacing.
+  return goog.dom.createTable_(document, rows, columns, !!opt_fillWithNbsp);
+};
+
+
+/**
+ * Create a table.
+ * @param {!Document} doc Document object to use to create the table.
+ * @param {number} rows The number of rows in the table.  Must be >= 1.
+ * @param {number} columns The number of columns in the table.  Must be >= 1.
+ * @param {boolean} fillWithNbsp If true, fills table entries with
+ *     {@code goog.string.Unicode.NBSP} characters.
+ * @return {!HTMLTableElement} The created table.
+ * @private
+ */
+goog.dom.createTable_ = function(doc, rows, columns, fillWithNbsp) {
+  var table = /** @type {!HTMLTableElement} */
+      (doc.createElement(goog.dom.TagName.TABLE));
+  var tbody = table.appendChild(doc.createElement(goog.dom.TagName.TBODY));
+  for (var i = 0; i < rows; i++) {
+    var tr = doc.createElement(goog.dom.TagName.TR);
+    for (var j = 0; j < columns; j++) {
+      var td = doc.createElement(goog.dom.TagName.TD);
+      // IE <= 9 will create a text node if we set text content to the empty
+      // string, so we avoid doing it unless necessary. This ensures that the
+      // same DOM tree is returned on all browsers.
+      if (fillWithNbsp) {
+        goog.dom.setTextContent(td, goog.string.Unicode.NBSP);
+      }
+      tr.appendChild(td);
+    }
+    tbody.appendChild(tr);
+  }
+  return table;
+};
+
+
+/**
+ * Converts HTML markup into a node.
+ * @param {!goog.html.SafeHtml} html The HTML markup to convert.
+ * @return {!Node} The resulting node.
+ */
+goog.dom.safeHtmlToNode = function(html) {
+  return goog.dom.safeHtmlToNode_(document, html);
+};
+
+
+/**
+ * Helper for {@code safeHtmlToNode}.
+ * @param {!Document} doc The document.
+ * @param {!goog.html.SafeHtml} html The HTML markup to convert.
+ * @return {!Node} The resulting node.
+ * @private
+ */
+goog.dom.safeHtmlToNode_ = function(doc, html) {
+  var tempDiv = doc.createElement(goog.dom.TagName.DIV);
+  if (goog.dom.BrowserFeature.INNER_HTML_NEEDS_SCOPED_ELEMENT) {
+    goog.dom.safe.setInnerHtml(tempDiv,
+        goog.html.SafeHtml.concat(goog.html.SafeHtml.create('br'), html));
+    tempDiv.removeChild(tempDiv.firstChild);
+  } else {
+    goog.dom.safe.setInnerHtml(tempDiv, html);
+  }
+  return goog.dom.childrenToNode_(doc, tempDiv);
+};
+
+
+/**
+ * Converts an HTML string into a document fragment. The string must be
+ * sanitized in order to avoid cross-site scripting. For example
+ * {@code goog.dom.htmlToDocumentFragment('&lt;img src=x onerror=alert(0)&gt;')}
+ * triggers an alert in all browsers, even if the returned document fragment
+ * is thrown away immediately.
+ *
+ * @param {string} htmlString The HTML string to convert.
+ * @return {!Node} The resulting document fragment.
+ */
+goog.dom.htmlToDocumentFragment = function(htmlString) {
+  return goog.dom.htmlToDocumentFragment_(document, htmlString);
+};
+
+
+// TODO(jakubvrana): Merge with {@code safeHtmlToNode_}.
+/**
+ * Helper for {@code htmlToDocumentFragment}.
+ *
+ * @param {!Document} doc The document.
+ * @param {string} htmlString The HTML string to convert.
+ * @return {!Node} The resulting document fragment.
+ * @private
+ */
+goog.dom.htmlToDocumentFragment_ = function(doc, htmlString) {
+  var tempDiv = doc.createElement(goog.dom.TagName.DIV);
+  if (goog.dom.BrowserFeature.INNER_HTML_NEEDS_SCOPED_ELEMENT) {
+    tempDiv.innerHTML = '<br>' + htmlString;
+    tempDiv.removeChild(tempDiv.firstChild);
+  } else {
+    tempDiv.innerHTML = htmlString;
+  }
+  return goog.dom.childrenToNode_(doc, tempDiv);
+};
+
+
+/**
+ * Helper for {@code htmlToDocumentFragment_}.
+ * @param {!Document} doc The document.
+ * @param {!Node} tempDiv The input node.
+ * @return {!Node} The resulting node.
+ * @private
+ */
+goog.dom.childrenToNode_ = function(doc, tempDiv) {
+  if (tempDiv.childNodes.length == 1) {
+    return tempDiv.removeChild(tempDiv.firstChild);
+  } else {
+    var fragment = doc.createDocumentFragment();
+    while (tempDiv.firstChild) {
+      fragment.appendChild(tempDiv.firstChild);
+    }
+    return fragment;
+  }
+};
+
+
+/**
+ * Returns true if the browser is in "CSS1-compatible" (standards-compliant)
+ * mode, false otherwise.
+ * @return {boolean} True if in CSS1-compatible mode.
+ */
+goog.dom.isCss1CompatMode = function() {
+  return goog.dom.isCss1CompatMode_(document);
+};
+
+
+/**
+ * Returns true if the browser is in "CSS1-compatible" (standards-compliant)
+ * mode, false otherwise.
+ * @param {!Document} doc The document to check.
+ * @return {boolean} True if in CSS1-compatible mode.
+ * @private
+ */
+goog.dom.isCss1CompatMode_ = function(doc) {
+  if (goog.dom.COMPAT_MODE_KNOWN_) {
+    return goog.dom.ASSUME_STANDARDS_MODE;
+  }
+
+  return doc.compatMode == 'CSS1Compat';
+};
+
+
+/**
+ * Determines if the given node can contain children, intended to be used for
+ * HTML generation.
+ *
+ * IE natively supports node.canHaveChildren but has inconsistent behavior.
+ * Prior to IE8 the base tag allows children and in IE9 all nodes return true
+ * for canHaveChildren.
+ *
+ * In practice all non-IE browsers allow you to add children to any node, but
+ * the behavior is inconsistent:
+ *
+ * <pre>
+ *   var a = document.createElement(goog.dom.TagName.BR);
+ *   a.appendChild(document.createTextNode('foo'));
+ *   a.appendChild(document.createTextNode('bar'));
+ *   console.log(a.childNodes.length);  // 2
+ *   console.log(a.innerHTML);  // Chrome: "", IE9: "foobar", FF3.5: "foobar"
+ * </pre>
+ *
+ * For more information, see:
+ * http://dev.w3.org/html5/markup/syntax.html#syntax-elements
+ *
+ * TODO(user): Rename shouldAllowChildren() ?
+ *
+ * @param {Node} node The node to check.
+ * @return {boolean} Whether the node can contain children.
+ */
+goog.dom.canHaveChildren = function(node) {
+  if (node.nodeType != goog.dom.NodeType.ELEMENT) {
+    return false;
+  }
+  switch (node.tagName) {
+    case goog.dom.TagName.APPLET:
+    case goog.dom.TagName.AREA:
+    case goog.dom.TagName.BASE:
+    case goog.dom.TagName.BR:
+    case goog.dom.TagName.COL:
+    case goog.dom.TagName.COMMAND:
+    case goog.dom.TagName.EMBED:
+    case goog.dom.TagName.FRAME:
+    case goog.dom.TagName.HR:
+    case goog.dom.TagName.IMG:
+    case goog.dom.TagName.INPUT:
+    case goog.dom.TagName.IFRAME:
+    case goog.dom.TagName.ISINDEX:
+    case goog.dom.TagName.KEYGEN:
+    case goog.dom.TagName.LINK:
+    case goog.dom.TagName.NOFRAMES:
+    case goog.dom.TagName.NOSCRIPT:
+    case goog.dom.TagName.META:
+    case goog.dom.TagName.OBJECT:
+    case goog.dom.TagName.PARAM:
+    case goog.dom.TagName.SCRIPT:
+    case goog.dom.TagName.SOURCE:
+    case goog.dom.TagName.STYLE:
+    case goog.dom.TagName.TRACK:
+    case goog.dom.TagName.WBR:
+      return false;
+  }
+  return true;
+};
+
+
+/**
+ * Appends a child to a node.
+ * @param {Node} parent Parent.
+ * @param {Node} child Child.
+ */
+goog.dom.appendChild = function(parent, child) {
+  parent.appendChild(child);
+};
+
+
+/**
+ * Appends a node with text or other nodes.
+ * @param {!Node} parent The node to append nodes to.
+ * @param {...goog.dom.Appendable} var_args The things to append to the node.
+ *     If this is a Node it is appended as is.
+ *     If this is a string then a text node is appended.
+ *     If this is an array like object then fields 0 to length - 1 are appended.
+ */
+goog.dom.append = function(parent, var_args) {
+  goog.dom.append_(goog.dom.getOwnerDocument(parent), parent, arguments, 1);
+};
+
+
+/**
+ * Removes all the child nodes on a DOM node.
+ * @param {Node} node Node to remove children from.
+ */
+goog.dom.removeChildren = function(node) {
+  // Note: Iterations over live collections can be slow, this is the fastest
+  // we could find. The double parenthesis are used to prevent JsCompiler and
+  // strict warnings.
+  var child;
+  while ((child = node.firstChild)) {
+    node.removeChild(child);
+  }
+};
+
+
+/**
+ * Inserts a new node before an existing reference node (i.e. as the previous
+ * sibling). If the reference node has no parent, then does nothing.
+ * @param {Node} newNode Node to insert.
+ * @param {Node} refNode Reference node to insert before.
+ */
+goog.dom.insertSiblingBefore = function(newNode, refNode) {
+  if (refNode.parentNode) {
+    refNode.parentNode.insertBefore(newNode, refNode);
+  }
+};
+
+
+/**
+ * Inserts a new node after an existing reference node (i.e. as the next
+ * sibling). If the reference node has no parent, then does nothing.
+ * @param {Node} newNode Node to insert.
+ * @param {Node} refNode Reference node to insert after.
+ */
+goog.dom.insertSiblingAfter = function(newNode, refNode) {
+  if (refNode.parentNode) {
+    refNode.parentNode.insertBefore(newNode, refNode.nextSibling);
+  }
+};
+
+
+/**
+ * Insert a child at a given index. If index is larger than the number of child
+ * nodes that the parent currently has, the node is inserted as the last child
+ * node.
+ * @param {Element} parent The element into which to insert the child.
+ * @param {Node} child The element to insert.
+ * @param {number} index The index at which to insert the new child node. Must
+ *     not be negative.
+ */
+goog.dom.insertChildAt = function(parent, child, index) {
+  // Note that if the second argument is null, insertBefore
+  // will append the child at the end of the list of children.
+  parent.insertBefore(child, parent.childNodes[index] || null);
+};
+
+
+/**
+ * Removes a node from its parent.
+ * @param {Node} node The node to remove.
+ * @return {Node} The node removed if removed; else, null.
+ */
+goog.dom.removeNode = function(node) {
+  return node && node.parentNode ? node.parentNode.removeChild(node) : null;
+};
+
+
+/**
+ * Replaces a node in the DOM tree. Will do nothing if {@code oldNode} has no
+ * parent.
+ * @param {Node} newNode Node to insert.
+ * @param {Node} oldNode Node to replace.
+ */
+goog.dom.replaceNode = function(newNode, oldNode) {
+  var parent = oldNode.parentNode;
+  if (parent) {
+    parent.replaceChild(newNode, oldNode);
+  }
+};
+
+
+/**
+ * Flattens an element. That is, removes it and replace it with its children.
+ * Does nothing if the element is not in the document.
+ * @param {Element} element The element to flatten.
+ * @return {Element|undefined} The original element, detached from the document
+ *     tree, sans children; or undefined, if the element was not in the document
+ *     to begin with.
+ */
+goog.dom.flattenElement = function(element) {
+  var child, parent = element.parentNode;
+  if (parent && parent.nodeType != goog.dom.NodeType.DOCUMENT_FRAGMENT) {
+    // Use IE DOM method (supported by Opera too) if available
+    if (element.removeNode) {
+      return /** @type {Element} */ (element.removeNode(false));
+    } else {
+      // Move all children of the original node up one level.
+      while ((child = element.firstChild)) {
+        parent.insertBefore(child, element);
+      }
+
+      // Detach the original element.
+      return /** @type {Element} */ (goog.dom.removeNode(element));
+    }
+  }
+};
+
+
+/**
+ * Returns an array containing just the element children of the given element.
+ * @param {Element} element The element whose element children we want.
+ * @return {!(Array|NodeList)} An array or array-like list of just the element
+ *     children of the given element.
+ */
+goog.dom.getChildren = function(element) {
+  // We check if the children attribute is supported for child elements
+  // since IE8 misuses the attribute by also including comments.
+  if (goog.dom.BrowserFeature.CAN_USE_CHILDREN_ATTRIBUTE &&
+      element.children != undefined) {
+    return element.children;
+  }
+  // Fall back to manually filtering the element's child nodes.
+  return goog.array.filter(element.childNodes, function(node) {
+    return node.nodeType == goog.dom.NodeType.ELEMENT;
+  });
+};
+
+
+/**
+ * Returns the first child node that is an element.
+ * @param {Node} node The node to get the first child element of.
+ * @return {Element} The first child node of {@code node} that is an element.
+ */
+goog.dom.getFirstElementChild = function(node) {
+  if (node.firstElementChild != undefined) {
+    return /** @type {!Element} */(node).firstElementChild;
+  }
+  return goog.dom.getNextElementNode_(node.firstChild, true);
+};
+
+
+/**
+ * Returns the last child node that is an element.
+ * @param {Node} node The node to get the last child element of.
+ * @return {Element} The last child node of {@code node} that is an element.
+ */
+goog.dom.getLastElementChild = function(node) {
+  if (node.lastElementChild != undefined) {
+    return /** @type {!Element} */(node).lastElementChild;
+  }
+  return goog.dom.getNextElementNode_(node.lastChild, false);
+};
+
+
+/**
+ * Returns the first next sibling that is an element.
+ * @param {Node} node The node to get the next sibling element of.
+ * @return {Element} The next sibling of {@code node} that is an element.
+ */
+goog.dom.getNextElementSibling = function(node) {
+  if (node.nextElementSibling != undefined) {
+    return /** @type {!Element} */(node).nextElementSibling;
+  }
+  return goog.dom.getNextElementNode_(node.nextSibling, true);
+};
+
+
+/**
+ * Returns the first previous sibling that is an element.
+ * @param {Node} node The node to get the previous sibling element of.
+ * @return {Element} The first previous sibling of {@code node} that is
+ *     an element.
+ */
+goog.dom.getPreviousElementSibling = function(node) {
+  if (node.previousElementSibling != undefined) {
+    return /** @type {!Element} */(node).previousElementSibling;
+  }
+  return goog.dom.getNextElementNode_(node.previousSibling, false);
+};
+
+
+/**
+ * Returns the first node that is an element in the specified direction,
+ * starting with {@code node}.
+ * @param {Node} node The node to get the next element from.
+ * @param {boolean} forward Whether to look forwards or backwards.
+ * @return {Element} The first element.
+ * @private
+ */
+goog.dom.getNextElementNode_ = function(node, forward) {
+  while (node && node.nodeType != goog.dom.NodeType.ELEMENT) {
+    node = forward ? node.nextSibling : node.previousSibling;
+  }
+
+  return /** @type {Element} */ (node);
+};
+
+
+/**
+ * Returns the next node in source order from the given node.
+ * @param {Node} node The node.
+ * @return {Node} The next node in the DOM tree, or null if this was the last
+ *     node.
+ */
+goog.dom.getNextNode = function(node) {
+  if (!node) {
+    return null;
+  }
+
+  if (node.firstChild) {
+    return node.firstChild;
+  }
+
+  while (node && !node.nextSibling) {
+    node = node.parentNode;
+  }
+
+  return node ? node.nextSibling : null;
+};
+
+
+/**
+ * Returns the previous node in source order from the given node.
+ * @param {Node} node The node.
+ * @return {Node} The previous node in the DOM tree, or null if this was the
+ *     first node.
+ */
+goog.dom.getPreviousNode = function(node) {
+  if (!node) {
+    return null;
+  }
+
+  if (!node.previousSibling) {
+    return node.parentNode;
+  }
+
+  node = node.previousSibling;
+  while (node && node.lastChild) {
+    node = node.lastChild;
+  }
+
+  return node;
+};
+
+
+/**
+ * Whether the object looks like a DOM node.
+ * @param {?} obj The object being tested for node likeness.
+ * @return {boolean} Whether the object looks like a DOM node.
+ */
+goog.dom.isNodeLike = function(obj) {
+  return goog.isObject(obj) && obj.nodeType > 0;
+};
+
+
+/**
+ * Whether the object looks like an Element.
+ * @param {?} obj The object being tested for Element likeness.
+ * @return {boolean} Whether the object looks like an Element.
+ */
+goog.dom.isElement = function(obj) {
+  return goog.isObject(obj) && obj.nodeType == goog.dom.NodeType.ELEMENT;
+};
+
+
+/**
+ * Returns true if the specified value is a Window object. This includes the
+ * global window for HTML pages, and iframe windows.
+ * @param {?} obj Variable to test.
+ * @return {boolean} Whether the variable is a window.
+ */
+goog.dom.isWindow = function(obj) {
+  return goog.isObject(obj) && obj['window'] == obj;
+};
+
+
+/**
+ * Returns an element's parent, if it's an Element.
+ * @param {Element} element The DOM element.
+ * @return {Element} The parent, or null if not an Element.
+ */
+goog.dom.getParentElement = function(element) {
+  var parent;
+  if (goog.dom.BrowserFeature.CAN_USE_PARENT_ELEMENT_PROPERTY) {
+    var isIe9 = goog.userAgent.IE &&
+        goog.userAgent.isVersionOrHigher('9') &&
+        !goog.userAgent.isVersionOrHigher('10');
+    // SVG elements in IE9 can't use the parentElement property.
+    // goog.global['SVGElement'] is not defined in IE9 quirks mode.
+    if (!(isIe9 && goog.global['SVGElement'] &&
+        element instanceof goog.global['SVGElement'])) {
+      parent = element.parentElement;
+      if (parent) {
+        return parent;
+      }
+    }
+  }
+  parent = element.parentNode;
+  return goog.dom.isElement(parent) ? /** @type {!Element} */ (parent) : null;
+};
+
+
+/**
+ * Whether a node contains another node.
+ * @param {Node} parent The node that should contain the other node.
+ * @param {Node} descendant The node to test presence of.
+ * @return {boolean} Whether the parent node contains the descendent node.
+ */
+goog.dom.contains = function(parent, descendant) {
+  // We use browser specific methods for this if available since it is faster
+  // that way.
+
+  // IE DOM
+  if (parent.contains && descendant.nodeType == goog.dom.NodeType.ELEMENT) {
+    return parent == descendant || parent.contains(descendant);
+  }
+
+  // W3C DOM Level 3
+  if (typeof parent.compareDocumentPosition != 'undefined') {
+    return parent == descendant ||
+        Boolean(parent.compareDocumentPosition(descendant) & 16);
+  }
+
+  // W3C DOM Level 1
+  while (descendant && parent != descendant) {
+    descendant = descendant.parentNode;
+  }
+  return descendant == parent;
+};
+
+
+/**
+ * Compares the document order of two nodes, returning 0 if they are the same
+ * node, a negative number if node1 is before node2, and a positive number if
+ * node2 is before node1.  Note that we compare the order the tags appear in the
+ * document so in the tree <b><i>text</i></b> the B node is considered to be
+ * before the I node.
+ *
+ * @param {Node} node1 The first node to compare.
+ * @param {Node} node2 The second node to compare.
+ * @return {number} 0 if the nodes are the same node, a negative number if node1
+ *     is before node2, and a positive number if node2 is before node1.
+ */
+goog.dom.compareNodeOrder = function(node1, node2) {
+  // Fall out quickly for equality.
+  if (node1 == node2) {
+    return 0;
+  }
+
+  // Use compareDocumentPosition where available
+  if (node1.compareDocumentPosition) {
+    // 4 is the bitmask for FOLLOWS.
+    return node1.compareDocumentPosition(node2) & 2 ? 1 : -1;
+  }
+
+  // Special case for document nodes on IE 7 and 8.
+  if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(9)) {
+    if (node1.nodeType == goog.dom.NodeType.DOCUMENT) {
+      return -1;
+    }
+    if (node2.nodeType == goog.dom.NodeType.DOCUMENT) {
+      return 1;
+    }
+  }
+
+  // Process in IE using sourceIndex - we check to see if the first node has
+  // a source index or if its parent has one.
+  if ('sourceIndex' in node1 ||
+      (node1.parentNode && 'sourceIndex' in node1.parentNode)) {
+    var isElement1 = node1.nodeType == goog.dom.NodeType.ELEMENT;
+    var isElement2 = node2.nodeType == goog.dom.NodeType.ELEMENT;
+
+    if (isElement1 && isElement2) {
+      return node1.sourceIndex - node2.sourceIndex;
+    } else {
+      var parent1 = node1.parentNode;
+      var parent2 = node2.parentNode;
+
+      if (parent1 == parent2) {
+        return goog.dom.compareSiblingOrder_(node1, node2);
+      }
+
+      if (!isElement1 && goog.dom.contains(parent1, node2)) {
+        return -1 * goog.dom.compareParentsDescendantNodeIe_(node1, node2);
+      }
+
+
+      if (!isElement2 && goog.dom.contains(parent2, node1)) {
+        return goog.dom.compareParentsDescendantNodeIe_(node2, node1);
+      }
+
+      return (isElement1 ? node1.sourceIndex : parent1.sourceIndex) -
+             (isElement2 ? node2.sourceIndex : parent2.sourceIndex);
+    }
+  }
+
+  // For Safari, we compare ranges.
+  var doc = goog.dom.getOwnerDocument(node1);
+
+  var range1, range2;
+  range1 = doc.createRange();
+  range1.selectNode(node1);
+  range1.collapse(true);
+
+  range2 = doc.createRange();
+  range2.selectNode(node2);
+  range2.collapse(true);
+
+  return range1.compareBoundaryPoints(goog.global['Range'].START_TO_END,
+      range2);
+};
+
+
+/**
+ * Utility function to compare the position of two nodes, when
+ * {@code textNode}'s parent is an ancestor of {@code node}.  If this entry
+ * condition is not met, this function will attempt to reference a null object.
+ * @param {!Node} textNode The textNode to compare.
+ * @param {Node} node The node to compare.
+ * @return {number} -1 if node is before textNode, +1 otherwise.
+ * @private
+ */
+goog.dom.compareParentsDescendantNodeIe_ = function(textNode, node) {
+  var parent = textNode.parentNode;
+  if (parent == node) {
+    // If textNode is a child of node, then node comes first.
+    return -1;
+  }
+  var sibling = node;
+  while (sibling.parentNode != parent) {
+    sibling = sibling.parentNode;
+  }
+  return goog.dom.compareSiblingOrder_(sibling, textNode);
+};
+
+
+/**
+ * Utility function to compare the position of two nodes known to be non-equal
+ * siblings.
+ * @param {Node} node1 The first node to compare.
+ * @param {!Node} node2 The second node to compare.
+ * @return {number} -1 if node1 is before node2, +1 otherwise.
+ * @private
+ */
+goog.dom.compareSiblingOrder_ = function(node1, node2) {
+  var s = node2;
+  while ((s = s.previousSibling)) {
+    if (s == node1) {
+      // We just found node1 before node2.
+      return -1;
+    }
+  }
+
+  // Since we didn't find it, node1 must be after node2.
+  return 1;
+};
+
+
+/**
+ * Find the deepest common ancestor of the given nodes.
+ * @param {...Node} var_args The nodes to find a common ancestor of.
+ * @return {Node} The common ancestor of the nodes, or null if there is none.
+ *     null will only be returned if two or more of the nodes are from different
+ *     documents.
+ */
+goog.dom.findCommonAncestor = function(var_args) {
+  var i, count = arguments.length;
+  if (!count) {
+    return null;
+  } else if (count == 1) {
+    return arguments[0];
+  }
+
+  var paths = [];
+  var minLength = Infinity;
+  for (i = 0; i < count; i++) {
+    // Compute the list of ancestors.
+    var ancestors = [];
+    var node = arguments[i];
+    while (node) {
+      ancestors.unshift(node);
+      node = node.parentNode;
+    }
+
+    // Save the list for comparison.
+    paths.push(ancestors);
+    minLength = Math.min(minLength, ancestors.length);
+  }
+  var output = null;
+  for (i = 0; i < minLength; i++) {
+    var first = paths[0][i];
+    for (var j = 1; j < count; j++) {
+      if (first != paths[j][i]) {
+        return output;
+      }
+    }
+    output = first;
+  }
+  return output;
+};
+
+
+/**
+ * Returns the owner document for a node.
+ * @param {Node|Window} node The node to get the document for.
+ * @return {!Document} The document owning the node.
+ */
+goog.dom.getOwnerDocument = function(node) {
+  // TODO(nnaze): Update param signature to be non-nullable.
+  goog.asserts.assert(node, 'Node cannot be null or undefined.');
+  return /** @type {!Document} */ (
+      node.nodeType == goog.dom.NodeType.DOCUMENT ? node :
+      node.ownerDocument || node.document);
+};
+
+
+/**
+ * Cross-browser function for getting the document element of a frame or iframe.
+ * @param {Element} frame Frame element.
+ * @return {!Document} The frame content document.
+ */
+goog.dom.getFrameContentDocument = function(frame) {
+  var doc = frame.contentDocument || frame.contentWindow.document;
+  return doc;
+};
+
+
+/**
+ * Cross-browser function for getting the window of a frame or iframe.
+ * @param {Element} frame Frame element.
+ * @return {Window} The window associated with the given frame.
+ */
+goog.dom.getFrameContentWindow = function(frame) {
+  return frame.contentWindow ||
+      goog.dom.getWindow(goog.dom.getFrameContentDocument(frame));
+};
+
+
+/**
+ * Sets the text content of a node, with cross-browser support.
+ * @param {Node} node The node to change the text content of.
+ * @param {string|number} text The value that should replace the node's content.
+ */
+goog.dom.setTextContent = function(node, text) {
+  goog.asserts.assert(node != null,
+      'goog.dom.setTextContent expects a non-null value for node');
+
+  if ('textContent' in node) {
+    node.textContent = text;
+  } else if (node.nodeType == goog.dom.NodeType.TEXT) {
+    node.data = text;
+  } else if (node.firstChild &&
+             node.firstChild.nodeType == goog.dom.NodeType.TEXT) {
+    // If the first child is a text node we just change its data and remove the
+    // rest of the children.
+    while (node.lastChild != node.firstChild) {
+      node.removeChild(node.lastChild);
+    }
+    node.firstChild.data = text;
+  } else {
+    goog.dom.removeChildren(node);
+    var doc = goog.dom.getOwnerDocument(node);
+    node.appendChild(doc.createTextNode(String(text)));
+  }
+};
+
+
+/**
+ * Gets the outerHTML of a node, which islike innerHTML, except that it
+ * actually contains the HTML of the node itself.
+ * @param {Element} element The element to get the HTML of.
+ * @return {string} The outerHTML of the given element.
+ */
+goog.dom.getOuterHtml = function(element) {
+  // IE, Opera and WebKit all have outerHTML.
+  if ('outerHTML' in element) {
+    return element.outerHTML;
+  } else {
+    var doc = goog.dom.getOwnerDocument(element);
+    var div = doc.createElement(goog.dom.TagName.DIV);
+    div.appendChild(element.cloneNode(true));
+    return div.innerHTML;
+  }
+};
+
+
+/**
+ * Finds the first descendant node that matches the filter function, using
+ * a depth first search. This function offers the most general purpose way
+ * of finding a matching element. You may also wish to consider
+ * {@code goog.dom.query} which can express many matching criteria using
+ * CSS selector expressions. These expressions often result in a more
+ * compact representation of the desired result.
+ * @see goog.dom.query
+ *
+ * @param {Node} root The root of the tree to search.
+ * @param {function(Node) : boolean} p The filter function.
+ * @return {Node|undefined} The found node or undefined if none is found.
+ */
+goog.dom.findNode = function(root, p) {
+  var rv = [];
+  var found = goog.dom.findNodes_(root, p, rv, true);
+  return found ? rv[0] : undefined;
+};
+
+
+/**
+ * Finds all the descendant nodes that match the filter function, using a
+ * a depth first search. This function offers the most general-purpose way
+ * of finding a set of matching elements. You may also wish to consider
+ * {@code goog.dom.query} which can express many matching criteria using
+ * CSS selector expressions. These expressions often result in a more
+ * compact representation of the desired result.
+
+ * @param {Node} root The root of the tree to search.
+ * @param {function(Node) : boolean} p The filter function.
+ * @return {!Array<!Node>} The found nodes or an empty array if none are found.
+ */
+goog.dom.findNodes = function(root, p) {
+  var rv = [];
+  goog.dom.findNodes_(root, p, rv, false);
+  return rv;
+};
+
+
+/**
+ * Finds the first or all the descendant nodes that match the filter function,
+ * using a depth first search.
+ * @param {Node} root The root of the tree to search.
+ * @param {function(Node) : boolean} p The filter function.
+ * @param {!Array<!Node>} rv The found nodes are added to this array.
+ * @param {boolean} findOne If true we exit after the first found node.
+ * @return {boolean} Whether the search is complete or not. True in case findOne
+ *     is true and the node is found. False otherwise.
+ * @private
+ */
+goog.dom.findNodes_ = function(root, p, rv, findOne) {
+  if (root != null) {
+    var child = root.firstChild;
+    while (child) {
+      if (p(child)) {
+        rv.push(child);
+        if (findOne) {
+          return true;
+        }
+      }
+      if (goog.dom.findNodes_(child, p, rv, findOne)) {
+        return true;
+      }
+      child = child.nextSibling;
+    }
+  }
+  return false;
+};
+
+
+/**
+ * Map of tags whose content to ignore when calculating text length.
+ * @private {!Object<string, number>}
+ * @const
+ */
+goog.dom.TAGS_TO_IGNORE_ = {
+  'SCRIPT': 1,
+  'STYLE': 1,
+  'HEAD': 1,
+  'IFRAME': 1,
+  'OBJECT': 1
+};
+
+
+/**
+ * Map of tags which have predefined values with regard to whitespace.
+ * @private {!Object<string, string>}
+ * @const
+ */
+goog.dom.PREDEFINED_TAG_VALUES_ = {'IMG': ' ', 'BR': '\n'};
+
+
+/**
+ * Returns true if the element has a tab index that allows it to receive
+ * keyboard focus (tabIndex >= 0), false otherwise.  Note that some elements
+ * natively support keyboard focus, even if they have no tab index.
+ * @param {!Element} element Element to check.
+ * @return {boolean} Whether the element has a tab index that allows keyboard
+ *     focus.
+ * @see http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
+ */
+goog.dom.isFocusableTabIndex = function(element) {
+  return goog.dom.hasSpecifiedTabIndex_(element) &&
+         goog.dom.isTabIndexFocusable_(element);
+};
+
+
+/**
+ * Enables or disables keyboard focus support on the element via its tab index.
+ * Only elements for which {@link goog.dom.isFocusableTabIndex} returns true
+ * (or elements that natively support keyboard focus, like form elements) can
+ * receive keyboard focus.  See http://go/tabindex for more info.
+ * @param {Element} element Element whose tab index is to be changed.
+ * @param {boolean} enable Whether to set or remove a tab index on the element
+ *     that supports keyboard focus.
+ */
+goog.dom.setFocusableTabIndex = function(element, enable) {
+  if (enable) {
+    element.tabIndex = 0;
+  } else {
+    // Set tabIndex to -1 first, then remove it. This is a workaround for
+    // Safari (confirmed in version 4 on Windows). When removing the attribute
+    // without setting it to -1 first, the element remains keyboard focusable
+    // despite not having a tabIndex attribute anymore.
+    element.tabIndex = -1;
+    element.removeAttribute('tabIndex'); // Must be camelCase!
+  }
+};
+
+
+/**
+ * Returns true if the element can be focused, i.e. it has a tab index that
+ * allows it to receive keyboard focus (tabIndex >= 0), or it is an element
+ * that natively supports keyboard focus.
+ * @param {!Element} element Element to check.
+ * @return {boolean} Whether the element allows keyboard focus.
+ */
+goog.dom.isFocusable = function(element) {
+  var focusable;
+  // Some elements can have unspecified tab index and still receive focus.
+  if (goog.dom.nativelySupportsFocus_(element)) {
+    // Make sure the element is not disabled ...
+    focusable = !element.disabled &&
+        // ... and if a tab index is specified, it allows focus.
+        (!goog.dom.hasSpecifiedTabIndex_(element) ||
+         goog.dom.isTabIndexFocusable_(element));
+  } else {
+    focusable = goog.dom.isFocusableTabIndex(element);
+  }
+
+  // IE requires elements to be visible in order to focus them.
+  return focusable && goog.userAgent.IE ?
+             goog.dom.hasNonZeroBoundingRect_(element) : focusable;
+};
+
+
+/**
+ * Returns true if the element has a specified tab index.
+ * @param {!Element} element Element to check.
+ * @return {boolean} Whether the element has a specified tab index.
+ * @private
+ */
+goog.dom.hasSpecifiedTabIndex_ = function(element) {
+  // IE returns 0 for an unset tabIndex, so we must use getAttributeNode(),
+  // which returns an object with a 'specified' property if tabIndex is
+  // specified.  This works on other browsers, too.
+  var attrNode = element.getAttributeNode('tabindex'); // Must be lowercase!
+  return goog.isDefAndNotNull(attrNode) && attrNode.specified;
+};
+
+
+/**
+ * Returns true if the element's tab index allows the element to be focused.
+ * @param {!Element} element Element to check.
+ * @return {boolean} Whether the element's tab index allows focus.
+ * @private
+ */
+goog.dom.isTabIndexFocusable_ = function(element) {
+  var index = element.tabIndex;
+  // NOTE: IE9 puts tabIndex in 16-bit int, e.g. -2 is 65534.
+  return goog.isNumber(index) && index >= 0 && index < 32768;
+};
+
+
+/**
+ * Returns true if the element is focusable even when tabIndex is not set.
+ * @param {!Element} element Element to check.
+ * @return {boolean} Whether the element natively supports focus.
+ * @private
+ */
+goog.dom.nativelySupportsFocus_ = function(element) {
+  return element.tagName == goog.dom.TagName.A ||
+         element.tagName == goog.dom.TagName.INPUT ||
+         element.tagName == goog.dom.TagName.TEXTAREA ||
+         element.tagName == goog.dom.TagName.SELECT ||
+         element.tagName == goog.dom.TagName.BUTTON;
+};
+
+
+/**
+ * Returns true if the element has a bounding rectangle that would be visible
+ * (i.e. its width and height are greater than zero).
+ * @param {!Element} element Element to check.
+ * @return {boolean} Whether the element has a non-zero bounding rectangle.
+ * @private
+ */
+goog.dom.hasNonZeroBoundingRect_ = function(element) {
+  var rect = goog.isFunction(element['getBoundingClientRect']) ?
+      element.getBoundingClientRect() :
+      {'height': element.offsetHeight, 'width': element.offsetWidth};
+  return goog.isDefAndNotNull(rect) && rect.height > 0 && rect.width > 0;
+};
+
+
+/**
+ * Returns the text content of the current node, without markup and invisible
+ * symbols. New lines are stripped and whitespace is collapsed,
+ * such that each character would be visible.
+ *
+ * In browsers that support it, innerText is used.  Other browsers attempt to
+ * simulate it via node traversal.  Line breaks are canonicalized in IE.
+ *
+ * @param {Node} node The node from which we are getting content.
+ * @return {string} The text content.
+ */
+goog.dom.getTextContent = function(node) {
+  var textContent;
+  // Note(arv): IE9, Opera, and Safari 3 support innerText but they include
+  // text nodes in script tags. So we revert to use a user agent test here.
+  if (goog.dom.BrowserFeature.CAN_USE_INNER_TEXT && ('innerText' in node)) {
+    textContent = goog.string.canonicalizeNewlines(node.innerText);
+    // Unfortunately .innerText() returns text with &shy; symbols
+    // We need to filter it out and then remove duplicate whitespaces
+  } else {
+    var buf = [];
+    goog.dom.getTextContent_(node, buf, true);
+    textContent = buf.join('');
+  }
+
+  // Strip &shy; entities. goog.format.insertWordBreaks inserts them in Opera.
+  textContent = textContent.replace(/ \xAD /g, ' ').replace(/\xAD/g, '');
+  // Strip &#8203; entities. goog.format.insertWordBreaks inserts them in IE8.
+  textContent = textContent.replace(/\u200B/g, '');
+
+  // Skip this replacement on old browsers with working innerText, which
+  // automatically turns &nbsp; into ' ' and / +/ into ' ' when reading
+  // innerText.
+  if (!goog.dom.BrowserFeature.CAN_USE_INNER_TEXT) {
+    textContent = textContent.replace(/ +/g, ' ');
+  }
+  if (textContent != ' ') {
+    textContent = textContent.replace(/^\s*/, '');
+  }
+
+  return textContent;
+};
+
+
+/**
+ * Returns the text content of the current node, without markup.
+ *
+ * Unlike {@code getTextContent} this method does not collapse whitespaces
+ * or normalize lines breaks.
+ *
+ * @param {Node} node The node from which we are getting content.
+ * @return {string} The raw text content.
+ */
+goog.dom.getRawTextContent = function(node) {
+  var buf = [];
+  goog.dom.getTextContent_(node, buf, false);
+
+  return buf.join('');
+};
+
+
+/**
+ * Recursive support function for text content retrieval.
+ *
+ * @param {Node} node The node from which we are getting content.
+ * @param {Array<string>} buf string buffer.
+ * @param {boolean} normalizeWhitespace Whether to normalize whitespace.
+ * @private
+ */
+goog.dom.getTextContent_ = function(node, buf, normalizeWhitespace) {
+  if (node.nodeName in goog.dom.TAGS_TO_IGNORE_) {
+    // ignore certain tags
+  } else if (node.nodeType == goog.dom.NodeType.TEXT) {
+    if (normalizeWhitespace) {
+      buf.push(String(node.nodeValue).replace(/(\r\n|\r|\n)/g, ''));
+    } else {
+      buf.push(node.nodeValue);
+    }
+  } else if (node.nodeName in goog.dom.PREDEFINED_TAG_VALUES_) {
+    buf.push(goog.dom.PREDEFINED_TAG_VALUES_[node.nodeName]);
+  } else {
+    var child = node.firstChild;
+    while (child) {
+      goog.dom.getTextContent_(child, buf, normalizeWhitespace);
+      child = child.nextSibling;
+    }
+  }
+};
+
+
+/**
+ * Returns the text length of the text contained in a node, without markup. This
+ * is equivalent to the selection length if the node was selected, or the number
+ * of cursor movements to traverse the node. Images & BRs take one space.  New
+ * lines are ignored.
+ *
+ * @param {Node} node The node whose text content length is being calculated.
+ * @return {number} The length of {@code node}'s text content.
+ */
+goog.dom.getNodeTextLength = function(node) {
+  return goog.dom.getTextContent(node).length;
+};
+
+
+/**
+ * Returns the text offset of a node relative to one of its ancestors. The text
+ * length is the same as the length calculated by goog.dom.getNodeTextLength.
+ *
+ * @param {Node} node The node whose offset is being calculated.
+ * @param {Node=} opt_offsetParent The node relative to which the offset will
+ *     be calculated. Defaults to the node's owner document's body.
+ * @return {number} The text offset.
+ */
+goog.dom.getNodeTextOffset = function(node, opt_offsetParent) {
+  var root = opt_offsetParent || goog.dom.getOwnerDocument(node).body;
+  var buf = [];
+  while (node && node != root) {
+    var cur = node;
+    while ((cur = cur.previousSibling)) {
+      buf.unshift(goog.dom.getTextContent(cur));
+    }
+    node = node.parentNode;
+  }
+  // Trim left to deal with FF cases when there might be line breaks and empty
+  // nodes at the front of the text
+  return goog.string.trimLeft(buf.join('')).replace(/ +/g, ' ').length;
+};
+
+
+/**
+ * Returns the node at a given offset in a parent node.  If an object is
+ * provided for the optional third parameter, the node and the remainder of the
+ * offset will stored as properties of this object.
+ * @param {Node} parent The parent node.
+ * @param {number} offset The offset into the parent node.
+ * @param {Object=} opt_result Object to be used to store the return value. The
+ *     return value will be stored in the form {node: Node, remainder: number}
+ *     if this object is provided.
+ * @return {Node} The node at the given offset.
+ */
+goog.dom.getNodeAtOffset = function(parent, offset, opt_result) {
+  var stack = [parent], pos = 0, cur = null;
+  while (stack.length > 0 && pos < offset) {
+    cur = stack.pop();
+    if (cur.nodeName in goog.dom.TAGS_TO_IGNORE_) {
+      // ignore certain tags
+    } else if (cur.nodeType == goog.dom.NodeType.TEXT) {
+      var text = cur.nodeValue.replace(/(\r\n|\r|\n)/g, '').replace(/ +/g, ' ');
+      pos += text.length;
+    } else if (cur.nodeName in goog.dom.PREDEFINED_TAG_VALUES_) {
+      pos += goog.dom.PREDEFINED_TAG_VALUES_[cur.nodeName].length;
+    } else {
+      for (var i = cur.childNodes.length - 1; i >= 0; i--) {
+        stack.push(cur.childNodes[i]);
+      }
+    }
+  }
+  if (goog.isObject(opt_result)) {
+    opt_result.remainder = cur ? cur.nodeValue.length + offset - pos - 1 : 0;
+    opt_result.node = cur;
+  }
+
+  return cur;
+};
+
+
+/**
+ * Returns true if the object is a {@code NodeList}.  To qualify as a NodeList,
+ * the object must have a numeric length property and an item function (which
+ * has type 'string' on IE for some reason).
+ * @param {Object} val Object to test.
+ * @return {boolean} Whether the object is a NodeList.
+ */
+goog.dom.isNodeList = function(val) {
+  // TODO(attila): Now the isNodeList is part of goog.dom we can use
+  // goog.userAgent to make this simpler.
+  // A NodeList must have a length property of type 'number' on all platforms.
+  if (val && typeof val.length == 'number') {
+    // A NodeList is an object everywhere except Safari, where it's a function.
+    if (goog.isObject(val)) {
+      // A NodeList must have an item function (on non-IE platforms) or an item
+      // property of type 'string' (on IE).
+      return typeof val.item == 'function' || typeof val.item == 'string';
+    } else if (goog.isFunction(val)) {
+      // On Safari, a NodeList is a function with an item property that is also
+      // a function.
+      return typeof val.item == 'function';
+    }
+  }
+
+  // Not a NodeList.
+  return false;
+};
+
+
+/**
+ * Walks up the DOM hierarchy returning the first ancestor that has the passed
+ * tag name and/or class name. If the passed element matches the specified
+ * criteria, the element itself is returned.
+ * @param {Node} element The DOM node to start with.
+ * @param {?(goog.dom.TagName|string)=} opt_tag The tag name to match (or
+ *     null/undefined to match only based on class name).
+ * @param {?string=} opt_class The class name to match (or null/undefined to
+ *     match only based on tag name).
+ * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the
+ *     dom.
+ * @return {Element} The first ancestor that matches the passed criteria, or
+ *     null if no match is found.
+ */
+goog.dom.getAncestorByTagNameAndClass = function(element, opt_tag, opt_class,
+    opt_maxSearchSteps) {
+  if (!opt_tag && !opt_class) {
+    return null;
+  }
+  var tagName = opt_tag ? opt_tag.toUpperCase() : null;
+  return /** @type {Element} */ (goog.dom.getAncestor(element,
+      function(node) {
+        return (!tagName || node.nodeName == tagName) &&
+               (!opt_class || goog.isString(node.className) &&
+                   goog.array.contains(node.className.split(/\s+/), opt_class));
+      }, true, opt_maxSearchSteps));
+};
+
+
+/**
+ * Walks up the DOM hierarchy returning the first ancestor that has the passed
+ * class name. If the passed element matches the specified criteria, the
+ * element itself is returned.
+ * @param {Node} element The DOM node to start with.
+ * @param {string} className The class name to match.
+ * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the
+ *     dom.
+ * @return {Element} The first ancestor that matches the passed criteria, or
+ *     null if none match.
+ */
+goog.dom.getAncestorByClass = function(element, className, opt_maxSearchSteps) {
+  return goog.dom.getAncestorByTagNameAndClass(element, null, className,
+      opt_maxSearchSteps);
+};
+
+
+/**
+ * Walks up the DOM hierarchy returning the first ancestor that passes the
+ * matcher function.
+ * @param {Node} element The DOM node to start with.
+ * @param {function(Node) : boolean} matcher A function that returns true if the
+ *     passed node matches the desired criteria.
+ * @param {boolean=} opt_includeNode If true, the node itself is included in
+ *     the search (the first call to the matcher will pass startElement as
+ *     the node to test).
+ * @param {number=} opt_maxSearchSteps Maximum number of levels to search up the
+ *     dom.
+ * @return {Node} DOM node that matched the matcher, or null if there was
+ *     no match.
+ */
+goog.dom.getAncestor = function(
+    element, matcher, opt_includeNode, opt_maxSearchSteps) {
+  if (!opt_includeNode) {
+    element = element.parentNode;
+  }
+  var ignoreSearchSteps = opt_maxSearchSteps == null;
+  var steps = 0;
+  while (element && (ignoreSearchSteps || steps <= opt_maxSearchSteps)) {
+    goog.asserts.assert(element.name != 'parentNode');
+    if (matcher(element)) {
+      return element;
+    }
+    element = element.parentNode;
+    steps++;
+  }
+  // Reached the root of the DOM without a match
+  return null;
+};
+
+
+/**
+ * Determines the active element in the given document.
+ * @param {Document} doc The document to look in.
+ * @return {Element} The active element.
+ */
+goog.dom.getActiveElement = function(doc) {
+  try {
+    return doc && doc.activeElement;
+  } catch (e) {
+    // NOTE(nicksantos): Sometimes, evaluating document.activeElement in IE
+    // throws an exception. I'm not 100% sure why, but I suspect it chokes
+    // on document.activeElement if the activeElement has been recently
+    // removed from the DOM by a JS operation.
+    //
+    // We assume that an exception here simply means
+    // "there is no active element."
+  }
+
+  return null;
+};
+
+
+/**
+ * Gives the current devicePixelRatio.
+ *
+ * By default, this is the value of window.devicePixelRatio (which should be
+ * preferred if present).
+ *
+ * If window.devicePixelRatio is not present, the ratio is calculated with
+ * window.matchMedia, if present. Otherwise, gives 1.0.
+ *
+ * Some browsers (including Chrome) consider the browser zoom level in the pixel
+ * ratio, so the value may change across multiple calls.
+ *
+ * @return {number} The number of actual pixels per virtual pixel.
+ */
+goog.dom.getPixelRatio = function() {
+  var win = goog.dom.getWindow();
+
+  // devicePixelRatio does not work on Mobile firefox.
+  // TODO(user): Enable this check on a known working mobile Gecko version.
+  // Filed a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=896804
+  var isFirefoxMobile = goog.userAgent.GECKO && goog.userAgent.MOBILE;
+
+  if (goog.isDef(win.devicePixelRatio) && !isFirefoxMobile) {
+    return win.devicePixelRatio;
+  } else if (win.matchMedia) {
+    return goog.dom.matchesPixelRatio_(.75) ||
+           goog.dom.matchesPixelRatio_(1.5) ||
+           goog.dom.matchesPixelRatio_(2) ||
+           goog.dom.matchesPixelRatio_(3) || 1;
+  }
+  return 1;
+};
+
+
+/**
+ * Calculates a mediaQuery to check if the current device supports the
+ * given actual to virtual pixel ratio.
+ * @param {number} pixelRatio The ratio of actual pixels to virtual pixels.
+ * @return {number} pixelRatio if applicable, otherwise 0.
+ * @private
+ */
+goog.dom.matchesPixelRatio_ = function(pixelRatio) {
+  var win = goog.dom.getWindow();
+  var query = ('(-webkit-min-device-pixel-ratio: ' + pixelRatio + '),' +
+               '(min--moz-device-pixel-ratio: ' + pixelRatio + '),' +
+               '(min-resolution: ' + pixelRatio + 'dppx)');
+  return win.matchMedia(query).matches ? pixelRatio : 0;
+};
+
+
+
+/**
+ * Create an instance of a DOM helper with a new document object.
+ * @param {Document=} opt_document Document object to associate with this
+ *     DOM helper.
+ * @constructor
+ */
+goog.dom.DomHelper = function(opt_document) {
+  /**
+   * Reference to the document object to use
+   * @type {!Document}
+   * @private
+   */
+  this.document_ = opt_document || goog.global.document || document;
+};
+
+
+/**
+ * Gets the dom helper object for the document where the element resides.
+ * @param {Node=} opt_node If present, gets the DomHelper for this node.
+ * @return {!goog.dom.DomHelper} The DomHelper.
+ */
+goog.dom.DomHelper.prototype.getDomHelper = goog.dom.getDomHelper;
+
+
+/**
+ * Sets the document object.
+ * @param {!Document} document Document object.
+ */
+goog.dom.DomHelper.prototype.setDocument = function(document) {
+  this.document_ = document;
+};
+
+
+/**
+ * Gets the document object being used by the dom library.
+ * @return {!Document} Document object.
+ */
+goog.dom.DomHelper.prototype.getDocument = function() {
+  return this.document_;
+};
+
+
+/**
+ * Alias for {@code getElementById}. If a DOM node is passed in then we just
+ * return that.
+ * @param {string|Element} element Element ID or a DOM node.
+ * @return {Element} The element with the given ID, or the node passed in.
+ */
+goog.dom.DomHelper.prototype.getElement = function(element) {
+  return goog.dom.getElementHelper_(this.document_, element);
+};
+
+
+/**
+ * Gets an element by id, asserting that the element is found.
+ *
+ * This is used when an element is expected to exist, and should fail with
+ * an assertion error if it does not (if assertions are enabled).
+ *
+ * @param {string} id Element ID.
+ * @return {!Element} The element with the given ID, if it exists.
+ */
+goog.dom.DomHelper.prototype.getRequiredElement = function(id) {
+  return goog.dom.getRequiredElementHelper_(this.document_, id);
+};
+
+
+/**
+ * Alias for {@code getElement}.
+ * @param {string|Element} element Element ID or a DOM node.
+ * @return {Element} The element with the given ID, or the node passed in.
+ * @deprecated Use {@link goog.dom.DomHelper.prototype.getElement} instead.
+ */
+goog.dom.DomHelper.prototype.$ = goog.dom.DomHelper.prototype.getElement;
+
+
+/**
+ * Looks up elements by both tag and class name, using browser native functions
+ * ({@code querySelectorAll}, {@code getElementsByTagName} or
+ * {@code getElementsByClassName}) where possible. The returned array is a live
+ * NodeList or a static list depending on the code path taken.
+ *
+ * @see goog.dom.query
+ *
+ * @param {?string=} opt_tag Element tag name or * for all tags.
+ * @param {?string=} opt_class Optional class name.
+ * @param {(Document|Element)=} opt_el Optional element to look in.
+ * @return { {length: number} } Array-like list of elements (only a length
+ *     property and numerical indices are guaranteed to exist).
+ */
+goog.dom.DomHelper.prototype.getElementsByTagNameAndClass = function(opt_tag,
+                                                                     opt_class,
+                                                                     opt_el) {
+  return goog.dom.getElementsByTagNameAndClass_(this.document_, opt_tag,
+                                                opt_class, opt_el);
+};
+
+
+/**
+ * Returns an array of all the elements with the provided className.
+ * @see {goog.dom.query}
+ * @param {string} className the name of the class to look for.
+ * @param {Element|Document=} opt_el Optional element to look in.
+ * @return { {length: number} } The items found with the class name provided.
+ */
+goog.dom.DomHelper.prototype.getElementsByClass = function(className, opt_el) {
+  var doc = opt_el || this.document_;
+  return goog.dom.getElementsByClass(className, doc);
+};
+
+
+/**
+ * Returns the first element we find matching the provided class name.
+ * @see {goog.dom.query}
+ * @param {string} className the name of the class to look for.
+ * @param {(Element|Document)=} opt_el Optional element to look in.
+ * @return {Element} The first item found with the class name provided.
+ */
+goog.dom.DomHelper.prototype.getElementByClass = function(className, opt_el) {
+  var doc = opt_el || this.document_;
+  return goog.dom.getElementByClass(className, doc);
+};
+
+
+/**
+ * Ensures an element with the given className exists, and then returns the
+ * first element with the provided className.
+ * @see {goog.dom.query}
+ * @param {string} className the name of the class to look for.
+ * @param {(!Element|!Document)=} opt_root Optional element or document to look
+ *     in.
+ * @return {!Element} The first item found with the class name provided.
+ * @throws {goog.asserts.AssertionError} Thrown if no element is found.
+ */
+goog.dom.DomHelper.prototype.getRequiredElementByClass = function(className,
+                                                                  opt_root) {
+  var root = opt_root || this.document_;
+  return goog.dom.getRequiredElementByClass(className, root);
+};
+
+
+/**
+ * Alias for {@code getElementsByTagNameAndClass}.
+ * @deprecated Use DomHelper getElementsByTagNameAndClass.
+ * @see goog.dom.query
+ *
+ * @param {?string=} opt_tag Element tag name.
+ * @param {?string=} opt_class Optional class name.
+ * @param {Element=} opt_el Optional element to look in.
+ * @return { {length: number} } Array-like list of elements (only a length
+ *     property and numerical indices are guaranteed to exist).
+ */
+goog.dom.DomHelper.prototype.$$ =
+    goog.dom.DomHelper.prototype.getElementsByTagNameAndClass;
+
+
+/**
+ * Sets a number of properties on a node.
+ * @param {Element} element DOM node to set properties on.
+ * @param {Object} properties Hash of property:value pairs.
+ */
+goog.dom.DomHelper.prototype.setProperties = goog.dom.setProperties;
+
+
+/**
+ * Gets the dimensions of the viewport.
+ * @param {Window=} opt_window Optional window element to test. Defaults to
+ *     the window of the Dom Helper.
+ * @return {!goog.math.Size} Object with values 'width' and 'height'.
+ */
+goog.dom.DomHelper.prototype.getViewportSize = function(opt_window) {
+  // TODO(arv): This should not take an argument. That breaks the rule of a
+  // a DomHelper representing a single frame/window/document.
+  return goog.dom.getViewportSize(opt_window || this.getWindow());
+};
+
+
+/**
+ * Calculates the height of the document.
+ *
+ * @return {number} The height of the document.
+ */
+goog.dom.DomHelper.prototype.getDocumentHeight = function() {
+  return goog.dom.getDocumentHeight_(this.getWindow());
+};
+
+
+/**
+ * Typedef for use with goog.dom.createDom and goog.dom.append.
+ * @typedef {Object|string|Array|NodeList}
+ */
+goog.dom.Appendable;
+
+
+/**
+ * Returns a dom node with a set of attributes.  This function accepts varargs
+ * for subsequent nodes to be added.  Subsequent nodes will be added to the
+ * first node as childNodes.
+ *
+ * So:
+ * <code>createDom('div', null, createDom('p'), createDom('p'));</code>
+ * would return a div with two child paragraphs
+ *
+ * An easy way to move all child nodes of an existing element to a new parent
+ * element is:
+ * <code>createDom('div', null, oldElement.childNodes);</code>
+ * which will remove all child nodes from the old element and add them as
+ * child nodes of the new DIV.
+ *
+ * @param {string} tagName Tag to create.
+ * @param {Object|string=} opt_attributes If object, then a map of name-value
+ *     pairs for attributes. If a string, then this is the className of the new
+ *     element.
+ * @param {...goog.dom.Appendable} var_args Further DOM nodes or
+ *     strings for text nodes. If one of the var_args is an array or
+ *     NodeList, its elements will be added as childNodes instead.
+ * @return {!Element} Reference to a DOM node.
+ */
+goog.dom.DomHelper.prototype.createDom = function(tagName,
+                                                  opt_attributes,
+                                                  var_args) {
+  return goog.dom.createDom_(this.document_, arguments);
+};
+
+
+/**
+ * Alias for {@code createDom}.
+ * @param {string} tagName Tag to create.
+ * @param {(Object|string)=} opt_attributes If object, then a map of name-value
+ *     pairs for attributes. If a string, then this is the className of the new
+ *     element.
+ * @param {...goog.dom.Appendable} var_args Further DOM nodes or strings for
+ *     text nodes.  If one of the var_args is an array, its children will be
+ *     added as childNodes instead.
+ * @return {!Element} Reference to a DOM node.
+ * @deprecated Use {@link goog.dom.DomHelper.prototype.createDom} instead.
+ */
+goog.dom.DomHelper.prototype.$dom = goog.dom.DomHelper.prototype.createDom;
+
+
+/**
+ * Creates a new element.
+ * @param {string} name Tag name.
+ * @return {!Element} The new element.
+ */
+goog.dom.DomHelper.prototype.createElement = function(name) {
+  return this.document_.createElement(name);
+};
+
+
+/**
+ * Creates a new text node.
+ * @param {number|string} content Content.
+ * @return {!Text} The new text node.
+ */
+goog.dom.DomHelper.prototype.createTextNode = function(content) {
+  return this.document_.createTextNode(String(content));
+};
+
+
+/**
+ * Create a table.
+ * @param {number} rows The number of rows in the table.  Must be >= 1.
+ * @param {number} columns The number of columns in the table.  Must be >= 1.
+ * @param {boolean=} opt_fillWithNbsp If true, fills table entries with
+ *     {@code goog.string.Unicode.NBSP} characters.
+ * @return {!HTMLElement} The created table.
+ */
+goog.dom.DomHelper.prototype.createTable = function(rows, columns,
+    opt_fillWithNbsp) {
+  return goog.dom.createTable_(this.document_, rows, columns,
+      !!opt_fillWithNbsp);
+};
+
+
+/**
+ * Converts an HTML into a node or a document fragment. A single Node is used if
+ * {@code html} only generates a single node. If {@code html} generates multiple
+ * nodes then these are put inside a {@code DocumentFragment}.
+ * @param {!goog.html.SafeHtml} html The HTML markup to convert.
+ * @return {!Node} The resulting node.
+ */
+goog.dom.DomHelper.prototype.safeHtmlToNode = function(html) {
+  return goog.dom.safeHtmlToNode_(this.document_, html);
+};
+
+
+/**
+ * Converts an HTML string into a node or a document fragment.  A single Node
+ * is used if the {@code htmlString} only generates a single node.  If the
+ * {@code htmlString} generates multiple nodes then these are put inside a
+ * {@code DocumentFragment}.
+ *
+ * @param {string} htmlString The HTML string to convert.
+ * @return {!Node} The resulting node.
+ */
+goog.dom.DomHelper.prototype.htmlToDocumentFragment = function(htmlString) {
+  return goog.dom.htmlToDocumentFragment_(this.document_, htmlString);
+};
+
+
+/**
+ * Returns true if the browser is in "CSS1-compatible" (standards-compliant)
+ * mode, false otherwise.
+ * @return {boolean} True if in CSS1-compatible mode.
+ */
+goog.dom.DomHelper.prototype.isCss1CompatMode = function() {
+  return goog.dom.isCss1CompatMode_(this.document_);
+};
+
+
+/**
+ * Gets the window object associated with the document.
+ * @return {!Window} The window associated with the given document.
+ */
+goog.dom.DomHelper.prototype.getWindow = function() {
+  return goog.dom.getWindow_(this.document_);
+};
+
+
+/**
+ * Gets the document scroll element.
+ * @return {!Element} Scrolling element.
+ */
+goog.dom.DomHelper.prototype.getDocumentScrollElement = function() {
+  return goog.dom.getDocumentScrollElement_(this.document_);
+};
+
+
+/**
+ * Gets the document scroll distance as a coordinate object.
+ * @return {!goog.math.Coordinate} Object with properties 'x' and 'y'.
+ */
+goog.dom.DomHelper.prototype.getDocumentScroll = function() {
+  return goog.dom.getDocumentScroll_(this.document_);
+};
+
+
+/**
+ * Determines the active element in the given document.
+ * @param {Document=} opt_doc The document to look in.
+ * @return {Element} The active element.
+ */
+goog.dom.DomHelper.prototype.getActiveElement = function(opt_doc) {
+  return goog.dom.getActiveElement(opt_doc || this.document_);
+};
+
+
+/**
+ * Appends a child to a node.
+ * @param {Node} parent Parent.
+ * @param {Node} child Child.
+ */
+goog.dom.DomHelper.prototype.appendChild = goog.dom.appendChild;
+
+
+/**
+ * Appends a node with text or other nodes.
+ * @param {!Node} parent The node to append nodes to.
+ * @param {...goog.dom.Appendable} var_args The things to append to the node.
+ *     If this is a Node it is appended as is.
+ *     If this is a string then a text node is appended.
+ *     If this is an array like object then fields 0 to length - 1 are appended.
+ */
+goog.dom.DomHelper.prototype.append = goog.dom.append;
+
+
+/**
+ * Determines if the given node can contain children, intended to be used for
+ * HTML generation.
+ *
+ * @param {Node} node The node to check.
+ * @return {boolean} Whether the node can contain children.
+ */
+goog.dom.DomHelper.prototype.canHaveChildren = goog.dom.canHaveChildren;
+
+
+/**
+ * Removes all the child nodes on a DOM node.
+ * @param {Node} node Node to remove children from.
+ */
+goog.dom.DomHelper.prototype.removeChildren = goog.dom.removeChildren;
+
+
+/**
+ * Inserts a new node before an existing reference node (i.e., as the previous
+ * sibling). If the reference node has no parent, then does nothing.
+ * @param {Node} newNode Node to insert.
+ * @param {Node} refNode Reference node to insert before.
+ */
+goog.dom.DomHelper.prototype.insertSiblingBefore = goog.dom.insertSiblingBefore;
+
+
+/**
+ * Inserts a new node after an existing reference node (i.e., as the next
+ * sibling). If the reference node has no parent, then does nothing.
+ * @param {Node} newNode Node to insert.
+ * @param {Node} refNode Reference node to insert after.
+ */
+goog.dom.DomHelper.prototype.insertSiblingAfter = goog.dom.insertSiblingAfter;
+
+
+/**
+ * Insert a child at a given index. If index is larger than the number of child
+ * nodes that the parent currently has, the node is inserted as the last child


<TRUNCATED>

[23/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/blockquote.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/blockquote.js b/externs/GCL/externs/goog/editor/plugins/blockquote.js
new file mode 100644
index 0000000..5f0387d
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/blockquote.js
@@ -0,0 +1,451 @@
+// Copyright 2008 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 goog.editor plugin to handle splitting block quotes.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.editor.plugins.Blockquote');
+
+goog.require('goog.dom');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.TagName');
+goog.require('goog.dom.classlist');
+goog.require('goog.editor.BrowserFeature');
+goog.require('goog.editor.Command');
+goog.require('goog.editor.Plugin');
+goog.require('goog.editor.node');
+goog.require('goog.functions');
+goog.require('goog.log');
+
+
+
+/**
+ * Plugin to handle splitting block quotes.  This plugin does nothing on its
+ * own and should be used in conjunction with EnterHandler or one of its
+ * subclasses.
+ * @param {boolean} requiresClassNameToSplit Whether to split only blockquotes
+ *     that have the given classname.
+ * @param {string=} opt_className The classname to apply to generated
+ *     blockquotes.  Defaults to 'tr_bq'.
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ * @final
+ */
+goog.editor.plugins.Blockquote = function(requiresClassNameToSplit,
+    opt_className) {
+  goog.editor.Plugin.call(this);
+
+  /**
+   * Whether we only split blockquotes that have {@link classname}, or whether
+   * all blockquote tags should be split on enter.
+   * @type {boolean}
+   * @private
+   */
+  this.requiresClassNameToSplit_ = requiresClassNameToSplit;
+
+  /**
+   * Classname to put on blockquotes that are generated via the toolbar for
+   * blockquote, so that we can internally distinguish these from blockquotes
+   * that are used for indentation.  This classname can be over-ridden by
+   * clients for styling or other purposes.
+   * @type {string}
+   * @private
+   */
+  this.className_ = opt_className || goog.getCssName('tr_bq');
+};
+goog.inherits(goog.editor.plugins.Blockquote, goog.editor.Plugin);
+
+
+/**
+ * Command implemented by this plugin.
+ * @type {string}
+ */
+goog.editor.plugins.Blockquote.SPLIT_COMMAND = '+splitBlockquote';
+
+
+/**
+ * Class ID used to identify this plugin.
+ * @type {string}
+ */
+goog.editor.plugins.Blockquote.CLASS_ID = 'Blockquote';
+
+
+/**
+ * Logging object.
+ * @type {goog.log.Logger}
+ * @protected
+ * @override
+ */
+goog.editor.plugins.Blockquote.prototype.logger =
+    goog.log.getLogger('goog.editor.plugins.Blockquote');
+
+
+/** @override */
+goog.editor.plugins.Blockquote.prototype.getTrogClassId = function() {
+  return goog.editor.plugins.Blockquote.CLASS_ID;
+};
+
+
+/**
+ * Since our exec command is always called from elsewhere, we make it silent.
+ * @override
+ */
+goog.editor.plugins.Blockquote.prototype.isSilentCommand = goog.functions.TRUE;
+
+
+/**
+ * Checks if a node is a blockquote which can be split. A splittable blockquote
+ * meets the following criteria:
+ * <ol>
+ *   <li>Node is a blockquote element</li>
+ *   <li>Node has the blockquote classname if the classname is required to
+ *       split</li>
+ * </ol>
+ *
+ * @param {Node} node DOM node in question.
+ * @return {boolean} Whether the node is a splittable blockquote.
+ */
+goog.editor.plugins.Blockquote.prototype.isSplittableBlockquote =
+    function(node) {
+  if (node.tagName != goog.dom.TagName.BLOCKQUOTE) {
+    return false;
+  }
+
+  if (!this.requiresClassNameToSplit_) {
+    return true;
+  }
+
+  return goog.dom.classlist.contains(/** @type {!Element} */ (node),
+      this.className_);
+};
+
+
+/**
+ * Checks if a node is a blockquote element which has been setup.
+ * @param {Node} node DOM node to check.
+ * @return {boolean} Whether the node is a blockquote with the required class
+ *     name applied.
+ */
+goog.editor.plugins.Blockquote.prototype.isSetupBlockquote =
+    function(node) {
+  return node.tagName == goog.dom.TagName.BLOCKQUOTE &&
+      goog.dom.classlist.contains(/** @type {!Element} */ (node),
+          this.className_);
+};
+
+
+/**
+ * Checks if a node is a blockquote element which has not been setup yet.
+ * @param {Node} node DOM node to check.
+ * @return {boolean} Whether the node is a blockquote without the required
+ *     class name applied.
+ */
+goog.editor.plugins.Blockquote.prototype.isUnsetupBlockquote =
+    function(node) {
+  return node.tagName == goog.dom.TagName.BLOCKQUOTE &&
+      !this.isSetupBlockquote(node);
+};
+
+
+/**
+ * Gets the class name required for setup blockquotes.
+ * @return {string} The blockquote class name.
+ */
+goog.editor.plugins.Blockquote.prototype.getBlockquoteClassName = function() {
+  return this.className_;
+};
+
+
+/**
+ * Helper routine which walks up the tree to find the topmost
+ * ancestor with only a single child. The ancestor node or the original
+ * node (if no ancestor was found) is then removed from the DOM.
+ *
+ * @param {Node} node The node whose ancestors have to be searched.
+ * @param {Node} root The root node to stop the search at.
+ * @private
+ */
+goog.editor.plugins.Blockquote.findAndRemoveSingleChildAncestor_ = function(
+    node, root) {
+  var predicateFunc = function(parentNode) {
+    return parentNode != root && parentNode.childNodes.length == 1;
+  };
+  var ancestor = goog.editor.node.findHighestMatchingAncestor(node,
+      predicateFunc);
+  if (!ancestor) {
+    ancestor = node;
+  }
+  goog.dom.removeNode(ancestor);
+};
+
+
+/**
+ * Remove every nodes from the DOM tree that are all white space nodes.
+ * @param {Array<Node>} nodes Nodes to be checked.
+ * @private
+ */
+goog.editor.plugins.Blockquote.removeAllWhiteSpaceNodes_ = function(nodes) {
+  for (var i = 0; i < nodes.length; ++i) {
+    if (goog.editor.node.isEmpty(nodes[i], true)) {
+      goog.dom.removeNode(nodes[i]);
+    }
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.Blockquote.prototype.isSupportedCommand = function(
+    command) {
+  return command == goog.editor.plugins.Blockquote.SPLIT_COMMAND;
+};
+
+
+/**
+ * Splits a quoted region if any.  To be called on a key press event.  When this
+ * function returns true, the event that caused it to be called should be
+ * canceled.
+ * @param {string} command The command to execute.
+ * @param {...*} var_args Single additional argument representing the current
+ *     cursor position. If BrowserFeature.HAS_W3C_RANGES it is an object with a
+ *     {@code node} key and an {@code offset} key. In other cases (legacy IE)
+ *     it is a single node.
+ * @return {boolean|undefined} Boolean true when the quoted region has been
+ *     split, false or undefined otherwise.
+ * @override
+ */
+goog.editor.plugins.Blockquote.prototype.execCommandInternal = function(
+    command, var_args) {
+  var pos = arguments[1];
+  if (command == goog.editor.plugins.Blockquote.SPLIT_COMMAND && pos &&
+      (this.className_ || !this.requiresClassNameToSplit_)) {
+    return goog.editor.BrowserFeature.HAS_W3C_RANGES ?
+        this.splitQuotedBlockW3C_(pos) :
+        this.splitQuotedBlockIE_(/** @type {Node} */ (pos));
+  }
+};
+
+
+/**
+ * Version of splitQuotedBlock_ that uses W3C ranges.
+ * @param {Object} anchorPos The current cursor position.
+ * @return {boolean} Whether the blockquote was split.
+ * @private
+ */
+goog.editor.plugins.Blockquote.prototype.splitQuotedBlockW3C_ =
+    function(anchorPos) {
+  var cursorNode = anchorPos.node;
+  var quoteNode = goog.editor.node.findTopMostEditableAncestor(
+      cursorNode.parentNode, goog.bind(this.isSplittableBlockquote, this));
+
+  var secondHalf, textNodeToRemove;
+  var insertTextNode = false;
+  // There are two special conditions that we account for here.
+  //
+  // 1. Whenever the cursor is after (one<BR>|) or just before a BR element
+  //    (one|<BR>) and the user presses enter, the second quoted block starts
+  //    with a BR which appears to the user as an extra newline. This stems
+  //    from the fact that we create two text nodes as our split boundaries
+  //    and the BR becomes a part of the second half because of this.
+  //
+  // 2. When the cursor is at the end of a text node with no siblings and
+  //    the user presses enter, the second blockquote might contain a
+  //    empty subtree that ends in a 0 length text node. We account for that
+  //    as a post-splitting operation.
+  if (quoteNode) {
+
+    // selection is in a line that has text in it
+    if (cursorNode.nodeType == goog.dom.NodeType.TEXT) {
+      if (anchorPos.offset == cursorNode.length) {
+        var siblingNode = cursorNode.nextSibling;
+
+        // This accounts for the condition where the cursor appears at the
+        // end of a text node and right before the BR eg: one|<BR>. We ensure
+        // that we split on the BR in that case.
+        if (siblingNode && siblingNode.tagName == goog.dom.TagName.BR) {
+          cursorNode = siblingNode;
+          // This might be null but splitDomTreeAt accounts for the null case.
+          secondHalf = siblingNode.nextSibling;
+        } else {
+          textNodeToRemove = cursorNode.splitText(anchorPos.offset);
+          secondHalf = textNodeToRemove;
+        }
+      } else {
+        secondHalf = cursorNode.splitText(anchorPos.offset);
+      }
+    } else if (cursorNode.tagName == goog.dom.TagName.BR) {
+      // This might be null but splitDomTreeAt accounts for the null case.
+      secondHalf = cursorNode.nextSibling;
+    } else {
+      // The selection is in a line that is empty, with more than 1 level
+      // of quote.
+      insertTextNode = true;
+    }
+  } else {
+    // Check if current node is a quote node.
+    // This will happen if user clicks in an empty line in the quote,
+    // when there is 1 level of quote.
+    if (this.isSetupBlockquote(cursorNode)) {
+      quoteNode = cursorNode;
+      insertTextNode = true;
+    }
+  }
+
+  if (insertTextNode) {
+    // Create two empty text nodes to split between.
+    cursorNode = this.insertEmptyTextNodeBeforeRange_();
+    secondHalf = this.insertEmptyTextNodeBeforeRange_();
+  }
+
+  if (!quoteNode) {
+    return false;
+  }
+
+  secondHalf = goog.editor.node.splitDomTreeAt(cursorNode, secondHalf,
+      quoteNode);
+  goog.dom.insertSiblingAfter(secondHalf, quoteNode);
+
+  // Set the insertion point.
+  var dh = this.getFieldDomHelper();
+  var tagToInsert =
+      this.getFieldObject().queryCommandValue(
+          goog.editor.Command.DEFAULT_TAG) ||
+          goog.dom.TagName.DIV;
+  var container = dh.createElement(/** @type {string} */ (tagToInsert));
+  container.innerHTML = '&nbsp;';  // Prevent the div from collapsing.
+  quoteNode.parentNode.insertBefore(container, secondHalf);
+  dh.getWindow().getSelection().collapse(container, 0);
+
+  // We need to account for the condition where the second blockquote
+  // might contain an empty DOM tree. This arises from trying to split
+  // at the end of an empty text node. We resolve this by walking up the tree
+  // till we either reach the blockquote or till we hit a node with more
+  // than one child. The resulting node is then removed from the DOM.
+  if (textNodeToRemove) {
+    goog.editor.plugins.Blockquote.findAndRemoveSingleChildAncestor_(
+        textNodeToRemove, secondHalf);
+  }
+
+  goog.editor.plugins.Blockquote.removeAllWhiteSpaceNodes_(
+      [quoteNode, secondHalf]);
+  return true;
+};
+
+
+/**
+ * Inserts an empty text node before the field's range.
+ * @return {!Node} The empty text node.
+ * @private
+ */
+goog.editor.plugins.Blockquote.prototype.insertEmptyTextNodeBeforeRange_ =
+    function() {
+  var range = this.getFieldObject().getRange();
+  var node = this.getFieldDomHelper().createTextNode('');
+  range.insertNode(node, true);
+  return node;
+};
+
+
+/**
+ * IE version of splitQuotedBlock_.
+ * @param {Node} splitNode The current cursor position.
+ * @return {boolean} Whether the blockquote was split.
+ * @private
+ */
+goog.editor.plugins.Blockquote.prototype.splitQuotedBlockIE_ =
+    function(splitNode) {
+  var dh = this.getFieldDomHelper();
+  var quoteNode = goog.editor.node.findTopMostEditableAncestor(
+      splitNode.parentNode, goog.bind(this.isSplittableBlockquote, this));
+
+  if (!quoteNode) {
+    return false;
+  }
+
+  var clone = splitNode.cloneNode(false);
+
+  // Whenever the cursor is just before a BR element (one|<BR>) and the user
+  // presses enter, the second quoted block starts with a BR which appears
+  // to the user as an extra newline. This stems from the fact that the
+  // dummy span that we create (splitNode) occurs before the BR and we split
+  // on that.
+  if (splitNode.nextSibling &&
+      splitNode.nextSibling.tagName == goog.dom.TagName.BR) {
+    splitNode = splitNode.nextSibling;
+  }
+  var secondHalf = goog.editor.node.splitDomTreeAt(splitNode, clone, quoteNode);
+  goog.dom.insertSiblingAfter(secondHalf, quoteNode);
+
+  // Set insertion point.
+  var tagToInsert =
+      this.getFieldObject().queryCommandValue(
+          goog.editor.Command.DEFAULT_TAG) ||
+          goog.dom.TagName.DIV;
+  var div = dh.createElement(/** @type {string} */ (tagToInsert));
+  quoteNode.parentNode.insertBefore(div, secondHalf);
+
+  // The div needs non-whitespace contents in order for the insertion point
+  // to get correctly inserted.
+  div.innerHTML = '&nbsp;';
+
+  // Moving the range 1 char isn't enough when you have markup.
+  // This moves the range to the end of the nbsp.
+  var range = dh.getDocument().selection.createRange();
+  range.moveToElementText(splitNode);
+  range.move('character', 2);
+  range.select();
+
+  // Remove the no-longer-necessary nbsp.
+  div.innerHTML = '';
+
+  // Clear the original selection.
+  range.pasteHTML('');
+
+  // We need to remove clone from the DOM but just removing clone alone will
+  // not suffice. Let's assume we have the following DOM structure and the
+  // cursor is placed after the first numbered list item "one".
+  //
+  // <blockquote class="gmail-quote">
+  //   <div><div>a</div><ol><li>one|</li></ol></div>
+  //   <div>b</div>
+  // </blockquote>
+  //
+  // After pressing enter, we have the following structure.
+  //
+  // <blockquote class="gmail-quote">
+  //   <div><div>a</div><ol><li>one|</li></ol></div>
+  // </blockquote>
+  // <div>&nbsp;</div>
+  // <blockquote class="gmail-quote">
+  //   <div><ol><li><span id=""></span></li></ol></div>
+  //   <div>b</div>
+  // </blockquote>
+  //
+  // The clone is contained in a subtree which should be removed. This stems
+  // from the fact that we invoke splitDomTreeAt with the dummy span
+  // as the starting splitting point and this results in the empty subtree
+  // <div><ol><li><span id=""></span></li></ol></div>.
+  //
+  // We resolve this by walking up the tree till we either reach the
+  // blockquote or till we hit a node with more than one child. The resulting
+  // node is then removed from the DOM.
+  goog.editor.plugins.Blockquote.findAndRemoveSingleChildAncestor_(
+      clone, secondHalf);
+
+  goog.editor.plugins.Blockquote.removeAllWhiteSpaceNodes_(
+      [quoteNode, secondHalf]);
+  return true;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/emoticons.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/emoticons.js b/externs/GCL/externs/goog/editor/plugins/emoticons.js
new file mode 100644
index 0000000..4d0c065
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/emoticons.js
@@ -0,0 +1,89 @@
+// 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.
+// All Rights Reserved
+
+/**
+ * @fileoverview Plugin for generating emoticons.
+ *
+ * @author nicksantos@google.com (Nick Santos)
+ */
+
+goog.provide('goog.editor.plugins.Emoticons');
+
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.Plugin');
+goog.require('goog.editor.range');
+goog.require('goog.functions');
+goog.require('goog.ui.emoji.Emoji');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Plugin for generating emoticons.
+ *
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ * @final
+ */
+goog.editor.plugins.Emoticons = function() {
+  goog.editor.plugins.Emoticons.base(this, 'constructor');
+};
+goog.inherits(goog.editor.plugins.Emoticons, goog.editor.Plugin);
+
+
+/** The emoticon command. */
+goog.editor.plugins.Emoticons.COMMAND = '+emoticon';
+
+
+/** @override */
+goog.editor.plugins.Emoticons.prototype.getTrogClassId =
+    goog.functions.constant(goog.editor.plugins.Emoticons.COMMAND);
+
+
+/** @override */
+goog.editor.plugins.Emoticons.prototype.isSupportedCommand = function(
+    command) {
+  return command == goog.editor.plugins.Emoticons.COMMAND;
+};
+
+
+/**
+ * Inserts an emoticon into the editor at the cursor location. Places the
+ * cursor to the right of the inserted emoticon.
+ * @param {string} command Command to execute.
+ * @param {*=} opt_arg Emoji to insert.
+ * @return {!Object|undefined} The result of the command.
+ * @override
+ */
+goog.editor.plugins.Emoticons.prototype.execCommandInternal = function(
+    command, opt_arg) {
+  var emoji = /** @type {goog.ui.emoji.Emoji} */ (opt_arg);
+  var dom = this.getFieldDomHelper();
+  var img = dom.createDom(goog.dom.TagName.IMG, {
+    'src': emoji.getUrl(),
+    'style': 'margin:0 0.2ex;vertical-align:middle'
+  });
+  img.setAttribute(goog.ui.emoji.Emoji.ATTRIBUTE, emoji.getId());
+
+  this.getFieldObject().getRange().replaceContentsWithNode(img);
+
+  // IE8 does the right thing with the cursor, and has a js error when we try
+  // to place the cursor manually.
+  // IE9 loses the cursor when the window is focused, so focus first.
+  if (!goog.userAgent.IE || goog.userAgent.isDocumentModeOrHigher(9)) {
+    this.getFieldObject().focus();
+    goog.editor.range.placeCursorNextTo(img, false);
+  }
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/enterhandler.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/enterhandler.js b/externs/GCL/externs/goog/editor/plugins/enterhandler.js
new file mode 100644
index 0000000..b6ebc1d
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/enterhandler.js
@@ -0,0 +1,768 @@
+// Copyright 2008 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 Plugin to handle enter keys.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+goog.provide('goog.editor.plugins.EnterHandler');
+
+goog.require('goog.dom');
+goog.require('goog.dom.NodeOffset');
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.Range');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.BrowserFeature');
+goog.require('goog.editor.Plugin');
+goog.require('goog.editor.node');
+goog.require('goog.editor.plugins.Blockquote');
+goog.require('goog.editor.range');
+goog.require('goog.editor.style');
+goog.require('goog.events.KeyCodes');
+goog.require('goog.functions');
+goog.require('goog.object');
+goog.require('goog.string');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Plugin to handle enter keys. This does all the crazy to normalize (as much as
+ * is reasonable) what happens when you hit enter. This also handles the
+ * special casing of hitting enter in a blockquote.
+ *
+ * In IE, Webkit, and Opera, the resulting HTML uses one DIV tag per line. In
+ * Firefox, the resulting HTML uses BR tags at the end of each line.
+ *
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ */
+goog.editor.plugins.EnterHandler = function() {
+  goog.editor.Plugin.call(this);
+};
+goog.inherits(goog.editor.plugins.EnterHandler, goog.editor.Plugin);
+
+
+/**
+ * The type of block level tag to add on enter, for browsers that support
+ * specifying the default block-level tag. Can be overriden by subclasses; must
+ * be either DIV or P.
+ * @type {goog.dom.TagName}
+ * @protected
+ */
+goog.editor.plugins.EnterHandler.prototype.tag = goog.dom.TagName.DIV;
+
+
+/** @override */
+goog.editor.plugins.EnterHandler.prototype.getTrogClassId = function() {
+  return 'EnterHandler';
+};
+
+
+/** @override */
+goog.editor.plugins.EnterHandler.prototype.enable = function(fieldObject) {
+  goog.editor.plugins.EnterHandler.base(this, 'enable', fieldObject);
+
+  if (goog.editor.BrowserFeature.SUPPORTS_OPERA_DEFAULTBLOCK_COMMAND &&
+      (this.tag == goog.dom.TagName.P || this.tag == goog.dom.TagName.DIV)) {
+    var doc = this.getFieldDomHelper().getDocument();
+    doc.execCommand('opera-defaultBlock', false, this.tag);
+  }
+};
+
+
+/**
+ * If the contents are empty, return the 'default' html for the field.
+ * The 'default' contents depend on the enter handling mode, so it
+ * makes the most sense in this plugin.
+ * @param {string} html The html to prepare.
+ * @return {string} The original HTML, or default contents if that
+ *    html is empty.
+ * @override
+ */
+goog.editor.plugins.EnterHandler.prototype.prepareContentsHtml = function(
+    html) {
+  if (!html || goog.string.isBreakingWhitespace(html)) {
+    return goog.editor.BrowserFeature.COLLAPSES_EMPTY_NODES ?
+        this.getNonCollapsingBlankHtml() : '';
+  }
+  return html;
+};
+
+
+/**
+ * Gets HTML with no contents that won't collapse, for browsers that
+ * collapse the empty string.
+ * @return {string} Blank html.
+ * @protected
+ */
+goog.editor.plugins.EnterHandler.prototype.getNonCollapsingBlankHtml =
+    goog.functions.constant('<br>');
+
+
+/**
+ * Internal backspace handler.
+ * @param {goog.events.Event} e The keypress event.
+ * @param {goog.dom.AbstractRange} range The closure range object.
+ * @protected
+ */
+goog.editor.plugins.EnterHandler.prototype.handleBackspaceInternal = function(e,
+    range) {
+  var field = this.getFieldObject().getElement();
+  var container = range && range.getStartNode();
+
+  if (field.firstChild == container && goog.editor.node.isEmpty(container)) {
+    e.preventDefault();
+    // TODO(user): I think we probably don't need to stopPropagation here
+    e.stopPropagation();
+  }
+};
+
+
+/**
+ * Fix paragraphs to be the correct type of node.
+ * @param {goog.events.Event} e The <enter> key event.
+ * @param {boolean} split Whether we already split up a blockquote by
+ *     manually inserting elements.
+ * @protected
+ */
+goog.editor.plugins.EnterHandler.prototype.processParagraphTagsInternal =
+    function(e, split) {
+  // Force IE to turn the node we are leaving into a DIV.  If we do turn
+  // it into a DIV, the node IE creates in response to ENTER will also be
+  // a DIV.  If we don't, it will be a P.  We handle that case
+  // in handleKeyUpIE_
+  if (goog.userAgent.IE || goog.userAgent.OPERA) {
+    this.ensureBlockIeOpera(goog.dom.TagName.DIV);
+  } else if (!split && goog.userAgent.WEBKIT) {
+    // WebKit duplicates a blockquote when the user hits enter. Let's cancel
+    // this and insert a BR instead, to make it more consistent with the other
+    // browsers.
+    var range = this.getFieldObject().getRange();
+    if (!range || !goog.editor.plugins.EnterHandler.isDirectlyInBlockquote(
+        range.getContainerElement())) {
+      return;
+    }
+
+    var dh = this.getFieldDomHelper();
+    var br = dh.createElement(goog.dom.TagName.BR);
+    range.insertNode(br, true);
+
+    // If the BR is at the end of a block element, Safari still thinks there is
+    // only one line instead of two, so we need to add another BR in that case.
+    if (goog.editor.node.isBlockTag(br.parentNode) &&
+        !goog.editor.node.skipEmptyTextNodes(br.nextSibling)) {
+      goog.dom.insertSiblingBefore(
+          dh.createElement(goog.dom.TagName.BR), br);
+    }
+
+    goog.editor.range.placeCursorNextTo(br, false);
+    e.preventDefault();
+  }
+};
+
+
+/**
+ * Determines whether the lowest containing block node is a blockquote.
+ * @param {Node} n The node.
+ * @return {boolean} Whether the deepest block ancestor of n is a blockquote.
+ */
+goog.editor.plugins.EnterHandler.isDirectlyInBlockquote = function(n) {
+  for (var current = n; current; current = current.parentNode) {
+    if (goog.editor.node.isBlockTag(current)) {
+      return current.tagName == goog.dom.TagName.BLOCKQUOTE;
+    }
+  }
+
+  return false;
+};
+
+
+/**
+ * Internal delete key handler.
+ * @param {goog.events.Event} e The keypress event.
+ * @protected
+ */
+goog.editor.plugins.EnterHandler.prototype.handleDeleteGecko = function(e) {
+  this.deleteBrGecko(e);
+};
+
+
+/**
+ * Deletes the element at the cursor if it is a BR node, and if it does, calls
+ * e.preventDefault to stop the browser from deleting. Only necessary in Gecko
+ * as a workaround for mozilla bug 205350 where deleting a BR that is followed
+ * by a block element doesn't work (the BR gets immediately replaced). We also
+ * need to account for an ill-formed cursor which occurs from us trying to
+ * stop the browser from deleting.
+ *
+ * @param {goog.events.Event} e The DELETE keypress event.
+ * @protected
+ */
+goog.editor.plugins.EnterHandler.prototype.deleteBrGecko = function(e) {
+  var range = this.getFieldObject().getRange();
+  if (range.isCollapsed()) {
+    var container = range.getEndNode();
+    if (container.nodeType == goog.dom.NodeType.ELEMENT) {
+      var nextNode = container.childNodes[range.getEndOffset()];
+      if (nextNode && nextNode.tagName == goog.dom.TagName.BR) {
+        // We want to retrieve the first non-whitespace previous sibling
+        // as we could have added an empty text node below and want to
+        // properly handle deleting a sequence of BR's.
+        var previousSibling = goog.editor.node.getPreviousSibling(nextNode);
+        var nextSibling = nextNode.nextSibling;
+
+        container.removeChild(nextNode);
+        e.preventDefault();
+
+        // When we delete a BR followed by a block level element, the cursor
+        // has a line-height which spans the height of the block level element.
+        // e.g. If we delete a BR followed by a UL, the resulting HTML will
+        // appear to the end user like:-
+        //
+        // |  * one
+        // |  * two
+        // |  * three
+        //
+        // There are a couple of cases that we have to account for in order to
+        // properly conform to what the user expects when DELETE is pressed.
+        //
+        // 1. If the BR has a previous sibling and the previous sibling is
+        //    not a block level element or a BR, we place the cursor at the
+        //    end of that.
+        // 2. If the BR doesn't have a previous sibling or the previous sibling
+        //    is a block level element or a BR, we place the cursor at the
+        //    beginning of the leftmost leaf of its next sibling.
+        if (nextSibling && goog.editor.node.isBlockTag(nextSibling)) {
+          if (previousSibling &&
+              !(previousSibling.tagName == goog.dom.TagName.BR ||
+                goog.editor.node.isBlockTag(previousSibling))) {
+            goog.dom.Range.createCaret(
+                previousSibling,
+                goog.editor.node.getLength(previousSibling)).select();
+          } else {
+            var leftMostLeaf = goog.editor.node.getLeftMostLeaf(nextSibling);
+            goog.dom.Range.createCaret(leftMostLeaf, 0).select();
+          }
+        }
+      }
+    }
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.EnterHandler.prototype.handleKeyPress = function(e) {
+  // If a dialog doesn't have selectable field, Gecko grabs the event and
+  // performs actions in editor window. This solves that problem and allows
+  // the event to be passed on to proper handlers.
+  if (goog.userAgent.GECKO && this.getFieldObject().inModalMode()) {
+    return false;
+  }
+
+  // Firefox will allow the first node in an iframe to be deleted
+  // on a backspace.  Disallow it if the node is empty.
+  if (e.keyCode == goog.events.KeyCodes.BACKSPACE) {
+    this.handleBackspaceInternal(e, this.getFieldObject().getRange());
+
+  } else if (e.keyCode == goog.events.KeyCodes.ENTER) {
+    if (goog.userAgent.GECKO) {
+      if (!e.shiftKey) {
+        // Behave similarly to IE's content editable return carriage:
+        // If the shift key is down or specified by the application, insert a
+        // BR, otherwise split paragraphs
+        this.handleEnterGecko_(e);
+      }
+    } else {
+      // In Gecko-based browsers, this is handled in the handleEnterGecko_
+      // method.
+      this.getFieldObject().dispatchBeforeChange();
+      var cursorPosition = this.deleteCursorSelection_();
+
+      var split = !!this.getFieldObject().execCommand(
+          goog.editor.plugins.Blockquote.SPLIT_COMMAND, cursorPosition);
+      if (split) {
+        // TODO(user): I think we probably don't need to stopPropagation here
+        e.preventDefault();
+        e.stopPropagation();
+      }
+
+      this.releasePositionObject_(cursorPosition);
+
+      if (goog.userAgent.WEBKIT) {
+        this.handleEnterWebkitInternal(e);
+      }
+
+      this.processParagraphTagsInternal(e, split);
+      this.getFieldObject().dispatchChange();
+    }
+
+  } else if (goog.userAgent.GECKO && e.keyCode == goog.events.KeyCodes.DELETE) {
+    this.handleDeleteGecko(e);
+  }
+
+  return false;
+};
+
+
+/** @override */
+goog.editor.plugins.EnterHandler.prototype.handleKeyUp = function(e) {
+  // If a dialog doesn't have selectable field, Gecko grabs the event and
+  // performs actions in editor window. This solves that problem and allows
+  // the event to be passed on to proper handlers.
+  if (goog.userAgent.GECKO && this.getFieldObject().inModalMode()) {
+    return false;
+  }
+  this.handleKeyUpInternal(e);
+  return false;
+};
+
+
+/**
+ * Internal handler for keyup events.
+ * @param {goog.events.Event} e The key event.
+ * @protected
+ */
+goog.editor.plugins.EnterHandler.prototype.handleKeyUpInternal = function(e) {
+  if ((goog.userAgent.IE || goog.userAgent.OPERA) &&
+      e.keyCode == goog.events.KeyCodes.ENTER) {
+    this.ensureBlockIeOpera(goog.dom.TagName.DIV, true);
+  }
+};
+
+
+/**
+ * Handles an enter keypress event on fields in Gecko.
+ * @param {goog.events.BrowserEvent} e The key event.
+ * @private
+ */
+goog.editor.plugins.EnterHandler.prototype.handleEnterGecko_ = function(e) {
+  // Retrieve whether the selection is collapsed before we delete it.
+  var range = this.getFieldObject().getRange();
+  var wasCollapsed = !range || range.isCollapsed();
+  var cursorPosition = this.deleteCursorSelection_();
+
+  var handled = this.getFieldObject().execCommand(
+      goog.editor.plugins.Blockquote.SPLIT_COMMAND, cursorPosition);
+  if (handled) {
+    // TODO(user): I think we probably don't need to stopPropagation here
+    e.preventDefault();
+    e.stopPropagation();
+  }
+
+  this.releasePositionObject_(cursorPosition);
+  if (!handled) {
+    this.handleEnterAtCursorGeckoInternal(e, wasCollapsed, range);
+  }
+};
+
+
+/**
+ * Handle an enter key press in WebKit.
+ * @param {goog.events.BrowserEvent} e The key press event.
+ * @protected
+ */
+goog.editor.plugins.EnterHandler.prototype.handleEnterWebkitInternal =
+    goog.nullFunction;
+
+
+/**
+ * Handle an enter key press on collapsed selection.  handleEnterGecko_ ensures
+ * the selection is collapsed by deleting its contents if it is not.  The
+ * default implementation does nothing.
+ * @param {goog.events.BrowserEvent} e The key press event.
+ * @param {boolean} wasCollapsed Whether the selection was collapsed before
+ *     the key press.  If it was not, code before this function has already
+ *     cleared the contents of the selection.
+ * @param {goog.dom.AbstractRange} range Object representing the selection.
+ * @protected
+ */
+goog.editor.plugins.EnterHandler.prototype.handleEnterAtCursorGeckoInternal =
+    goog.nullFunction;
+
+
+/**
+ * Names of all the nodes that we don't want to turn into block nodes in IE when
+ * the user hits enter.
+ * @type {Object}
+ * @private
+ */
+goog.editor.plugins.EnterHandler.DO_NOT_ENSURE_BLOCK_NODES_ =
+    goog.object.createSet(
+        goog.dom.TagName.LI, goog.dom.TagName.DIV, goog.dom.TagName.H1,
+        goog.dom.TagName.H2, goog.dom.TagName.H3, goog.dom.TagName.H4,
+        goog.dom.TagName.H5, goog.dom.TagName.H6);
+
+
+/**
+ * Whether this is a node that contains a single BR tag and non-nbsp
+ * whitespace.
+ * @param {Node} node Node to check.
+ * @return {boolean} Whether this is an element that only contains a BR.
+ * @protected
+ */
+goog.editor.plugins.EnterHandler.isBrElem = function(node) {
+  return goog.editor.node.isEmpty(node) &&
+      node.getElementsByTagName(goog.dom.TagName.BR).length == 1;
+};
+
+
+/**
+ * Ensures all text in IE and Opera to be in the given tag in order to control
+ * Enter spacing. Call this when Enter is pressed if desired.
+ *
+ * We want to make sure the user is always inside of a block (or other nodes
+ * listed in goog.editor.plugins.EnterHandler.IGNORE_ENSURE_BLOCK_NODES_).  We
+ * listen to keypress to force nodes that the user is leaving to turn into
+ * blocks, but we also need to listen to keyup to force nodes that the user is
+ * entering to turn into blocks.
+ * Example:  html is: "<h2>foo[cursor]</h2>", and the user hits enter.  We
+ * don't want to format the h2, but we do want to format the P that is
+ * created on enter.  The P node is not available until keyup.
+ * @param {goog.dom.TagName} tag The tag name to convert to.
+ * @param {boolean=} opt_keyUp Whether the function is being called on key up.
+ *     When called on key up, the cursor is in the newly created node, so the
+ *     semantics for when to change it to a block are different.  Specifically,
+ *     if the resulting node contains only a BR, it is converted to <tag>.
+ * @protected
+ */
+goog.editor.plugins.EnterHandler.prototype.ensureBlockIeOpera = function(tag,
+    opt_keyUp) {
+  var range = this.getFieldObject().getRange();
+  var container = range.getContainer();
+  var field = this.getFieldObject().getElement();
+
+  var paragraph;
+  while (container && container != field) {
+    // We don't need to ensure a block if we are already in the same block, or
+    // in another block level node that we don't want to change the format of
+    // (unless we're handling keyUp and that block node just contains a BR).
+    var nodeName = container.nodeName;
+    // Due to @bug 2455389, the call to isBrElem needs to be inlined in the if
+    // instead of done before and saved in a variable, so that it can be
+    // short-circuited and avoid a weird IE edge case.
+    if (nodeName == tag ||
+        (goog.editor.plugins.EnterHandler.
+            DO_NOT_ENSURE_BLOCK_NODES_[nodeName] && !(opt_keyUp &&
+                goog.editor.plugins.EnterHandler.isBrElem(container)))) {
+      // Opera can create a <p> inside of a <div> in some situations,
+      // such as when breaking out of a list that is contained in a <div>.
+      if (goog.userAgent.OPERA && paragraph) {
+        if (nodeName == tag &&
+            paragraph == container.lastChild &&
+            goog.editor.node.isEmpty(paragraph)) {
+          goog.dom.insertSiblingAfter(paragraph, container);
+          goog.dom.Range.createFromNodeContents(paragraph).select();
+        }
+        break;
+      }
+      return;
+    }
+    if (goog.userAgent.OPERA && opt_keyUp && nodeName == goog.dom.TagName.P &&
+        nodeName != tag) {
+      paragraph = container;
+    }
+
+    container = container.parentNode;
+  }
+
+
+  if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher(9)) {
+    // IE (before IE9) has a bug where if the cursor is directly before a block
+    // node (e.g., the content is "foo[cursor]<blockquote>bar</blockquote>"),
+    // the FormatBlock command actually formats the "bar" instead of the "foo".
+    // This is just wrong. To work-around this, we want to move the
+    // selection back one character, and then restore it to its prior position.
+    // NOTE: We use the following "range math" to detect this situation because
+    // using Closure ranges here triggers a bug in IE that causes a crash.
+    // parent2 != parent3 ensures moving the cursor forward one character
+    // crosses at least 1 element boundary, and therefore tests if the cursor is
+    // at such a boundary.  The second check, parent3 != range.parentElement()
+    // weeds out some cases where the elements are siblings instead of cousins.
+    var needsHelp = false;
+    range = range.getBrowserRangeObject();
+    var range2 = range.duplicate();
+    range2.moveEnd('character', 1);
+    // In whitebox mode, when the cursor is at the end of the field, trying to
+    // move the end of the range will do nothing, and hence the range's text
+    // will be empty.  In this case, the cursor clearly isn't sitting just
+    // before a block node, since it isn't before anything.
+    if (range2.text.length) {
+      var parent2 = range2.parentElement();
+
+      var range3 = range2.duplicate();
+      range3.collapse(false);
+      var parent3 = range3.parentElement();
+
+      if ((needsHelp = parent2 != parent3 &&
+                       parent3 != range.parentElement())) {
+        range.move('character', -1);
+        range.select();
+      }
+    }
+  }
+
+  this.getFieldObject().getEditableDomHelper().getDocument().execCommand(
+      'FormatBlock', false, '<' + tag + '>');
+
+  if (needsHelp) {
+    range.move('character', 1);
+    range.select();
+  }
+};
+
+
+/**
+ * Deletes the content at the current cursor position.
+ * @return {!Node|!Object} Something representing the current cursor position.
+ *    See deleteCursorSelectionIE_ and deleteCursorSelectionW3C_ for details.
+ *    Should be passed to releasePositionObject_ when no longer in use.
+ * @private
+ */
+goog.editor.plugins.EnterHandler.prototype.deleteCursorSelection_ = function() {
+  return goog.editor.BrowserFeature.HAS_W3C_RANGES ?
+      this.deleteCursorSelectionW3C_() : this.deleteCursorSelectionIE_();
+};
+
+
+/**
+ * Releases the object returned by deleteCursorSelection_.
+ * @param {Node|Object} position The object returned by deleteCursorSelection_.
+ * @private
+ */
+goog.editor.plugins.EnterHandler.prototype.releasePositionObject_ =
+    function(position) {
+  if (!goog.editor.BrowserFeature.HAS_W3C_RANGES) {
+    (/** @type {Node} */ (position)).removeNode(true);
+  }
+};
+
+
+/**
+ * Delete the selection at the current cursor position, then returns a temporary
+ * node at the current position.
+ * @return {!Node} A temporary node marking the current cursor position. This
+ *     node should eventually be removed from the DOM.
+ * @private
+ */
+goog.editor.plugins.EnterHandler.prototype.deleteCursorSelectionIE_ =
+    function() {
+  var doc = this.getFieldDomHelper().getDocument();
+  var range = doc.selection.createRange();
+
+  var id = goog.string.createUniqueString();
+  range.pasteHTML('<span id="' + id + '"></span>');
+  var splitNode = doc.getElementById(id);
+  splitNode.id = '';
+  return splitNode;
+};
+
+
+/**
+ * Delete the selection at the current cursor position, then returns the node
+ * at the current position.
+ * @return {!goog.editor.range.Point} The current cursor position. Note that
+ *    unlike simulateEnterIE_, this should not be removed from the DOM.
+ * @private
+ */
+goog.editor.plugins.EnterHandler.prototype.deleteCursorSelectionW3C_ =
+    function() {
+  var range = this.getFieldObject().getRange();
+
+  // Delete the current selection if it's is non-collapsed.
+  // Although this is redundant in FF, it's necessary for Safari
+  if (!range.isCollapsed()) {
+    var shouldDelete = true;
+    // Opera selects the <br> in an empty block if there is no text node
+    // preceding it. To preserve inline formatting when pressing [enter] inside
+    // an empty block, don't delete the selection if it only selects a <br> at
+    // the end of the block.
+    // TODO(user): Move this into goog.dom.Range. It should detect this state
+    // when creating a range from the window selection and fix it in the created
+    // range.
+    if (goog.userAgent.OPERA) {
+      var startNode = range.getStartNode();
+      var startOffset = range.getStartOffset();
+      if (startNode == range.getEndNode() &&
+          // This weeds out cases where startNode is a text node.
+          startNode.lastChild &&
+          startNode.lastChild.tagName == goog.dom.TagName.BR &&
+          // If this check is true, then endOffset is implied to be
+          // startOffset + 1, because the selection is not collapsed and
+          // it starts and ends within the same element.
+          startOffset == startNode.childNodes.length - 1) {
+        shouldDelete = false;
+      }
+    }
+    if (shouldDelete) {
+      goog.editor.plugins.EnterHandler.deleteW3cRange_(range);
+    }
+  }
+
+  return goog.editor.range.getDeepEndPoint(range, true);
+};
+
+
+/**
+ * Deletes the contents of the selection from the DOM.
+ * @param {goog.dom.AbstractRange} range The range to remove contents from.
+ * @return {goog.dom.AbstractRange} The resulting range. Used for testing.
+ * @private
+ */
+goog.editor.plugins.EnterHandler.deleteW3cRange_ = function(range) {
+  if (range && !range.isCollapsed()) {
+    var reselect = true;
+    var baseNode = range.getContainerElement();
+    var nodeOffset = new goog.dom.NodeOffset(range.getStartNode(), baseNode);
+    var rangeOffset = range.getStartOffset();
+
+    // Whether the selection crosses no container boundaries.
+    var isInOneContainer =
+        goog.editor.plugins.EnterHandler.isInOneContainerW3c_(range);
+
+    // Whether the selection ends in a container it doesn't fully select.
+    var isPartialEnd = !isInOneContainer &&
+        goog.editor.plugins.EnterHandler.isPartialEndW3c_(range);
+
+    // Remove The range contents, and ensure the correct content stays selected.
+    range.removeContents();
+    var node = nodeOffset.findTargetNode(baseNode);
+    if (node) {
+      range = goog.dom.Range.createCaret(node, rangeOffset);
+    } else {
+      // This occurs when the node that would have been referenced has now been
+      // deleted and there are no other nodes in the baseNode. Thus need to
+      // set the caret to the end of the base node.
+      range =
+          goog.dom.Range.createCaret(baseNode, baseNode.childNodes.length);
+      reselect = false;
+    }
+    range.select();
+
+    // If we just deleted everything from the container, add an nbsp
+    // to the container, and leave the cursor inside of it
+    if (isInOneContainer) {
+      var container = goog.editor.style.getContainer(range.getStartNode());
+      if (goog.editor.node.isEmpty(container, true)) {
+        var html = '&nbsp;';
+        if (goog.userAgent.OPERA &&
+            container.tagName == goog.dom.TagName.LI) {
+          // Don't break Opera's native break-out-of-lists behavior.
+          html = '<br>';
+        }
+        goog.editor.node.replaceInnerHtml(container, html);
+        goog.editor.range.selectNodeStart(container.firstChild);
+        reselect = false;
+      }
+    }
+
+    if (isPartialEnd) {
+      /*
+       This code handles the following, where | is the cursor:
+         <div>a|b</div><div>c|d</div>
+       After removeContents, the remaining HTML is
+         <div>a</div><div>d</div>
+       which means the line break between the two divs remains.  This block
+       moves children of the second div in to the first div to get the correct
+       result:
+         <div>ad</div>
+
+       TODO(robbyw): Should we wrap the second div's contents in a span if they
+                     have inline style?
+      */
+      var rangeStart = goog.editor.style.getContainer(range.getStartNode());
+      var redundantContainer = goog.editor.node.getNextSibling(rangeStart);
+      if (rangeStart && redundantContainer) {
+        goog.dom.append(rangeStart, redundantContainer.childNodes);
+        goog.dom.removeNode(redundantContainer);
+      }
+    }
+
+    if (reselect) {
+      // The contents of the original range are gone, so restore the cursor
+      // position at the start of where the range once was.
+      range = goog.dom.Range.createCaret(nodeOffset.findTargetNode(baseNode),
+          rangeOffset);
+      range.select();
+    }
+  }
+
+  return range;
+};
+
+
+/**
+ * Checks whether the whole range is in a single block-level element.
+ * @param {goog.dom.AbstractRange} range The range to check.
+ * @return {boolean} Whether the whole range is in a single block-level element.
+ * @private
+ */
+goog.editor.plugins.EnterHandler.isInOneContainerW3c_ = function(range) {
+  // Find the block element containing the start of the selection.
+  var startContainer = range.getStartNode();
+  if (goog.editor.style.isContainer(startContainer)) {
+    startContainer = startContainer.childNodes[range.getStartOffset()] ||
+                     startContainer;
+  }
+  startContainer = goog.editor.style.getContainer(startContainer);
+
+  // Find the block element containing the end of the selection.
+  var endContainer = range.getEndNode();
+  if (goog.editor.style.isContainer(endContainer)) {
+    endContainer = endContainer.childNodes[range.getEndOffset()] ||
+                   endContainer;
+  }
+  endContainer = goog.editor.style.getContainer(endContainer);
+
+  // Compare the two.
+  return startContainer == endContainer;
+};
+
+
+/**
+ * Checks whether the end of the range is not at the end of a block-level
+ * element.
+ * @param {goog.dom.AbstractRange} range The range to check.
+ * @return {boolean} Whether the end of the range is not at the end of a
+ *     block-level element.
+ * @private
+ */
+goog.editor.plugins.EnterHandler.isPartialEndW3c_ = function(range) {
+  var endContainer = range.getEndNode();
+  var endOffset = range.getEndOffset();
+  var node = endContainer;
+  if (goog.editor.style.isContainer(node)) {
+    var child = node.childNodes[endOffset];
+    // Child is null when end offset is >= length, which indicates the entire
+    // container is selected.  Otherwise, we also know the entire container
+    // is selected if the selection ends at a new container.
+    if (!child ||
+        child.nodeType == goog.dom.NodeType.ELEMENT &&
+        goog.editor.style.isContainer(child)) {
+      return false;
+    }
+  }
+
+  var container = goog.editor.style.getContainer(node);
+  while (container != node) {
+    if (goog.editor.node.getNextSibling(node)) {
+      return true;
+    }
+    node = node.parentNode;
+  }
+
+  return endOffset != goog.editor.node.getLength(endContainer);
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/firststrong.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/firststrong.js b/externs/GCL/externs/goog/editor/plugins/firststrong.js
new file mode 100644
index 0000000..7342bad
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/firststrong.js
@@ -0,0 +1,334 @@
+// 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 plugin to enable the First Strong Bidi algorithm.  The First
+ * Strong algorithm as a heuristic used to automatically set paragraph direction
+ * depending on its content.
+ *
+ * In the documentation below, a 'paragraph' is the local element which we
+ * evaluate as a whole for purposes of determining directionality. It may be a
+ * block-level element (e.g. &lt;div&gt;) or a whole list (e.g. &lt;ul&gt;).
+ *
+ * This implementation is based on, but is not identical to, the original
+ * First Strong algorithm defined in Unicode
+ * @see http://www.unicode.org/reports/tr9/
+ * The central difference from the original First Strong algorithm is that this
+ * implementation decides the paragraph direction based on the first strong
+ * character that is <em>typed</em> into the paragraph, regardless of its
+ * location in the paragraph, as opposed to the original algorithm where it is
+ * the first character in the paragraph <em>by location</em>, regardless of
+ * whether other strong characters already appear in the paragraph, further its
+ * start.
+ *
+ * <em>Please note</em> that this plugin does not perform the direction change
+ * itself. Rather, it fires editor commands upon the key up event when a
+ * direction change needs to be performed; {@code goog.editor.Command.DIR_RTL}
+ * or {@code goog.editor.Command.DIR_RTL}.
+ *
+ */
+
+goog.provide('goog.editor.plugins.FirstStrong');
+
+goog.require('goog.dom.NodeType');
+goog.require('goog.dom.TagIterator');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.Command');
+goog.require('goog.editor.Field');
+goog.require('goog.editor.Plugin');
+goog.require('goog.editor.node');
+goog.require('goog.editor.range');
+goog.require('goog.i18n.bidi');
+goog.require('goog.i18n.uChar');
+goog.require('goog.iter');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * First Strong plugin.
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ * @final
+ */
+goog.editor.plugins.FirstStrong = function() {
+  goog.editor.plugins.FirstStrong.base(this, 'constructor');
+
+  /**
+   * Indicates whether or not the cursor is in a paragraph we have not yet
+   * finished evaluating for directionality. This is set to true whenever the
+   * cursor is moved, and set to false after seeing a strong character in the
+   * paragraph the cursor is currently in.
+   *
+   * @type {boolean}
+   * @private
+   */
+  this.isNewBlock_ = true;
+
+  /**
+   * Indicates whether or not the current paragraph the cursor is in should be
+   * set to Right-To-Left directionality.
+   *
+   * @type {boolean}
+   * @private
+   */
+  this.switchToRtl_ = false;
+
+  /**
+   * Indicates whether or not the current paragraph the cursor is in should be
+   * set to Left-To-Right directionality.
+   *
+   * @type {boolean}
+   * @private
+   */
+  this.switchToLtr_ = false;
+};
+goog.inherits(goog.editor.plugins.FirstStrong, goog.editor.Plugin);
+
+
+/** @override */
+goog.editor.plugins.FirstStrong.prototype.getTrogClassId = function() {
+  return 'FirstStrong';
+};
+
+
+/** @override */
+goog.editor.plugins.FirstStrong.prototype.queryCommandValue =
+    function(command) {
+  return false;
+};
+
+
+/** @override */
+goog.editor.plugins.FirstStrong.prototype.handleSelectionChange =
+    function(e, node) {
+  this.isNewBlock_ = true;
+  return false;
+};
+
+
+/**
+ * The name of the attribute which records the input text.
+ *
+ * @type {string}
+ * @const
+ */
+goog.editor.plugins.FirstStrong.INPUT_ATTRIBUTE = 'fs-input';
+
+
+/** @override */
+goog.editor.plugins.FirstStrong.prototype.handleKeyPress = function(e) {
+  if (goog.editor.Field.SELECTION_CHANGE_KEYCODES[e.keyCode]) {
+    // Key triggered selection change event (e.g. on ENTER) is throttled and a
+    // later LTR/RTL strong keypress may come before it. Need to capture it.
+    this.isNewBlock_ = true;
+    return false;  // A selection-changing key is not LTR/RTL strong.
+  }
+  if (!this.isNewBlock_) {
+    return false;  // We've already determined this paragraph's direction.
+  }
+  // Ignore non-character key press events.
+  if (e.ctrlKey || e.metaKey) {
+    return false;
+  }
+  var newInput = goog.i18n.uChar.fromCharCode(e.charCode);
+
+  // IME's may return 0 for the charCode, which is a legitimate, non-Strong
+  // charCode, or they may return an illegal charCode (for which newInput will
+  // be false).
+  if (!newInput || !e.charCode) {
+    var browserEvent = e.getBrowserEvent();
+    if (browserEvent) {
+      if (goog.userAgent.IE && browserEvent['getAttribute']) {
+        newInput = browserEvent['getAttribute'](
+            goog.editor.plugins.FirstStrong.INPUT_ATTRIBUTE);
+      } else {
+        newInput = browserEvent[
+            goog.editor.plugins.FirstStrong.INPUT_ATTRIBUTE];
+      }
+    }
+  }
+
+  if (!newInput) {
+    return false;  // Unrecognized key.
+  }
+
+  var isLtr = goog.i18n.bidi.isLtrChar(newInput);
+  var isRtl = !isLtr && goog.i18n.bidi.isRtlChar(newInput);
+  if (!isLtr && !isRtl) {
+    return false;  // This character cannot change anything (it is not Strong).
+  }
+  // This character is Strongly LTR or Strongly RTL. We might switch direction
+  // on it now, but in any case we do not need to check any more characters in
+  // this paragraph after it.
+  this.isNewBlock_ = false;
+
+  // Are there no Strong characters already in the paragraph?
+  if (this.isNeutralBlock_()) {
+    this.switchToRtl_ = isRtl;
+    this.switchToLtr_ = isLtr;
+  }
+  return false;
+};
+
+
+/**
+ * Calls the flip directionality commands.  This is done here so things go into
+ * the redo-undo stack at the expected order; fist enter the input, then flip
+ * directionality.
+ * @override
+ */
+goog.editor.plugins.FirstStrong.prototype.handleKeyUp = function(e) {
+  if (this.switchToRtl_) {
+    var field = this.getFieldObject();
+    field.dispatchChange(true);
+    field.execCommand(goog.editor.Command.DIR_RTL);
+    this.switchToRtl_ = false;
+  } else if (this.switchToLtr_) {
+    var field = this.getFieldObject();
+    field.dispatchChange(true);
+    field.execCommand(goog.editor.Command.DIR_LTR);
+    this.switchToLtr_ = false;
+  }
+  return false;
+};
+
+
+/**
+ * @return {Element} The lowest Block element ancestor of the node where the
+ *     next character will be placed.
+ * @private
+ */
+goog.editor.plugins.FirstStrong.prototype.getBlockAncestor_ = function() {
+  var start = this.getFieldObject().getRange().getStartNode();
+  // Go up in the DOM until we reach a Block element.
+  while (!goog.editor.plugins.FirstStrong.isBlock_(start)) {
+    start = start.parentNode;
+  }
+  return /** @type {Element} */ (start);
+};
+
+
+/**
+ * @return {boolean} Whether the paragraph where the next character will be
+ *     entered contains only non-Strong characters.
+ * @private
+ */
+goog.editor.plugins.FirstStrong.prototype.isNeutralBlock_ = function() {
+  var root = this.getBlockAncestor_();
+  // The exact node with the cursor location. Simply calling getStartNode() on
+  // the range only returns the containing block node.
+  var cursor = goog.editor.range.getDeepEndPoint(
+      this.getFieldObject().getRange(), false).node;
+
+  // In FireFox the BR tag also represents a change in paragraph if not inside a
+  // list. So we need special handling to only look at the sub-block between
+  // BR elements.
+  var blockFunction = (goog.userAgent.GECKO &&
+      !this.isList_(root)) ?
+          goog.editor.plugins.FirstStrong.isGeckoBlock_ :
+          goog.editor.plugins.FirstStrong.isBlock_;
+  var paragraph = this.getTextAround_(root, cursor,
+      blockFunction);
+  // Not using {@code goog.i18n.bidi.isNeutralText} as it contains additional,
+  // unwanted checks to the content.
+  return !goog.i18n.bidi.hasAnyLtr(paragraph) &&
+      !goog.i18n.bidi.hasAnyRtl(paragraph);
+};
+
+
+/**
+ * Checks if an element is a list element ('UL' or 'OL').
+ *
+ * @param {Element} element The element to test.
+ * @return {boolean} Whether the element is a list element ('UL' or 'OL').
+ * @private
+ */
+goog.editor.plugins.FirstStrong.prototype.isList_ = function(element) {
+  if (!element) {
+    return false;
+  }
+  var tagName = element.tagName;
+  return tagName == goog.dom.TagName.UL || tagName == goog.dom.TagName.OL;
+};
+
+
+/**
+ * Returns the text within the local paragraph around the cursor.
+ * Notice that for GECKO a BR represents a pargraph change despite not being a
+ * block element.
+ *
+ * @param {Element} root The first block element ancestor of the node the cursor
+ *     is in.
+ * @param {Node} cursorLocation Node where the cursor currently is, marking the
+ *     paragraph whose text we will return.
+ * @param {function(Node): boolean} isParagraphBoundary The function to
+ *     determine if a node represents the start or end of the paragraph.
+ * @return {string} the text in the paragraph around the cursor location.
+ * @private
+ */
+goog.editor.plugins.FirstStrong.prototype.getTextAround_ = function(root,
+    cursorLocation, isParagraphBoundary) {
+  // The buffer where we're collecting the text.
+  var buffer = [];
+  // Have we reached the cursor yet, or are we still before it?
+  var pastCursorLocation = false;
+
+  if (root && cursorLocation) {
+    goog.iter.some(new goog.dom.TagIterator(root), function(node) {
+      if (node == cursorLocation) {
+        pastCursorLocation = true;
+      } else if (isParagraphBoundary(node)) {
+        if (pastCursorLocation) {
+          // This is the end of the paragraph containing the cursor. We're done.
+          return true;
+        } else {
+          // All we collected so far does not count; it was in a previous
+          // paragraph that did not contain the cursor.
+          buffer = [];
+        }
+      }
+      if (node.nodeType == goog.dom.NodeType.TEXT) {
+        buffer.push(node.nodeValue);
+      }
+      return false;  // Keep going.
+    });
+  }
+  return buffer.join('');
+};
+
+
+/**
+ * @param {Node} node Node to check.
+ * @return {boolean} Does the given node represent a Block element? Notice we do
+ *     not consider list items as Block elements in the algorithm.
+ * @private
+ */
+goog.editor.plugins.FirstStrong.isBlock_ = function(node) {
+  return !!node && goog.editor.node.isBlockTag(node) &&
+      node.tagName != goog.dom.TagName.LI;
+};
+
+
+/**
+ * @param {Node} node Node to check.
+ * @return {boolean} Does the given node represent a Block element from the
+ *     point of view of FireFox? Notice we do not consider list items as Block
+ *     elements in the algorithm.
+ * @private
+ */
+goog.editor.plugins.FirstStrong.isGeckoBlock_ = function(node) {
+  return !!node && (node.tagName == goog.dom.TagName.BR ||
+      goog.editor.plugins.FirstStrong.isBlock_(node));
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/headerformatter.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/headerformatter.js b/externs/GCL/externs/goog/editor/plugins/headerformatter.js
new file mode 100644
index 0000000..fa4bb1f
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/headerformatter.js
@@ -0,0 +1,96 @@
+// Copyright 2008 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 Handles applying header styles to text.
+ *
+ */
+
+goog.provide('goog.editor.plugins.HeaderFormatter');
+
+goog.require('goog.editor.Command');
+goog.require('goog.editor.Plugin');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * Applies header styles to text.
+ * @constructor
+ * @extends {goog.editor.Plugin}
+ * @final
+ */
+goog.editor.plugins.HeaderFormatter = function() {
+  goog.editor.Plugin.call(this);
+};
+goog.inherits(goog.editor.plugins.HeaderFormatter, goog.editor.Plugin);
+
+
+/** @override */
+goog.editor.plugins.HeaderFormatter.prototype.getTrogClassId = function() {
+  return 'HeaderFormatter';
+};
+
+// TODO(user):  Move execCommand functionality from basictextformatter into
+// here for headers.  I'm not doing this now because it depends on the
+// switch statements in basictextformatter and we'll need to abstract that out
+// in order to seperate out any of the functions from basictextformatter.
+
+
+/**
+ * Commands that can be passed as the optional argument to execCommand.
+ * @enum {string}
+ */
+goog.editor.plugins.HeaderFormatter.HEADER_COMMAND = {
+  H1: 'H1',
+  H2: 'H2',
+  H3: 'H3',
+  H4: 'H4'
+};
+
+
+/**
+ * @override
+ */
+goog.editor.plugins.HeaderFormatter.prototype.handleKeyboardShortcut = function(
+    e, key, isModifierPressed) {
+  if (!isModifierPressed) {
+    return false;
+  }
+  var command = null;
+  switch (key) {
+    case '1':
+      command = goog.editor.plugins.HeaderFormatter.HEADER_COMMAND.H1;
+      break;
+    case '2':
+      command = goog.editor.plugins.HeaderFormatter.HEADER_COMMAND.H2;
+      break;
+    case '3':
+      command = goog.editor.plugins.HeaderFormatter.HEADER_COMMAND.H3;
+      break;
+    case '4':
+      command = goog.editor.plugins.HeaderFormatter.HEADER_COMMAND.H4;
+      break;
+  }
+  if (command) {
+    this.getFieldObject().execCommand(
+        goog.editor.Command.FORMAT_BLOCK, command);
+    // Prevent default isn't enough to cancel tab navigation in FF.
+    if (goog.userAgent.GECKO) {
+      e.stopPropagation();
+    }
+    return true;
+  }
+  return false;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/editor/plugins/linkbubble.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/editor/plugins/linkbubble.js b/externs/GCL/externs/goog/editor/plugins/linkbubble.js
new file mode 100644
index 0000000..01c84f3
--- /dev/null
+++ b/externs/GCL/externs/goog/editor/plugins/linkbubble.js
@@ -0,0 +1,585 @@
+// Copyright 2008 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 Base class for bubble plugins.
+ *
+ */
+
+goog.provide('goog.editor.plugins.LinkBubble');
+goog.provide('goog.editor.plugins.LinkBubble.Action');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.editor.Command');
+goog.require('goog.editor.Link');
+goog.require('goog.editor.plugins.AbstractBubblePlugin');
+goog.require('goog.editor.range');
+goog.require('goog.functions');
+goog.require('goog.string');
+goog.require('goog.style');
+goog.require('goog.ui.editor.messages');
+goog.require('goog.uri.utils');
+goog.require('goog.window');
+
+
+
+/**
+ * Property bubble plugin for links.
+ * @param {...!goog.editor.plugins.LinkBubble.Action} var_args List of
+ *     extra actions supported by the bubble.
+ * @constructor
+ * @extends {goog.editor.plugins.AbstractBubblePlugin}
+ */
+goog.editor.plugins.LinkBubble = function(var_args) {
+  goog.editor.plugins.LinkBubble.base(this, 'constructor');
+
+  /**
+   * List of extra actions supported by the bubble.
+   * @type {Array<!goog.editor.plugins.LinkBubble.Action>}
+   * @private
+   */
+  this.extraActions_ = goog.array.toArray(arguments);
+
+  /**
+   * List of spans corresponding to the extra actions.
+   * @type {Array<!Element>}
+   * @private
+   */
+  this.actionSpans_ = [];
+
+  /**
+   * A list of whitelisted URL schemes which are safe to open.
+   * @type {Array<string>}
+   * @private
+   */
+  this.safeToOpenSchemes_ = ['http', 'https', 'ftp'];
+};
+goog.inherits(goog.editor.plugins.LinkBubble,
+    goog.editor.plugins.AbstractBubblePlugin);
+
+
+/**
+ * Element id for the link text.
+ * type {string}
+ * @private
+ */
+goog.editor.plugins.LinkBubble.LINK_TEXT_ID_ = 'tr_link-text';
+
+
+/**
+ * Element id for the test link span.
+ * type {string}
+ * @private
+ */
+goog.editor.plugins.LinkBubble.TEST_LINK_SPAN_ID_ = 'tr_test-link-span';
+
+
+/**
+ * Element id for the test link.
+ * type {string}
+ * @private
+ */
+goog.editor.plugins.LinkBubble.TEST_LINK_ID_ = 'tr_test-link';
+
+
+/**
+ * Element id for the change link span.
+ * type {string}
+ * @private
+ */
+goog.editor.plugins.LinkBubble.CHANGE_LINK_SPAN_ID_ = 'tr_change-link-span';
+
+
+/**
+ * Element id for the link.
+ * type {string}
+ * @private
+ */
+goog.editor.plugins.LinkBubble.CHANGE_LINK_ID_ = 'tr_change-link';
+
+
+/**
+ * Element id for the delete link span.
+ * type {string}
+ * @private
+ */
+goog.editor.plugins.LinkBubble.DELETE_LINK_SPAN_ID_ = 'tr_delete-link-span';
+
+
+/**
+ * Element id for the delete link.
+ * type {string}
+ * @private
+ */
+goog.editor.plugins.LinkBubble.DELETE_LINK_ID_ = 'tr_delete-link';
+
+
+/**
+ * Element id for the link bubble wrapper div.
+ * type {string}
+ * @private
+ */
+goog.editor.plugins.LinkBubble.LINK_DIV_ID_ = 'tr_link-div';
+
+
+/**
+ * @desc Text label for link that lets the user click it to see where the link
+ *     this bubble is for point to.
+ */
+goog.editor.plugins.LinkBubble.MSG_LINK_BUBBLE_TEST_LINK = goog.getMsg(
+    'Go to link: ');
+
+
+/**
+ * @desc Label that pops up a dialog to change the link.
+ */
+goog.editor.plugins.LinkBubble.MSG_LINK_BUBBLE_CHANGE = goog.getMsg(
+    'Change');
+
+
+/**
+ * @desc Label that allow the user to remove this link.
+ */
+goog.editor.plugins.LinkBubble.MSG_LINK_BUBBLE_REMOVE = goog.getMsg(
+    'Remove');
+
+
+/**
+ * @desc Message shown in a link bubble when the link is not a valid url.
+ */
+goog.editor.plugins.LinkBubble.MSG_INVALID_URL_LINK_BUBBLE = goog.getMsg(
+    'invalid url');
+
+
+/**
+ * Whether to stop leaking the page's url via the referrer header when the
+ * link text link is clicked.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.plugins.LinkBubble.prototype.stopReferrerLeaks_ = false;
+
+
+/**
+ * Whether to block opening links with a non-whitelisted URL scheme.
+ * @type {boolean}
+ * @private
+ */
+goog.editor.plugins.LinkBubble.prototype.blockOpeningUnsafeSchemes_ =
+    true;
+
+
+/**
+ * Tells the plugin to stop leaking the page's url via the referrer header when
+ * the link text link is clicked. When the user clicks on a link, the
+ * browser makes a request for the link url, passing the url of the current page
+ * in the request headers. If the user wants the current url to be kept secret
+ * (e.g. an unpublished document), the owner of the url that was clicked will
+ * see the secret url in the request headers, and it will no longer be a secret.
+ * Calling this method will not send a referrer header in the request, just as
+ * if the user had opened a blank window and typed the url in themselves.
+ */
+goog.editor.plugins.LinkBubble.prototype.stopReferrerLeaks = function() {
+  // TODO(user): Right now only 2 plugins have this API to stop
+  // referrer leaks. If more plugins need to do this, come up with a way to
+  // enable the functionality in all plugins at once. Same thing for
+  // setBlockOpeningUnsafeSchemes and associated functionality.
+  this.stopReferrerLeaks_ = true;
+};
+
+
+/**
+ * Tells the plugin whether to block URLs with schemes not in the whitelist.
+ * If blocking is enabled, this plugin will not linkify the link in the bubble
+ * popup.
+ * @param {boolean} blockOpeningUnsafeSchemes Whether to block non-whitelisted
+ *     schemes.
+ */
+goog.editor.plugins.LinkBubble.prototype.setBlockOpeningUnsafeSchemes =
+    function(blockOpeningUnsafeSchemes) {
+  this.blockOpeningUnsafeSchemes_ = blockOpeningUnsafeSchemes;
+};
+
+
+/**
+ * Sets a whitelist of allowed URL schemes that are safe to open.
+ * Schemes should all be in lowercase. If the plugin is set to block opening
+ * unsafe schemes, user-entered URLs will be converted to lowercase and checked
+ * against this list. The whitelist has no effect if blocking is not enabled.
+ * @param {Array<string>} schemes String array of URL schemes to allow (http,
+ *     https, etc.).
+ */
+goog.editor.plugins.LinkBubble.prototype.setSafeToOpenSchemes =
+    function(schemes) {
+  this.safeToOpenSchemes_ = schemes;
+};
+
+
+/** @override */
+goog.editor.plugins.LinkBubble.prototype.getTrogClassId = function() {
+  return 'LinkBubble';
+};
+
+
+/** @override */
+goog.editor.plugins.LinkBubble.prototype.isSupportedCommand =
+    function(command) {
+  return command == goog.editor.Command.UPDATE_LINK_BUBBLE;
+};
+
+
+/** @override */
+goog.editor.plugins.LinkBubble.prototype.execCommandInternal =
+    function(command, var_args) {
+  if (command == goog.editor.Command.UPDATE_LINK_BUBBLE) {
+    this.updateLink_();
+  }
+};
+
+
+/**
+ * Updates the href in the link bubble with a new link.
+ * @private
+ */
+goog.editor.plugins.LinkBubble.prototype.updateLink_ = function() {
+  var targetEl = this.getTargetElement();
+  if (targetEl) {
+    this.closeBubble();
+    this.createBubble(targetEl);
+  }
+};
+
+
+/** @override */
+goog.editor.plugins.LinkBubble.prototype.getBubbleTargetFromSelection =
+    function(selectedElement) {
+  var bubbleTarget = goog.dom.getAncestorByTagNameAndClass(selectedElement,
+      goog.dom.TagName.A);
+
+  if (!bubbleTarget) {
+    // See if the selection is touching the right side of a link, and if so,
+    // show a bubble for that link.  The check for "touching" is very brittle,
+    // and currently only guarantees that it will pop up a bubble at the
+    // position the cursor is placed at after the link dialog is closed.
+    // NOTE(robbyw): This assumes this method is always called with
+    // selected element = range.getContainerElement().  Right now this is true,
+    // but attempts to re-use this method for other purposes could cause issues.
+    // TODO(robbyw): Refactor this method to also take a range, and use that.
+    var range = this.getFieldObject().getRange();
+    if (range && range.isCollapsed() && range.getStartOffset() == 0) {
+      var startNode = range.getStartNode();
+      var previous = startNode.previousSibling;
+      if (previous && previous.tagName == goog.dom.TagName.A) {
+        bubbleTarget = previous;
+      }
+    }
+  }
+
+  return /** @type {Element} */ (bubbleTarget);
+};
+
+
+/**
+ * Set the optional function for getting the "test" link of a url.
+ * @param {function(string) : string} func The function to use.
+ */
+goog.editor.plugins.LinkBubble.prototype.setTestLinkUrlFn = function(func) {
+  this.testLinkUrlFn_ = func;
+};
+
+
+/**
+ * Returns the target element url for the bubble.
+ * @return {string} The url href.
+ * @protected
+ */
+goog.editor.plugins.LinkBubble.prototype.getTargetUrl = function() {
+  // Get the href-attribute through getAttribute() rather than the href property
+  // because Google-Toolbar on Firefox with "Send with Gmail" turned on
+  // modifies the href-property of 'mailto:' links but leaves the attribute
+  // untouched.
+  return this.getTargetElement().getAttribute('href') || '';
+};
+
+
+/** @override */
+goog.editor.plugins.LinkBubble.prototype.getBubbleType = function() {
+  return goog.dom.TagName.A;
+};
+
+
+/** @override */
+goog.editor.plugins.LinkBubble.prototype.getBubbleTitle = function() {
+  return goog.ui.editor.messages.MSG_LINK_CAPTION;
+};
+
+
+/**
+ * Returns the message to display for testing a link.
+ * @return {string} The message for testing a link.
+ * @protected
+ */
+goog.editor.plugins.LinkBubble.prototype.getTestLinkMessage = function() {
+  return goog.editor.plugins.LinkBubble.MSG_LINK_BUBBLE_TEST_LINK;
+};
+
+
+/** @override */
+goog.editor.plugins.LinkBubble.prototype.createBubbleContents = function(
+    bubbleContainer) {
+  var linkObj = this.getLinkToTextObj_();
+
+  // Create linkTextSpan, show plain text for e-mail address or truncate the
+  // text to <= 48 characters so that property bubbles don't grow too wide and
+  // create a link if URL.  Only linkify valid links.
+  // TODO(robbyw): Repalce this color with a CSS class.
+  var color = linkObj.valid ? 'black' : 'red';
+  var shouldOpenUrl = this.shouldOpenUrl(linkObj.linkText);
+  var linkTextSpan;
+  if (goog.editor.Link.isLikelyEmailAddress(linkObj.linkText) ||
+      !linkObj.valid || !shouldOpenUrl) {
+    linkTextSpan = this.dom_.createDom(goog.dom.TagName.SPAN,
+        {
+          id: goog.editor.plugins.LinkBubble.LINK_TEXT_ID_,
+          style: 'color:' + color
+        }, this.dom_.createTextNode(linkObj.linkText));
+  } else {
+    var testMsgSpan = this.dom_.createDom(goog.dom.TagName.SPAN,
+        {id: goog.editor.plugins.LinkBubble.TEST_LINK_SPAN_ID_},
+        this.getTestLinkMessage());
+    linkTextSpan = this.dom_.createDom(goog.dom.TagName.SPAN,
+        {
+          id: goog.editor.plugins.LinkBubble.LINK_TEXT_ID_,
+          style: 'color:' + color
+        }, '');
+    var linkText = goog.string.truncateMiddle(linkObj.linkText, 48);
+    // Actually creates a pseudo-link that can't be right-clicked to open in a
+    // new tab, because that would avoid the logic to stop referrer leaks.
+    this.createLink(goog.editor.plugins.LinkBubble.TEST_LINK_ID_,
+                    this.dom_.createTextNode(linkText).data,
+                    this.testLink,
+                    linkTextSpan);
+  }
+
+  var changeLinkSpan = this.createLinkOption(
+      goog.editor.plugins.LinkBubble.CHANGE_LINK_SPAN_ID_);
+  this.createLink(goog.editor.plugins.LinkBubble.CHANGE_LINK_ID_,
+      goog.editor.plugins.LinkBubble.MSG_LINK_BUBBLE_CHANGE,
+      this.showLinkDialog_, changeLinkSpan);
+
+  // This function is called multiple times - we have to reset the array.
+  this.actionSpans_ = [];
+  for (var i = 0; i < this.extraActions_.length; i++) {
+    var action = this.extraActions_[i];
+    var actionSpan = this.createLinkOption(action.spanId_);
+    this.actionSpans_.push(actionSpan);
+    this.createLink(action.linkId_, action.message_,
+        function() {
+          action.actionFn_(this.getTargetUrl());
+        },
+        actionSpan);
+  }
+
+  var removeLinkSpan = this.createLinkOption(
+      goog.editor.plugins.LinkBubble.DELETE_LINK_SPAN_ID_);
+  this.createLink(goog.editor.plugins.LinkBubble.DELETE_LINK_ID_,
+      goog.editor.plugins.LinkBubble.MSG_LINK_BUBBLE_REMOVE,
+      this.deleteLink_, removeLinkSpan);
+
+  this.onShow();
+
+  var bubbleContents = this.dom_.createDom(goog.dom.TagName.DIV,
+      {id: goog.editor.plugins.LinkBubble.LINK_DIV_ID_},
+      testMsgSpan || '', linkTextSpan, changeLinkSpan);
+
+  for (i = 0; i < this.actionSpans_.length; i++) {
+    bubbleContents.appendChild(this.actionSpans_[i]);
+  }
+  bubbleContents.appendChild(removeLinkSpan);
+
+  goog.dom.appendChild(bubbleContainer, bubbleContents);
+};
+
+
+/**
+ * Tests the link by opening it in a new tab/window. Should be used as the
+ * click event handler for the test pseudo-link.
+ * @protected
+ */
+goog.editor.plugins.LinkBubble.prototype.testLink = function() {
+  goog.window.open(this.getTestLinkAction_(),
+      {
+        'target': '_blank',
+        'noreferrer': this.stopReferrerLeaks_
+      }, this.getFieldObject().getAppWindow());
+};
+
+
+/**
+ * Returns whether the URL should be considered invalid.  This always returns
+ * false in the base class, and should be overridden by subclasses that wish
+ * to impose validity rules on URLs.
+ * @param {string} url The url to check.
+ * @return {boolean} Whether the URL should be considered invalid.
+ */
+goog.editor.plugins.LinkBubble.prototype.isInvalidUrl = goog.functions.FALSE;
+
+
+/**
+ * Gets the text to display for a link, based on the type of link
+ * @return {!Object} Returns an object of the form:
+ *     {linkText: displayTextForLinkTarget, valid: ifTheLinkIsValid}.
+ * @private
+ */
+goog.editor.plugins.LinkBubble.prototype.getLinkToTextObj_ = function() {
+  var isError;
+  var targetUrl = this.getTargetUrl();
+
+  if (this.isInvalidUrl(targetUrl)) {
+
+    targetUrl = goog.editor.plugins.LinkBubble.MSG_INVALID_URL_LINK_BUBBLE;
+    isError = true;
+  } else if (goog.editor.Link.isMailto(targetUrl)) {
+    targetUrl = targetUrl.substring(7); // 7 == "mailto:".length
+  }
+
+  return {linkText: targetUrl, valid: !isError};
+};
+
+
+/**
+ * Shows the link dialog.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.editor.plugins.LinkBubble.prototype.showLinkDialog_ = function(e) {
+  // Needed when this occurs due to an ENTER key event, else the newly created
+  // dialog manages to have its OK button pressed, causing it to disappear.
+  e.preventDefault();
+
+  this.getFieldObject().execCommand(goog.editor.Command.MODAL_LINK_EDITOR,
+      new goog.editor.Link(
+          /** @type {HTMLAnchorElement} */ (this.getTargetElement()),
+          false));
+  this.closeBubble();
+};
+
+
+/**
+ * Deletes the link associated with the bubble
+ * @private
+ */
+goog.editor.plugins.LinkBubble.prototype.deleteLink_ = function() {
+  this.getFieldObject().dispatchBeforeChange();
+
+  var link = this.getTargetElement();
+  var child = link.lastChild;
+  goog.dom.flattenElement(link);
+  goog.editor.range.placeCursorNextTo(child, false);
+
+  this.closeBubble();
+
+  this.getFieldObject().dispatchChange();
+  this.getFieldObject().focus();
+};
+
+
+/**
+ * Sets the proper state for the action links.
+ * @protected
+ * @override
+ */
+goog.editor.plugins.LinkBubble.prototype.onShow = function() {
+  var linkDiv = this.dom_.getElement(
+      goog.editor.plugins.LinkBubble.LINK_DIV_ID_);
+  if (linkDiv) {
+    var testLinkSpan = this.dom_.getElement(
+        goog.editor.plugins.LinkBubble.TEST_LINK_SPAN_ID_);
+    if (testLinkSpan) {
+      var url = this.getTargetUrl();
+      goog.style.setElementShown(testLinkSpan, !goog.editor.Link.isMailto(url));
+    }
+
+    for (var i = 0; i < this.extraActions_.length; i++) {
+      var action = this.extraActions_[i];
+      var actionSpan = this.dom_.getElement(action.spanId_);
+      if (actionSpan) {
+        goog.style.setElementShown(actionSpan, action.toShowFn_(
+            this.getTargetUrl()));
+      }
+    }
+  }
+};
+
+
+/**
+ * Gets the url for the bubble test link.  The test link is the link in the
+ * bubble the user can click on to make sure the link they entered is correct.
+ * @return {string} The url for the bubble link href.
+ * @private
+ */
+goog.editor.plugins.LinkBubble.prototype.getTestLinkAction_ = function() {
+  var targetUrl = this.getTargetUrl();
+  return this.testLinkUrlFn_ ? this.testLinkUrlFn_(targetUrl) : targetUrl;
+};
+
+
+/**
+ * Checks whether the plugin should open the given url in a new window.
+ * @param {string} url The url to check.
+ * @return {boolean} If the plugin should open the given url in a new window.
+ * @protected
+ */
+goog.editor.plugins.LinkBubble.prototype.shouldOpenUrl = function(url) {
+  return !this.blockOpeningUnsafeSchemes_ || this.isSafeSchemeToOpen_(url);
+};
+
+
+/**
+ * Determines whether or not a url has a scheme which is safe to open.
+ * Schemes like javascript are unsafe due to the possibility of XSS.
+ * @param {string} url A url.
+ * @return {boolean} Whether the url has a safe scheme.
+ * @private
+ */
+goog.editor.plugins.LinkBubble.prototype.isSafeSchemeToOpen_ =
+    function(url) {
+  var scheme = goog.uri.utils.getScheme(url) || 'http';
+  return goog.array.contains(this.safeToOpenSchemes_, scheme.toLowerCase());
+};
+
+
+
+/**
+ * Constructor for extra actions that can be added to the link bubble.
+ * @param {string} spanId The ID for the span showing the action.
+ * @param {string} linkId The ID for the link showing the action.
+ * @param {string} message The text for the link showing the action.
+ * @param {function(string):boolean} toShowFn Test function to determine whether
+ *     to show the action for the given URL.
+ * @param {function(string):void} actionFn Action function to run when the
+ *     action is clicked.  Takes the current target URL as a parameter.
+ * @constructor
+ * @final
+ */
+goog.editor.plugins.LinkBubble.Action = function(spanId, linkId, message,
+    toShowFn, actionFn) {
+  this.spanId_ = spanId;
+  this.linkId_ = linkId;
+  this.message_ = message;
+  this.toShowFn_ = toShowFn;
+  this.actionFn_ = actionFn;
+};


[13/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/dragger.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/dragger.js b/externs/GCL/externs/goog/fx/dragger.js
new file mode 100644
index 0000000..30a5a57
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/dragger.js
@@ -0,0 +1,869 @@
+// 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 Drag Utilities.
+ *
+ * Provides extensible functionality for drag & drop behaviour.
+ *
+ * @see ../demos/drag.html
+ * @see ../demos/dragger.html
+ */
+
+
+goog.provide('goog.fx.DragEvent');
+goog.provide('goog.fx.Dragger');
+goog.provide('goog.fx.Dragger.EventType');
+
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+goog.require('goog.events');
+goog.require('goog.events.Event');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.math.Coordinate');
+goog.require('goog.math.Rect');
+goog.require('goog.style');
+goog.require('goog.style.bidi');
+goog.require('goog.userAgent');
+
+
+
+/**
+ * A class that allows mouse or touch-based dragging (moving) of an element
+ *
+ * @param {Element} target The element that will be dragged.
+ * @param {Element=} opt_handle An optional handle to control the drag, if null
+ *     the target is used.
+ * @param {goog.math.Rect=} opt_limits Object containing left, top, width,
+ *     and height.
+ *
+ * @extends {goog.events.EventTarget}
+ * @constructor
+ */
+goog.fx.Dragger = function(target, opt_handle, opt_limits) {
+  goog.events.EventTarget.call(this);
+  this.target = target;
+  this.handle = opt_handle || target;
+  this.limits = opt_limits || new goog.math.Rect(NaN, NaN, NaN, NaN);
+
+  this.document_ = goog.dom.getOwnerDocument(target);
+  this.eventHandler_ = new goog.events.EventHandler(this);
+  this.registerDisposable(this.eventHandler_);
+
+  // Add listener. Do not use the event handler here since the event handler is
+  // used for listeners added and removed during the drag operation.
+  goog.events.listen(this.handle,
+      [goog.events.EventType.TOUCHSTART, goog.events.EventType.MOUSEDOWN],
+      this.startDrag, false, this);
+};
+goog.inherits(goog.fx.Dragger, goog.events.EventTarget);
+// Dragger is meant to be extended, but defines most properties on its
+// prototype, thus making it unsuitable for sealing.
+goog.tagUnsealableClass(goog.fx.Dragger);
+
+
+/**
+ * Whether setCapture is supported by the browser.
+ * @private {boolean}
+ * @const
+ */
+goog.fx.Dragger.HAS_SET_CAPTURE_ =
+    // IE (up to and including IE 11) and Gecko after 1.9.3 have setCapture
+    // WebKit does not yet: https://bugs.webkit.org/show_bug.cgi?id=27330
+    (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('12')) ||
+    (goog.userAgent.GECKO && goog.userAgent.isVersionOrHigher('1.9.3'));
+
+
+/**
+ * Creates copy of node being dragged.  This is a utility function to be used
+ * wherever it is inappropriate for the original source to follow the mouse
+ * cursor itself.
+ *
+ * @param {Element} sourceEl Element to copy.
+ * @return {!Element} The clone of {@code sourceEl}.
+ */
+goog.fx.Dragger.cloneNode = function(sourceEl) {
+  var clonedEl = /** @type {Element} */ (sourceEl.cloneNode(true)),
+      origTexts = sourceEl.getElementsByTagName(goog.dom.TagName.TEXTAREA),
+      dragTexts = clonedEl.getElementsByTagName(goog.dom.TagName.TEXTAREA);
+  // Cloning does not copy the current value of textarea elements, so correct
+  // this manually.
+  for (var i = 0; i < origTexts.length; i++) {
+    dragTexts[i].value = origTexts[i].value;
+  }
+  switch (sourceEl.tagName) {
+    case goog.dom.TagName.TR:
+      return goog.dom.createDom(goog.dom.TagName.TABLE, null,
+                                goog.dom.createDom(goog.dom.TagName.TBODY,
+                                                   null, clonedEl));
+    case goog.dom.TagName.TD:
+    case goog.dom.TagName.TH:
+      return goog.dom.createDom(
+          goog.dom.TagName.TABLE, null, goog.dom.createDom(
+              goog.dom.TagName.TBODY, null, goog.dom.createDom(
+                  goog.dom.TagName.TR, null, clonedEl)));
+    case goog.dom.TagName.TEXTAREA:
+      clonedEl.value = sourceEl.value;
+    default:
+      return clonedEl;
+  }
+};
+
+
+/**
+ * Constants for event names.
+ * @enum {string}
+ */
+goog.fx.Dragger.EventType = {
+  // The drag action was canceled before the START event. Possible reasons:
+  // disabled dragger, dragging with the right mouse button or releasing the
+  // button before reaching the hysteresis distance.
+  EARLY_CANCEL: 'earlycancel',
+  START: 'start',
+  BEFOREDRAG: 'beforedrag',
+  DRAG: 'drag',
+  END: 'end'
+};
+
+
+/**
+ * Reference to drag target element.
+ * @type {Element}
+ */
+goog.fx.Dragger.prototype.target;
+
+
+/**
+ * Reference to the handler that initiates the drag.
+ * @type {Element}
+ */
+goog.fx.Dragger.prototype.handle;
+
+
+/**
+ * Object representing the limits of the drag region.
+ * @type {goog.math.Rect}
+ */
+goog.fx.Dragger.prototype.limits;
+
+
+/**
+ * Whether the element is rendered right-to-left. We initialize this lazily.
+ * @type {boolean|undefined}}
+ * @private
+ */
+goog.fx.Dragger.prototype.rightToLeft_;
+
+
+/**
+ * Current x position of mouse or touch relative to viewport.
+ * @type {number}
+ */
+goog.fx.Dragger.prototype.clientX = 0;
+
+
+/**
+ * Current y position of mouse or touch relative to viewport.
+ * @type {number}
+ */
+goog.fx.Dragger.prototype.clientY = 0;
+
+
+/**
+ * Current x position of mouse or touch relative to screen. Deprecated because
+ * it doesn't take into affect zoom level or pixel density.
+ * @type {number}
+ * @deprecated Consider switching to clientX instead.
+ */
+goog.fx.Dragger.prototype.screenX = 0;
+
+
+/**
+ * Current y position of mouse or touch relative to screen. Deprecated because
+ * it doesn't take into affect zoom level or pixel density.
+ * @type {number}
+ * @deprecated Consider switching to clientY instead.
+ */
+goog.fx.Dragger.prototype.screenY = 0;
+
+
+/**
+ * The x position where the first mousedown or touchstart occurred.
+ * @type {number}
+ */
+goog.fx.Dragger.prototype.startX = 0;
+
+
+/**
+ * The y position where the first mousedown or touchstart occurred.
+ * @type {number}
+ */
+goog.fx.Dragger.prototype.startY = 0;
+
+
+/**
+ * Current x position of drag relative to target's parent.
+ * @type {number}
+ */
+goog.fx.Dragger.prototype.deltaX = 0;
+
+
+/**
+ * Current y position of drag relative to target's parent.
+ * @type {number}
+ */
+goog.fx.Dragger.prototype.deltaY = 0;
+
+
+/**
+ * The current page scroll value.
+ * @type {goog.math.Coordinate}
+ */
+goog.fx.Dragger.prototype.pageScroll;
+
+
+/**
+ * Whether dragging is currently enabled.
+ * @type {boolean}
+ * @private
+ */
+goog.fx.Dragger.prototype.enabled_ = true;
+
+
+/**
+ * Whether object is currently being dragged.
+ * @type {boolean}
+ * @private
+ */
+goog.fx.Dragger.prototype.dragging_ = false;
+
+
+/**
+ * Whether mousedown should be default prevented.
+ * @private {boolean}
+ */
+goog.fx.Dragger.prototype.preventMouseDown_ = true;
+
+
+/**
+ * The amount of distance, in pixels, after which a mousedown or touchstart is
+ * considered a drag.
+ * @type {number}
+ * @private
+ */
+goog.fx.Dragger.prototype.hysteresisDistanceSquared_ = 0;
+
+
+/**
+ * Timestamp of when the mousedown or touchstart occurred.
+ * @type {number}
+ * @private
+ */
+goog.fx.Dragger.prototype.mouseDownTime_ = 0;
+
+
+/**
+ * Reference to a document object to use for the events.
+ * @type {Document}
+ * @private
+ */
+goog.fx.Dragger.prototype.document_;
+
+
+/**
+ * The SCROLL event target used to make drag element follow scrolling.
+ * @type {EventTarget}
+ * @private
+ */
+goog.fx.Dragger.prototype.scrollTarget_;
+
+
+/**
+ * Whether IE drag events cancelling is on.
+ * @type {boolean}
+ * @private
+ */
+goog.fx.Dragger.prototype.ieDragStartCancellingOn_ = false;
+
+
+/**
+ * Whether the dragger implements the changes described in http://b/6324964,
+ * making it truly RTL.  This is a temporary flag to allow clients to transition
+ * to the new behavior at their convenience.  At some point it will be the
+ * default.
+ * @type {boolean}
+ * @private
+ */
+goog.fx.Dragger.prototype.useRightPositioningForRtl_ = false;
+
+
+/**
+ * Turns on/off true RTL behavior.  This should be called immediately after
+ * construction.  This is a temporary flag to allow clients to transition
+ * to the new component at their convenience.  At some point true will be the
+ * default.
+ * @param {boolean} useRightPositioningForRtl True if "right" should be used for
+ *     positioning, false if "left" should be used for positioning.
+ */
+goog.fx.Dragger.prototype.enableRightPositioningForRtl =
+    function(useRightPositioningForRtl) {
+  this.useRightPositioningForRtl_ = useRightPositioningForRtl;
+};
+
+
+/**
+ * Returns the event handler, intended for subclass use.
+ * @return {!goog.events.EventHandler<T>} The event handler.
+ * @this T
+ * @template T
+ */
+goog.fx.Dragger.prototype.getHandler = function() {
+  // TODO(user): templated "this" values currently result in "this" being
+  // "unknown" in the body of the function.
+  var self = /** @type {goog.fx.Dragger} */ (this);
+  return self.eventHandler_;
+};
+
+
+/**
+ * Sets (or reset) the Drag limits after a Dragger is created.
+ * @param {goog.math.Rect?} limits Object containing left, top, width,
+ *     height for new Dragger limits. If target is right-to-left and
+ *     enableRightPositioningForRtl(true) is called, then rect is interpreted as
+ *     right, top, width, and height.
+ */
+goog.fx.Dragger.prototype.setLimits = function(limits) {
+  this.limits = limits || new goog.math.Rect(NaN, NaN, NaN, NaN);
+};
+
+
+/**
+ * Sets the distance the user has to drag the element before a drag operation is
+ * started.
+ * @param {number} distance The number of pixels after which a mousedown and
+ *     move is considered a drag.
+ */
+goog.fx.Dragger.prototype.setHysteresis = function(distance) {
+  this.hysteresisDistanceSquared_ = Math.pow(distance, 2);
+};
+
+
+/**
+ * Gets the distance the user has to drag the element before a drag operation is
+ * started.
+ * @return {number} distance The number of pixels after which a mousedown and
+ *     move is considered a drag.
+ */
+goog.fx.Dragger.prototype.getHysteresis = function() {
+  return Math.sqrt(this.hysteresisDistanceSquared_);
+};
+
+
+/**
+ * Sets the SCROLL event target to make drag element follow scrolling.
+ *
+ * @param {EventTarget} scrollTarget The event target that dispatches SCROLL
+ *     events.
+ */
+goog.fx.Dragger.prototype.setScrollTarget = function(scrollTarget) {
+  this.scrollTarget_ = scrollTarget;
+};
+
+
+/**
+ * Enables cancelling of built-in IE drag events.
+ * @param {boolean} cancelIeDragStart Whether to enable cancelling of IE
+ *     dragstart event.
+ */
+goog.fx.Dragger.prototype.setCancelIeDragStart = function(cancelIeDragStart) {
+  this.ieDragStartCancellingOn_ = cancelIeDragStart;
+};
+
+
+/**
+ * @return {boolean} Whether the dragger is enabled.
+ */
+goog.fx.Dragger.prototype.getEnabled = function() {
+  return this.enabled_;
+};
+
+
+/**
+ * Set whether dragger is enabled
+ * @param {boolean} enabled Whether dragger is enabled.
+ */
+goog.fx.Dragger.prototype.setEnabled = function(enabled) {
+  this.enabled_ = enabled;
+};
+
+
+/**
+ * Set whether mousedown should be default prevented.
+ * @param {boolean} preventMouseDown Whether mousedown should be default
+ *     prevented.
+ */
+goog.fx.Dragger.prototype.setPreventMouseDown = function(preventMouseDown) {
+  this.preventMouseDown_ = preventMouseDown;
+};
+
+
+/** @override */
+goog.fx.Dragger.prototype.disposeInternal = function() {
+  goog.fx.Dragger.superClass_.disposeInternal.call(this);
+  goog.events.unlisten(this.handle,
+      [goog.events.EventType.TOUCHSTART, goog.events.EventType.MOUSEDOWN],
+      this.startDrag, false, this);
+  this.cleanUpAfterDragging_();
+
+  this.target = null;
+  this.handle = null;
+};
+
+
+/**
+ * Whether the DOM element being manipulated is rendered right-to-left.
+ * @return {boolean} True if the DOM element is rendered right-to-left, false
+ *     otherwise.
+ * @private
+ */
+goog.fx.Dragger.prototype.isRightToLeft_ = function() {
+  if (!goog.isDef(this.rightToLeft_)) {
+    this.rightToLeft_ = goog.style.isRightToLeft(this.target);
+  }
+  return this.rightToLeft_;
+};
+
+
+/**
+ * Event handler that is used to start the drag
+ * @param {goog.events.BrowserEvent} e Event object.
+ */
+goog.fx.Dragger.prototype.startDrag = function(e) {
+  var isMouseDown = e.type == goog.events.EventType.MOUSEDOWN;
+
+  // Dragger.startDrag() can be called by AbstractDragDrop with a mousemove
+  // event and IE does not report pressed mouse buttons on mousemove. Also,
+  // it does not make sense to check for the button if the user is already
+  // dragging.
+
+  if (this.enabled_ && !this.dragging_ &&
+      (!isMouseDown || e.isMouseActionButton())) {
+    this.maybeReinitTouchEvent_(e);
+    if (this.hysteresisDistanceSquared_ == 0) {
+      if (this.fireDragStart_(e)) {
+        this.dragging_ = true;
+        if (this.preventMouseDown_) {
+          e.preventDefault();
+        }
+      } else {
+        // If the start drag is cancelled, don't setup for a drag.
+        return;
+      }
+    } else if (this.preventMouseDown_) {
+      // Need to preventDefault for hysteresis to prevent page getting selected.
+      e.preventDefault();
+    }
+    this.setupDragHandlers();
+
+    this.clientX = this.startX = e.clientX;
+    this.clientY = this.startY = e.clientY;
+    this.screenX = e.screenX;
+    this.screenY = e.screenY;
+    this.computeInitialPosition();
+    this.pageScroll = goog.dom.getDomHelper(this.document_).getDocumentScroll();
+
+    this.mouseDownTime_ = goog.now();
+  } else {
+    this.dispatchEvent(goog.fx.Dragger.EventType.EARLY_CANCEL);
+  }
+};
+
+
+/**
+ * Sets up event handlers when dragging starts.
+ * @protected
+ */
+goog.fx.Dragger.prototype.setupDragHandlers = function() {
+  var doc = this.document_;
+  var docEl = doc.documentElement;
+  // Use bubbling when we have setCapture since we got reports that IE has
+  // problems with the capturing events in combination with setCapture.
+  var useCapture = !goog.fx.Dragger.HAS_SET_CAPTURE_;
+
+  this.eventHandler_.listen(doc,
+      [goog.events.EventType.TOUCHMOVE, goog.events.EventType.MOUSEMOVE],
+      this.handleMove_, useCapture);
+  this.eventHandler_.listen(doc,
+      [goog.events.EventType.TOUCHEND, goog.events.EventType.MOUSEUP],
+      this.endDrag, useCapture);
+
+  if (goog.fx.Dragger.HAS_SET_CAPTURE_) {
+    docEl.setCapture(false);
+    this.eventHandler_.listen(docEl,
+                              goog.events.EventType.LOSECAPTURE,
+                              this.endDrag);
+  } else {
+    // Make sure we stop the dragging if the window loses focus.
+    // Don't use capture in this listener because we only want to end the drag
+    // if the actual window loses focus. Since blur events do not bubble we use
+    // a bubbling listener on the window.
+    this.eventHandler_.listen(goog.dom.getWindow(doc),
+                              goog.events.EventType.BLUR,
+                              this.endDrag);
+  }
+
+  if (goog.userAgent.IE && this.ieDragStartCancellingOn_) {
+    // Cancel IE's 'ondragstart' event.
+    this.eventHandler_.listen(doc, goog.events.EventType.DRAGSTART,
+                              goog.events.Event.preventDefault);
+  }
+
+  if (this.scrollTarget_) {
+    this.eventHandler_.listen(this.scrollTarget_, goog.events.EventType.SCROLL,
+                              this.onScroll_, useCapture);
+  }
+};
+
+
+/**
+ * Fires a goog.fx.Dragger.EventType.START event.
+ * @param {goog.events.BrowserEvent} e Browser event that triggered the drag.
+ * @return {boolean} False iff preventDefault was called on the DragEvent.
+ * @private
+ */
+goog.fx.Dragger.prototype.fireDragStart_ = function(e) {
+  return this.dispatchEvent(new goog.fx.DragEvent(
+      goog.fx.Dragger.EventType.START, this, e.clientX, e.clientY, e));
+};
+
+
+/**
+ * Unregisters the event handlers that are only active during dragging, and
+ * releases mouse capture.
+ * @private
+ */
+goog.fx.Dragger.prototype.cleanUpAfterDragging_ = function() {
+  this.eventHandler_.removeAll();
+  if (goog.fx.Dragger.HAS_SET_CAPTURE_) {
+    this.document_.releaseCapture();
+  }
+};
+
+
+/**
+ * Event handler that is used to end the drag.
+ * @param {goog.events.BrowserEvent} e Event object.
+ * @param {boolean=} opt_dragCanceled Whether the drag has been canceled.
+ */
+goog.fx.Dragger.prototype.endDrag = function(e, opt_dragCanceled) {
+  this.cleanUpAfterDragging_();
+
+  if (this.dragging_) {
+    this.maybeReinitTouchEvent_(e);
+    this.dragging_ = false;
+
+    var x = this.limitX(this.deltaX);
+    var y = this.limitY(this.deltaY);
+    var dragCanceled = opt_dragCanceled ||
+        e.type == goog.events.EventType.TOUCHCANCEL;
+    this.dispatchEvent(new goog.fx.DragEvent(
+        goog.fx.Dragger.EventType.END, this, e.clientX, e.clientY, e, x, y,
+        dragCanceled));
+  } else {
+    this.dispatchEvent(goog.fx.Dragger.EventType.EARLY_CANCEL);
+  }
+};
+
+
+/**
+ * Event handler that is used to end the drag by cancelling it.
+ * @param {goog.events.BrowserEvent} e Event object.
+ */
+goog.fx.Dragger.prototype.endDragCancel = function(e) {
+  this.endDrag(e, true);
+};
+
+
+/**
+ * Re-initializes the event with the first target touch event or, in the case
+ * of a stop event, the last changed touch.
+ * @param {goog.events.BrowserEvent} e A TOUCH... event.
+ * @private
+ */
+goog.fx.Dragger.prototype.maybeReinitTouchEvent_ = function(e) {
+  var type = e.type;
+
+  if (type == goog.events.EventType.TOUCHSTART ||
+      type == goog.events.EventType.TOUCHMOVE) {
+    e.init(e.getBrowserEvent().targetTouches[0], e.currentTarget);
+  } else if (type == goog.events.EventType.TOUCHEND ||
+             type == goog.events.EventType.TOUCHCANCEL) {
+    e.init(e.getBrowserEvent().changedTouches[0], e.currentTarget);
+  }
+};
+
+
+/**
+ * Event handler that is used on mouse / touch move to update the drag
+ * @param {goog.events.BrowserEvent} e Event object.
+ * @private
+ */
+goog.fx.Dragger.prototype.handleMove_ = function(e) {
+  if (this.enabled_) {
+    this.maybeReinitTouchEvent_(e);
+    // dx in right-to-left cases is relative to the right.
+    var sign = this.useRightPositioningForRtl_ &&
+        this.isRightToLeft_() ? -1 : 1;
+    var dx = sign * (e.clientX - this.clientX);
+    var dy = e.clientY - this.clientY;
+    this.clientX = e.clientX;
+    this.clientY = e.clientY;
+    this.screenX = e.screenX;
+    this.screenY = e.screenY;
+
+    if (!this.dragging_) {
+      var diffX = this.startX - this.clientX;
+      var diffY = this.startY - this.clientY;
+      var distance = diffX * diffX + diffY * diffY;
+      if (distance > this.hysteresisDistanceSquared_) {
+        if (this.fireDragStart_(e)) {
+          this.dragging_ = true;
+        } else {
+          // DragListGroup disposes of the dragger if BEFOREDRAGSTART is
+          // canceled.
+          if (!this.isDisposed()) {
+            this.endDrag(e);
+          }
+          return;
+        }
+      }
+    }
+
+    var pos = this.calculatePosition_(dx, dy);
+    var x = pos.x;
+    var y = pos.y;
+
+    if (this.dragging_) {
+
+      var rv = this.dispatchEvent(new goog.fx.DragEvent(
+          goog.fx.Dragger.EventType.BEFOREDRAG, this, e.clientX, e.clientY,
+          e, x, y));
+
+      // Only do the defaultAction and dispatch drag event if predrag didn't
+      // prevent default
+      if (rv) {
+        this.doDrag(e, x, y, false);
+        e.preventDefault();
+      }
+    }
+  }
+};
+
+
+/**
+ * Calculates the drag position.
+ *
+ * @param {number} dx The horizontal movement delta.
+ * @param {number} dy The vertical movement delta.
+ * @return {!goog.math.Coordinate} The newly calculated drag element position.
+ * @private
+ */
+goog.fx.Dragger.prototype.calculatePosition_ = function(dx, dy) {
+  // Update the position for any change in body scrolling
+  var pageScroll = goog.dom.getDomHelper(this.document_).getDocumentScroll();
+  dx += pageScroll.x - this.pageScroll.x;
+  dy += pageScroll.y - this.pageScroll.y;
+  this.pageScroll = pageScroll;
+
+  this.deltaX += dx;
+  this.deltaY += dy;
+
+  var x = this.limitX(this.deltaX);
+  var y = this.limitY(this.deltaY);
+  return new goog.math.Coordinate(x, y);
+};
+
+
+/**
+ * Event handler for scroll target scrolling.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.fx.Dragger.prototype.onScroll_ = function(e) {
+  var pos = this.calculatePosition_(0, 0);
+  e.clientX = this.clientX;
+  e.clientY = this.clientY;
+  this.doDrag(e, pos.x, pos.y, true);
+};
+
+
+/**
+ * @param {goog.events.BrowserEvent} e The closure object
+ *     representing the browser event that caused a drag event.
+ * @param {number} x The new horizontal position for the drag element.
+ * @param {number} y The new vertical position for the drag element.
+ * @param {boolean} dragFromScroll Whether dragging was caused by scrolling
+ *     the associated scroll target.
+ * @protected
+ */
+goog.fx.Dragger.prototype.doDrag = function(e, x, y, dragFromScroll) {
+  this.defaultAction(x, y);
+  this.dispatchEvent(new goog.fx.DragEvent(
+      goog.fx.Dragger.EventType.DRAG, this, e.clientX, e.clientY, e, x, y));
+};
+
+
+/**
+ * Returns the 'real' x after limits are applied (allows for some
+ * limits to be undefined).
+ * @param {number} x X-coordinate to limit.
+ * @return {number} The 'real' X-coordinate after limits are applied.
+ */
+goog.fx.Dragger.prototype.limitX = function(x) {
+  var rect = this.limits;
+  var left = !isNaN(rect.left) ? rect.left : null;
+  var width = !isNaN(rect.width) ? rect.width : 0;
+  var maxX = left != null ? left + width : Infinity;
+  var minX = left != null ? left : -Infinity;
+  return Math.min(maxX, Math.max(minX, x));
+};
+
+
+/**
+ * Returns the 'real' y after limits are applied (allows for some
+ * limits to be undefined).
+ * @param {number} y Y-coordinate to limit.
+ * @return {number} The 'real' Y-coordinate after limits are applied.
+ */
+goog.fx.Dragger.prototype.limitY = function(y) {
+  var rect = this.limits;
+  var top = !isNaN(rect.top) ? rect.top : null;
+  var height = !isNaN(rect.height) ? rect.height : 0;
+  var maxY = top != null ? top + height : Infinity;
+  var minY = top != null ? top : -Infinity;
+  return Math.min(maxY, Math.max(minY, y));
+};
+
+
+/**
+ * Overridable function for computing the initial position of the target
+ * before dragging begins.
+ * @protected
+ */
+goog.fx.Dragger.prototype.computeInitialPosition = function() {
+  this.deltaX = this.useRightPositioningForRtl_ ?
+      goog.style.bidi.getOffsetStart(this.target) : this.target.offsetLeft;
+  this.deltaY = this.target.offsetTop;
+};
+
+
+/**
+ * Overridable function for handling the default action of the drag behaviour.
+ * Normally this is simply moving the element to x,y though in some cases it
+ * might be used to resize the layer.  This is basically a shortcut to
+ * implementing a default ondrag event handler.
+ * @param {number} x X-coordinate for target element. In right-to-left, x this
+ *     is the number of pixels the target should be moved to from the right.
+ * @param {number} y Y-coordinate for target element.
+ */
+goog.fx.Dragger.prototype.defaultAction = function(x, y) {
+  if (this.useRightPositioningForRtl_ && this.isRightToLeft_()) {
+    this.target.style.right = x + 'px';
+  } else {
+    this.target.style.left = x + 'px';
+  }
+  this.target.style.top = y + 'px';
+};
+
+
+/**
+ * @return {boolean} Whether the dragger is currently in the midst of a drag.
+ */
+goog.fx.Dragger.prototype.isDragging = function() {
+  return this.dragging_;
+};
+
+
+
+/**
+ * Object representing a drag event
+ * @param {string} type Event type.
+ * @param {goog.fx.Dragger} dragobj Drag object initiating event.
+ * @param {number} clientX X-coordinate relative to the viewport.
+ * @param {number} clientY Y-coordinate relative to the viewport.
+ * @param {goog.events.BrowserEvent} browserEvent The closure object
+ *   representing the browser event that caused this drag event.
+ * @param {number=} opt_actX Optional actual x for drag if it has been limited.
+ * @param {number=} opt_actY Optional actual y for drag if it has been limited.
+ * @param {boolean=} opt_dragCanceled Whether the drag has been canceled.
+ * @constructor
+ * @extends {goog.events.Event}
+ */
+goog.fx.DragEvent = function(type, dragobj, clientX, clientY, browserEvent,
+                             opt_actX, opt_actY, opt_dragCanceled) {
+  goog.events.Event.call(this, type);
+
+  /**
+   * X-coordinate relative to the viewport
+   * @type {number}
+   */
+  this.clientX = clientX;
+
+  /**
+   * Y-coordinate relative to the viewport
+   * @type {number}
+   */
+  this.clientY = clientY;
+
+  /**
+   * The closure object representing the browser event that caused this drag
+   * event.
+   * @type {goog.events.BrowserEvent}
+   */
+  this.browserEvent = browserEvent;
+
+  /**
+   * The real x-position of the drag if it has been limited
+   * @type {number}
+   */
+  this.left = goog.isDef(opt_actX) ? opt_actX : dragobj.deltaX;
+
+  /**
+   * The real y-position of the drag if it has been limited
+   * @type {number}
+   */
+  this.top = goog.isDef(opt_actY) ? opt_actY : dragobj.deltaY;
+
+  /**
+   * Reference to the drag object for this event
+   * @type {goog.fx.Dragger}
+   */
+  this.dragger = dragobj;
+
+  /**
+   * Whether drag was canceled with this event. Used to differentiate between
+   * a legitimate drag END that can result in an action and a drag END which is
+   * a result of a drag cancelation. For now it can happen 1) with drag END
+   * event on FireFox when user drags the mouse out of the window, 2) with
+   * drag END event on IE7 which is generated on MOUSEMOVE event when user
+   * moves the mouse into the document after the mouse button has been
+   * released, 3) when TOUCHCANCEL is raised instead of TOUCHEND (on touch
+   * events).
+   * @type {boolean}
+   */
+  this.dragCanceled = !!opt_dragCanceled;
+};
+goog.inherits(goog.fx.DragEvent, goog.events.Event);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/draglistgroup.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/draglistgroup.js b/externs/GCL/externs/goog/fx/draglistgroup.js
new file mode 100644
index 0000000..dc20ec0
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/draglistgroup.js
@@ -0,0 +1,1312 @@
+// Copyright 2008 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 DragListGroup is a class representing a group of one or more
+ * "drag lists" with items that can be dragged within them and between them.
+ *
+ * @see ../demos/draglistgroup.html
+ */
+
+
+goog.provide('goog.fx.DragListDirection');
+goog.provide('goog.fx.DragListGroup');
+goog.provide('goog.fx.DragListGroup.EventType');
+goog.provide('goog.fx.DragListGroupEvent');
+
+goog.require('goog.array');
+goog.require('goog.asserts');
+goog.require('goog.dom');
+goog.require('goog.dom.classlist');
+goog.require('goog.events');
+goog.require('goog.events.Event');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventTarget');
+goog.require('goog.events.EventType');
+goog.require('goog.fx.Dragger');
+goog.require('goog.math.Coordinate');
+goog.require('goog.string');
+goog.require('goog.style');
+
+
+
+/**
+ * A class representing a group of one or more "drag lists" with items that can
+ * be dragged within them and between them.
+ *
+ * Example usage:
+ *   var dragListGroup = new goog.fx.DragListGroup();
+ *   dragListGroup.setDragItemHandleHoverClass(className1, className2);
+ *   dragListGroup.setDraggerElClass(className3);
+ *   dragListGroup.addDragList(vertList, goog.fx.DragListDirection.DOWN);
+ *   dragListGroup.addDragList(horizList, goog.fx.DragListDirection.RIGHT);
+ *   dragListGroup.init();
+ *
+ * @extends {goog.events.EventTarget}
+ * @constructor
+ */
+goog.fx.DragListGroup = function() {
+  goog.events.EventTarget.call(this);
+
+  /**
+   * The drag lists.
+   * @type {Array<Element>}
+   * @private
+   */
+  this.dragLists_ = [];
+
+  /**
+   * All the drag items. Set by init().
+   * @type {Array<Element>}
+   * @private
+   */
+  this.dragItems_ = [];
+
+  /**
+   * Which drag item corresponds to a given handle.  Set by init().
+   * Specifically, this maps from the unique ID (as given by goog.getUid)
+   * of the handle to the drag item.
+   * @type {Object}
+   * @private
+   */
+  this.dragItemForHandle_ = {};
+
+  /**
+   * The event handler for this instance.
+   * @type {goog.events.EventHandler<!goog.fx.DragListGroup>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+  /**
+   * Whether the setup has been done to make all items in all lists draggable.
+   * @type {boolean}
+   * @private
+   */
+  this.isInitialized_ = false;
+
+  /**
+   * Whether the currDragItem is always displayed. By default the list
+   * collapses, the currDragItem's display is set to none, when we do not
+   * hover over a draglist.
+   * @type {boolean}
+   * @private
+   */
+  this.isCurrDragItemAlwaysDisplayed_ = false;
+
+  /**
+   * Whether to update the position of the currDragItem as we drag, i.e.,
+   * insert the currDragItem each time to the position where it would land if
+   * we were to end the drag at that point. Defaults to true.
+   * @type {boolean}
+   * @private
+   */
+  this.updateWhileDragging_ = true;
+};
+goog.inherits(goog.fx.DragListGroup, goog.events.EventTarget);
+
+
+/**
+ * Enum to indicate the direction that a drag list grows.
+ * @enum {number}
+ */
+goog.fx.DragListDirection = {
+  DOWN: 0,  // common
+  RIGHT: 2,  // common
+  LEFT: 3,  // uncommon (except perhaps for right-to-left interfaces)
+  RIGHT_2D: 4, // common + handles multiple lines if items are wrapped
+  LEFT_2D: 5 // for rtl languages
+};
+
+
+/**
+ * Events dispatched by this class.
+ * @const
+ */
+goog.fx.DragListGroup.EventType = {
+  BEFOREDRAGSTART: 'beforedragstart',
+  DRAGSTART: 'dragstart',
+  BEFOREDRAGMOVE: 'beforedragmove',
+  DRAGMOVE: 'dragmove',
+  BEFOREDRAGEND: 'beforedragend',
+  DRAGEND: 'dragend'
+};
+
+
+// The next 4 are user-supplied CSS classes.
+
+
+/**
+ * The user-supplied CSS classes to add to a drag item on hover (not during a
+ * drag action).
+ * @type {Array|undefined}
+ * @private
+ */
+goog.fx.DragListGroup.prototype.dragItemHoverClasses_;
+
+
+/**
+ * The user-supplied CSS classes to add to a drag item handle on hover (not
+ * during a drag action).
+ * @type {Array|undefined}
+ * @private
+ */
+goog.fx.DragListGroup.prototype.dragItemHandleHoverClasses_;
+
+
+/**
+ * The user-supplied CSS classes to add to the current drag item (during a drag
+ * action).
+ * @type {Array|undefined}
+ * @private
+ */
+goog.fx.DragListGroup.prototype.currDragItemClasses_;
+
+
+/**
+ * The user-supplied CSS classes to add to the clone of the current drag item
+ * that's actually being dragged around (during a drag action).
+ * @type {Array<string>|undefined}
+ * @private
+ */
+goog.fx.DragListGroup.prototype.draggerElClasses_;
+
+
+// The next 5 are info applicable during a drag action.
+
+
+/**
+ * The current drag item being moved.
+ * Note: This is only defined while a drag action is happening.
+ * @type {Element}
+ * @private
+ */
+goog.fx.DragListGroup.prototype.currDragItem_;
+
+
+/**
+ * The drag list that {@code this.currDragItem_} is currently hovering over, or
+ * null if it is not hovering over a list.
+ * @type {Element}
+ * @private
+ */
+goog.fx.DragListGroup.prototype.currHoverList_;
+
+
+/**
+ * The original drag list that the current drag item came from. We need to
+ * remember this in case the user drops the item outside of any lists, in which
+ * case we return the item to its original location.
+ * Note: This is only defined while a drag action is happening.
+ * @type {Element}
+ * @private
+ */
+goog.fx.DragListGroup.prototype.origList_;
+
+
+/**
+ * The original next item in the original list that the current drag item came
+ * from. We need to remember this in case the user drops the item outside of
+ * any lists, in which case we return the item to its original location.
+ * Note: This is only defined while a drag action is happening.
+ * @type {Element}
+ * @private
+ */
+goog.fx.DragListGroup.prototype.origNextItem_;
+
+
+/**
+ * The current item in the list we are hovering over. We need to remember
+ * this in case we do not update the position of the current drag item while
+ * dragging (see {@code updateWhileDragging_}). In this case the current drag
+ * item will be inserted into the list before this element when the drag ends.
+ * @type {Element}
+ * @private
+ */
+goog.fx.DragListGroup.prototype.currHoverItem_;
+
+
+/**
+ * The clone of the current drag item that's actually being dragged around.
+ * Note: This is only defined while a drag action is happening.
+ * @type {Element}
+ * @private
+ */
+goog.fx.DragListGroup.prototype.draggerEl_;
+
+
+/**
+ * The dragger object.
+ * Note: This is only defined while a drag action is happening.
+ * @type {goog.fx.Dragger}
+ * @private
+ */
+goog.fx.DragListGroup.prototype.dragger_;
+
+
+/**
+ * The amount of distance, in pixels, after which a mousedown or touchstart is
+ * considered a drag.
+ * @type {number}
+ * @private
+ */
+goog.fx.DragListGroup.prototype.hysteresisDistance_ = 0;
+
+
+/**
+ * Sets the property of the currDragItem that it is always displayed in the
+ * list.
+ */
+goog.fx.DragListGroup.prototype.setIsCurrDragItemAlwaysDisplayed = function() {
+  this.isCurrDragItemAlwaysDisplayed_ = true;
+};
+
+
+/**
+ * Sets the private property updateWhileDragging_ to false. This disables the
+ * update of the position of the currDragItem while dragging. It will only be
+ * placed to its new location once the drag ends.
+ */
+goog.fx.DragListGroup.prototype.setNoUpdateWhileDragging = function() {
+  this.updateWhileDragging_ = false;
+};
+
+
+/**
+ * Sets the distance the user has to drag the element before a drag operation
+ * is started.
+ * @param {number} distance The number of pixels after which a mousedown and
+ *     move is considered a drag.
+ */
+goog.fx.DragListGroup.prototype.setHysteresis = function(distance) {
+  this.hysteresisDistance_ = distance;
+};
+
+
+/**
+ * @return {number} distance The number of pixels after which a mousedown and
+ *     move is considered a drag.
+ */
+goog.fx.DragListGroup.prototype.getHysteresis = function() {
+  return this.hysteresisDistance_;
+};
+
+
+/**
+ * Adds a drag list to this DragListGroup.
+ * All calls to this method must happen before the call to init().
+ * Remember that all child nodes (except text nodes) will be made draggable to
+ * any other drag list in this group.
+ *
+ * @param {Element} dragListElement Must be a container for a list of items
+ *     that should all be made draggable.
+ * @param {goog.fx.DragListDirection} growthDirection The direction that this
+ *     drag list grows in (i.e. if an item is appended to the DOM, the list's
+ *     bounding box expands in this direction).
+ * @param {boolean=} opt_unused Unused argument.
+ * @param {string=} opt_dragHoverClass CSS class to apply to this drag list when
+ *     the draggerEl hovers over it during a drag action.  If present, must be a
+ *     single, valid classname (not a string of space-separated classnames).
+ */
+goog.fx.DragListGroup.prototype.addDragList = function(
+    dragListElement, growthDirection, opt_unused, opt_dragHoverClass) {
+  goog.asserts.assert(!this.isInitialized_);
+
+  dragListElement.dlgGrowthDirection_ = growthDirection;
+  dragListElement.dlgDragHoverClass_ = opt_dragHoverClass;
+  this.dragLists_.push(dragListElement);
+};
+
+
+/**
+ * Sets a user-supplied function used to get the "handle" element for a drag
+ * item. The function must accept exactly one argument. The argument may be
+ * any drag item element.
+ *
+ * If not set, the default implementation uses the whole drag item as the
+ * handle.
+ *
+ * @param {function(Element): Element} getHandleForDragItemFn A function that,
+ *     given any drag item, returns a reference to its "handle" element
+ *     (which may be the drag item element itself).
+ */
+goog.fx.DragListGroup.prototype.setFunctionToGetHandleForDragItem = function(
+    getHandleForDragItemFn) {
+  goog.asserts.assert(!this.isInitialized_);
+  this.getHandleForDragItem_ = getHandleForDragItemFn;
+};
+
+
+/**
+ * Sets a user-supplied CSS class to add to a drag item on hover (not during a
+ * drag action).
+ * @param {...!string} var_args The CSS class or classes.
+ */
+goog.fx.DragListGroup.prototype.setDragItemHoverClass = function(var_args) {
+  goog.asserts.assert(!this.isInitialized_);
+  this.dragItemHoverClasses_ = goog.array.slice(arguments, 0);
+};
+
+
+/**
+ * Sets a user-supplied CSS class to add to a drag item handle on hover (not
+ * during a drag action).
+ * @param {...!string} var_args The CSS class or classes.
+ */
+goog.fx.DragListGroup.prototype.setDragItemHandleHoverClass = function(
+    var_args) {
+  goog.asserts.assert(!this.isInitialized_);
+  this.dragItemHandleHoverClasses_ = goog.array.slice(arguments, 0);
+};
+
+
+/**
+ * Sets a user-supplied CSS class to add to the current drag item (during a
+ * drag action).
+ *
+ * If not set, the default behavior adds visibility:hidden to the current drag
+ * item so that it is a block of empty space in the hover drag list (if any).
+ * If this class is set by the user, then the default behavior does not happen
+ * (unless, of course, the class also contains visibility:hidden).
+ *
+ * @param {...!string} var_args The CSS class or classes.
+ */
+goog.fx.DragListGroup.prototype.setCurrDragItemClass = function(var_args) {
+  goog.asserts.assert(!this.isInitialized_);
+  this.currDragItemClasses_ = goog.array.slice(arguments, 0);
+};
+
+
+/**
+ * Sets a user-supplied CSS class to add to the clone of the current drag item
+ * that's actually being dragged around (during a drag action).
+ * @param {string} draggerElClass The CSS class.
+ */
+goog.fx.DragListGroup.prototype.setDraggerElClass = function(draggerElClass) {
+  goog.asserts.assert(!this.isInitialized_);
+  // Split space-separated classes up into an array.
+  this.draggerElClasses_ = goog.string.trim(draggerElClass).split(' ');
+};
+
+
+/**
+ * Performs the initial setup to make all items in all lists draggable.
+ */
+goog.fx.DragListGroup.prototype.init = function() {
+  if (this.isInitialized_) {
+    return;
+  }
+
+  for (var i = 0, numLists = this.dragLists_.length; i < numLists; i++) {
+    var dragList = this.dragLists_[i];
+
+    var dragItems = goog.dom.getChildren(dragList);
+    for (var j = 0, numItems = dragItems.length; j < numItems; ++j) {
+      this.listenForDragEvents(dragItems[j]);
+    }
+  }
+
+  this.isInitialized_ = true;
+};
+
+
+/**
+ * Adds a single item to the given drag list and sets up the drag listeners for
+ * it.
+ * If opt_index is specified the item is inserted at this index, otherwise the
+ * item is added as the last child of the list.
+ *
+ * @param {!Element} list The drag list where to add item to.
+ * @param {!Element} item The new element to add.
+ * @param {number=} opt_index Index where to insert the item in the list. If not
+ * specified item is inserted as the last child of list.
+ */
+goog.fx.DragListGroup.prototype.addItemToDragList = function(list, item,
+    opt_index) {
+  if (goog.isDef(opt_index)) {
+    goog.dom.insertChildAt(list, item, opt_index);
+  } else {
+    goog.dom.appendChild(list, item);
+  }
+  this.listenForDragEvents(item);
+};
+
+
+/** @override */
+goog.fx.DragListGroup.prototype.disposeInternal = function() {
+  this.eventHandler_.dispose();
+
+  for (var i = 0, n = this.dragLists_.length; i < n; i++) {
+    var dragList = this.dragLists_[i];
+    // Note: IE doesn't allow 'delete' for fields on HTML elements (because
+    // they're not real JS objects in IE), so we just set them to undefined.
+    dragList.dlgGrowthDirection_ = undefined;
+    dragList.dlgDragHoverClass_ = undefined;
+  }
+
+  this.dragLists_.length = 0;
+  this.dragItems_.length = 0;
+  this.dragItemForHandle_ = null;
+
+  // In the case where a drag event is currently in-progress and dispose is
+  // called, this cleans up the extra state.
+  this.cleanupDragDom_();
+
+  goog.fx.DragListGroup.superClass_.disposeInternal.call(this);
+};
+
+
+/**
+ * Caches the heights of each drag list and drag item, except for the current
+ * drag item.
+ *
+ * @param {Element} currDragItem The item currently being dragged.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.recacheListAndItemBounds_ = function(
+    currDragItem) {
+  for (var i = 0, n = this.dragLists_.length; i < n; i++) {
+    var dragList = this.dragLists_[i];
+    dragList.dlgBounds_ = goog.style.getBounds(dragList);
+  }
+
+  for (var i = 0, n = this.dragItems_.length; i < n; i++) {
+    var dragItem = this.dragItems_[i];
+    if (dragItem != currDragItem) {
+      dragItem.dlgBounds_ = goog.style.getBounds(dragItem);
+    }
+  }
+};
+
+
+/**
+ * Listens for drag events on the given drag item. This method is currently used
+ * to initialize drag items.
+ *
+ * @param {Element} dragItem the element to initialize. This element has to be
+ * in one of the drag lists.
+ * @protected
+ */
+goog.fx.DragListGroup.prototype.listenForDragEvents = function(dragItem) {
+  var dragItemHandle = this.getHandleForDragItem_(dragItem);
+  var uid = goog.getUid(dragItemHandle);
+  this.dragItemForHandle_[uid] = dragItem;
+
+  if (this.dragItemHoverClasses_) {
+    this.eventHandler_.listen(
+        dragItem, goog.events.EventType.MOUSEOVER,
+        this.handleDragItemMouseover_);
+    this.eventHandler_.listen(
+        dragItem, goog.events.EventType.MOUSEOUT,
+        this.handleDragItemMouseout_);
+  }
+  if (this.dragItemHandleHoverClasses_) {
+    this.eventHandler_.listen(
+        dragItemHandle, goog.events.EventType.MOUSEOVER,
+        this.handleDragItemHandleMouseover_);
+    this.eventHandler_.listen(
+        dragItemHandle, goog.events.EventType.MOUSEOUT,
+        this.handleDragItemHandleMouseout_);
+  }
+
+  this.dragItems_.push(dragItem);
+  this.eventHandler_.listen(dragItemHandle,
+      [goog.events.EventType.MOUSEDOWN, goog.events.EventType.TOUCHSTART],
+      this.handlePotentialDragStart_);
+};
+
+
+/**
+ * Handles mouse and touch events which may start a drag action.
+ * @param {!goog.events.BrowserEvent} e MOUSEDOWN or TOUCHSTART event.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.handlePotentialDragStart_ = function(e) {
+  var uid = goog.getUid(/** @type {Node} */ (e.currentTarget));
+  this.currDragItem_ = /** @type {Element} */ (this.dragItemForHandle_[uid]);
+
+  this.draggerEl_ = this.createDragElementInternal(this.currDragItem_);
+  if (this.draggerElClasses_) {
+    // Add CSS class for the clone, if any.
+    goog.dom.classlist.addAll(
+        goog.asserts.assert(this.draggerEl_), this.draggerElClasses_ || []);
+  }
+
+  // Place the clone (i.e. draggerEl) at the same position as the actual
+  // current drag item. This is a bit tricky since
+  //   goog.style.getPageOffset() gets the left-top pos of the border, but
+  //   goog.style.setPageOffset() sets the left-top pos of the margin.
+  // It's difficult to adjust for the margins of the clone because it's
+  // difficult to read it: goog.style.getComputedStyle() doesn't work for IE.
+  // Instead, our workaround is simply to set the clone's margins to 0px.
+  this.draggerEl_.style.margin = '0';
+  this.draggerEl_.style.position = 'absolute';
+  this.draggerEl_.style.visibility = 'hidden';
+  var doc = goog.dom.getOwnerDocument(this.currDragItem_);
+  doc.body.appendChild(this.draggerEl_);
+
+  // Important: goog.style.setPageOffset() only works correctly for IE when the
+  // element is already in the document.
+  var currDragItemPos = goog.style.getPageOffset(this.currDragItem_);
+  goog.style.setPageOffset(this.draggerEl_, currDragItemPos);
+
+  this.dragger_ = new goog.fx.Dragger(this.draggerEl_);
+  this.dragger_.setHysteresis(this.hysteresisDistance_);
+
+  // Listen to events on the dragger. These handlers will be unregistered at
+  // DRAGEND, when the dragger is disposed of. We can't use eventHandler_,
+  // because it creates new references to the handler functions at each
+  // dragging action, and keeps them until DragListGroup is disposed of.
+  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.START,
+      this.handleDragStart_, false, this);
+  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.END,
+      this.handleDragEnd_, false, this);
+  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.EARLY_CANCEL,
+      this.cleanup_, false, this);
+  this.dragger_.startDrag(e);
+};
+
+
+/**
+ * Creates copy of node being dragged.
+ *
+ * @param {Element} sourceEl Element to copy.
+ * @return {!Element} The clone of {@code sourceEl}.
+ * @deprecated Use goog.fx.Dragger.cloneNode().
+ * @private
+ */
+goog.fx.DragListGroup.prototype.cloneNode_ = function(sourceEl) {
+  return goog.fx.Dragger.cloneNode(sourceEl);
+};
+
+
+/**
+ * Generates an element to follow the cursor during dragging, given a drag
+ * source element.  The default behavior is simply to clone the source element,
+ * but this may be overridden in subclasses.  This method is called by
+ * {@code createDragElement()} before the drag class is added.
+ *
+ * @param {Element} sourceEl Drag source element.
+ * @return {!Element} The new drag element.
+ * @protected
+ * @suppress {deprecated}
+ */
+goog.fx.DragListGroup.prototype.createDragElementInternal =
+    function(sourceEl) {
+  return this.cloneNode_(sourceEl);
+};
+
+
+/**
+ * Handles the start of a drag action.
+ * @param {!goog.fx.DragEvent} e goog.fx.Dragger.EventType.START event.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.handleDragStart_ = function(e) {
+  if (!this.dispatchEvent(new goog.fx.DragListGroupEvent(
+      goog.fx.DragListGroup.EventType.BEFOREDRAGSTART, this, e.browserEvent,
+      this.currDragItem_, null, null))) {
+    e.preventDefault();
+    this.cleanup_();
+    return;
+  }
+
+  // Record the original location of the current drag item.
+  // Note: this.origNextItem_ may be null.
+  this.origList_ = /** @type {Element} */ (this.currDragItem_.parentNode);
+  this.origNextItem_ = goog.dom.getNextElementSibling(this.currDragItem_);
+  this.currHoverItem_ = this.origNextItem_;
+  this.currHoverList_ = this.origList_;
+
+  // If there's a CSS class specified for the current drag item, add it.
+  // Otherwise, make the actual current drag item hidden (takes up space).
+  if (this.currDragItemClasses_) {
+    goog.dom.classlist.addAll(
+        goog.asserts.assert(this.currDragItem_),
+        this.currDragItemClasses_ || []);
+  } else {
+    this.currDragItem_.style.visibility = 'hidden';
+  }
+
+  // Precompute distances from top-left corner to center for efficiency.
+  var draggerElSize = goog.style.getSize(this.draggerEl_);
+  this.draggerEl_.halfWidth = draggerElSize.width / 2;
+  this.draggerEl_.halfHeight = draggerElSize.height / 2;
+
+  this.draggerEl_.style.visibility = '';
+
+  // Record the bounds of all the drag lists and all the other drag items. This
+  // caching is for efficiency, so that we don't have to recompute the bounds on
+  // each drag move. Do this in the state where the current drag item is not in
+  // any of the lists, except when update while dragging is disabled, as in this
+  // case the current drag item does not get removed until drag ends.
+  if (this.updateWhileDragging_) {
+    this.currDragItem_.style.display = 'none';
+  }
+  this.recacheListAndItemBounds_(this.currDragItem_);
+  this.currDragItem_.style.display = '';
+
+  // Listen to events on the dragger.
+  goog.events.listen(this.dragger_, goog.fx.Dragger.EventType.DRAG,
+      this.handleDragMove_, false, this);
+
+  this.dispatchEvent(
+      new goog.fx.DragListGroupEvent(
+          goog.fx.DragListGroup.EventType.DRAGSTART, this, e.browserEvent,
+          this.currDragItem_, this.draggerEl_, this.dragger_));
+};
+
+
+/**
+ * Handles a drag movement (i.e. DRAG event fired by the dragger).
+ *
+ * @param {goog.fx.DragEvent} dragEvent Event object fired by the dragger.
+ * @return {boolean} The return value for the event.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.handleDragMove_ = function(dragEvent) {
+
+  // Compute the center of the dragger element (i.e. the cloned drag item).
+  var draggerElPos = goog.style.getPageOffset(this.draggerEl_);
+  var draggerElCenter = new goog.math.Coordinate(
+      draggerElPos.x + this.draggerEl_.halfWidth,
+      draggerElPos.y + this.draggerEl_.halfHeight);
+
+  // Check whether the center is hovering over one of the drag lists.
+  var hoverList = this.getHoverDragList_(draggerElCenter);
+
+  // If hovering over a list, find the next item (if drag were to end now).
+  var hoverNextItem =
+      hoverList ? this.getHoverNextItem_(hoverList, draggerElCenter) : null;
+
+  var rv = this.dispatchEvent(
+      new goog.fx.DragListGroupEvent(
+          goog.fx.DragListGroup.EventType.BEFOREDRAGMOVE, this, dragEvent,
+          this.currDragItem_, this.draggerEl_, this.dragger_,
+          draggerElCenter, hoverList, hoverNextItem));
+  if (!rv) {
+    return false;
+  }
+
+  if (hoverList) {
+    if (this.updateWhileDragging_) {
+      this.insertCurrDragItem_(hoverList, hoverNextItem);
+    } else {
+      // If update while dragging is disabled do not insert
+      // the dragged item, but update the hovered item instead.
+      this.updateCurrHoverItem(hoverNextItem, draggerElCenter);
+    }
+    this.currDragItem_.style.display = '';
+    // Add drag list's hover class (if any).
+    if (hoverList.dlgDragHoverClass_) {
+      goog.dom.classlist.add(
+          goog.asserts.assert(hoverList), hoverList.dlgDragHoverClass_);
+    }
+
+  } else {
+    // Not hovering over a drag list, so remove the item altogether unless
+    // specified otherwise by the user.
+    if (!this.isCurrDragItemAlwaysDisplayed_) {
+      this.currDragItem_.style.display = 'none';
+    }
+
+    // Remove hover classes (if any) from all drag lists.
+    for (var i = 0, n = this.dragLists_.length; i < n; i++) {
+      var dragList = this.dragLists_[i];
+      if (dragList.dlgDragHoverClass_) {
+        goog.dom.classlist.remove(
+            goog.asserts.assert(dragList), dragList.dlgDragHoverClass_);
+      }
+    }
+  }
+
+  // If the current hover list is different than the last, the lists may have
+  // shrunk, so we should recache the bounds.
+  if (hoverList != this.currHoverList_) {
+    this.currHoverList_ = hoverList;
+    this.recacheListAndItemBounds_(this.currDragItem_);
+  }
+
+  this.dispatchEvent(
+      new goog.fx.DragListGroupEvent(
+          goog.fx.DragListGroup.EventType.DRAGMOVE, this, dragEvent,
+          /** @type {Element} */ (this.currDragItem_),
+          this.draggerEl_, this.dragger_,
+          draggerElCenter, hoverList, hoverNextItem));
+
+  // Return false to prevent selection due to mouse drag.
+  return false;
+};
+
+
+/**
+ * Clear all our temporary fields that are only defined while dragging, and
+ * all the bounds info stored on the drag lists and drag elements.
+ * @param {!goog.events.Event=} opt_e EARLY_CANCEL event from the dragger if
+ *     cleanup_ was called as an event handler.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.cleanup_ = function(opt_e) {
+  this.cleanupDragDom_();
+
+  this.currDragItem_ = null;
+  this.currHoverList_ = null;
+  this.origList_ = null;
+  this.origNextItem_ = null;
+  this.draggerEl_ = null;
+  this.dragger_ = null;
+
+  // Note: IE doesn't allow 'delete' for fields on HTML elements (because
+  // they're not real JS objects in IE), so we just set them to null.
+  for (var i = 0, n = this.dragLists_.length; i < n; i++) {
+    this.dragLists_[i].dlgBounds_ = null;
+  }
+  for (var i = 0, n = this.dragItems_.length; i < n; i++) {
+    this.dragItems_[i].dlgBounds_ = null;
+  }
+};
+
+
+/**
+ * Handles the end or the cancellation of a drag action, i.e. END or CLEANUP
+ * event fired by the dragger.
+ *
+ * @param {!goog.fx.DragEvent} dragEvent Event object fired by the dragger.
+ * @return {boolean} Whether the event was handled.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.handleDragEnd_ = function(dragEvent) {
+  var rv = this.dispatchEvent(
+      new goog.fx.DragListGroupEvent(
+          goog.fx.DragListGroup.EventType.BEFOREDRAGEND, this, dragEvent,
+          /** @type {Element} */ (this.currDragItem_),
+          this.draggerEl_, this.dragger_));
+  if (!rv) {
+    return false;
+  }
+
+  // If update while dragging is disabled insert the current drag item into
+  // its intended location.
+  if (!this.updateWhileDragging_) {
+    this.insertCurrHoverItem();
+  }
+
+  // The DRAGEND handler may need the new order of the list items. Clean up the
+  // garbage.
+  // TODO(user): Regression test.
+  this.cleanupDragDom_();
+
+  this.dispatchEvent(
+      new goog.fx.DragListGroupEvent(
+          goog.fx.DragListGroup.EventType.DRAGEND, this, dragEvent,
+          this.currDragItem_, this.draggerEl_, this.dragger_));
+
+  this.cleanup_();
+
+  return true;
+};
+
+
+/**
+ * Cleans up DOM changes that are made by the {@code handleDrag*} methods.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.cleanupDragDom_ = function() {
+  // Disposes of the dragger and remove the cloned drag item.
+  goog.dispose(this.dragger_);
+  if (this.draggerEl_) {
+    goog.dom.removeNode(this.draggerEl_);
+  }
+
+  // If the current drag item is not in any list, put it back in its original
+  // location.
+  if (this.currDragItem_ && this.currDragItem_.style.display == 'none') {
+    // Note: this.origNextItem_ may be null, but insertBefore() still works.
+    this.origList_.insertBefore(this.currDragItem_, this.origNextItem_);
+    this.currDragItem_.style.display = '';
+  }
+
+  // If there's a CSS class specified for the current drag item, remove it.
+  // Otherwise, make the current drag item visible (instead of empty space).
+  if (this.currDragItemClasses_ && this.currDragItem_) {
+    goog.dom.classlist.removeAll(
+        goog.asserts.assert(this.currDragItem_),
+        this.currDragItemClasses_ || []);
+  } else if (this.currDragItem_) {
+    this.currDragItem_.style.visibility = 'visible';
+  }
+
+  // Remove hover classes (if any) from all drag lists.
+  for (var i = 0, n = this.dragLists_.length; i < n; i++) {
+    var dragList = this.dragLists_[i];
+    if (dragList.dlgDragHoverClass_) {
+      goog.dom.classlist.remove(
+          goog.asserts.assert(dragList), dragList.dlgDragHoverClass_);
+    }
+  }
+};
+
+
+/**
+ * Default implementation of the function to get the "handle" element for a
+ * drag item. By default, we use the whole drag item as the handle. Users can
+ * change this by calling setFunctionToGetHandleForDragItem().
+ *
+ * @param {Element} dragItem The drag item to get the handle for.
+ * @return {Element} The dragItem element itself.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.getHandleForDragItem_ = function(dragItem) {
+  return dragItem;
+};
+
+
+/**
+ * Handles a MOUSEOVER event fired on a drag item.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.handleDragItemMouseover_ = function(e) {
+  var targetEl = goog.asserts.assertElement(e.currentTarget);
+  goog.dom.classlist.addAll(targetEl, this.dragItemHoverClasses_ || []);
+};
+
+
+/**
+ * Handles a MOUSEOUT event fired on a drag item.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.handleDragItemMouseout_ = function(e) {
+  var targetEl = goog.asserts.assertElement(e.currentTarget);
+  goog.dom.classlist.removeAll(targetEl, this.dragItemHoverClasses_ || []);
+};
+
+
+/**
+ * Handles a MOUSEOVER event fired on the handle element of a drag item.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.handleDragItemHandleMouseover_ = function(e) {
+  var targetEl = goog.asserts.assertElement(e.currentTarget);
+  goog.dom.classlist.addAll(targetEl, this.dragItemHandleHoverClasses_ || []);
+};
+
+
+/**
+ * Handles a MOUSEOUT event fired on the handle element of a drag item.
+ * @param {goog.events.BrowserEvent} e The event.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.handleDragItemHandleMouseout_ = function(e) {
+  var targetEl = goog.asserts.assertElement(e.currentTarget);
+  goog.dom.classlist.removeAll(targetEl,
+      this.dragItemHandleHoverClasses_ || []);
+};
+
+
+/**
+ * Helper for handleDragMove_().
+ * Given the position of the center of the dragger element, figures out whether
+ * it's currently hovering over any of the drag lists.
+ *
+ * @param {goog.math.Coordinate} draggerElCenter The center position of the
+ *     dragger element.
+ * @return {Element} If currently hovering over a drag list, returns the drag
+ *     list element. Else returns null.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.getHoverDragList_ = function(draggerElCenter) {
+
+  // If the current drag item was in a list last time we did this, then check
+  // that same list first.
+  var prevHoverList = null;
+  if (this.currDragItem_.style.display != 'none') {
+    prevHoverList = /** @type {Element} */ (this.currDragItem_.parentNode);
+    // Important: We can't use the cached bounds for this list because the
+    // cached bounds are based on the case where the current drag item is not
+    // in the list. Since the current drag item is known to be in this list, we
+    // must recompute the list's bounds.
+    var prevHoverListBounds = goog.style.getBounds(prevHoverList);
+    if (this.isInRect_(draggerElCenter, prevHoverListBounds)) {
+      return prevHoverList;
+    }
+  }
+
+  for (var i = 0, n = this.dragLists_.length; i < n; i++) {
+    var dragList = this.dragLists_[i];
+    if (dragList == prevHoverList) {
+      continue;
+    }
+    if (this.isInRect_(draggerElCenter, dragList.dlgBounds_)) {
+      return dragList;
+    }
+  }
+
+  return null;
+};
+
+
+/**
+ * Checks whether a coordinate position resides inside a rectangle.
+ * @param {goog.math.Coordinate} pos The coordinate position.
+ * @param {goog.math.Rect} rect The rectangle.
+ * @return {boolean} True if 'pos' is within the bounds of 'rect'.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.isInRect_ = function(pos, rect) {
+  return pos.x > rect.left && pos.x < rect.left + rect.width &&
+         pos.y > rect.top && pos.y < rect.top + rect.height;
+};
+
+
+/**
+ * Updates the value of currHoverItem_.
+ *
+ * This method is used for insertion only when updateWhileDragging_ is false.
+ * The below implementation is the basic one. This method can be extended by
+ * a subclass to support changes to hovered item (eg: highlighting). Parametr
+ * opt_draggerElCenter can be used for more sophisticated effects.
+ *
+ * @param {Element} hoverNextItem element of the list that is hovered over.
+ * @param {goog.math.Coordinate=} opt_draggerElCenter current position of
+ *     the dragged element.
+ * @protected
+ */
+goog.fx.DragListGroup.prototype.updateCurrHoverItem = function(
+    hoverNextItem, opt_draggerElCenter) {
+  if (hoverNextItem) {
+    this.currHoverItem_ = hoverNextItem;
+  }
+};
+
+
+/**
+ * Inserts the currently dragged item in its new place.
+ *
+ * This method is used for insertion only when updateWhileDragging_ is false
+ * (otherwise there is no need for that). In the basic implementation
+ * the element is inserted before the currently hovered over item (this can
+ * be changed by overriding the method in subclasses).
+ *
+ * @protected
+ */
+goog.fx.DragListGroup.prototype.insertCurrHoverItem = function() {
+  this.origList_.insertBefore(this.currDragItem_, this.currHoverItem_);
+};
+
+
+/**
+ * Helper for handleDragMove_().
+ * Given the position of the center of the dragger element, plus the drag list
+ * that it's currently hovering over, figures out the next drag item in the
+ * list that follows the current position of the dragger element. (I.e. if
+ * the drag action ends right now, it would become the item after the current
+ * drag item.)
+ *
+ * @param {Element} hoverList The drag list that we're hovering over.
+ * @param {goog.math.Coordinate} draggerElCenter The center position of the
+ *     dragger element.
+ * @return {Element} Returns the earliest item in the hover list that belongs
+ *     after the current position of the dragger element. If all items in the
+ *     list should come before the current drag item, then returns null.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.getHoverNextItem_ = function(
+    hoverList, draggerElCenter) {
+  if (hoverList == null) {
+    throw Error('getHoverNextItem_ called with null hoverList.');
+  }
+
+  // The definition of what it means for the draggerEl to be "before" a given
+  // item in the hover drag list is not always the same. It changes based on
+  // the growth direction of the hover drag list in question.
+  /** @type {number} */
+  var relevantCoord;
+  var getRelevantBoundFn;
+  var isBeforeFn;
+  var pickClosestRow = false;
+  var distanceToClosestRow = undefined;
+  switch (hoverList.dlgGrowthDirection_) {
+    case goog.fx.DragListDirection.DOWN:
+      // "Before" means draggerElCenter.y is less than item's bottom y-value.
+      relevantCoord = draggerElCenter.y;
+      getRelevantBoundFn = goog.fx.DragListGroup.getBottomBound_;
+      isBeforeFn = goog.fx.DragListGroup.isLessThan_;
+      break;
+    case goog.fx.DragListDirection.RIGHT_2D:
+      pickClosestRow = true;
+    case goog.fx.DragListDirection.RIGHT:
+      // "Before" means draggerElCenter.x is less than item's right x-value.
+      relevantCoord = draggerElCenter.x;
+      getRelevantBoundFn = goog.fx.DragListGroup.getRightBound_;
+      isBeforeFn = goog.fx.DragListGroup.isLessThan_;
+      break;
+    case goog.fx.DragListDirection.LEFT_2D:
+      pickClosestRow = true;
+    case goog.fx.DragListDirection.LEFT:
+      // "Before" means draggerElCenter.x is greater than item's left x-value.
+      relevantCoord = draggerElCenter.x;
+      getRelevantBoundFn = goog.fx.DragListGroup.getLeftBound_;
+      isBeforeFn = goog.fx.DragListGroup.isGreaterThan_;
+      break;
+  }
+
+  // This holds the earliest drag item found so far that should come after
+  // this.currDragItem_ in the hover drag list (based on draggerElCenter).
+  var earliestAfterItem = null;
+  // This is the position of the relevant bound for the earliestAfterItem,
+  // where "relevant" is determined by the growth direction of hoverList.
+  var earliestAfterItemRelevantBound;
+
+  var hoverListItems = goog.dom.getChildren(hoverList);
+  for (var i = 0, n = hoverListItems.length; i < n; i++) {
+    var item = hoverListItems[i];
+    if (item == this.currDragItem_) {
+      continue;
+    }
+
+    var relevantBound = getRelevantBoundFn(item.dlgBounds_);
+    // When the hoverlist is broken into multiple rows (i.e., in the case of
+    // LEFT_2D and RIGHT_2D) it is no longer enough to only look at the
+    // x-coordinate alone in order to find the {@earliestAfterItem} in the
+    // hoverlist. Make sure it is chosen from the row closest to the
+    // {@code draggerElCenter}.
+    if (pickClosestRow) {
+      var distanceToRow = goog.fx.DragListGroup.verticalDistanceFromItem_(item,
+          draggerElCenter);
+      // Initialize the distance to the closest row to the current value if
+      // undefined.
+      if (!goog.isDef(distanceToClosestRow)) {
+        distanceToClosestRow = distanceToRow;
+      }
+      if (isBeforeFn(relevantCoord, relevantBound) &&
+          (earliestAfterItemRelevantBound == undefined ||
+           (distanceToRow < distanceToClosestRow) ||
+           ((distanceToRow == distanceToClosestRow) &&
+            (isBeforeFn(relevantBound, earliestAfterItemRelevantBound) ||
+            relevantBound == earliestAfterItemRelevantBound)))) {
+        earliestAfterItem = item;
+        earliestAfterItemRelevantBound = relevantBound;
+      }
+      // Update distance to closest row.
+      if (distanceToRow < distanceToClosestRow) {
+        distanceToClosestRow = distanceToRow;
+      }
+    } else if (isBeforeFn(relevantCoord, relevantBound) &&
+        (earliestAfterItemRelevantBound == undefined ||
+         isBeforeFn(relevantBound, earliestAfterItemRelevantBound))) {
+      earliestAfterItem = item;
+      earliestAfterItemRelevantBound = relevantBound;
+    }
+  }
+  // If we ended up picking an element that is not in the closest row it can
+  // only happen if we should have picked the last one in which case there is
+  // no consecutive element.
+  if (!goog.isNull(earliestAfterItem) &&
+      goog.fx.DragListGroup.verticalDistanceFromItem_(
+          earliestAfterItem, draggerElCenter) > distanceToClosestRow) {
+    return null;
+  } else {
+    return earliestAfterItem;
+  }
+};
+
+
+/**
+ * Private helper for getHoverNextItem().
+ * Given an item and a target determine the vertical distance from the item's
+ * center to the target.
+ * @param {Element} item The item to measure the distance from.
+ * @param {goog.math.Coordinate} target The (x,y) coordinate of the target
+ *     to measure the distance to.
+ * @return {number} The vertical distance between the center of the item and
+ *     the target.
+ * @private
+ */
+goog.fx.DragListGroup.verticalDistanceFromItem_ = function(item, target) {
+  var itemBounds = item.dlgBounds_;
+  var itemCenterY = itemBounds.top + (itemBounds.height - 1) / 2;
+  return Math.abs(target.y - itemCenterY);
+};
+
+
+/**
+ * Private helper for getHoverNextItem_().
+ * Given the bounds of an item, computes the item's bottom y-value.
+ * @param {goog.math.Rect} itemBounds The bounds of the item.
+ * @return {number} The item's bottom y-value.
+ * @private
+ */
+goog.fx.DragListGroup.getBottomBound_ = function(itemBounds) {
+  return itemBounds.top + itemBounds.height - 1;
+};
+
+
+/**
+ * Private helper for getHoverNextItem_().
+ * Given the bounds of an item, computes the item's right x-value.
+ * @param {goog.math.Rect} itemBounds The bounds of the item.
+ * @return {number} The item's right x-value.
+ * @private
+ */
+goog.fx.DragListGroup.getRightBound_ = function(itemBounds) {
+  return itemBounds.left + itemBounds.width - 1;
+};
+
+
+/**
+ * Private helper for getHoverNextItem_().
+ * Given the bounds of an item, computes the item's left x-value.
+ * @param {goog.math.Rect} itemBounds The bounds of the item.
+ * @return {number} The item's left x-value.
+ * @private
+ */
+goog.fx.DragListGroup.getLeftBound_ = function(itemBounds) {
+  return itemBounds.left || 0;
+};
+
+
+/**
+ * Private helper for getHoverNextItem_().
+ * @param {number} a Number to compare.
+ * @param {number} b Number to compare.
+ * @return {boolean} Whether a is less than b.
+ * @private
+ */
+goog.fx.DragListGroup.isLessThan_ = function(a, b) {
+  return a < b;
+};
+
+
+/**
+ * Private helper for getHoverNextItem_().
+ * @param {number} a Number to compare.
+ * @param {number} b Number to compare.
+ * @return {boolean} Whether a is greater than b.
+ * @private
+ */
+goog.fx.DragListGroup.isGreaterThan_ = function(a, b) {
+  return a > b;
+};
+
+
+/**
+ * Inserts the current drag item to the appropriate location in the drag list
+ * that we're hovering over (if the current drag item is not already there).
+ *
+ * @param {Element} hoverList The drag list we're hovering over.
+ * @param {Element} hoverNextItem The next item in the hover drag list.
+ * @private
+ */
+goog.fx.DragListGroup.prototype.insertCurrDragItem_ = function(
+    hoverList, hoverNextItem) {
+  if (this.currDragItem_.parentNode != hoverList ||
+      goog.dom.getNextElementSibling(this.currDragItem_) != hoverNextItem) {
+    // The current drag item is not in the correct location, so we move it.
+    // Note: hoverNextItem may be null, but insertBefore() still works.
+    hoverList.insertBefore(this.currDragItem_, hoverNextItem);
+  }
+};
+
+
+
+/**
+ * The event object dispatched by DragListGroup.
+ * The fields draggerElCenter, hoverList, and hoverNextItem are only available
+ * for the BEFOREDRAGMOVE and DRAGMOVE events.
+ *
+ * @param {string} type The event type string.
+ * @param {goog.fx.DragListGroup} dragListGroup A reference to the associated
+ *     DragListGroup object.
+ * @param {goog.events.BrowserEvent|goog.fx.DragEvent} event The event fired
+ *     by the browser or fired by the dragger.
+ * @param {Element} currDragItem The current drag item being moved.
+ * @param {Element} draggerEl The clone of the current drag item that's actually
+ *     being dragged around.
+ * @param {goog.fx.Dragger} dragger The dragger object.
+ * @param {goog.math.Coordinate=} opt_draggerElCenter The current center
+ *     position of the draggerEl.
+ * @param {Element=} opt_hoverList The current drag list that's being hovered
+ *     over, or null if the center of draggerEl is outside of any drag lists.
+ *     If not null and the drag action ends right now, then currDragItem will
+ *     end up in this list.
+ * @param {Element=} opt_hoverNextItem The current next item in the hoverList
+ *     that the draggerEl is hovering over. (I.e. If the drag action ends
+ *     right now, then this item would become the next item after the new
+ *     location of currDragItem.) May be null if not applicable or if
+ *     currDragItem would be added to the end of hoverList.
+ * @constructor
+ * @extends {goog.events.Event}
+ */
+goog.fx.DragListGroupEvent = function(
+    type, dragListGroup, event, currDragItem, draggerEl, dragger,
+    opt_draggerElCenter, opt_hoverList, opt_hoverNextItem) {
+  goog.events.Event.call(this, type);
+
+  /**
+   * A reference to the associated DragListGroup object.
+   * @type {goog.fx.DragListGroup}
+   */
+  this.dragListGroup = dragListGroup;
+
+  /**
+   * The event fired by the browser or fired by the dragger.
+   * @type {goog.events.BrowserEvent|goog.fx.DragEvent}
+   */
+  this.event = event;
+
+  /**
+   * The current drag item being move.
+   * @type {Element}
+   */
+  this.currDragItem = currDragItem;
+
+  /**
+   * The clone of the current drag item that's actually being dragged around.
+   * @type {Element}
+   */
+  this.draggerEl = draggerEl;
+
+  /**
+   * The dragger object.
+   * @type {goog.fx.Dragger}
+   */
+  this.dragger = dragger;
+
+  /**
+   * The current center position of the draggerEl.
+   * @type {goog.math.Coordinate|undefined}
+   */
+  this.draggerElCenter = opt_draggerElCenter;
+
+  /**
+   * The current drag list that's being hovered over, or null if the center of
+   * draggerEl is outside of any drag lists. (I.e. If not null and the drag
+   * action ends right now, then currDragItem will end up in this list.)
+   * @type {Element|undefined}
+   */
+  this.hoverList = opt_hoverList;
+
+  /**
+   * The current next item in the hoverList that the draggerEl is hovering over.
+   * (I.e. If the drag action ends right now, then this item would become the
+   * next item after the new location of currDragItem.) May be null if not
+   * applicable or if currDragItem would be added to the end of hoverList.
+   * @type {Element|undefined}
+   */
+  this.hoverNextItem = opt_hoverNextItem;
+};
+goog.inherits(goog.fx.DragListGroupEvent, goog.events.Event);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/dragscrollsupport.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/dragscrollsupport.js b/externs/GCL/externs/goog/fx/dragscrollsupport.js
new file mode 100644
index 0000000..66072e8
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/dragscrollsupport.js
@@ -0,0 +1,300 @@
+// Copyright 2008 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 Class to support scrollable containers for drag and drop.
+ *
+ * @author dgajda@google.com (Damian Gajda)
+ */
+
+goog.provide('goog.fx.DragScrollSupport');
+
+goog.require('goog.Disposable');
+goog.require('goog.Timer');
+goog.require('goog.dom');
+goog.require('goog.events.EventHandler');
+goog.require('goog.events.EventType');
+goog.require('goog.math.Coordinate');
+goog.require('goog.style');
+
+
+
+/**
+ * A scroll support class. Currently this class will automatically scroll
+ * a scrollable container node and scroll it by a fixed amount at a timed
+ * interval when the mouse is moved above or below the container or in vertical
+ * margin areas. Intended for use in drag and drop. This could potentially be
+ * made more general and could support horizontal scrolling.
+ *
+ * @param {Element} containerNode A container that can be scrolled.
+ * @param {number=} opt_margin Optional margin to use while scrolling.
+ * @param {boolean=} opt_externalMouseMoveTracking Whether mouse move events
+ *     are tracked externally by the client object which calls the mouse move
+ *     event handler, useful when events are generated for more than one source
+ *     element and/or are not real mousemove events.
+ * @constructor
+ * @extends {goog.Disposable}
+ * @see ../demos/dragscrollsupport.html
+ */
+goog.fx.DragScrollSupport = function(containerNode, opt_margin,
+                                     opt_externalMouseMoveTracking) {
+  goog.Disposable.call(this);
+
+  /**
+   * The container to be scrolled.
+   * @type {Element}
+   * @private
+   */
+  this.containerNode_ = containerNode;
+
+  /**
+   * Scroll timer that will scroll the container until it is stopped.
+   * It will scroll when the mouse is outside the scrolling area of the
+   * container.
+   *
+   * @type {goog.Timer}
+   * @private
+   */
+  this.scrollTimer_ = new goog.Timer(goog.fx.DragScrollSupport.TIMER_STEP_);
+
+  /**
+   * EventHandler used to set up and tear down listeners.
+   * @type {goog.events.EventHandler<!goog.fx.DragScrollSupport>}
+   * @private
+   */
+  this.eventHandler_ = new goog.events.EventHandler(this);
+
+  /**
+   * The current scroll delta.
+   * @type {goog.math.Coordinate}
+   * @private
+   */
+  this.scrollDelta_ = new goog.math.Coordinate();
+
+  /**
+   * The container bounds.
+   * @type {goog.math.Rect}
+   * @private
+   */
+  this.containerBounds_ = goog.style.getBounds(containerNode);
+
+  /**
+   * The margin for triggering a scroll.
+   * @type {number}
+   * @private
+   */
+  this.margin_ = opt_margin || 0;
+
+  /**
+   * The bounding rectangle which if left triggers scrolling.
+   * @type {goog.math.Rect}
+   * @private
+   */
+  this.scrollBounds_ = opt_margin ?
+      this.constrainBounds_(this.containerBounds_.clone()) :
+      this.containerBounds_;
+
+  this.setupListeners_(!!opt_externalMouseMoveTracking);
+};
+goog.inherits(goog.fx.DragScrollSupport, goog.Disposable);
+
+
+/**
+ * The scroll timer step in ms.
+ * @type {number}
+ * @private
+ */
+goog.fx.DragScrollSupport.TIMER_STEP_ = 50;
+
+
+/**
+ * The scroll step in pixels.
+ * @type {number}
+ * @private
+ */
+goog.fx.DragScrollSupport.SCROLL_STEP_ = 8;
+
+
+/**
+ * The suggested scrolling margin.
+ * @type {number}
+ */
+goog.fx.DragScrollSupport.MARGIN = 32;
+
+
+/**
+ * Whether scrolling should be constrained to happen only when the cursor is
+ * inside the container node.
+ * @type {boolean}
+ * @private
+ */
+goog.fx.DragScrollSupport.prototype.constrainScroll_ = false;
+
+
+/**
+ * Whether horizontal scrolling is allowed.
+ * @type {boolean}
+ * @private
+ */
+goog.fx.DragScrollSupport.prototype.horizontalScrolling_ = true;
+
+
+/**
+ * Sets whether scrolling should be constrained to happen only when the cursor
+ * is inside the container node.
+ * NOTE: If a margin is not set, then it does not make sense to
+ * contain the scroll, because in that case scroll will never be triggered.
+ * @param {boolean} constrain Whether scrolling should be constrained to happen
+ *     only when the cursor is inside the container node.
+ */
+goog.fx.DragScrollSupport.prototype.setConstrainScroll = function(constrain) {
+  this.constrainScroll_ = !!this.margin_ && constrain;
+};
+
+
+/**
+ * Sets whether horizontal scrolling is allowed.
+ * @param {boolean} scrolling Whether horizontal scrolling is allowed.
+ */
+goog.fx.DragScrollSupport.prototype.setHorizontalScrolling =
+    function(scrolling) {
+  this.horizontalScrolling_ = scrolling;
+};
+
+
+/**
+ * Constrains the container bounds with respect to the margin.
+ *
+ * @param {goog.math.Rect} bounds The container element.
+ * @return {goog.math.Rect} The bounding rectangle used to calculate scrolling
+ *     direction.
+ * @private
+ */
+goog.fx.DragScrollSupport.prototype.constrainBounds_ = function(bounds) {
+  var margin = this.margin_;
+  if (margin) {
+    var quarterHeight = bounds.height * 0.25;
+    var yMargin = Math.min(margin, quarterHeight);
+    bounds.top += yMargin;
+    bounds.height -= 2 * yMargin;
+
+    var quarterWidth = bounds.width * 0.25;
+    var xMargin = Math.min(margin, quarterWidth);
+    bounds.top += xMargin;
+    bounds.height -= 2 * xMargin;
+  }
+  return bounds;
+};
+
+
+/**
+ * Attaches listeners and activates automatic scrolling.
+ * @param {boolean} externalMouseMoveTracking Whether to enable internal
+ *     mouse move event handling.
+ * @private
+ */
+goog.fx.DragScrollSupport.prototype.setupListeners_ = function(
+    externalMouseMoveTracking) {
+  if (!externalMouseMoveTracking) {
+    // Track mouse pointer position to determine scroll direction.
+    this.eventHandler_.listen(goog.dom.getOwnerDocument(this.containerNode_),
+        goog.events.EventType.MOUSEMOVE, this.onMouseMove);
+  }
+
+  // Scroll with a constant speed.
+  this.eventHandler_.listen(this.scrollTimer_, goog.Timer.TICK, this.onTick_);
+};
+
+
+/**
+ * Handler for timer tick event, scrolls the container by one scroll step if
+ * needed.
+ * @param {goog.events.Event} event Timer tick event.
+ * @private
+ */
+goog.fx.DragScrollSupport.prototype.onTick_ = function(event) {
+  this.containerNode_.scrollTop += this.scrollDelta_.y;
+  this.containerNode_.scrollLeft += this.scrollDelta_.x;
+};
+
+
+/**
+ * Handler for mouse moves events.
+ * @param {goog.events.Event} event Mouse move event.
+ */
+goog.fx.DragScrollSupport.prototype.onMouseMove = function(event) {
+  var deltaX = this.horizontalScrolling_ ? this.calculateScrollDelta(
+      event.clientX, this.scrollBounds_.left, this.scrollBounds_.width) : 0;
+  var deltaY = this.calculateScrollDelta(event.clientY,
+      this.scrollBounds_.top, this.scrollBounds_.height);
+  this.scrollDelta_.x = deltaX;
+  this.scrollDelta_.y = deltaY;
+
+  // If the scroll data is 0 or the event fired outside of the
+  // bounds of the container node.
+  if ((!deltaX && !deltaY) ||
+      (this.constrainScroll_ &&
+       !this.isInContainerBounds_(event.clientX, event.clientY))) {
+    this.scrollTimer_.stop();
+  } else if (!this.scrollTimer_.enabled) {
+    this.scrollTimer_.start();
+  }
+};
+
+
+/**
+ * Gets whether the input coordinate is in the container bounds.
+ * @param {number} x The x coordinate.
+ * @param {number} y The y coordinate.
+ * @return {boolean} Whether the input coordinate is in the container bounds.
+ * @private
+ */
+goog.fx.DragScrollSupport.prototype.isInContainerBounds_ = function(x, y) {
+  var containerBounds = this.containerBounds_;
+  return containerBounds.left <= x &&
+         containerBounds.left + containerBounds.width >= x &&
+         containerBounds.top <= y &&
+         containerBounds.top + containerBounds.height >= y;
+};
+
+
+/**
+ * Calculates scroll delta.
+ *
+ * @param {number} coordinate Current mouse pointer coordinate.
+ * @param {number} min The coordinate value below which scrolling up should be
+ *     started.
+ * @param {number} rangeLength The length of the range in which scrolling should
+ *     be disabled and above which scrolling down should be started.
+ * @return {number} The calculated scroll delta.
+ * @protected
+ */
+goog.fx.DragScrollSupport.prototype.calculateScrollDelta = function(
+    coordinate, min, rangeLength) {
+  var delta = 0;
+  if (coordinate < min) {
+    delta = -goog.fx.DragScrollSupport.SCROLL_STEP_;
+  } else if (coordinate > min + rangeLength) {
+    delta = goog.fx.DragScrollSupport.SCROLL_STEP_;
+  }
+  return delta;
+};
+
+
+/** @override */
+goog.fx.DragScrollSupport.prototype.disposeInternal = function() {
+  goog.fx.DragScrollSupport.superClass_.disposeInternal.call(this);
+  this.eventHandler_.dispose();
+  this.scrollTimer_.dispose();
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/easing.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/easing.js b/externs/GCL/externs/goog/fx/easing.js
new file mode 100644
index 0000000..fda5122
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/easing.js
@@ -0,0 +1,85 @@
+// 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 Easing functions for animations.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+goog.provide('goog.fx.easing');
+
+
+/**
+ * Ease in - Start slow and speed up.
+ * @param {number} t Input between 0 and 1.
+ * @return {number} Output between 0 and 1.
+ */
+goog.fx.easing.easeIn = function(t) {
+  return goog.fx.easing.easeInInternal_(t, 3);
+};
+
+
+/**
+ * Ease in with specifiable exponent.
+ * @param {number} t Input between 0 and 1.
+ * @param {number} exp Ease exponent.
+ * @return {number} Output between 0 and 1.
+ * @private
+ */
+goog.fx.easing.easeInInternal_ = function(t, exp) {
+  return Math.pow(t, exp);
+};
+
+
+/**
+ * Ease out - Start fastest and slows to a stop.
+ * @param {number} t Input between 0 and 1.
+ * @return {number} Output between 0 and 1.
+ */
+goog.fx.easing.easeOut = function(t) {
+  return goog.fx.easing.easeOutInternal_(t, 3);
+};
+
+
+/**
+ * Ease out with specifiable exponent.
+ * @param {number} t Input between 0 and 1.
+ * @param {number} exp Ease exponent.
+ * @return {number} Output between 0 and 1.
+ * @private
+ */
+goog.fx.easing.easeOutInternal_ = function(t, exp) {
+  return 1 - goog.fx.easing.easeInInternal_(1 - t, exp);
+};
+
+
+/**
+ * Ease out long - Start fastest and slows to a stop with a long ease.
+ * @param {number} t Input between 0 and 1.
+ * @return {number} Output between 0 and 1.
+ */
+goog.fx.easing.easeOutLong = function(t) {
+  return goog.fx.easing.easeOutInternal_(t, 4);
+};
+
+
+/**
+ * Ease in and out - Start slow, speed up, then slow down.
+ * @param {number} t Input between 0 and 1.
+ * @return {number} Output between 0 and 1.
+ */
+goog.fx.easing.inAndOut = function(t) {
+  return 3 * t * t - 2 * t * t * t;
+};

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/fx.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/fx.js b/externs/GCL/externs/goog/fx/fx.js
new file mode 100644
index 0000000..10314b6
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/fx.js
@@ -0,0 +1,34 @@
+// Copyright 2010 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 Legacy stub for the goog.fx namespace.  Requires the moved
+ * namespaces. Animation and easing have been moved to animation.js and
+ * easing.js.  Users of this stub should move off so we may remove it in the
+ * future.
+ *
+ * @author nnaze@google.com (Nathan Naze)
+ * @suppress {extraRequire} All the requires in this file are "extra"
+ * because this file is not actually using them.
+ */
+
+goog.provide('goog.fx');
+
+goog.require('goog.asserts');
+goog.require('goog.fx.Animation');
+goog.require('goog.fx.Animation.EventType');
+goog.require('goog.fx.Animation.State');
+goog.require('goog.fx.AnimationEvent');
+goog.require('goog.fx.Transition.EventType');
+goog.require('goog.fx.easing');

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/fx/transition.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/fx/transition.js b/externs/GCL/externs/goog/fx/transition.js
new file mode 100644
index 0000000..57c4304
--- /dev/null
+++ b/externs/GCL/externs/goog/fx/transition.js
@@ -0,0 +1,76 @@
+// Copyright 2011 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 An interface for transition animation. This is a simple
+ * interface that allows for playing and stopping a transition. It adds
+ * a simple event model with BEGIN and END event.
+ *
+ * @author chrishenry@google.com (Chris Henry)
+ */
+
+goog.provide('goog.fx.Transition');
+goog.provide('goog.fx.Transition.EventType');
+
+
+
+/**
+ * An interface for programmatic transition. Must extend
+ * {@code goog.events.EventTarget}.
+ * @interface
+ */
+goog.fx.Transition = function() {};
+
+
+/**
+ * Transition event types.
+ * @enum {string}
+ */
+goog.fx.Transition.EventType = {
+  /** Dispatched when played for the first time OR when it is resumed. */
+  PLAY: 'play',
+
+  /** Dispatched only when the animation starts from the beginning. */
+  BEGIN: 'begin',
+
+  /** Dispatched only when animation is restarted after a pause. */
+  RESUME: 'resume',
+
+  /**
+   * Dispatched when animation comes to the end of its duration OR stop
+   * is called.
+   */
+  END: 'end',
+
+  /** Dispatched only when stop is called. */
+  STOP: 'stop',
+
+  /** Dispatched only when animation comes to its end naturally. */
+  FINISH: 'finish',
+
+  /** Dispatched when an animation is paused. */
+  PAUSE: 'pause'
+};
+
+
+/**
+ * Plays the transition.
+ */
+goog.fx.Transition.prototype.play;
+
+
+/**
+ * Stops the transition.
+ */
+goog.fx.Transition.prototype.stop;


[32/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
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 robbyw@google.com (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 robbyw@google.com (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 robbyw@google.com (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 robbyw@google.com (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 robbyw@google.com (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 arv@google.com (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;
+};


[43/51] [abbrv] [partial] git commit: [flex-falcon] [refs/heads/JsToAs] - Added GCL extern.

Posted by ft...@apache.org.
http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/flatbutton.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/flatbutton.css b/externs/GCL/externs/goog/css/flatbutton.css
new file mode 100644
index 0000000..1cc39b6
--- /dev/null
+++ b/externs/GCL/externs/goog/css/flatbutton.css
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Styling for flat buttons created by goog.ui.FlatButtonRenderer.
+ *
+ * @author brianp@google.com (Brian Peterson)
+ */
+
+.goog-flat-button {
+  position: relative;
+  /*width: 20ex;*/
+  margin: 2px;
+  border: 1px solid #000;
+  padding: 2px 6px;
+  font: normal 13px "Trebuchet MS", Tahoma, Arial, sans-serif;
+  color: #fff;
+  background-color: #8c2425;
+  cursor: pointer;
+  outline: none;
+}
+
+/* State: disabled. */
+.goog-flat-button-disabled {
+  border-color: #888;
+  color: #888;
+  background-color: #ccc;
+  cursor: default;
+}
+
+/* State: hover. */
+.goog-flat-button-hover {
+  border-color: #8c2425;
+  color: #8c2425;
+  background-color: #eaa4a5;
+}
+
+/* State: active, selected, checked. */
+.goog-flat-button-active,
+.goog-flat-button-selected,
+.goog-flat-button-checked {
+  border-color: #5b4169;
+  color: #5b4169;
+  background-color: #d1a8ea;
+}
+
+/* State: focused. */
+.goog-flat-button-focused {
+  border-color: #5b4169;
+}
+
+/* Pill (collapsed border) styles. */
+.goog-flat-button-collapse-right {
+  margin-right: 0;
+}
+
+.goog-flat-button-collapse-left {
+  margin-left: 0;
+  border-left: none;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/flatmenubutton.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/flatmenubutton.css b/externs/GCL/externs/goog/css/flatmenubutton.css
new file mode 100644
index 0000000..5778217
--- /dev/null
+++ b/externs/GCL/externs/goog/css/flatmenubutton.css
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for buttons created by goog.ui.FlatMenuButtonRenderer.
+ *
+ * @author attila@google.com (Attila Bodis)
+ * @author tlb@google.com (Thierry Le Boulenge)
+ */
+
+
+.goog-flat-menu-button {
+  background-color: #fff;
+  border: 1px solid #c9c9c9;
+  color: #333;
+  cursor: pointer;
+  font: normal 95%;
+  list-style: none;
+  margin: 0 2px;
+  outline: none;
+  padding: 1px 4px;
+  position: relative;
+  text-decoration: none;
+  vertical-align: middle;
+}
+
+.goog-flat-menu-button-disabled * {
+  border-color: #ccc;
+  color: #999;
+  cursor: default;
+}
+
+.goog-flat-menu-button-hover {
+  border-color: #9cf #69e #69e #7af !important; /* Hover border wins. */
+}
+
+.goog-flat-menu-button-active {
+  background-color: #bbb;
+  background-position: bottom left;
+}
+
+.goog-flat-menu-button-focused {
+  border-color: #bbb;
+}
+
+.goog-flat-menu-button-caption {
+  padding-right: 10px;
+  vertical-align: top;
+}
+
+.goog-flat-menu-button-dropdown {
+  /* Client apps may override the URL at which they serve the sprite. */
+  background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -388px 0;
+  position: absolute;
+  right: 2px;
+  top: 0;
+  vertical-align: top;
+  width: 7px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/hovercard.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/hovercard.css b/externs/GCL/externs/goog/css/hovercard.css
new file mode 100644
index 0000000..2d64e4f
--- /dev/null
+++ b/externs/GCL/externs/goog/css/hovercard.css
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2008 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: larrypo@google.com (Larry Powelson) */
+
+.goog-hovercard div {
+  border: solid 5px #69748C;
+  width: 300px;
+  height: 115px;
+  background-color: white;
+  font-family: arial, sans-serif;
+}
+
+.goog-hovercard .goog-shadow {
+  border: transparent;
+  background-color: black;
+  filter: alpha(Opacity=1);
+  opacity: 0.01;
+  -moz-opacity: 0.01;
+}
+
+.goog-hovercard table {
+  border-collapse: collapse;
+  border-spacing: 0px;
+}
+
+.goog-hovercard-icons td {
+  border-bottom: 1px solid #ccc;
+  padding: 0px;
+  margin: 0px;
+  text-align: center;
+  height: 19px;
+  width: 100px;
+  font-size: 90%;
+}
+
+.goog-hovercard-icons td + td {
+  border-left: 1px solid #ccc;
+}
+
+.goog-hovercard-content {
+  border-collapse: collapse;
+}
+
+.goog-hovercard-content td {
+  padding-left: 15px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/hsvapalette.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/hsvapalette.css b/externs/GCL/externs/goog/css/hsvapalette.css
new file mode 100644
index 0000000..ec52e39
--- /dev/null
+++ b/externs/GCL/externs/goog/css/hsvapalette.css
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2008 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * All Rights Reserved.
+ *
+ * Styles for the HSV color palette.
+ *
+ * @author smcbride@google.com (Sean McBride)
+ * @author arv@google.com (Erik Arvidsson)
+ * @author manucornet@google.com (Manu Cornet)
+ */
+
+.goog-hsva-palette,
+.goog-hsva-palette-sm {
+  position: relative;
+  border: 1px solid #999;
+  border-color: #ccc #999 #999 #ccc;
+  width: 442px;
+  height: 276px;
+}
+
+.goog-hsva-palette-sm {
+  width: 205px;
+  height: 185px;
+}
+
+.goog-hsva-palette label span,
+.goog-hsva-palette-sm label span {
+  display: none;
+}
+
+.goog-hsva-palette-hs-backdrop,
+.goog-hsva-palette-sm-hs-backdrop,
+.goog-hsva-palette-hs-image,
+.goog-hsva-palette-sm-hs-image {
+  position: absolute;
+  top: 10px;
+  left: 10px;
+  width: 256px;
+  height: 256px;
+  border: 1px solid #999;
+}
+
+.goog-hsva-palette-sm-hs-backdrop,
+.goog-hsva-palette-sm-hs-image {
+  top: 45px;
+  width: 128px;
+  height: 128px;
+}
+
+.goog-hsva-palette-hs-backdrop,
+.goog-hsva-palette-sm-hs-backdrop {
+  background-color: #000;
+}
+
+.goog-hsva-palette-hs-image,
+.goog-hsva-palette-v-image,
+.goog-hsva-palette-a-image,
+.goog-hsva-palette-hs-handle,
+.goog-hsva-palette-v-handle,
+.goog-hsva-palette-a-handle,
+.goog-hsva-palette-swatch-backdrop {
+  background-image: url(//ssl.gstatic.com/closure/hsva-sprite.png);
+}
+
+.goog-hsva-palette-noalpha .goog-hsva-palette-hs-image,
+.goog-hsva-palette-noalpha .goog-hsva-palette-v-image,
+.goog-hsva-palette-noalpha .goog-hsva-palette-a-image,
+.goog-hsva-palette-noalpha .goog-hsva-palette-hs-handle,
+.goog-hsva-palette-noalpha .goog-hsva-palette-v-handle,
+.goog-hsva-palette-noalpha .goog-hsva-palette-a-handle,
+.goog-hsva-palette-noalpha .goog-hsva-palette-swatch-backdrop {
+  background-image: url(//ssl.gstatic.com/closure/hsva-sprite.gif);
+}
+
+.goog-hsva-palette-sm-hs-image,
+.goog-hsva-palette-sm-v-image,
+.goog-hsva-palette-sm-a-image,
+.goog-hsva-palette-sm-hs-handle,
+.goog-hsva-palette-sm-v-handle,
+.goog-hsva-palette-sm-a-handle,
+.goog-hsva-palette-sm-swatch-backdrop {
+  background-image: url(//ssl.gstatic.com/closure/hsva-sprite-sm.png);
+}
+
+.goog-hsva-palette-noalpha .goog-hsva-palette-sm-hs-image,
+.goog-hsva-palette-noalpha .goog-hsva-palette-sm-v-image,
+.goog-hsva-palette-noalpha .goog-hsva-palette-sm-a-image,
+.goog-hsva-palette-noalpha .goog-hsva-palette-sm-hs-handle,
+.goog-hsva-palette-noalpha .goog-hsva-palette-sm-v-handle,
+.goog-hsva-palette-noalpha .goog-hsva-palette-sm-a-handle,
+.goog-hsva-palette-noalpha .goog-hsva-palette-swatch-backdrop {
+  background-image: url(//ssl.gstatic.com/closure/hsva-sprite-sm.gif);
+}
+
+.goog-hsva-palette-hs-image,
+.goog-hsva-palette-sm-hs-image {
+  background-position: 0 0;
+}
+
+.goog-hsva-palette-hs-handle,
+.goog-hsva-palette-sm-hs-handle {
+  position: absolute;
+  left: 5px;
+  top: 5px;
+  width: 11px;
+  height: 11px;
+  overflow: hidden;
+  background-position: 0 -256px;
+}
+
+.goog-hsva-palette-sm-hs-handle {
+  top: 40px;
+  background-position: 0 -128px;
+}
+
+.goog-hsva-palette-v-image,
+.goog-hsva-palette-a-image,
+.goog-hsva-palette-sm-v-image,
+.goog-hsva-palette-sm-a-image {
+  position: absolute;
+  top: 10px;
+  left: 286px;
+  width: 19px;
+  height: 256px;
+  border: 1px solid #999;
+  background-color: #fff;
+  background-position: -256px 0;
+}
+
+.goog-hsva-palette-a-image {
+  left: 325px;
+  background-position: -275px 0;
+}
+
+.goog-hsva-palette-sm-v-image,
+.goog-hsva-palette-sm-a-image {
+  top: 45px;
+  left: 155px;
+  width: 9px;
+  height: 128px;
+  background-position: -128px 0;
+}
+
+.goog-hsva-palette-sm-a-image {
+  left: 182px;
+  background-position: -137px 0;
+}
+
+.goog-hsva-palette-v-handle,
+.goog-hsva-palette-a-handle,
+.goog-hsva-palette-sm-v-handle,
+.goog-hsva-palette-sm-a-handle {
+  position: absolute;
+  top: 5px;
+  left: 279px;
+  width: 35px;
+  height: 11px;
+  background-position: -11px -256px;
+  overflow: hidden;
+}
+
+.goog-hsva-palette-a-handle {
+  left: 318px;
+}
+
+.goog-hsva-palette-sm-v-handle,
+.goog-hsva-palette-sm-a-handle {
+  top: 40px;
+  left: 148px;
+  width: 25px;
+  background-position: -11px -128px;
+}
+
+.goog-hsva-palette-sm-a-handle {
+  left: 175px;
+}
+
+.goog-hsva-palette-swatch,
+.goog-hsva-palette-swatch-backdrop,
+.goog-hsva-palette-sm-swatch,
+.goog-hsva-palette-sm-swatch-backdrop {
+  position: absolute;
+  top: 10px;
+  right: 10px;
+  width: 65px;
+  height: 65px;
+  border: 1px solid #999;
+  background-color: #fff;
+  background-position: -294px 0;
+}
+
+.goog-hsva-palette-sm-swatch,
+.goog-hsva-palette-sm-swatch-backdrop {
+  top: 10px;
+  right: auto;
+  left: 10px;
+  width: 30px;
+  height: 22px;
+  background-position: -36px -128px;
+}
+
+.goog-hsva-palette-swatch,
+.goog-hsva-palette-sm-swatch {
+  z-index: 5;
+}
+
+.goog-hsva-palette-swatch-backdrop,
+.goog-hsva-palette-sm-swatch-backdrop {
+  z-index: 1;
+}
+
+.goog-hsva-palette-input,
+.goog-hsva-palette-sm-input {
+  position: absolute;
+  top: 85px;
+  right: 10px;
+  width: 65px;
+  font-size: 80%;
+}
+
+.goog-hsva-palette-sm-input {
+  top: 10px;
+  right: auto;
+  left: 50px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/hsvpalette.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/hsvpalette.css b/externs/GCL/externs/goog/css/hsvpalette.css
new file mode 100644
index 0000000..8449ed5
--- /dev/null
+++ b/externs/GCL/externs/goog/css/hsvpalette.css
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2008 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * All Rights Reserved.
+ *
+ * Styles for the HSV color palette.
+ *
+ * @author smcbride@google.com (Sean McBride)
+ * @author arv@google.com (Erik Arvidsson)
+ * @author manucornet@google.com (Manu Cornet)
+ */
+
+.goog-hsv-palette,
+.goog-hsv-palette-sm {
+  position: relative;
+  border: 1px solid #999;
+  border-color: #ccc #999 #999 #ccc;
+  width: 400px;
+  height: 276px;
+}
+
+.goog-hsv-palette-sm {
+  width: 182px;
+  height: 185px;
+}
+
+.goog-hsv-palette label span,
+.goog-hsv-palette-sm label span {
+  display: none;
+}
+
+.goog-hsv-palette-hs-backdrop,
+.goog-hsv-palette-sm-hs-backdrop,
+.goog-hsv-palette-hs-image,
+.goog-hsv-palette-sm-hs-image {
+  position: absolute;
+  top: 10px;
+  left: 10px;
+  width: 256px;
+  height: 256px;
+  border: 1px solid #999;
+}
+
+.goog-hsv-palette-sm-hs-backdrop,
+.goog-hsv-palette-sm-hs-image {
+  top: 45px;
+  width: 128px;
+  height: 128px;
+}
+
+.goog-hsv-palette-hs-backdrop,
+.goog-hsv-palette-sm-hs-backdrop {
+  background-color: #000;
+}
+
+.goog-hsv-palette-hs-image,
+.goog-hsv-palette-v-image,
+.goog-hsv-palette-hs-handle,
+.goog-hsv-palette-v-handle {
+  background-image: url(//ssl.gstatic.com/closure/hsv-sprite.png);
+}
+
+.goog-hsv-palette-noalpha .goog-hsv-palette-hs-image,
+.goog-hsv-palette-noalpha .goog-hsv-palette-v-image,
+.goog-hsv-palette-noalpha .goog-hsv-palette-hs-handle,
+.goog-hsv-palette-noalpha .goog-hsv-palette-v-handle {
+  background-image: url(//ssl.gstatic.com/closure/hsv-sprite.gif);
+}
+
+.goog-hsv-palette-sm-hs-image,
+.goog-hsv-palette-sm-v-image,
+.goog-hsv-palette-sm-hs-handle,
+.goog-hsv-palette-sm-v-handle {
+  background-image: url(//ssl.gstatic.com/closure/hsv-sprite-sm.png);
+}
+
+.goog-hsv-palette-noalpha .goog-hsv-palette-sm-hs-image,
+.goog-hsv-palette-noalpha .goog-hsv-palette-sm-v-image,
+.goog-hsv-palette-noalpha .goog-hsv-palette-sm-hs-handle,
+.goog-hsv-palette-noalpha .goog-hsv-palette-sm-v-handle {
+  background-image: url(//ssl.gstatic.com/closure/hsv-sprite-sm.gif);
+}
+
+.goog-hsv-palette-hs-image,
+.goog-hsv-palette-sm-hs-image {
+  background-position: 0 0;
+}
+
+.goog-hsv-palette-hs-handle,
+.goog-hsv-palette-sm-hs-handle {
+  position: absolute;
+  left: 5px;
+  top: 5px;
+  width: 11px;
+  height: 11px;
+  overflow: hidden;
+  background-position: 0 -256px;
+}
+
+.goog-hsv-palette-sm-hs-handle {
+  top: 40px;
+  background-position: 0 -128px;
+}
+
+.goog-hsv-palette-v-image,
+.goog-hsv-palette-sm-v-image {
+  position: absolute;
+  top: 10px;
+  left: 286px;
+  width: 19px;
+  height: 256px;
+  border: 1px solid #999;
+  background-color: #fff;
+  background-position: -256px 0;
+}
+
+.goog-hsv-palette-sm-v-image {
+  top: 45px;
+  left: 155px;
+  width: 9px;
+  height: 128px;
+  background-position: -128px 0;
+}
+
+.goog-hsv-palette-v-handle,
+.goog-hsv-palette-sm-v-handle {
+  position: absolute;
+  top: 5px;
+  left: 279px;
+  width: 35px;
+  height: 11px;
+  background-position: -11px -256px;
+  overflow: hidden;
+}
+
+.goog-hsv-palette-sm-v-handle {
+  top: 40px;
+  left: 148px;
+  width: 25px;
+  background-position: -11px -128px;
+}
+
+.goog-hsv-palette-swatch,
+.goog-hsv-palette-sm-swatch {
+  position: absolute;
+  top: 10px;
+  right: 10px;
+  width: 65px;
+  height: 65px;
+  border: 1px solid #999;
+  background-color: #fff;
+}
+
+.goog-hsv-palette-sm-swatch {
+  top: 10px;
+  right: auto;
+  left: 10px;
+  width: 30px;
+  height: 22px;
+}
+
+.goog-hsv-palette-input,
+.goog-hsv-palette-sm-input {
+  position: absolute;
+  top: 85px;
+  right: 10px;
+  width: 65px;
+}
+
+.goog-hsv-palette-sm-input {
+  top: 10px;
+  right: auto;
+  left: 50px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/imagelessbutton.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/imagelessbutton.css b/externs/GCL/externs/goog/css/imagelessbutton.css
new file mode 100644
index 0000000..23c7fee
--- /dev/null
+++ b/externs/GCL/externs/goog/css/imagelessbutton.css
@@ -0,0 +1,160 @@
+/*
+ * Copyright 2008 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Styling for buttons created by goog.ui.ImagelessButtonRenderer.
+ *
+ * WARNING: This file uses some ineffecient selectors and it may be
+ * best to avoid using this file in extremely large, or performance
+ * critical applications.
+ *
+ * @author: eae@google.com (Emil A Eklund)
+ * @author: gboyer@google.com (Garrett Boyer)
+ */
+
+
+/* Imageless button styles. */
+
+/* The base element of the button. */
+.goog-imageless-button {
+  /* Set the background color at the outermost level. */
+  background: #e3e3e3;
+  /* Place a top and bottom border.  Do it on this outermost div so that
+   * it is easier to make pill buttons work properly. */
+  border-color: #bbb;
+  border-style: solid;
+  border-width: 1px 0;
+  color: #222; /* Text content color. */
+  cursor: default;
+  font-family: Arial, sans-serif;
+  line-height: 0; /* For Opera and old WebKit. */
+  list-style: none;
+  /* Built-in margin for the component.  Because of the negative margins
+   * used to simulate corner rounding, the effective left and right margin is
+   * actually only 1px. */
+  margin: 2px;
+  outline: none;
+  padding: 0;
+  text-decoration: none;
+  vertical-align: middle;
+}
+
+/*
+ * Pseudo-rounded corners.  Works by pulling the left and right sides slightly
+ * outside of the parent bounding box before drawing the left and right
+ * borders.
+ */
+.goog-imageless-button-outer-box {
+  /* Left and right border that protrude outside the parent. */
+  border-color: #bbb;
+  border-style: solid;
+  border-width: 0 1px;
+  /* Same as margin: 0 -1px, except works better cross browser.  These are
+   * intended to be RTL flipped to work better in IE7. */
+  left: -1px;
+  margin-right: -2px;
+}
+
+/*
+ * A div to give the light and medium shades of the button that takes up no
+ * vertical space.
+ */
+.goog-imageless-button-top-shadow {
+  /* Light top color in the content. */
+  background: #f9f9f9;
+  /* Thin medium shade. */
+  border-bottom: 3px solid #eee;
+  /* Control height with line-height, since height: will trigger hasLayout.
+   * Specified in pixels, as a compromise to avoid rounding errors. */
+  line-height: 9px;
+  /* Undo all space this takes up. */
+  margin-bottom: -12px;
+}
+
+/* Actual content area for the button. */
+.goog-imageless-button-content {
+  line-height: 1.5em;
+  padding: 0px 4px;
+  text-align: center;
+}
+
+
+/* Pill (collapsed border) styles. */
+.goog-imageless-button-collapse-right {
+  /* Draw a border on the root element to square the button off.  The border
+   * on the outer-box element remains, but gets obscured by the next button. */
+  border-right-width: 1px;
+  margin-right: -2px; /* Undoes the margins between the two buttons. */
+}
+
+.goog-imageless-button-collapse-left .goog-imageless-button-outer-box {
+  /* Don't bleed to the left -- keep the border self contained in the box. */
+  border-left-color: #eee;
+  left: 0;
+  margin-right: -1px; /* Versus the default of -2px. */
+}
+
+
+/* Disabled styles. */
+.goog-imageless-button-disabled,
+.goog-imageless-button-disabled .goog-imageless-button-outer-box {
+  background: #eee;
+  border-color: #ccc;
+  color: #666; /* For text */
+}
+
+.goog-imageless-button-disabled .goog-imageless-button-top-shadow {
+  /* Just hide the shadow instead of setting individual colors. */
+  visibility: hidden;
+}
+
+
+/*
+ * Active and checked styles.
+ * Identical except for text color according to GUIG.
+ */
+.goog-imageless-button-active, .goog-imageless-button-checked {
+  background: #f9f9f9;
+}
+
+.goog-imageless-button-active .goog-imageless-button-top-shadow,
+.goog-imageless-button-checked .goog-imageless-button-top-shadow {
+  background: #e3e3e3;
+}
+
+.goog-imageless-button-active {
+  color: #000;
+}
+
+
+/* Hover styles. Higher priority to override other border styles. */
+.goog-imageless-button-hover,
+.goog-imageless-button-hover .goog-imageless-button-outer-box,
+.goog-imageless-button-focused,
+.goog-imageless-button-focused .goog-imageless-button-outer-box {
+  border-color: #000;
+}
+
+
+/* IE6 hacks.  This is the only place inner-box is used. */
+* html .goog-imageless-button-inner-box {
+  /* Give the element inline-block behavior so that the shadow appears.
+   * The main requirement is to give the element layout without having the side
+   * effect of taking up a full line. */
+  display: inline;
+  /* Allow the shadow to show through, overriding position:relative from the
+   * goog-inline-block styles. */
+  position: static;
+  zoom: 1;
+}
+
+* html .goog-imageless-button-outer-box {
+  /* In RTL mode, IE is off by one pixel.  To fix, override the left: -1px
+   * (which was flipped to right) without having any effect on LTR mode
+   * (where IE ignores right when left is specified). */
+  /* @noflip */ right: 0;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/imagelessmenubutton.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/imagelessmenubutton.css b/externs/GCL/externs/goog/css/imagelessmenubutton.css
new file mode 100644
index 0000000..0c8b6fd
--- /dev/null
+++ b/externs/GCL/externs/goog/css/imagelessmenubutton.css
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2010 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for buttons created by goog.ui.ImagelessMenuButtonRenderer.
+ *
+ * @author attila@google.com (Attila Bodis)
+ * @author dalewis@google.com (Darren Lewis)
+ */
+
+/* Dropdown arrow style. */
+.goog-imageless-button-dropdown {
+  height: 16px;
+  width: 7px;
+  /* Client apps may override the URL at which they serve the sprite. */
+  background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -388px 0;
+  vertical-align: top;
+  margin-right: 2px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/inputdatepicker.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/inputdatepicker.css b/externs/GCL/externs/goog/css/inputdatepicker.css
new file mode 100644
index 0000000..4f93182
--- /dev/null
+++ b/externs/GCL/externs/goog/css/inputdatepicker.css
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2008 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: arv@google.com (Erik Arvidsson) */
+
+/* goog.ui.InputDatePicker */
+
+@import url(popupdatepicker.css);

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/linkbutton.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/linkbutton.css b/externs/GCL/externs/goog/css/linkbutton.css
new file mode 100644
index 0000000..9f9ec3a
--- /dev/null
+++ b/externs/GCL/externs/goog/css/linkbutton.css
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2010 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Styling for link buttons created by goog.ui.LinkButtonRenderer.
+ *
+ * @author robbyw@google.com (Robby Walker)
+ */
+
+.goog-link-button {
+  position: relative;
+  color: #00f;
+  text-decoration: underline;
+  cursor: pointer;
+}
+
+/* State: disabled. */
+.goog-link-button-disabled {
+  color: #888;
+  text-decoration: none;
+  cursor: default;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/menu.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/menu.css b/externs/GCL/externs/goog/css/menu.css
new file mode 100644
index 0000000..da66222
--- /dev/null
+++ b/externs/GCL/externs/goog/css/menu.css
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for menus created by goog.ui.MenuRenderer.
+ *
+ * @author attila@google.com (Attila Bodis)
+ */
+
+
+.goog-menu {
+  background: #fff;
+  border-color: #ccc #666 #666 #ccc;
+  border-style: solid;
+  border-width: 1px;
+  cursor: default;
+  font: normal 13px Arial, sans-serif;
+  margin: 0;
+  outline: none;
+  padding: 4px 0;
+  position: absolute;
+  z-index: 20000; /* Arbitrary, but some apps depend on it... */
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/menubar.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/menubar.css b/externs/GCL/externs/goog/css/menubar.css
new file mode 100644
index 0000000..6f69b46
--- /dev/null
+++ b/externs/GCL/externs/goog/css/menubar.css
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * styling for goog.ui.menuBar and child buttons.
+ *
+ * @author tvykruta@google.com (Tomas Vykruta)
+ */
+
+
+.goog-menubar {
+  cursor: default;
+  outline: none;
+  position: relative;
+  white-space: nowrap;
+  background: #fff;
+}
+
+.goog-menubar .goog-menu-button {
+  padding: 1px 1px;
+  margin: 0px 0px;
+  outline: none;
+  border: none;
+  background: #fff;
+  /* @alternate */ border: 1px solid #fff;
+}
+
+.goog-menubar .goog-menu-button-dropdown {
+  display: none;
+}
+
+.goog-menubar .goog-menu-button-outer-box {
+  border: none;
+}
+
+.goog-menubar .goog-menu-button-inner-box {
+  border: none;
+}
+
+.goog-menubar .goog-menu-button-hover {
+  background: #eee;
+  border: 1px solid #eee;
+}
+
+.goog-menubar .goog-menu-button-open {
+  background: #fff;
+  border-left: 1px solid #ccc;
+  border-right: 1px solid #ccc;
+}
+
+.goog-menubar .goog-menu-button-disabled {
+  color: #ccc;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/menubutton.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/menubutton.css b/externs/GCL/externs/goog/css/menubutton.css
new file mode 100644
index 0000000..82c94b2
--- /dev/null
+++ b/externs/GCL/externs/goog/css/menubutton.css
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for buttons created by goog.ui.MenuButtonRenderer.
+ *
+ * @author attila@google.com (Attila Bodis)
+ */
+
+
+/* State: resting. */
+.goog-menu-button {
+  /* Client apps may override the URL at which they serve the image. */
+  background: #ddd url(//ssl.gstatic.com/editor/button-bg.png) repeat-x top left;
+  border: 0;
+  color: #000;
+  cursor: pointer;
+  list-style: none;
+  margin: 2px;
+  outline: none;
+  padding: 0;
+  text-decoration: none;
+  vertical-align: middle;
+}
+
+/* Pseudo-rounded corners. */
+.goog-menu-button-outer-box,
+.goog-menu-button-inner-box {
+  border-style: solid;
+  border-color: #aaa;
+  vertical-align: top;
+}
+.goog-menu-button-outer-box {
+  margin: 0;
+  border-width: 1px 0;
+  padding: 0;
+}
+.goog-menu-button-inner-box {
+  margin: 0 -1px;
+  border-width: 0 1px;
+  padding: 3px 4px;
+}
+
+/* Pre-IE7 IE hack; ignored by IE7 and all non-IE browsers. */
+* html .goog-menu-button-inner-box {
+  /* IE6 needs to have the box shifted to make the borders line up. */
+  left: -1px;
+}
+
+/* Pre-IE7 BiDi fixes. */
+* html .goog-menu-button-rtl .goog-menu-button-outer-box {
+  /* @noflip */ left: -1px;
+  /* @noflip */ right: auto;
+}
+* html .goog-menu-button-rtl .goog-menu-button-inner-box {
+  /* @noflip */ right: auto;
+}
+
+/* IE7-only hack; ignored by all other browsers. */
+*:first-child+html .goog-menu-button-inner-box {
+  /* IE7 needs to have the box shifted to make the borders line up. */
+  left: -1px;
+}
+/* IE7 BiDi fix. */
+*:first-child+html .goog-menu-button-rtl .goog-menu-button-inner-box {
+  /* @noflip */ left: 1px;
+  /* @noflip */ right: auto;
+}
+
+/* Safari-only hacks. */
+::root .goog-menu-button,
+::root .goog-menu-button-outer-box,
+::root .goog-menu-button-inner-box {
+  /* Required to make pseudo-rounded corners work on Safari. */
+  line-height: 0;
+}
+::root .goog-menu-button-caption,
+::root .goog-menu-button-dropdown {
+  /* Required to make pseudo-rounded corners work on Safari. */
+  line-height: normal;
+}
+
+/* State: disabled. */
+.goog-menu-button-disabled {
+  background-image: none !important;
+  opacity: 0.3;
+  -moz-opacity: 0.3;
+  filter: alpha(opacity=30);
+}
+.goog-menu-button-disabled .goog-menu-button-outer-box,
+.goog-menu-button-disabled .goog-menu-button-inner-box,
+.goog-menu-button-disabled .goog-menu-button-caption,
+.goog-menu-button-disabled .goog-menu-button-dropdown {
+  color: #333 !important;
+  border-color: #999 !important;
+}
+
+/* Pre-IE7 IE hack; ignored by IE7 and all non-IE browsers. */
+* html .goog-menu-button-disabled {
+  margin: 2px 1px !important;
+  padding: 0 1px !important;
+}
+
+/* IE7-only hack; ignored by all other browsers. */
+*:first-child+html .goog-menu-button-disabled {
+  margin: 2px 1px !important;
+  padding: 0 1px !important;
+}
+
+/* State: hover. */
+.goog-menu-button-hover .goog-menu-button-outer-box,
+.goog-menu-button-hover .goog-menu-button-inner-box {
+  border-color: #9cf #69e #69e #7af !important; /* Hover border wins. */
+}
+
+/* State: active, open. */
+.goog-menu-button-active,
+.goog-menu-button-open {
+  background-color: #bbb;
+  background-position: bottom left;
+}
+
+/* State: focused. */
+.goog-menu-button-focused .goog-menu-button-outer-box,
+.goog-menu-button-focused .goog-menu-button-inner-box {
+  border-color: orange;
+}
+
+/* Caption style. */
+.goog-menu-button-caption {
+  padding: 0 4px 0 0;
+  vertical-align: top;
+}
+
+/* Dropdown arrow style. */
+.goog-menu-button-dropdown {
+  height: 15px;
+  width: 7px;
+  /* Client apps may override the URL at which they serve the sprite. */
+  background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -388px 0;
+  vertical-align: top;
+}
+
+/* Pill (collapsed border) styles. */
+/* TODO(gboyer): Remove specific menu button styles and have any button support being a menu button. */
+.goog-menu-button-collapse-right,
+.goog-menu-button-collapse-right .goog-menu-button-outer-box,
+.goog-menu-button-collapse-right .goog-menu-button-inner-box {
+  margin-right: 0;
+}
+
+.goog-menu-button-collapse-left,
+.goog-menu-button-collapse-left .goog-menu-button-outer-box,
+.goog-menu-button-collapse-left .goog-menu-button-inner-box {
+  margin-left: 0;
+}
+
+.goog-menu-button-collapse-left .goog-menu-button-inner-box  {
+  border-left: 1px solid #fff;
+}
+
+.goog-menu-button-collapse-left.goog-menu-button-checked
+.goog-menu-button-inner-box {
+  border-left: 1px solid #ddd;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/menuitem.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/menuitem.css b/externs/GCL/externs/goog/css/menuitem.css
new file mode 100644
index 0000000..cea9de6
--- /dev/null
+++ b/externs/GCL/externs/goog/css/menuitem.css
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for menus created by goog.ui.MenuItemRenderer.
+ *
+ * @author attila@google.com (Attila Bodis)
+ */
+
+
+/**
+ * State: resting.
+ *
+ * NOTE(mleibman,chrishenry):
+ * The RTL support in Closure is provided via two mechanisms -- "rtl" CSS
+ * classes and BiDi flipping done by the CSS compiler.  Closure supports RTL
+ * with or without the use of the CSS compiler.  In order for them not
+ * to conflict with each other, the "rtl" CSS classes need to have the @noflip
+ * annotation.  The non-rtl counterparts should ideally have them as well, but,
+ * since .goog-menuitem existed without .goog-menuitem-rtl for so long before
+ * being added, there is a risk of people having templates where they are not
+ * rendering the .goog-menuitem-rtl class when in RTL and instead rely solely
+ * on the BiDi flipping by the CSS compiler.  That's why we're not adding the
+ * @noflip to .goog-menuitem.
+ */
+.goog-menuitem {
+  color: #000;
+  font: normal 13px Arial, sans-serif;
+  list-style: none;
+  margin: 0;
+  /* 28px on the left for icon or checkbox; 7em on the right for shortcut. */
+  padding: 4px 7em 4px 28px;
+  white-space: nowrap;
+}
+
+/* BiDi override for the resting state. */
+/* @noflip */
+.goog-menuitem.goog-menuitem-rtl {
+  /* Flip left/right padding for BiDi. */
+  padding-left: 7em;
+  padding-right: 28px;
+}
+
+/* If a menu doesn't have checkable items or items with icons, remove padding. */
+.goog-menu-nocheckbox .goog-menuitem,
+.goog-menu-noicon .goog-menuitem {
+  padding-left: 12px;
+}
+
+/*
+ * If a menu doesn't have items with shortcuts, leave just enough room for
+ * submenu arrows, if they are rendered.
+ */
+.goog-menu-noaccel .goog-menuitem {
+  padding-right: 20px;
+}
+
+.goog-menuitem-content {
+  color: #000;
+  font: normal 13px Arial, sans-serif;
+}
+
+/* State: disabled. */
+.goog-menuitem-disabled .goog-menuitem-accel,
+.goog-menuitem-disabled .goog-menuitem-content {
+  color: #ccc !important;
+}
+.goog-menuitem-disabled .goog-menuitem-icon {
+  opacity: 0.3;
+  -moz-opacity: 0.3;
+  filter: alpha(opacity=30);
+}
+
+/* State: hover. */
+.goog-menuitem-highlight,
+.goog-menuitem-hover {
+  background-color: #d6e9f8;
+  /* Use an explicit top and bottom border so that the selection is visible
+   * in high contrast mode. */
+  border-color: #d6e9f8;
+  border-style: dotted;
+  border-width: 1px 0;
+  padding-bottom: 3px;
+  padding-top: 3px;
+}
+
+/* State: selected/checked. */
+.goog-menuitem-checkbox,
+.goog-menuitem-icon {
+  background-repeat: no-repeat;
+  height: 16px;
+  left: 6px;
+  position: absolute;
+  right: auto;
+  vertical-align: middle;
+  width: 16px;
+}
+
+/* BiDi override for the selected/checked state. */
+/* @noflip */
+.goog-menuitem-rtl .goog-menuitem-checkbox,
+.goog-menuitem-rtl .goog-menuitem-icon {
+  /* Flip left/right positioning. */
+  left: auto;
+  right: 6px;
+}
+
+.goog-option-selected .goog-menuitem-checkbox,
+.goog-option-selected .goog-menuitem-icon {
+  /* Client apps may override the URL at which they serve the sprite. */
+  background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -512px 0;
+}
+
+/* Keyboard shortcut ("accelerator") style. */
+.goog-menuitem-accel {
+  color: #999;
+  /* Keyboard shortcuts are untranslated; always left-to-right. */
+  /* @noflip */ direction: ltr;
+  left: auto;
+  padding: 0 6px;
+  position: absolute;
+  right: 0;
+  text-align: right;
+}
+
+/* BiDi override for shortcut style. */
+/* @noflip */
+.goog-menuitem-rtl .goog-menuitem-accel {
+  /* Flip left/right positioning and text alignment. */
+  left: 0;
+  right: auto;
+  text-align: left;
+}
+
+/* Mnemonic styles. */
+.goog-menuitem-mnemonic-hint {
+  text-decoration: underline;
+}
+
+.goog-menuitem-mnemonic-separator {
+  color: #999;
+  font-size: 12px;
+  padding-left: 4px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/menuseparator.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/menuseparator.css b/externs/GCL/externs/goog/css/menuseparator.css
new file mode 100644
index 0000000..de1354f
--- /dev/null
+++ b/externs/GCL/externs/goog/css/menuseparator.css
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for menus created by goog.ui.MenuSeparatorRenderer.
+ *
+ * @author attila@google.com (Attila Bodis)
+ */
+
+
+.goog-menuseparator {
+  border-top: 1px solid #ccc;
+  margin: 4px 0;
+  padding: 0;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/multitestrunner.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/multitestrunner.css b/externs/GCL/externs/goog/css/multitestrunner.css
new file mode 100644
index 0000000..2cdffea
--- /dev/null
+++ b/externs/GCL/externs/goog/css/multitestrunner.css
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2008 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: pupius@google.com (Daniel Pupius) */
+
+.goog-testrunner {
+  background-color: #EEE;
+  border: 1px solid #999;
+  padding: 10px;
+  padding-bottom: 25px;
+}
+
+.goog-testrunner-progress {
+  width: auto;
+  height: 20px;
+  background-color: #FFF;
+  border: 1px solid #999;
+}
+
+.goog-testrunner-progress table {
+  width: 100%;
+  height: 20px;
+  border-collapse: collapse;
+}
+
+.goog-testrunner-buttons {
+  margin-top: 7px;
+}
+
+.goog-testrunner-buttons button {
+  width: 75px;
+}
+
+.goog-testrunner-log,
+.goog-testrunner-report,
+.goog-testrunner-stats {
+  margin-top: 7px;
+  width: auto;
+  height: 400px;
+  background-color: #FFF;
+  border: 1px solid #999;
+  font: normal medium monospace;
+  padding: 5px;
+  overflow: auto;  /* Opera doesn't support overflow-y. */
+  overflow-y: scroll;
+  overflow-x: auto;
+}
+
+.goog-testrunner-report div {
+  margin-bottom: 6px;
+  border-bottom: 1px solid #999;
+}
+
+.goog-testrunner-stats table {
+  margin-top: 20px;
+  border-collapse: collapse;
+  border: 1px solid #EEE;
+}
+
+.goog-testrunner-stats td,
+.goog-testrunner-stats th {
+  padding: 2px 6px;
+  border: 1px solid #F0F0F0;
+}
+
+.goog-testrunner-stats th {
+  font-weight: bold;
+}
+
+.goog-testrunner-stats .center {
+  text-align: center;
+}
+
+.goog-testrunner-progress-summary {
+  font: bold small sans-serif;
+}
+
+.goog-testrunner iframe {
+  position: absolute;
+  left: -640px;
+  top: -480px;
+  width: 640px;
+  height: 480px;
+  margin: 0;
+  border: 0;
+  padding: 0;
+}
+
+.goog-testrunner-report-failure {
+  color: #900;
+}
+
+.goog-testrunner-reporttab,
+.goog-testrunner-logtab,
+.goog-testrunner-statstab {
+  float: left;
+  width: 50px;
+  height: 16px;
+  text-align: center;
+  font: normal small arial, helvetica, sans-serif;
+  color: #666;
+  background-color: #DDD;
+  border: 1px solid #999;
+  border-top: 0;
+  cursor: pointer;
+}
+
+.goog-testrunner-reporttab,
+.goog-testrunner-logtab {
+  border-right: 0;
+}
+
+.goog-testrunner-activetab {
+  font-weight: bold;
+  color: #000;
+  background-color: #CCC;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/palette.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/palette.css b/externs/GCL/externs/goog/css/palette.css
new file mode 100644
index 0000000..8360afc
--- /dev/null
+++ b/externs/GCL/externs/goog/css/palette.css
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for palettes created by goog.ui.PaletteRenderer.
+ *
+ * @author pupius@google.com (Daniel Pupius)
+ * @author attila@google.com (Attila Bodis)
+ */
+
+
+.goog-palette {
+  cursor: default;
+  outline: none;
+}
+
+.goog-palette-table {
+  border: 1px solid #666;
+  border-collapse: collapse;
+  margin: 5px;
+}
+
+.goog-palette-cell {
+  border: 0;
+  border-right: 1px solid #666;
+  cursor: pointer;
+  height: 18px;
+  margin: 0;
+  text-align: center;
+  vertical-align: middle;
+  width: 18px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/popupdatepicker.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/popupdatepicker.css b/externs/GCL/externs/goog/css/popupdatepicker.css
new file mode 100644
index 0000000..133173a
--- /dev/null
+++ b/externs/GCL/externs/goog/css/popupdatepicker.css
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for a goog.ui.PopupDatePicker.
+ *
+ * @author arv@google.com (Erik Arvidsson)
+ */
+
+.goog-date-picker {
+  position: absolute;
+}
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/roundedpanel.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/roundedpanel.css b/externs/GCL/externs/goog/css/roundedpanel.css
new file mode 100644
index 0000000..d931e41
--- /dev/null
+++ b/externs/GCL/externs/goog/css/roundedpanel.css
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2010 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styles for RoundedPanel.
+ *
+ * @author pallosp@google.com (Peter Pallos)
+ */
+
+.goog-roundedpanel {
+  position: relative;
+  z-index: 0;
+}
+
+.goog-roundedpanel-background {
+  position: absolute;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  z-index: -1;
+}
+
+.goog-roundedpanel-content {
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/roundedtab.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/roundedtab.css b/externs/GCL/externs/goog/css/roundedtab.css
new file mode 100644
index 0000000..17fe155
--- /dev/null
+++ b/externs/GCL/externs/goog/css/roundedtab.css
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2008 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: attila@google.com (Attila Bodis) */
+
+
+/*
+ * Styles used by goog.ui.RoundedTabRenderer.
+ */
+.goog-rounded-tab {
+  border: 0;
+  cursor: default;
+  padding: 0;
+}
+
+.goog-tab-bar-top .goog-rounded-tab,
+.goog-tab-bar-bottom .goog-rounded-tab {
+  float: left;
+  margin: 0 4px 0 0;
+}
+
+.goog-tab-bar-start .goog-rounded-tab,
+.goog-tab-bar-end .goog-rounded-tab {
+  margin: 0 0 4px 0;
+}
+
+.goog-rounded-tab-caption {
+  border: 0;
+  color: #fff;
+  margin: 0;
+  padding: 4px 8px;
+}
+
+.goog-rounded-tab-caption,
+.goog-rounded-tab-inner-edge,
+.goog-rounded-tab-outer-edge {
+  background: #036;
+  border-right: 1px solid #003;
+}
+
+.goog-rounded-tab-inner-edge,
+.goog-rounded-tab-outer-edge {
+  font-size: 1px;
+  height: 1px;
+  overflow: hidden;
+}
+
+/* State: Hover */
+.goog-rounded-tab-hover .goog-rounded-tab-caption,
+.goog-rounded-tab-hover .goog-rounded-tab-inner-edge,
+.goog-rounded-tab-hover .goog-rounded-tab-outer-edge {
+  background-color: #69c;
+  border-right: 1px solid #369;
+}
+
+/* State: Disabled */
+.goog-rounded-tab-disabled .goog-rounded-tab-caption,
+.goog-rounded-tab-disabled .goog-rounded-tab-inner-edge,
+.goog-rounded-tab-disabled .goog-rounded-tab-outer-edge {
+  background: #ccc;
+  border-right: 1px solid #ccc;
+}
+
+/* State: Selected */
+.goog-rounded-tab-selected .goog-rounded-tab-caption,
+.goog-rounded-tab-selected .goog-rounded-tab-inner-edge,
+.goog-rounded-tab-selected .goog-rounded-tab-outer-edge {
+  background: #369 !important; /* Selected trumps hover. */
+  border-right: 1px solid #036 !important;
+}
+
+
+/*
+ * Styles for horizontal (top or bottom) tabs.
+ */
+.goog-tab-bar-top .goog-rounded-tab {
+  vertical-align: bottom;
+}
+
+.goog-tab-bar-bottom .goog-rounded-tab {
+  vertical-align: top;
+}
+
+.goog-tab-bar-top .goog-rounded-tab-outer-edge,
+.goog-tab-bar-bottom .goog-rounded-tab-outer-edge {
+  margin: 0 3px;
+}
+
+.goog-tab-bar-top .goog-rounded-tab-inner-edge,
+.goog-tab-bar-bottom .goog-rounded-tab-inner-edge {
+  margin: 0 1px;
+}
+
+
+/*
+ * Styles for vertical (start or end) tabs.
+ */
+.goog-tab-bar-start .goog-rounded-tab-table,
+.goog-tab-bar-end .goog-rounded-tab-table {
+  width: 100%;
+}
+
+.goog-tab-bar-start .goog-rounded-tab-inner-edge {
+  margin-left: 1px;
+}
+
+.goog-tab-bar-start .goog-rounded-tab-outer-edge {
+  margin-left: 3px;
+}
+
+.goog-tab-bar-end .goog-rounded-tab-inner-edge {
+  margin-right: 1px;
+}
+
+.goog-tab-bar-end .goog-rounded-tab-outer-edge {
+  margin-right: 3px;
+}
+
+
+/*
+ * Overrides for start tabs.
+ */
+.goog-tab-bar-start .goog-rounded-tab-table,
+.goog-tab-bar-end .goog-rounded-tab-table {
+  width: 12ex; /* TODO(attila): Make this work for variable width. */
+}
+
+.goog-tab-bar-start .goog-rounded-tab-caption,
+.goog-tab-bar-start .goog-rounded-tab-inner-edge,
+.goog-tab-bar-start .goog-rounded-tab-outer-edge {
+  border-left: 1px solid #003;
+  border-right: 0;
+}
+
+.goog-tab-bar-start .goog-rounded-tab-hover .goog-rounded-tab-caption,
+.goog-tab-bar-start .goog-rounded-tab-hover .goog-rounded-tab-inner-edge,
+.goog-tab-bar-start .goog-rounded-tab-hover .goog-rounded-tab-outer-edge {
+  border-left: 1px solid #369 !important;
+  border-right: 0 !important;
+}
+
+.goog-tab-bar-start .goog-rounded-tab-selected .goog-rounded-tab-outer-edge,
+.goog-tab-bar-start .goog-rounded-tab-selected .goog-rounded-tab-inner-edge,
+.goog-tab-bar-start .goog-rounded-tab-selected .goog-rounded-tab-caption {
+  border-left: 1px solid #036 !important;
+  border-right: 0 !important;
+}
+
+.goog-tab-bar-start .goog-rounded-tab-disabled .goog-rounded-tab-outer-edge,
+.goog-tab-bar-start .goog-rounded-tab-disabled .goog-rounded-tab-inner-edge,
+.goog-tab-bar-start .goog-rounded-tab-disabled .goog-rounded-tab-caption {
+  border-left: 1px solid #ccc !important;
+  border-right: 0 !important;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/submenu.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/submenu.css b/externs/GCL/externs/goog/css/submenu.css
new file mode 100644
index 0000000..1159b28
--- /dev/null
+++ b/externs/GCL/externs/goog/css/submenu.css
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for menus created by goog.ui.SubMenuRenderer.
+ *
+ * @author attila@google.com (Attila Bodis)
+ */
+
+
+/* State: resting. */
+/* @noflip */
+.goog-submenu-arrow {
+  color: #000;
+  left: auto;
+  padding-right: 6px;
+  position: absolute;
+  right: 0;
+  text-align: right;
+}
+
+/* BiDi override. */
+/* @noflip */
+.goog-menuitem-rtl .goog-submenu-arrow {
+  text-align: left;
+  left: 0;
+  right: auto;
+  padding-left: 6px;
+}
+
+/* State: disabled. */
+.goog-menuitem-disabled .goog-submenu-arrow {
+  color: #ccc;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/tab.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/tab.css b/externs/GCL/externs/goog/css/tab.css
new file mode 100644
index 0000000..6c7dfe2
--- /dev/null
+++ b/externs/GCL/externs/goog/css/tab.css
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2008 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: attila@google.com (Attila Bodis) */
+/* Author: eae@google.com (Emil A. Eklund) */
+
+
+/*
+ * Styles used by goog.ui.TabRenderer.
+ */
+.goog-tab {
+  position: relative;
+  padding: 4px 8px;
+  color: #00c;
+  text-decoration: underline;
+  cursor: default;
+}
+
+.goog-tab-bar-top .goog-tab {
+  margin: 1px 4px 0 0;
+  border-bottom: 0;
+  float: left;
+}
+
+.goog-tab-bar-top:after,
+.goog-tab-bar-bottom:after {
+  content: " ";
+  display: block;
+  height: 0;
+  clear: both;
+  visibility: hidden;
+}
+
+.goog-tab-bar-bottom .goog-tab {
+  margin: 0 4px 1px 0;
+  border-top: 0;
+  float: left;
+}
+
+.goog-tab-bar-start .goog-tab {
+  margin: 0 0 4px 1px;
+  border-right: 0;
+}
+
+.goog-tab-bar-end .goog-tab {
+  margin: 0 1px 4px 0;
+  border-left: 0;
+}
+
+/* State: Hover */
+.goog-tab-hover {
+  background: #eee;
+}
+
+/* State: Disabled */
+.goog-tab-disabled {
+  color: #666;
+}
+
+/* State: Selected */
+.goog-tab-selected {
+  color: #000;
+  background: #fff;
+  text-decoration: none;
+  font-weight: bold;
+  border: 1px solid #6b90da;
+}
+
+.goog-tab-bar-top {
+  padding-top: 5px !important;
+  padding-left: 5px !important;
+  border-bottom: 1px solid #6b90da !important;
+}
+/*
+ * Shift selected tabs 1px towards the contents (and compensate via margin and
+ * padding) to visually merge the borders of the tab with the borders of the
+ * content area.
+ */
+.goog-tab-bar-top .goog-tab-selected {
+  top: 1px;
+  margin-top: 0;
+  padding-bottom: 5px;
+}
+
+.goog-tab-bar-bottom .goog-tab-selected {
+  top: -1px;
+  margin-bottom: 0;
+  padding-top: 5px;
+}
+
+.goog-tab-bar-start .goog-tab-selected {
+  left: 1px;
+  margin-left: 0;
+  padding-right: 9px;
+}
+
+.goog-tab-bar-end .goog-tab-selected {
+  left: -1px;
+  margin-right: 0;
+  padding-left: 9px;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/tabbar.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/tabbar.css b/externs/GCL/externs/goog/css/tabbar.css
new file mode 100644
index 0000000..514aa9b
--- /dev/null
+++ b/externs/GCL/externs/goog/css/tabbar.css
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2008 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: attila@google.com (Attila Bodis) */
+/* Author: eae@google.com (Emil A. Eklund) */
+
+
+/*
+ * Styles used by goog.ui.TabBarRenderer.
+ */
+.goog-tab-bar {
+  margin: 0;
+  border: 0;
+  padding: 0;
+  list-style: none;
+  cursor: default;
+  outline: none;
+  background: #ebeff9;
+}
+
+.goog-tab-bar-clear {
+  clear: both;
+  height: 0;
+  overflow: hidden;
+}
+
+.goog-tab-bar-start {
+  float: left;
+}
+
+.goog-tab-bar-end {
+  float: right;
+}
+
+
+/*
+ * IE6-only hacks to fix the gap between the floated tabs and the content.
+ * IE7 and later will ignore these.
+ */
+/* @if user.agent ie6 */
+* html .goog-tab-bar-start {
+  margin-right: -3px;
+}
+
+* html .goog-tab-bar-end {
+  margin-left: -3px;
+}
+/* @endif */

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/tablesorter.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/tablesorter.css b/externs/GCL/externs/goog/css/tablesorter.css
new file mode 100644
index 0000000..126f007
--- /dev/null
+++ b/externs/GCL/externs/goog/css/tablesorter.css
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2008 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: robbyw@google.com (Robby Walker) */
+
+/* Styles for goog.ui.TableSorter. */
+
+.goog-tablesorter-header {
+  cursor: pointer
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/toolbar.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/toolbar.css b/externs/GCL/externs/goog/css/toolbar.css
new file mode 100644
index 0000000..5c39dde
--- /dev/null
+++ b/externs/GCL/externs/goog/css/toolbar.css
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2009 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/*
+ * Standard styling for toolbars and toolbar items.
+ *
+ * @author attila@google.com (Attila Bodis)
+ */
+
+
+/*
+ * Styles used by goog.ui.ToolbarRenderer.
+ */
+
+.goog-toolbar {
+  /* Client apps may override the URL at which they serve the image. */
+  background: #fafafa url(//ssl.gstatic.com/editor/toolbar-bg.png) repeat-x bottom left;
+  border-bottom: 1px solid #d5d5d5;
+  cursor: default;
+  font: normal 12px Arial, sans-serif;
+  margin: 0;
+  outline: none;
+  padding: 2px;
+  position: relative;
+  zoom: 1; /* The toolbar element must have layout on IE. */
+}
+
+/*
+ * Styles used by goog.ui.ToolbarButtonRenderer.
+ */
+
+.goog-toolbar-button {
+  margin: 0 2px;
+  border: 0;
+  padding: 0;
+  font-family: Arial, sans-serif;
+  color: #333;
+  text-decoration: none;
+  list-style: none;
+  vertical-align: middle;
+  cursor: default;
+  outline: none;
+}
+
+/* Pseudo-rounded corners. */
+.goog-toolbar-button-outer-box,
+.goog-toolbar-button-inner-box {
+  border: 0;
+  vertical-align: top;
+}
+
+.goog-toolbar-button-outer-box {
+  margin: 0;
+  padding: 1px 0;
+}
+
+.goog-toolbar-button-inner-box {
+  margin: 0 -1px;
+  padding: 3px 4px;
+}
+
+/* Pre-IE7 IE hack; ignored by IE7 and all non-IE browsers. */
+* html .goog-toolbar-button-inner-box {
+  /* IE6 needs to have the box shifted to make the borders line up. */
+  left: -1px;
+}
+
+/* Pre-IE7 BiDi fixes. */
+* html .goog-toolbar-button-rtl .goog-toolbar-button-outer-box {
+  /* @noflip */ left: -1px;
+}
+* html .goog-toolbar-button-rtl .goog-toolbar-button-inner-box {
+  /* @noflip */ right: auto;
+}
+
+
+/* IE7-only hack; ignored by all other browsers. */
+*:first-child+html .goog-toolbar-button-inner-box {
+  /* IE7 needs to have the box shifted to make the borders line up. */
+  left: -1px;
+}
+
+/* IE7 BiDi fix. */
+*:first-child+html .goog-toolbar-button-rtl .goog-toolbar-button-inner-box {
+  /* @noflip */ left: 1px;
+  /* @noflip */ right: auto;
+}
+
+/* Safari-only hacks. */
+::root .goog-toolbar-button,
+::root .goog-toolbar-button-outer-box {
+  /* Required to make pseudo-rounded corners work on Safari. */
+  line-height: 0;
+}
+
+::root .goog-toolbar-button-inner-box {
+  /* Required to make pseudo-rounded corners work on Safari. */
+  line-height: normal;
+}
+
+/* Disabled styles. */
+.goog-toolbar-button-disabled {
+  opacity: 0.3;
+  -moz-opacity: 0.3;
+  filter: alpha(opacity=30);
+}
+
+.goog-toolbar-button-disabled .goog-toolbar-button-outer-box,
+.goog-toolbar-button-disabled .goog-toolbar-button-inner-box {
+  /* Disabled text/border color trumps everything else. */
+  color: #333 !important;
+  border-color: #999 !important;
+}
+
+/* Pre-IE7 IE hack; ignored by IE7 and all non-IE browsers. */
+* html .goog-toolbar-button-disabled {
+  /* IE can't apply alpha to an element with a transparent background... */
+  background-color: #f0f0f0;
+  margin: 0 1px;
+  padding: 0 1px;
+}
+
+/* IE7-only hack; ignored by all other browsers. */
+*:first-child+html .goog-toolbar-button-disabled {
+  /* IE can't apply alpha to an element with a transparent background... */
+  background-color: #f0f0f0;
+  margin: 0 1px;
+  padding: 0 1px;
+}
+
+/* Only draw borders when in a non-default state. */
+.goog-toolbar-button-hover .goog-toolbar-button-outer-box,
+.goog-toolbar-button-active .goog-toolbar-button-outer-box,
+.goog-toolbar-button-checked .goog-toolbar-button-outer-box,
+.goog-toolbar-button-selected .goog-toolbar-button-outer-box {
+  border-width: 1px 0;
+  border-style: solid;
+  padding: 0;
+}
+
+.goog-toolbar-button-hover .goog-toolbar-button-inner-box,
+.goog-toolbar-button-active .goog-toolbar-button-inner-box,
+.goog-toolbar-button-checked .goog-toolbar-button-inner-box,
+.goog-toolbar-button-selected .goog-toolbar-button-inner-box {
+  border-width: 0 1px;
+  border-style: solid;
+  padding: 3px;
+}
+
+/* Hover styles. */
+.goog-toolbar-button-hover .goog-toolbar-button-outer-box,
+.goog-toolbar-button-hover .goog-toolbar-button-inner-box {
+  /* Hover border style wins over active/checked/selected. */
+  border-color: #a1badf !important;
+}
+
+/* Active/checked/selected styles. */
+.goog-toolbar-button-active,
+.goog-toolbar-button-checked,
+.goog-toolbar-button-selected {
+  /* Active/checked/selected background color always wins. */
+  background-color: #dde1eb !important;
+}
+
+.goog-toolbar-button-active .goog-toolbar-button-outer-box,
+.goog-toolbar-button-active .goog-toolbar-button-inner-box,
+.goog-toolbar-button-checked .goog-toolbar-button-outer-box,
+.goog-toolbar-button-checked .goog-toolbar-button-inner-box,
+.goog-toolbar-button-selected .goog-toolbar-button-outer-box,
+.goog-toolbar-button-selected .goog-toolbar-button-inner-box {
+  border-color: #729bd1;
+}
+
+/* Pill (collapsed border) styles. */
+.goog-toolbar-button-collapse-right,
+.goog-toolbar-button-collapse-right .goog-toolbar-button-outer-box,
+.goog-toolbar-button-collapse-right .goog-toolbar-button-inner-box {
+  margin-right: 0;
+}
+
+.goog-toolbar-button-collapse-left,
+.goog-toolbar-button-collapse-left .goog-toolbar-button-outer-box,
+.goog-toolbar-button-collapse-left .goog-toolbar-button-inner-box {
+  margin-left: 0;
+}
+
+/* Pre-IE7 IE hack; ignored by IE7 and all non-IE browsers. */
+* html .goog-toolbar-button-collapse-left .goog-toolbar-button-inner-box {
+  left: 0;
+}
+
+/* IE7-only hack; ignored by all other browsers. */
+*:first-child+html .goog-toolbar-button-collapse-left
+.goog-toolbar-button-inner-box {
+  left: 0;
+}
+
+
+/*
+ * Styles used by goog.ui.ToolbarMenuButtonRenderer.
+ */
+
+.goog-toolbar-menu-button {
+  margin: 0 2px;
+  border: 0;
+  padding: 0;
+  font-family: Arial, sans-serif;
+  color: #333;
+  text-decoration: none;
+  list-style: none;
+  vertical-align: middle;
+  cursor: default;
+  outline: none;
+}
+
+/* Pseudo-rounded corners. */
+.goog-toolbar-menu-button-outer-box,
+.goog-toolbar-menu-button-inner-box {
+  border: 0;
+  vertical-align: top;
+}
+
+.goog-toolbar-menu-button-outer-box {
+  margin: 0;
+  padding: 1px 0;
+}
+
+.goog-toolbar-menu-button-inner-box {
+  margin: 0 -1px;
+  padding: 3px 4px;
+}
+
+/* Pre-IE7 IE hack; ignored by IE7 and all non-IE browsers. */
+* html .goog-toolbar-menu-button-inner-box {
+  /* IE6 needs to have the box shifted to make the borders line up. */
+  left: -1px;
+}
+
+/* Pre-IE7 BiDi fixes. */
+* html .goog-toolbar-menu-button-rtl .goog-toolbar-menu-button-outer-box {
+  /* @noflip */ left: -1px;
+}
+* html .goog-toolbar-menu-button-rtl .goog-toolbar-menu-button-inner-box {
+  /* @noflip */ right: auto;
+}
+
+/* IE7-only hack; ignored by all other browsers. */
+*:first-child+html .goog-toolbar-menu-button-inner-box {
+  /* IE7 needs to have the box shifted to make the borders line up. */
+  left: -1px;
+}
+
+/* IE7 BiDi fix. */
+*:first-child+html .goog-toolbar-menu-button-rtl
+  .goog-toolbar-menu-button-inner-box {
+  /* @noflip */ left: 1px;
+  /* @noflip */ right: auto;
+}
+
+/* Safari-only hacks. */
+::root .goog-toolbar-menu-button,
+::root .goog-toolbar-menu-button-outer-box,
+::root .goog-toolbar-menu-button-inner-box {
+  /* Required to make pseudo-rounded corners work on Safari. */
+  line-height: 0;
+}
+
+::root .goog-toolbar-menu-button-caption,
+::root .goog-toolbar-menu-button-dropdown {
+  /* Required to make pseudo-rounded corners work on Safari. */
+  line-height: normal;
+}
+
+/* Disabled styles. */
+.goog-toolbar-menu-button-disabled {
+  opacity: 0.3;
+  -moz-opacity: 0.3;
+  filter: alpha(opacity=30);
+}
+
+.goog-toolbar-menu-button-disabled .goog-toolbar-menu-button-outer-box,
+.goog-toolbar-menu-button-disabled .goog-toolbar-menu-button-inner-box {
+  /* Disabled text/border color trumps everything else. */
+  color: #333 !important;
+  border-color: #999 !important;
+}
+
+/* Pre-IE7 IE hack; ignored by IE7 and all non-IE browsers. */
+* html .goog-toolbar-menu-button-disabled {
+  /* IE can't apply alpha to an element with a transparent background... */
+  background-color: #f0f0f0;
+  margin: 0 1px;
+  padding: 0 1px;
+}
+
+/* IE7-only hack; ignored by all other browsers. */
+*:first-child+html .goog-toolbar-menu-button-disabled {
+  /* IE can't apply alpha to an element with a transparent background... */
+  background-color: #f0f0f0;
+  margin: 0 1px;
+  padding: 0 1px;
+}
+
+/* Only draw borders when in a non-default state. */
+.goog-toolbar-menu-button-hover .goog-toolbar-menu-button-outer-box,
+.goog-toolbar-menu-button-active .goog-toolbar-menu-button-outer-box,
+.goog-toolbar-menu-button-open .goog-toolbar-menu-button-outer-box {
+  border-width: 1px 0;
+  border-style: solid;
+  padding: 0;
+}
+
+.goog-toolbar-menu-button-hover .goog-toolbar-menu-button-inner-box,
+.goog-toolbar-menu-button-active .goog-toolbar-menu-button-inner-box,
+.goog-toolbar-menu-button-open .goog-toolbar-menu-button-inner-box {
+  border-width: 0 1px;
+  border-style: solid;
+  padding: 3px;
+}
+
+/* Hover styles. */
+.goog-toolbar-menu-button-hover .goog-toolbar-menu-button-outer-box,
+.goog-toolbar-menu-button-hover .goog-toolbar-menu-button-inner-box {
+  /* Hover border color trumps active/open style. */
+  border-color: #a1badf !important;
+}
+
+/* Active/open styles. */
+.goog-toolbar-menu-button-active,
+.goog-toolbar-menu-button-open {
+  /* Active/open background color wins. */
+  background-color: #dde1eb !important;
+}
+
+.goog-toolbar-menu-button-active .goog-toolbar-menu-button-outer-box,
+.goog-toolbar-menu-button-active .goog-toolbar-menu-button-inner-box,
+.goog-toolbar-menu-button-open .goog-toolbar-menu-button-outer-box,
+.goog-toolbar-menu-button-open .goog-toolbar-menu-button-inner-box {
+  border-color: #729bd1;
+}
+
+/* Menu button caption style. */
+.goog-toolbar-menu-button-caption {
+  padding: 0 4px 0 0;
+  vertical-align: middle;
+}
+
+/* Dropdown style. */
+.goog-toolbar-menu-button-dropdown {
+  width: 7px;
+  /* Client apps may override the URL at which they serve the sprite. */
+  background: url(//ssl.gstatic.com/editor/editortoolbar.png) no-repeat -388px 0;
+  vertical-align: middle;
+}
+
+
+/*
+ * Styles used by goog.ui.ToolbarSeparatorRenderer.
+ */
+
+.goog-toolbar-separator {
+  margin: 0 2px;
+  border-left: 1px solid #d6d6d6;
+  border-right: 1px solid #f7f7f7;
+  padding: 0;
+  width: 0;
+  text-decoration: none;
+  list-style: none;
+  outline: none;
+  vertical-align: middle;
+  line-height: normal;
+  font-size: 120%;
+  overflow: hidden;
+}
+
+
+/*
+ * Additional styling for toolbar select controls, which always have borders.
+ */
+
+.goog-toolbar-select .goog-toolbar-menu-button-outer-box {
+  border-width: 1px 0;
+  border-style: solid;
+  padding: 0;
+}
+
+.goog-toolbar-select .goog-toolbar-menu-button-inner-box {
+  border-width: 0 1px;
+  border-style: solid;
+  padding: 3px;
+}
+
+.goog-toolbar-select .goog-toolbar-menu-button-outer-box,
+.goog-toolbar-select .goog-toolbar-menu-button-inner-box {
+  border-color: #bfcbdf;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/tooltip.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/tooltip.css b/externs/GCL/externs/goog/css/tooltip.css
new file mode 100644
index 0000000..0264583
--- /dev/null
+++ b/externs/GCL/externs/goog/css/tooltip.css
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2010 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+.goog-tooltip {
+  background: #ffe;
+  border: 1px solid #999;
+  border-width: 1px 2px 2px 1px;
+  padding: 6px;
+  z-index: 30000;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/tree.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/tree.css b/externs/GCL/externs/goog/css/tree.css
new file mode 100644
index 0000000..aeb1d0b
--- /dev/null
+++ b/externs/GCL/externs/goog/css/tree.css
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2007 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: arv@google.com (Erik Arvidsson) */
+/* Author: eae@google.com (Emil A Eklund) */
+/* Author: jonp@google.com (Jon Perlow) */
+
+/*
+  TODO(arv): Currently the sprite image has the height 16px. We should make the
+  image taller which would allow better flexibility when it comes to the height
+  of a tree row.
+*/
+
+.goog-tree-root:focus {
+  outline: none;
+}
+
+.goog-tree-row {
+  white-space: nowrap;
+  font: icon;
+  line-height: 16px;
+  height: 16px;
+}
+
+.goog-tree-row span {
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.goog-tree-children {
+  background-repeat: repeat-y;
+  background-image: url(//ssl.gstatic.com/closure/tree/I.png) !important;
+  background-position-y: 1px !important;	/* IE only */
+  font: icon;
+}
+
+.goog-tree-children-nolines {
+  font: icon;
+}
+
+.goog-tree-icon {
+  background-image: url(//ssl.gstatic.com/closure/tree/tree.png);
+}
+
+.goog-tree-expand-icon {
+  vertical-align: middle;
+  height: 16px;
+  width: 16px;
+  cursor: default;
+}
+
+.goog-tree-expand-icon-plus {
+  width: 19px;
+  background-position: 0 0;
+}
+
+.goog-tree-expand-icon-minus {
+  width: 19px;
+  background-position: -24px 0;
+}
+
+.goog-tree-expand-icon-tplus {
+  width: 19px;
+  background-position: -48px 0;
+}
+
+.goog-tree-expand-icon-tminus {
+  width: 19px;
+  background-position: -72px 0;
+}
+
+.goog-tree-expand-icon-lplus {
+  width: 19px;
+  background-position: -96px 0;
+}
+
+.goog-tree-expand-icon-lminus {
+  width: 19px;
+  background-position: -120px 0;
+}
+
+.goog-tree-expand-icon-t {
+  width: 19px;
+  background-position: -144px 0;
+}
+
+.goog-tree-expand-icon-l {
+  width: 19px;
+  background-position: -168px 0;
+}
+
+.goog-tree-expand-icon-blank {
+  width: 19px;
+  background-position: -168px -24px;
+}
+
+.goog-tree-collapsed-folder-icon {
+  vertical-align: middle;
+  height: 16px;
+  width: 16px;
+  background-position: -0px -24px;
+}
+
+.goog-tree-expanded-folder-icon {
+  vertical-align: middle;
+  height: 16px;
+  width: 16px;
+  background-position: -24px -24px;
+}
+
+.goog-tree-file-icon {
+  vertical-align: middle;
+  height: 16px;
+  width: 16px;
+  background-position: -48px -24px;
+}
+
+.goog-tree-item-label {
+  margin-left: 3px;
+  padding: 1px 2px 1px 2px;
+  text-decoration: none;
+  color: WindowText;
+  cursor: default;
+}
+
+.goog-tree-item-label:hover {
+  text-decoration: underline;
+}
+
+.selected .goog-tree-item-label {
+  background-color: ButtonFace;
+  color: ButtonText;
+}
+
+.focused .selected .goog-tree-item-label {
+  background-color: Highlight;
+  color: HighlightText;
+}
+
+.goog-tree-hide-root {
+  display: none;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/css/tristatemenuitem.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/css/tristatemenuitem.css b/externs/GCL/externs/goog/css/tristatemenuitem.css
new file mode 100644
index 0000000..8c98448
--- /dev/null
+++ b/externs/GCL/externs/goog/css/tristatemenuitem.css
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2007 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+/* Author: pupius@google.com (Daniel Pupius) */
+
+/* goog.ui.TriStateMenuItem */
+
+.goog-tristatemenuitem {
+  padding: 2px 5px;
+  margin: 0;
+  list-style: none;
+}
+
+.goog-tristatemenuitem-highlight {
+  background-color: #4279A5;
+  color: #FFF;
+}
+
+.goog-tristatemenuitem-disabled {
+  color: #999;
+}
+
+.goog-tristatemenuitem-checkbox {
+  float: left;
+  width: 10px;
+  height: 1.1em;
+}
+
+.goog-tristatemenuitem-partially-checked {
+  background-image: url(//ssl.gstatic.com/closure/check-outline.gif);
+  background-position: 4px 50%;
+  background-repeat: no-repeat;
+}
+
+.goog-tristatemenuitem-fully-checked {
+  background-image: url(//ssl.gstatic.com/closure/check.gif);
+  background-position: 4px 50%;
+  background-repeat: no-repeat;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/cssom/cssom.js
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/cssom/cssom.js b/externs/GCL/externs/goog/cssom/cssom.js
new file mode 100644
index 0000000..86a4235
--- /dev/null
+++ b/externs/GCL/externs/goog/cssom/cssom.js
@@ -0,0 +1,455 @@
+// Copyright 2008 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 CSS Object Model helper functions.
+ * References:
+ * - W3C: http://dev.w3.org/csswg/cssom/
+ * - MSDN: http://msdn.microsoft.com/en-us/library/ms531209(VS.85).aspx.
+ * @supported in FF3, IE6, IE7, Safari 3.1.2, Chrome
+ * TODO(user): Fix in Opera.
+ * TODO(user): Consider hacking page, media, etc.. to work.
+ *     This would be pretty challenging. IE returns the text for any rule
+ *     regardless of whether or not the media is correct or not. Firefox at
+ *     least supports CSSRule.type to figure out if it's a media type and then
+ *     we could do something interesting, but IE offers no way for us to tell.
+ */
+
+goog.provide('goog.cssom');
+goog.provide('goog.cssom.CssRuleType');
+
+goog.require('goog.array');
+goog.require('goog.dom');
+goog.require('goog.dom.TagName');
+
+
+/**
+ * Enumeration of {@code CSSRule} types.
+ * @enum {number}
+ */
+goog.cssom.CssRuleType = {
+  STYLE: 1,
+  IMPORT: 3,
+  MEDIA: 4,
+  FONT_FACE: 5,
+  PAGE: 6,
+  NAMESPACE: 7
+};
+
+
+/**
+ * Recursively gets all CSS as text, optionally starting from a given
+ * CSSStyleSheet.
+ * @param {(CSSStyleSheet|StyleSheetList)=} opt_styleSheet The CSSStyleSheet.
+ * @return {string} css text.
+ */
+goog.cssom.getAllCssText = function(opt_styleSheet) {
+  var styleSheet = opt_styleSheet || document.styleSheets;
+  return /** @type {string} */ (goog.cssom.getAllCss_(styleSheet, true));
+};
+
+
+/**
+ * Recursively gets all CSSStyleRules, optionally starting from a given
+ * CSSStyleSheet.
+ * Note that this excludes any CSSImportRules, CSSMediaRules, etc..
+ * @param {(CSSStyleSheet|StyleSheetList)=} opt_styleSheet The CSSStyleSheet.
+ * @return {Array<CSSStyleRule>} A list of CSSStyleRules.
+ */
+goog.cssom.getAllCssStyleRules = function(opt_styleSheet) {
+  var styleSheet = opt_styleSheet || document.styleSheets;
+  return /** @type {!Array<CSSStyleRule>} */ (
+      goog.cssom.getAllCss_(styleSheet, false));
+};
+
+
+/**
+ * Returns the CSSRules from a styleSheet.
+ * Worth noting here is that IE and FF differ in terms of what they will return.
+ * Firefox will return styleSheet.cssRules, which includes ImportRules and
+ * anything which implements the CSSRules interface. IE returns simply a list of
+ * CSSRules.
+ * @param {CSSStyleSheet} styleSheet The CSSStyleSheet.
+ * @throws {Error} If we cannot access the rules on a stylesheet object - this
+ *     can  happen if a stylesheet object's rules are accessed before the rules
+ *     have been downloaded and parsed and are "ready".
+ * @return {CSSRuleList} An array of CSSRules or null.
+ */
+goog.cssom.getCssRulesFromStyleSheet = function(styleSheet) {
+  var cssRuleList = null;
+  try {
+    // Select cssRules unless it isn't present.  For pre-IE9 IE, use the rules
+    // collection instead.
+    // It's important to be consistent in using only the W3C or IE apis on
+    // IE9+ where both are present to ensure that there is no indexing
+    // mismatches - the collections are subtly different in what the include or
+    // exclude which can lead to one collection being longer than the other
+    // depending on the page's construction.
+    cssRuleList = styleSheet.cssRules /* W3C */ || styleSheet.rules /* IE */;
+  } catch (e) {
+    // This can happen if we try to access the CSSOM before it's "ready".
+    if (e.code == 15) {
+      // Firefox throws an NS_ERROR_DOM_INVALID_ACCESS_ERR error if a stylesheet
+      // is read before it has been fully parsed. Let the caller know which
+      // stylesheet failed.
+      e.styleSheet = styleSheet;
+      throw e;
+    }
+  }
+  return cssRuleList;
+};
+
+
+/**
+ * Gets all CSSStyleSheet objects starting from some CSSStyleSheet. Note that we
+ * want to return the sheets in the order of the cascade, therefore if we
+ * encounter an import, we will splice that CSSStyleSheet object in front of
+ * the CSSStyleSheet that contains it in the returned array of CSSStyleSheets.
+ * @param {(CSSStyleSheet|StyleSheetList)=} opt_styleSheet A CSSStyleSheet.
+ * @param {boolean=} opt_includeDisabled If true, includes disabled stylesheets,
+ *    defaults to false.
+ * @return {!Array<CSSStyleSheet>} A list of CSSStyleSheet objects.
+ */
+goog.cssom.getAllCssStyleSheets = function(opt_styleSheet,
+    opt_includeDisabled) {
+  var styleSheetsOutput = [];
+  var styleSheet = opt_styleSheet || document.styleSheets;
+  var includeDisabled = goog.isDef(opt_includeDisabled) ? opt_includeDisabled :
+      false;
+
+  // Imports need to go first.
+  if (styleSheet.imports && styleSheet.imports.length) {
+    for (var i = 0, n = styleSheet.imports.length; i < n; i++) {
+      goog.array.extend(styleSheetsOutput,
+          goog.cssom.getAllCssStyleSheets(styleSheet.imports[i]));
+    }
+
+  } else if (styleSheet.length) {
+    // In case we get a StyleSheetList object.
+    // http://dev.w3.org/csswg/cssom/#the-stylesheetlist
+    for (var i = 0, n = styleSheet.length; i < n; i++) {
+      goog.array.extend(styleSheetsOutput,
+          goog.cssom.getAllCssStyleSheets(styleSheet[i]));
+    }
+  } else {
+    // We need to walk through rules in browsers which implement .cssRules
+    // to see if there are styleSheets buried in there.
+    // If we have a CSSStyleSheet within CssRules.
+    var cssRuleList = goog.cssom.getCssRulesFromStyleSheet(
+        /** @type {!CSSStyleSheet} */ (styleSheet));
+    if (cssRuleList && cssRuleList.length) {
+      // Chrome does not evaluate cssRuleList[i] to undefined when i >=n;
+      // so we use a (i < n) check instead of cssRuleList[i] in the loop below
+      // and in other places where we iterate over a rules list.
+      // See issue # 5917 in Chromium.
+      for (var i = 0, n = cssRuleList.length, cssRule; i < n; i++) {
+        cssRule = cssRuleList[i];
+        // There are more stylesheets to get on this object..
+        if (cssRule.styleSheet) {
+          goog.array.extend(styleSheetsOutput,
+              goog.cssom.getAllCssStyleSheets(cssRule.styleSheet));
+        }
+      }
+    }
+  }
+
+  // This is a CSSStyleSheet. (IE uses .rules, W3c and Opera cssRules.)
+  if ((styleSheet.type || styleSheet.rules || styleSheet.cssRules) &&
+      (!styleSheet.disabled || includeDisabled)) {
+    styleSheetsOutput.push(styleSheet);
+  }
+
+  return styleSheetsOutput;
+};
+
+
+/**
+ * Gets the cssText from a CSSRule object cross-browserly.
+ * @param {CSSRule} cssRule A CSSRule.
+ * @return {string} cssText The text for the rule, including the selector.
+ */
+goog.cssom.getCssTextFromCssRule = function(cssRule) {
+  var cssText = '';
+
+  if (cssRule.cssText) {
+    // W3C.
+    cssText = cssRule.cssText;
+  } else if (cssRule.style && cssRule.style.cssText && cssRule.selectorText) {
+    // IE: The spacing here is intended to make the result consistent with
+    // FF and Webkit.
+    // We also remove the special properties that we may have added in
+    // getAllCssStyleRules since IE includes those in the cssText.
+    var styleCssText = cssRule.style.cssText.
+        replace(/\s*-closure-parent-stylesheet:\s*\[object\];?\s*/gi, '').
+        replace(/\s*-closure-rule-index:\s*[\d]+;?\s*/gi, '');
+    var thisCssText = cssRule.selectorText + ' { ' + styleCssText + ' }';
+    cssText = thisCssText;
+  }
+
+  return cssText;
+};
+
+
+/**
+ * Get the index of the CSSRule in it's CSSStyleSheet.
+ * @param {CSSRule} cssRule A CSSRule.
+ * @param {CSSStyleSheet=} opt_parentStyleSheet A reference to the stylesheet
+ *     object this cssRule belongs to.
+ * @throws {Error} When we cannot get the parentStyleSheet.
+ * @return {number} The index of the CSSRule, or -1.
+ */
+goog.cssom.getCssRuleIndexInParentStyleSheet = function(cssRule,
+    opt_parentStyleSheet) {
+  // Look for our special style.ruleIndex property from getAllCss.
+  if (cssRule.style && cssRule.style['-closure-rule-index']) {
+    return cssRule.style['-closure-rule-index'];
+  }
+
+  var parentStyleSheet = opt_parentStyleSheet ||
+      goog.cssom.getParentStyleSheet(cssRule);
+
+  if (!parentStyleSheet) {
+    // We could call getAllCssStyleRules() here to get our special indexes on
+    // the style object, but that seems like it could be wasteful.
+    throw Error('Cannot find a parentStyleSheet.');
+  }
+
+  var cssRuleList = goog.cssom.getCssRulesFromStyleSheet(parentStyleSheet);
+  if (cssRuleList && cssRuleList.length) {
+    for (var i = 0, n = cssRuleList.length, thisCssRule; i < n; i++) {
+      thisCssRule = cssRuleList[i];
+      if (thisCssRule == cssRule) {
+        return i;
+      }
+    }
+  }
+  return -1;
+};
+
+
+/**
+ * We do some trickery in getAllCssStyleRules that hacks this in for IE.
+ * If the cssRule object isn't coming from a result of that function call, this
+ * method will return undefined in IE.
+ * @param {CSSRule} cssRule The CSSRule.
+ * @return {CSSStyleSheet} A styleSheet object.
+ */
+goog.cssom.getParentStyleSheet = function(cssRule) {
+  return cssRule.parentStyleSheet ||
+      cssRule.style &&
+      cssRule.style['-closure-parent-stylesheet'];
+};
+
+
+/**
+ * Replace a cssRule with some cssText for a new rule.
+ * If the cssRule object is not one of objects returned by
+ * getAllCssStyleRules, then you'll need to provide both the styleSheet and
+ * possibly the index, since we can't infer them from the standard cssRule
+ * object in IE. We do some trickery in getAllCssStyleRules to hack this in.
+ * @param {CSSRule} cssRule A CSSRule.
+ * @param {string} cssText The text for the new CSSRule.
+ * @param {CSSStyleSheet=} opt_parentStyleSheet A reference to the stylesheet
+ *     object this cssRule belongs to.
+ * @param {number=} opt_index The index of the cssRule in its parentStylesheet.
+ * @throws {Error} If we cannot find a parentStyleSheet.
+ * @throws {Error} If we cannot find a css rule index.
+ */
+goog.cssom.replaceCssRule = function(cssRule, cssText, opt_parentStyleSheet,
+    opt_index) {
+  var parentStyleSheet = opt_parentStyleSheet ||
+      goog.cssom.getParentStyleSheet(cssRule);
+  if (parentStyleSheet) {
+    var index = opt_index >= 0 ? opt_index :
+        goog.cssom.getCssRuleIndexInParentStyleSheet(cssRule, parentStyleSheet);
+    if (index >= 0) {
+      goog.cssom.removeCssRule(parentStyleSheet, index);
+      goog.cssom.addCssRule(parentStyleSheet, cssText, index);
+    } else {
+      throw Error('Cannot proceed without the index of the cssRule.');
+    }
+  } else {
+    throw Error('Cannot proceed without the parentStyleSheet.');
+  }
+};
+
+
+/**
+ * Cross browser function to add a CSSRule into a CSSStyleSheet, optionally
+ * at a given index.
+ * @param {CSSStyleSheet} cssStyleSheet The CSSRule's parentStyleSheet.
+ * @param {string} cssText The text for the new CSSRule.
+ * @param {number=} opt_index The index of the cssRule in its parentStylesheet.
+ * @throws {Error} If the css rule text appears to be ill-formatted.
+ * TODO(bowdidge): Inserting at index 0 fails on Firefox 2 and 3 with an
+ *     exception warning "Node cannot be inserted at the specified point in
+ *     the hierarchy."
+ */
+goog.cssom.addCssRule = function(cssStyleSheet, cssText, opt_index) {
+  var index = opt_index;
+  if (index < 0 || index == undefined) {
+    // If no index specified, insert at the end of the current list
+    // of rules.
+    var rules = goog.cssom.getCssRulesFromStyleSheet(cssStyleSheet);
+    index = rules.length;
+  }
+  if (cssStyleSheet.insertRule) {
+    // W3C (including IE9+).
+    cssStyleSheet.insertRule(cssText, index);
+
+  } else {
+    // IE, pre 9: We have to parse the cssRule text to get the selector
+    // separated from the style text.
+    // aka Everything that isn't a colon, followed by a colon, then
+    // the rest is the style part.
+    var matches = /^([^\{]+)\{([^\{]+)\}/.exec(cssText);
+    if (matches.length == 3) {
+      var selector = matches[1];
+      var style = matches[2];
+      cssStyleSheet.addRule(selector, style, index);
+    } else {
+      throw Error('Your CSSRule appears to be ill-formatted.');
+    }
+  }
+};
+
+
+/**
+ * Cross browser function to remove a CSSRule in a CSSStyleSheet at an index.
+ * @param {CSSStyleSheet} cssStyleSheet The CSSRule's parentStyleSheet.
+ * @param {number} index The CSSRule's index in the parentStyleSheet.
+ */
+goog.cssom.removeCssRule = function(cssStyleSheet, index) {
+  if (cssStyleSheet.deleteRule) {
+    // W3C.
+    cssStyleSheet.deleteRule(index);
+
+  } else {
+    // IE.
+    cssStyleSheet.removeRule(index);
+  }
+};
+
+
+/**
+ * Appends a DOM node to HEAD containing the css text that's passed in.
+ * @param {string} cssText CSS to add to the end of the document.
+ * @param {goog.dom.DomHelper=} opt_domHelper Optional DOM helper user for
+ *     document interactions.
+ * @return {!Element} The newly created STYLE element.
+ */
+goog.cssom.addCssText = function(cssText, opt_domHelper) {
+  var document = opt_domHelper ? opt_domHelper.getDocument() :
+      goog.dom.getDocument();
+  var cssNode = document.createElement(goog.dom.TagName.STYLE);
+  cssNode.type = 'text/css';
+  var head = document.getElementsByTagName(goog.dom.TagName.HEAD)[0];
+  head.appendChild(cssNode);
+  if (cssNode.styleSheet) {
+    // IE.
+    cssNode.styleSheet.cssText = cssText;
+  } else {
+    // W3C.
+    var cssTextNode = document.createTextNode(cssText);
+    cssNode.appendChild(cssTextNode);
+  }
+  return cssNode;
+};
+
+
+/**
+ * Cross browser method to get the filename from the StyleSheet's href.
+ * Explorer only returns the filename in the href, while other agents return
+ * the full path.
+ * @param {!StyleSheet} styleSheet Any valid StyleSheet object with an href.
+ * @throws {Error} When there's no href property found.
+ * @return {?string} filename The filename, or null if not an external
+ *    styleSheet.
+ */
+goog.cssom.getFileNameFromStyleSheet = function(styleSheet) {
+  var href = styleSheet.href;
+
+  // Another IE/FF difference. IE returns an empty string, while FF and others
+  // return null for CSSStyleSheets not from an external file.
+  if (!href) {
+    return null;
+  }
+
+  // We need the regexp to ensure we get the filename minus any query params.
+  var matches = /([^\/\?]+)[^\/]*$/.exec(href);
+  var filename = matches[1];
+  return filename;
+};
+
+
+/**
+ * Recursively gets all CSS text or rules.
+ * @param {CSSStyleSheet|StyleSheetList} styleSheet The CSSStyleSheet.
+ * @param {boolean} isTextOutput If true, output is cssText, otherwise cssRules.
+ * @return {string|!Array<CSSRule>} cssText or cssRules.
+ * @private
+ */
+goog.cssom.getAllCss_ = function(styleSheet, isTextOutput) {
+  var cssOut = [];
+  var styleSheets = goog.cssom.getAllCssStyleSheets(styleSheet);
+
+  for (var i = 0; styleSheet = styleSheets[i]; i++) {
+    var cssRuleList = goog.cssom.getCssRulesFromStyleSheet(styleSheet);
+
+    if (cssRuleList && cssRuleList.length) {
+
+      // We're going to track cssRule index if we want rule output.
+      if (!isTextOutput) {
+        var ruleIndex = 0;
+      }
+
+      for (var j = 0, n = cssRuleList.length, cssRule; j < n; j++) {
+        cssRule = cssRuleList[j];
+        // Gets cssText output, ignoring CSSImportRules.
+        if (isTextOutput && !cssRule.href) {
+          var res = goog.cssom.getCssTextFromCssRule(cssRule);
+          cssOut.push(res);
+
+        } else if (!cssRule.href) {
+          // Gets cssRules output, ignoring CSSImportRules.
+          if (cssRule.style) {
+            // This is a fun little hack to get parentStyleSheet into the rule
+            // object for IE since it failed to implement rule.parentStyleSheet.
+            // We can later read this property when doing things like hunting
+            // for indexes in order to delete a given CSSRule.
+            // Unfortunately we have to use the style object to store these
+            // pieces of info since the rule object is read-only.
+            if (!cssRule.parentStyleSheet) {
+              cssRule.style['-closure-parent-stylesheet'] = styleSheet;
+            }
+
+            // This is a hack to help with possible removal of the rule later,
+            // where we just append the rule's index in its parentStyleSheet
+            // onto the style object as a property.
+            // Unfortunately we have to use the style object to store these
+            // pieces of info since the rule object is read-only.
+            cssRule.style['-closure-rule-index'] = ruleIndex;
+          }
+          cssOut.push(cssRule);
+        }
+
+        if (!isTextOutput) {
+          ruleIndex++;
+        }
+      }
+    }
+  }
+  return isTextOutput ? cssOut.join(' ') : cssOut;
+};
+

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/cssom/cssom_test_import_1.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/cssom/cssom_test_import_1.css b/externs/GCL/externs/goog/cssom/cssom_test_import_1.css
new file mode 100644
index 0000000..566f907
--- /dev/null
+++ b/externs/GCL/externs/goog/cssom/cssom_test_import_1.css
@@ -0,0 +1,11 @@
+/*
+ * Copyright 2010 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+@import "cssom_test_import_2.css";
+.css-import-1 {
+  display: block;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/cssom/cssom_test_import_2.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/cssom/cssom_test_import_2.css b/externs/GCL/externs/goog/cssom/cssom_test_import_2.css
new file mode 100644
index 0000000..dc31c96
--- /dev/null
+++ b/externs/GCL/externs/goog/cssom/cssom_test_import_2.css
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2010 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+.css-import-2 {
+  display: block;
+}

http://git-wip-us.apache.org/repos/asf/flex-falcon/blob/e2cad6e6/externs/GCL/externs/goog/cssom/cssom_test_link_1.css
----------------------------------------------------------------------
diff --git a/externs/GCL/externs/goog/cssom/cssom_test_link_1.css b/externs/GCL/externs/goog/cssom/cssom_test_link_1.css
new file mode 100644
index 0000000..832a8e3
--- /dev/null
+++ b/externs/GCL/externs/goog/cssom/cssom_test_link_1.css
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2010 The Closure Library Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by the Apache License, Version 2.0.
+ * See the COPYING file for details.
+ */
+
+.css-link-1 {
+  display: block;
+}