var gadgets = {};


/************** end core.js ********************/


/*
 * 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.
 */

var gadgets = gadgets || {};

/**
 * @fileoverview General purpose utilities that gadgets can use.
 */

/**
 * @static
 * @class Provides general-purpose utility functions.
 * @name gadgets.util
 */

gadgets.util = function() {
  /**
   * Parses URL parameters into an object.
   * @return {Array.&lt;String&gt;} The parameters
   */
  function parseUrlParams() {
    // Get settings from url, 'hash' takes precedence over 'search' component
    // don't use document.location.hash due to browser differences.
    var query;
    var l = document.location.href;
    var queryIdx = l.indexOf("?");
    var hashIdx = l.indexOf("#");
    if (hashIdx === -1) {
      query = l.substr(queryIdx + 1);
    } else {
      // essentially replaces "#" with "&"
      query = [l.substr(queryIdx + 1, hashIdx - queryIdx - 1), "&",
               l.substr(hashIdx + 1)].join("");
    }
    return query.split("&");
  }

  var parameters = null;
  var features = {};
  var onLoadHandlers = [];

  return /** @scope gadgets.util */ {

    /**
     * Gets the URL parameters.
     *
     * @return {Object} Parameters passed into the query string
     * @member gadgets.util
     * @private Implementation detail.
     */
    getUrlParameters : function () {
      if (parameters !== null) {
        return parameters;
      }
      parameters = {};
      var pairs = parseUrlParams();
      var unesc = window.decodeURIComponent ? decodeURIComponent : unescape;
      for (var i = 0, j = pairs.length; i < j; ++i) {
        var pos = pairs[i].indexOf('=');
        if (pos === -1) {
          continue;
        }
        var argName = pairs[i].substring(0, pos);
        var value = pairs[i].substring(pos + 1);
        // difference to IG_Prefs, is that args doesn't replace spaces in
        // argname. Unclear on if it should do:
        // argname = argname.replace(/\+/g, " ");
        value = value.replace(/\+/g, " ");
        parameters[argName] = unesc(value);
      }
      return parameters;
    },

    /**
     * Creates a closure that is suitable for passing as a callback.
     * Any number of arguments
     * may be passed to the callback;
     * they will be received in the order they are passed in.
     *
     * @param {Object} scope The execution scope; may be null if there is no
     *     need to associate a specific instance of an object with this
     *     callback
     * @param {Function} callback The callback to invoke when this is run;
     *     any arguments passed in will be passed after your initial arguments
     * @param {Object} var_args Initial arguments to be passed to the callback
     *
     * @member gadgets.util
     * @private Implementation detail.
     */
    makeClosure : function (scope, callback, var_args) {
      // arguments isn't a real array, so we copy it into one.
      var tmpArgs = [];
      for (var i = 2, j = arguments.length; i < j; ++i) {
       tmpArgs.push(arguments[i]);
      }
      return function() {
        // append new arguments.
        for (var i = 0, j = arguments.length; i < j; ++i) {
          tmpArgs.push(arguments[i]);
        }
        callback.apply(scope, tmpArgs);
      };
    },

    /**
     * Utility function for generating an "enum" from an array.
     *
     * @param {Array.<String>} values The values to generate.
     * @return {Map&lt;String,String&gt;} An object with member fields to handle
     *   the enum.
     *
     * @private Implementation detail.
     */
    makeEnum : function (values) {
      var obj = {};
      for (var i = 0, v; v = values[i]; ++i) {
        obj[v] = v;
      }
      return obj;
    },

    /**
     * Gets the feature parameters.
     *
     * @param {String} feature The feature to get parameters for
     * @return {Object} The parameters for the given feature, or null
     *
     * @member gadgets.util
     */
    getFeatureParameters : function (feature) {
      return typeof features[feature] === "undefined"
          ? null : features[feature];
    },

    /**
     * Returns whether the current feature is supported.
     *
     * @param {String} feature The feature to test for
     * @return {Boolean} True if the feature is supported
     *
     * @member gadgets.util
     */
    hasFeature : function (feature) {
      return typeof features[feature] === "undefined";
    },

    /**
     * Registers an onload handler.
     * @param {Function} callback The handler to run
     *
     * @member gadgets.util
     */
    registerOnLoadHandler : function (callback) {
      onLoadHandlers.push(callback);
    },

    /**
     * Runs all functions registered via registerOnLoadHandler.
     * @private Only to be used by the container, not gadgets.
     */
    runOnLoadHandlers : function () {
      for (var i = 0, j = onLoadHandlers.length; i < j; ++i) {
        onLoadHandlers[i]();
      }
    },

    /**
     * @param {Object} featureData The features that are supported, and
     *    their parameters.
     * @private Only to be used by the container, not gadgets.
     */
    init : function (featureData) {
      features = featureData;
    }
  };
}();

/************** end util.js ********************/


/*
 * 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.
 */

var gadgets = gadgets || {};

/**
 * @fileoverview Provides remote content retrieval facilities.
 *     Available to every gadget.
 */

/**
 * @static
 * @class Provides remote content retrieval functions.
 * @name gadgets.io
 */

gadgets.io = function() {
  /**
   * Holds configuration-related data such as proxy urls.
   */
  var config = {};

  /**
   * Internal facility to create an xhr request.
   */
  function makeXhr() {
    if (window.XMLHttpRequest) {
      return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
      var x = new ActiveXObject("Msxml2.XMLHTTP");
      if (!x) {
        x = new ActiveXObject("Microsoft.XMLHTTP");
      }
      return x;
    }
  }

  var UNPARSEABLE_CRUFT = "throw 1; < don't be evil' >";

  /**
   * Handles XHR callback processing.
   *
   * @param {String} url
   * @param {Function} callback
   * @param {Object} params
   * @param {Object} xobj
   */
  function processResponse(url, callback, params, xobj) {
    if (xobj.readyState !== 4) {
      return;
    }
    if (xobj.status !== 200) {
      // TODO Need to work on standardizing errors
      callback({errors : ["Error " + xobj.status] });
      return;
    }
    var txt = xobj.responseText;
    // remove unparseable cruft.
    // TODO: really remove this by eliminating it. It's not any real security
    //    to begin with, and we can solve this problem by using post requests
    //    and / or passing the url in the http headers.
    txt = txt.substr(UNPARSEABLE_CRUFT.length);
    var data = gadgets.json.parse(txt);
    data = data[url];
    var resp = {
     text: data.body,
     errors: []
    };
    switch (params.CONTENT_TYPE) {
      case "JSON":
      case "FEED":
        resp.data = gadgets.json.parse(resp.text);
        if (!resp.data) {
          resp.errors.push("failed to parse JSON");
          resp.data = null;
        }
        break;
      case "DOM":
        var dom;
        if (window.ActiveXObject) {
          dom = new ActiveXObject("Microsoft.XMLDOM");
          dom.async = false;
          dom.validateOnParse = false;
          dom.resolveExternals = false;
          if (!dom.loadXML(resp.text)) {
            resp.errors.push("failed to parse XML");
          } else {
            resp.data = dom;
          }
        } else {
          var parser = new DOMParser();
          dom = parser.parseFromString(resp.text, "text/xml");
          if ("parsererror" === dom.documentElement.nodeName) {
            resp.errors.push("failed to parse XML");
          } else {
            resp.data = dom;
          }
        }
        break;
      default:
        resp.data = resp.text;
        break;
    }
    callback(resp);
  }

  return /** @scope gadgets.io */ {
    /**
     * Fetches content from the provided URL and feeds that content into the
     * callback function.
     *
     * Example:
     * <pre>
     * gadgets.io.makeRequest(url, fn,
     *    {contentType: gadgets.io.ContentType.FEED});
     * </pre>
     *
     * @param {String} url The URL where the content is located
     * @param {Function} callback The function to call with the data from the
     *     URL once it is fetched
     * @param {Map.&lt;gadgets.io.RequestParameters, Object&gt;} opt_params
     *     Additional
     *     <a href="gadgets.io.RequestParameters.html">parameters</a>
     *     to pass to the request
     *
     * @member gadgets.io
     */
    makeRequest : function (url, callback, opt_params) {
      // TODO: This method also needs to respect all members of
      // gadgets.io.RequestParameters, and validate them.
      var xhr = makeXhr();
      var params = opt_params || {};

      xhr.open("POST", config.jsonProxyUrl, true);
      if (callback) {
        xhr.onreadystatechange = gadgets.util.makeClosure(
            null, processResponse, url, callback, params, xhr);
      }
      // We always send a POST request; we just hide the details.
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

      // Check if authorization is requested
      var auth, st;
      if (params.AUTHORIZATION && params.AUTHORIZATION !== "NONE") {
        auth = params.AUTHORIZATION.toLowerCase();
        st = gadgets.util.getUrlParameters().st;
      }

      var headers = params.HEADERS || {};
      if (params.METHOD === "POST" && !headers["Content-Type"]) {
        headers["Content-Type"] = "application/x-www-form-urlencoded";
      }

      var postData = {
        url: url,
        httpMethod : params.METHOD || "GET",
        headers: gadgets.io.encodeValues(headers),
        postData : params.POST_DATA || "",
        auth : auth || "",
        st : st || ""
      };
      xhr.send(gadgets.io.encodeValues(postData));
    },

    /**
     * Converts an input object into a URL-encoded data string.
     * (key=value&amp;...)
     *
     * @param {Object} fields The post fields you wish to encode
     * @return {String} The processed post data in www-form-urlencoded format.
     *
     * @member gadgets.io
     */
    encodeValues : function (fields) {
      var buf = [];
      var first = false;
      for (var i in fields) {
        if (!first) {
          first = true;
        } else {
          buf.push("&");
        }
        buf.push(encodeURIComponent(i));
        buf.push("=");
        buf.push(encodeURIComponent(fields[i]));
      }
      return buf.join("");
    },

    /**
     * Gets the proxy version of the passed-in URL.
     *
     * @param {String} url The URL to get the proxy URL for
     * @return {String} The proxied version of the URL
     *
     * @member gadgets.io
     */
    getProxyUrl : function (url) {
      return config.proxyUrl.replace("%url%", encodeURIComponent(url));
    },

    /**
     * Initializes fetchers
     *
     * @param {Object} configuration Configuration settings
     *     Required:
     *       - proxyUrl: The url for content proxy requests. Include %url%
     *           as a placeholder for the actual url.
     *       - jsonProxyUrl: The url for dynamic proxy requests. Include %url%
     *           as a placeholder for the actual url.
     * @private
     */
    init : function (configuration) {
      config = configuration;
      if (!config.proxyUrl || !config.jsonProxyUrl) {
        throw new Error("proxyUrl and jsonProxyUrl are required.");
      }
    }
  };
}();

gadgets.io.RequestParameters = gadgets.util.makeEnum([
  "METHOD",
  "CONTENT_TYPE",
  "POST_DATA",
  "HEADERS",
  "AUTHORIZATION",
  "NUM_ENTRIES",
  "GET_SUMMARIES"
]);

// PUT, DELETE, and HEAD not supported currently.
gadgets.io.MethodType = gadgets.util.makeEnum([
  "GET", "POST", "PUT", "DELETE", "HEAD"
]);

gadgets.io.ContentType = gadgets.util.makeEnum([
  "TEXT", "DOM", "JSON", "FEED"
]);

gadgets.io.AuthorizationType = gadgets.util.makeEnum([
  "NONE", "SIGNED", "AUTHENTICATED"
]);
 
 
/************** end io.js ********************/

/*
 * 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.
 */

/**
 * @fileoverview
 *
 * Provides access to user prefs, module dimensions, and messages.
 *
 * Clients can access their preferences by constructing an instance of
 * gadgets.Prefs and passing in their module id.  Example:
 *
 *   var prefs = new gadgets.Prefs();
 *   var name = prefs.getString("name");
 *   var lang = prefs.getLang();
 *
 * Modules with type=url can also use this library to parse arguments passed
 * by URL, but this is not the common case:
 *
 *   &lt;script src="http://apache.org/shindig/prefs.js"&gt;&lt;/script&gt;
 *   &lt;script&gt;
 *   gadgets.Prefs.parseUrl();
 *   var prefs = new gadgets.Prefs();
 *   var name = prefs.getString("name");
 *   &lt;/script&lg;
 */

var gadgets = gadgets || {};

/**
 * Stores preferences for the default shindig implementation.
 * @private
 */
gadgets.prefs_ = function() {
  var modules = {};

  /**
   * Returns the module named by moduleId
   * @param {Number | String} moduleId The module id to fetch
   * @return {Object} An object containing module data
   */
  function getModuleData(moduleId) {
    if (!modules[moduleId]) {
      modules[moduleId] = {
        prefs:{},
        msgs:{},
        language:"all",
        country:"all"
      };
    }
    return modules[moduleId];
  }

  /**
   * Adds a new user preference to the stored set for the given module id.
   *
   * @param {String | Number} moduleId The module id to add the pref for
   * @param {String} key The key to add; may be an object where keys = key and
   *     values = value
   * @param {String} opt_value An optional value used to set the value of the
   *     key.
   */
  function setPref(moduleId, key, opt_value) {
    var module = getModuleData(moduleId);
    if (typeof key !== "string") {
      for (var i in key) {
        module.prefs[i] = key[i];
      }
    } else {
      module.prefs[key] = opt_value;
    }
  }

  /**
   * Adds a new message to the stored set for the given module id.
   *
   * @param {String | Number} moduleId The module id to add the pref for
   * @param {String | Object} key The key to add; may be an object where keys =
   *     key and values = value
   * @param {String} opt_value An optional value used to set the value of the
   *     key.
   */
  function setMsg(moduleId, key, opt_value) {
    var module = getModuleData(moduleId);
    if (typeof key !== "string") {
      for (var i in key) {
        module.msgs[i] = key[i];
      }
    } else {
      module.msgs[key] = opt_value;
    }
  }

  var defaultModuleId = 0;

  /**
   * Sets the default module id.
   *
   * @param {String | Number} moduleId The module id to set as default
   */
  function setDefaultModuleId(moduleId) {
    defaultModuleId = moduleId;
  }

  /**
   * Gets the default module id.
   *
   * @return {String | Number} The default module id
   */
  function getDefaultModuleId() {
    return defaultModuleId;
  }

  /**
   * Sets the default language for this module id.
   *
   * @param {String | Number} moduleId The module id to set the language for
   * @param {String} language The language code as an ISO 639-1 code
   */
  function setLanguage(moduleId, language) {
    getModuleData(moduleId).language = language;
  }

  /**
   * Sets the default country for this module id.
   *
   * @param {String | Number} moduleId The id of the gagdet instance
   * @param {String} country The country code as an ISO 3166-1 alpha-2 code
   */
  function setCountry(moduleId, country) {
    getModuleData(moduleId).country = country;
  }

  // Export public API for the gadget container code. Gadget authors should
  // not use this class.
  return {
    setPref: setPref,
    setMsg: setMsg,
    setCountry: setCountry,
    setLanguage: setLanguage,
    getModuleData: getModuleData,
    setDefaultModuleId: setDefaultModuleId,
    getDefaultModuleId: getDefaultModuleId
  };
}();

/**
 * @class
 * Provides access to user preferences, module dimensions, and messages.
 *
 * Clients can access their preferences by constructing an instance of
 * gadgets.Prefs and passing in their module id.  Example:
 *
<pre>var prefs = new gadgets.Prefs();
var name = prefs.getString("name");
var lang = prefs.getLang();</pre>
 *
 * @description Creates a new Prefs object.
 * @param {String | Number} opt_moduleId An optional parameter specifying the
 *     module id to create prefs for; if not provided, the default module id
 *     is used
 */
gadgets.Prefs = function(opt_moduleId) {
  if (typeof opt_moduleId === "undefined") {
    this.moduleId_ = gadgets.prefs_.getDefaultModuleId();
  } else {
    this.moduleId_ = opt_moduleId;
  }
  this.data_ = gadgets.prefs_.getModuleData(this.moduleId_);
  // This is used to eliminate one hash table lookup per value fetched.
  this.prefs_ = this.data_.prefs;
  this.msgs_ = this.data_.msgs;

};

/**
 * @static
 * @method
 * @scope gadgets.Prefs
 *
 * Static pref parser. Parses all parameters from the url and stores them
 * for later use when creating a new gadgets.Prefs object.
 * You should only ever call this if you are a type=url gadget.
 *
 * @param {String | Number} moduleId The id of the gadget instance
 * @private
 */
gadgets.Prefs.parseUrl = function(moduleId) {
  var prefs = {};
  var msgs = {};
  var country = "all";
  var language = "all";
  if (gadgets.util) {
    var params = gadgets.util.getUrlParameters();
    for (var i in params) {
      if (i.indexOf("up_") === 0 && i.length > 3) {
        prefs[i.substr(3)] = String(params[i]);
      } else if (i.indexOf("msg_") === 0 && i.length > 4) {
        msgs[i.substr(4)] = String(params[i]);
      } else if (i === "country") {
        country = params[i];
      } else if (i === "lang") {
        language = params[i];
      } else if (i === "mid") {
        moduleId = params[i];
      }
    }
  }
  gadgets.prefs_.setDefaultModuleId(moduleId);
  gadgets.prefs_.setPref(moduleId, prefs);
  gadgets.prefs_.setMsg(moduleId, msgs);
  gadgets.prefs_.setLanguage(moduleId, language);
  gadgets.prefs_.setCountry(moduleId, country);
};


gadgets.Prefs.setMessages_ = function(msgs) {
  gadgets.prefs_.setMsg(gadgets.prefs_.getDefaultModuleId(),msgs);
};
 
/**
 * Initializes default user prefs values.
 */
gadgets.Prefs.setDefaultPrefs_ = function(defprefs) {
  gadgets.prefs_.setPref(gadgets.prefs_.getDefaultModuleId(),defprefs);
};
 
/**
 * Internal helper for pref fetching.
 * @param {String} key The key to fetch
 * @return {Object} The preference
 * @private
 */
gadgets.Prefs.prototype.getPref_ = function(key) {
  var val = this.prefs_[key];
  return typeof val === "undefined" ? null : val;
}

/**
 * Retrieves a preference as a string.
 * @param {String} key The preference to fetch
 * @return {String} The preference; if not set, an empty string
 */
gadgets.Prefs.prototype.getString = function(key) {
  var val = this.getPref_(key);
  return val === null ? "" : val;
};

/**
 * Retrieves a preference as an integer.
 * @param {String} key The preference to fetch
 * @return {Number} The preference; if not set, 0
 */
gadgets.Prefs.prototype.getInt = function(key) {
  var val = parseInt(this.getPref_(key), 10);
  return isNaN(val) ? 0 : val;
};

/**
 * Retrieves a preference as a floating-point value.
 * @param {String} key The preference to fetch
 * @return {Number} The preference; if not set, 0
 */
gadgets.Prefs.prototype.getFloat = function(key) {
  var val = parseFloat(this.getPref_(key));
  return isNaN(val) ? 0 : val;
};

/**
 * Retrieves a preference as a boolean.
 * @param {String} key The preference to fetch
 * @return {Boolean} The preference; if not set, false
 */
gadgets.Prefs.prototype.getBool = function(key) {
  var val = this.getPref_(key);
  if (val !== null) {
    return val === "true" || val === true || !!parseInt(val, 10);
  }
  return false;
};

/**
 * Stores a preference.
 * To use this call,
 * the gadget must require the feature setprefs.
 *
 * <p class="note">
 * <b>Note:</b>
 * If the gadget needs to store an Array it should use setArray instead of
 * this call.
 * </p>
 *
 * @param {String} key The pref to store
 * @param {Object} val The values to store
 */
gadgets.Prefs.prototype.set = function(key, value) {
  throw new Error("setprefs feature required to make this call.");
};

/**
 * Retrieves a preference as an array.
 * UserPref values that were not declared as lists are treated as
 * one-element arrays.
 *
 * @param {String} key The preference to fetch
 * @return {Array.&lt;String&gt;} The preference; if not set, an empty array
 */
gadgets.Prefs.prototype.getArray = function(key) {
  var val = this.getPref_(key);
  if (val !== null) {
    var arr = val.split("|");
    // Decode pipe characters.
    for (var i = 0, j = arr.length; i < j; ++i) {
      arr[i] = arr[i].replace(/%7C/g, "|");
    }
    return arr;
  }
  return [];
};

/**
 * Stores an array preference.
 * To use this call,
 * the gadget must require the feature setprefs.
 *
 * @param {String} key The pref to store
 * @param {Array} val The values to store
 */
gadgets.Prefs.prototype.setArray = function(key, val) {
  throw new Error("setprefs feature required to make this call.");
};

/**
 * Fetches an unformatted message.
 * @param {String} key The message to fetch
 * @return {String} The message
 */
gadgets.Prefs.prototype.getMsg = function(key) {
  var val = this.msgs_[key];
  return typeof val === "undefined" ? "" : val;
};

/**
 * Gets the current country, returned as ISO 3166-1 alpha-2 code.
 *
 * @return {String} The country for this module instance
 */
gadgets.Prefs.prototype.getCountry = function() {
  return this.data_.country;
};

/**
 * Gets the current language the gadget should use when rendering, returned as a
 * ISO 639-1 language code.
 *
 * @return {String} The language for this module instance
 */
gadgets.Prefs.prototype.getLang = function() {
  return this.data_.language;
};

/**
 * Gets the module id for the current instance.
 *
 * @return {String | Number} The module id for this module instance
 */
gadgets.Prefs.prototype.getModuleId = function() {
  return this.moduleId_;
};




/************** end prefs.js ********************/

/*
Copyright (c) 2005 JSON.org

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The Software shall be used for Good, not Evil.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

/**
 * @fileoverview
 * The global object gadgets.json contains two methods.
 *
 * gadgets.json.stringify(value) takes a JavaScript value and produces a JSON
 * text. The value must not be cyclical.
 *
 * gadgets.json.parse(text) takes a JSON text and produces a JavaScript value.
 * It will return false if there is an error.
*/

var gadgets = gadgets || {};

/**
 * @static
 * @class Provides operations for translating objects to and from JSON.
 * @name gadgets.json
 */

/**
 * @scope gadgets.json
 */
gadgets.json = function () {
    var m = {
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        s = {
            'boolean': function (x) {
                return String(x);
            },
           /** @private */
            number: function (x) {
                return isFinite(x) ? String(x) : 'null';
            },
            /** @private */
            string: function (x) {
                if (/["\\\x00-\x1f]/.test(x)) {
                    x = x.replace(/([\x00-\x1f\\"])/g, function(a, b) {
                        var c = m[b];
                        if (c) {
                            return c;
                        }
                        c = b.charCodeAt();
                        return '\\u00' +
                            Math.floor(c / 16).toString(16) +
                            (c % 16).toString(16);
                    });
                }
                return '"' + x + '"';
            },
            /** @private */
            object: function (x) {
                if (x) {
                    var a = [], b, f, i, l, v;
                    if (x instanceof Array) {
                        a[0] = '[';
                        l = x.length;
                        for (i = 0; i < l; i += 1) {
                            v = x[i];
                            f = s[typeof v];
                            if (f) {
                                v = f(v);
                                if (typeof v == 'string') {
                                    if (b) {
                                        a[a.length] = ',';
                                    }
                                    a[a.length] = v;
                                    b = true;
                                }
                            }
                        }
                        a[a.length] = ']';
                    } else if (typeof x.hasOwnProperty === 'function') {
                        a[0] = '{';
                        for (i in x) {
                            if (x.hasOwnProperty(i)) {
                                v = x[i];
                                f = s[typeof v];
                                if (f) {
                                    v = f(v);
                                    if (typeof v == 'string') {
                                        if (b) {
                                            a[a.length] = ',';
                                        }
                                        a.push(s.string(i), ':', v);
                                        b = true;
                                    }
                                }
                            }
                        }
                        a[a.length] = '}';
                    } else {
                        return;
                    }
                    return a.join('');
                }
                return 'null';
            }
        };
    return {
        copyright: '(c)2005 JSON.org',
        license: 'http://www.JSON.org/license.html',

        /**
         * Converts a JavaScript value to a JSON string.
         *
         * @param {Object} v The object to convert
         * @return {String} The JSON equivalent
	 *
         * @member gadgets.json
         */
        stringify: function (v) {
            var f = s[typeof v];
            if (f) {
                v = f(v);
                if (typeof v == 'string') {
                    return v;
                }
            }
            return null;
        },

        /**
         * Parses a JSON string, producing a JavaScript value.
         *
         * @param {String} text The string to transform into an object &mdash;
	 *     usually the result of a previous stringify call
         * @return {Object} The object parsed from the passed in text; false if
         *     an error occurred
	 *
         * @member gadgets.json
         */
        parse: function (text) {
            try {
                return !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
                        text.replace(/("(\\.|[^"\\])*")|('(\\.|[^'\\])*')/g, ''))) &&
                    eval('(' + text + ')');
            } catch (e) {
                return false;
            }
        }
    };
}();

var JSON = gadgets.json;





/************** end json.js ********************/


/*
 * 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.
 */

/**
 * @fileoverview
 *
 * Provides unified configuration for all features.
 *
 * This is a custom shindig library that has not yet been submitted for
 * standardization. It is designed to make developing of features for the
 * opensocial / gadgets platforms easier and is intended as a supplemental
 * tool to Shindig's standardized feature loading mechanism.
 *
 * Usage:
 * First, you must register a component that needs configuration:
 * <pre>
 *   var config = {
 *     name : gadgets.config.NonEmptyStringValidator,
 *     url : new gadgets.config.RegExValidator(/.+%mySpecialValue%.+/)
 *   };
 *   gadgets.config.register("my-feature", config, myCallback);
 * </pre>
 *
 * This will register a component named "my-feature" that expects input config
 * containing a "name" field with a value that is a non-empty string, and a
 * "url" field with a value that matches the given regular expression.
 *
 * When gadgets.config.init is invoked by the container, it will automatically
 * validate your registered configuration and will throw an exception if
 * the provided configuration does not match what was required.
 *
 * Your callback will be invoked by passing all configuration data passed to
 * gadgets.config.init, which allows you to optionally inspect configuration
 * from other features, if present.
 *
 * Note that the container may optionally bypass configuration validation for
 * performance reasons. This does not mean that you should duplicate validation
 * code, it simply means that validation will likely only be performed in debug
 * builds, and you should assume that production builds always have valid
 * configuration.
 */

var gadgets = gadgets || {};

gadgets.config = function() {
  var components = {};

  return {
    /**
     * Registers a configurable component and its configuration parameters.
     *
     * @param {String} component The name of the component to register. Should
     *     be the same as the fully qualified name of the <Require> feature or
     *     the fully qualified javascript object reference (e.g. gadgets.io).
     * @param {Object} opt_validators Mapping of option name to validation
     *     functions that take the form function(data) {return isValid(data);}
     * @param {Function} opt_callback A function to be invoked when a
     *     configuration is registered. If passed, this function will be invoked
     *     immediately after a call to init has been made. Do not assume that
     *     dependent libraries have been configured until after init is
     *     complete. If you rely on this, it is better to defer calling
     *     dependent libraries until you can be sure that configuration is
     *     complete. Takes the form function(config), where config will be
     *     all registered config data for all components. This allows your
     *     component to read configuration from other components.
     * @throws {Error} If the component has already been registered.
     */
    register: function(component, opt_validators, opt_callback) {
      if (components[component]) {
        throw new Error('Component "' + component + '" is already registered.');
      }
      components[component] = {
        validators: opt_validators || {},
        callback: opt_callback
      };
    },

    /**
     * Retrieves configuration data on demand.
     *
     * @param {String} opt_component The component to fetch. If not provided
     *     all configuration will be returned.
     * @return {Object} The requested configuration.
     * @throws {Error} If the given component has not been registered
     */
    get: function(opt_component) {
      if (opt_component) {
        if (!components[opt_component]) {
          throw new Error('Component "' + opt_component + '" not registered.');
        }
        return configuration[opt_component] || {};
      }
      return configuration;
    },

    /**
     * Initializes the configuration.
     *
     * @param {Object} config The full set of configuration data.
     * @param {Boolean} opt_noValidation True if you want to skip validation.
     * @throws {Error} If there is a configuration error.
     */
    init: function(config, opt_noValidation) {
      configuration = config;
      for (var name in components) {
        var component = components[name],
            conf = config[name],
            validators = component.validators;
        if (!opt_noValidation) {
          for (var validator in validators) {
            if (!validators[validator](conf[validator])) {
              throw new Error('Invalid config value "' + conf[validator] +
                  '" for parameter "' + validator + '" in component "' +
                  name + '"');
            }
          }
        }
        if (component.callback) {
          component.callback(config);
        }
      }
    },

    // Standard validators go here.

    /**
     * Ensures that data is one of a fixed set of items.
     * @param {Array.<String>} list The list of valid values.
     * Also supports argument sytax: EnumValidator("Dog", "Cat", "Fish");
     */
    EnumValidator: function(list) {
      var listItems = [];
      if (arguments.length > 1) {
        for (var i = 0, arg; arg = arguments[i]; ++i) {
          listItems.push(arg);
        }
      } else {
        listItems = list;
      }
      return function(data) {
        for (var i = 0, test; test = listItems[i]; ++i) {
          if (data === listItems[i]) {
            return true;
          }
        }
      }
      return false;
    },

    /**
     * Tests the value against a regular expression.
     */
    RegExValidator: function(re) {
      return function(data) {
        return re.test(data);
      }
    },

    /**
     * Validates that a value was provided.
     */
    ExistsValidator: function(data) {
      return typeof data !== "undefined";
    },

    /**
     * Validates that a value is a non-empty string.
     */
    NonEmptyStringValidator: function(data) {
      return typeof data === "string" && data.length > 0
    },

    /**
     * Validates that the value is a boolean.
     */
    BooleanValidator: function(data) {
      return !!data;
    },

    /**
     * Similar to the ECMAScript4 virtual typing system, ensures that
     * whatever object was passed in is "like" the existing object.
     * Doesn't actually do type validation though, but instead relies
     * on other validators.
     *
     * example:
     *
     *  var validator = new gadgets.config.LikeValidator(
     *    "booleanField" : gadgets.config.BooleanValidator,
     *    "regexField" : new gadgets.config.RegExValidator(/foo.+/);
     *  );
     *
     * This can be used recursively as well to validate sub-objects.
     *
     * @param {Object} test The object to test against.
     */
    LikeValidator : function(test) {
      return function(data) {
        for (var member in test) {
          var t = test[member];
          if (!t(data[member])) {
            return false;
          }
        }
        return true;
      };
    }
  };
}();


/************** end config.js ********************/



/*
 * 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.
 */

/**
 * @fileoverview This library provides functions for navigating to and dealing
 *     with views of the current gadget.
 */

var gadgets = gadgets || {};

/**
 * Implements the gadgets.views API spec. See
 * http://code.google.com/apis/gadgets/docs/reference/gadgets.views.html
 */
gadgets.views = function() {

  /**
   * Reference to the current view object.
   */
  var currentView = null;

  /**
   * Map of all supported views for this container.
   */
  var supportedViews = {};

  /**
   * Map of parameters passed to the current request.
   */
  var params = {};

  /**
   * Initializes views. Assumes that the current view is the "view"
   * url parameter (or default if "view" isn't supported), and that
   * all view parameters are in the form view-<name>
   * TODO: Use unified configuration when it becomes available.
   *
   */
  function init(config) {
    var supported = config["views"];

    var x = 0;
    for (var s in supported) if (supported.hasOwnProperty(s)) {
      var obj = supported[s];
      supportedViews[s] = new gadgets.views.View(obj.name_, obj.isOnlyVisible_);
      //HACK BELOW
      supportedViews[x] = supportedViews[s];x++;//HACK for back compat to 0.6 container
      //REMOVE ABOVE LINE AT SOME POINT
      var aliases = obj.aliases || [];
      for (var i = 0, alias; alias = aliases[i]; ++i) {
        supportedViews[alias] = new gadgets.views.View(obj.name_, obj.isOnlyVisible_);
      }
   } 

    var urlParams = gadgets.util.getUrlParameters();
    // View parameters are passed as a single parameter.
    if (urlParams["view-params"]) {
      var tmpParams = gadgets.json.parse(
          decodeURIComponent(urlParams["view-params"]));
      if (tmpParams) {
        params = tmpParams;
      }
    }
    currentView = supportedViews[urlParams.views] || supportedViews["default"];
  }

  var requiredConfig = {
    "default": new gadgets.config.LikeValidator({
      "isOnlyVisible_" : gadgets.config.BooleanValidator
    })
  };

  gadgets.config.register("views", requiredConfig, init);

  return {
    requestNavigateTo : function(view, opt_params) {
      gadgets.rpc.call(
          null, "requestNavigateTo", null, view.getName(), opt_params);
    },

    getCurrentView : function() {
      return currentView;
    },

    getSupportedViews : function() {
      return supportedViews;
    },

    getParams : function() {
      return params;
    }
  };
}();

gadgets.views.View = function(name, opt_isOnlyVisible) {
  this.name_ = name;
  this.isOnlyVisible_ = !!opt_isOnlyVisible;
};

gadgets.views.View.prototype.getName = function() {
  return this.name_;
};

gadgets.views.View.prototype.isOnlyVisibleGadget = function() {
  return this.isOnlyVisible_;
};

gadgets.views.ViewType = gadgets.util.makeEnum([
  "FULL_PAGE", "DASHBOARD", "POPUP"
]);



/************** end views.js ********************/



/*
 * 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.
 */

/**
 * @fileoverview This library augments gadgets.window with functionality
 * to change the height of a gadget dynamically.
 */

var gadgets = gadgets || {};

/**
 * @static
 * @class Provides operations for getting information about and modifying the
 *     window the gadget is placed in.
 * @name gadgets.window
 */
gadgets.window = gadgets.window || {};

// we wrap these in an anonymous function to avoid storing private data
// as members of gadgets.window.
(function() {

  var oldHeight;

  /**
   * Detects the inner dimensions of a frame.
   * See: http://www.quirksmode.org/viewport/compatibility.html for more
   * information.
   * @returns {Object} An object with width and height properties.
   * @member gadgets.window
   */
  gadgets.window.getViewportDimensions = function() {
    var x,y;
    if (self.innerHeight) {
      // all except Explorer
      x = self.innerWidth;
      y = self.innerHeight;
    } else if (document.documentElement &&
               document.documentElement.clientHeight) {
      // Explorer 6 Strict Mode
      x = document.documentElement.clientWidth;
      y = document.documentElement.clientHeight;
    } else if (document.body) {
      // other Explorers
      x = document.body.clientWidth;
      y = document.body.clientHeight;
    } else {
      x = 0;
      y = 0;
    }
    return {width: x, height: y};
  };

  /**
   * Adjusts the gadget height
   * @param {Number} opt_height An optional preferred height in pixels. If not
   *     specified, will attempt to fit the gadget to its content.
   * @member gadgets.window
   */
  gadgets.window.adjustHeight = function(opt_height) {
    var newHeight = parseInt(opt_height, 10);
    if (isNaN(newHeight)) {
      var vh = gadgets.window.getViewportDimensions().height;
      var body = document.body;
      var docEl = document.documentElement;
      if (document.compatMode == 'CSS1Compat' && docEl.scrollHeight) {
        newHeight = docEl.scrollHeight != vh ? docEl.scrollHeight : docEl.offsetHeight;
      } else {
        var sh = docEl.scrollHeight;
        var oh = docEl.offsetHeight;
        if (docEl.clientHeight != oh) {
          sh = body.scrollHeight;
          oh = body.offsetHeight;
        }

        if (sh > vh) {
          newHeight = sh > oh ? sh : oh;
        } else {
          newHeight = sh < oh ? sh : oh;
        }
      }
    }

    if (newHeight != oldHeight) {
      oldHeight = newHeight;
      var p = opensocial.Container.get().params_;
      _IFPC.call(
           p.panelId,
           "resizeWidget",
           [p.panelId , newHeight],
           p.remoteRelay,
           null,
           p.localRelay,
           null); 
    }
  };
}());   



/************** end dynamic-height.js ********************/