
// includes in order: Smoothbox.js.aspx, google api ajax feed loader
/** Smoothbox v20080623 by Boris Popoff (http://gueschla.com)* To be used with mootools 1.2** Based on Cody Lindley's Thickbox, MIT License** Licensed under the MIT License:*   http://www.opensource.org/licenses/mit-license.php*/
window.addEvent("domready", TB_init); TB_WIDTH = 0; TB_HEIGHT = 0; var TB_doneOnce = 0; function TB_init() { $$("a.smoothbox").each(function(a) { a.onclick = TB_bind }) } function TB_bind(b) { var b = new Event(b); b.preventDefault(); this.blur(); var a = this.title || this.name || ""; var c = this.rel || false; TB_show(a, this.href, c); this.onclick = TB_bind; return false } function TB_show(q, e, b) { if (!$("TB_overlay")) { new Element("iframe").setProperty("id", "TB_HideSelect").injectInside(document.body); $("TB_HideSelect").setOpacity(0); new Element("div").setProperty("id", "TB_overlay").injectInside(document.body); $("TB_overlay").setOpacity(0); TB_overlaySize(); new Element("div").setProperty("id", "TB_load").injectInside(document.body); $("TB_load").innerHTML = "<img src='art/loading.gif' />"; TB_load_position(); $("TB_overlay").set("tween", { duration: 400 }); $("TB_overlay").tween("opacity", 0, 0.6) } if (!$("TB_load")) { new Element("div").setProperty("id", "TB_load").injectInside(document.body); $("TB_load").innerHTML = "<img src='../loading.gif' />"; TB_load_position() } if (!$("TB_window")) { new Element("div").setProperty("id", "TB_window").injectInside(document.body); $("TB_window").setOpacity(0) } $("TB_overlay").onclick = TB_remove; window.onscroll = TB_position; var r = e.match(/(.+)?/)[1] || e; var o = /\.(jpe?g|png|gif|bmp)/gi; if (r.match(o)) { var u = { caption: "", url: "", html: "" }; var l = u, m = u, a = ""; if (b) { function j(v, w, i) { return { caption: v.title, url: v.href, html: "<span id='TB_" + w + "'>&nbsp;&nbsp;<a href='#'>" + i + "</a></span>"} } var c = []; $$("a.smoothbox").each(function(i) { if (i.rel == b) { c[c.length] = i } }); var t = false; for (var p = 0; p < c.length; p++) { var k = c[p]; var g = k.href.match(o); if (k.href == e) { t = true; a = "Image " + (p + 1) + " of " + (c.length) } else { if (t) { m = j(k, "next", "Next &gt;"); break } else { l = j(k, "prev", "&lt; Prev") } } } } imgPreloader = new Image(); imgPreloader.onload = function() { imgPreloader.onload = null; var w = window.getWidth() - 150; var C = window.getHeight() - 150; var z = imgPreloader.width; var v = imgPreloader.height; if (z > w) { v = v * (w / z); z = w; if (v > C) { z = z * (C / v); v = C } } else { if (v > C) { z = z * (C / v); v = C; if (z > w) { v = v * (w / z); z = w } } } TB_WIDTH = z + 30; TB_HEIGHT = v + 60; $("TB_window").innerHTML += "<a href='' id='TB_ImageOff' title='Close'><img id='TB_Image' src='" + e + "' width='" + z + "' height='" + v + "' alt='" + q + "'/></a><div id='TB_caption'>" + q + "<div id='TB_secondLine'>" + a + l.html + m.html + "</div></div><div id='TB_closeWindow'><a href='#' id='TB_closeWindowButton' title='Close'>close</a></div>"; $("TB_closeWindowButton").onclick = TB_remove; function i(x) { return function() { $("TB_window").dispose(); new Element("div").setProperty("id", "TB_window").injectInside(document.body); TB_show(x.caption, x.url, b); return false } } var B = i(l); var A = i(m); if ($("TB_prev")) { $("TB_prev").onclick = B } if ($("TB_next")) { $("TB_next").onclick = A } document.onkeydown = function(x) { var x = new Event(x); switch (x.code) { case 27: TB_remove(); break; case 190: if ($("TB_next")) { document.onkeydown = null; A() } break; case 188: if ($("TB_prev")) { document.onkeydown = null; B() } break } }; $("TB_ImageOff").onclick = TB_remove; TB_position(); TB_showWindow() }; imgPreloader.src = e } else { var d = e.match(/\?(.+)/)[1]; var s = TB_parseQuery(d); TB_WIDTH = (s.width * 1) + 30; TB_HEIGHT = (s.height * 1) + 40; var h = TB_WIDTH - 30, n = TB_HEIGHT - 45; if (e.indexOf("TB_iframe") != -1) { urlNoQuery = e.split("TB_"); $("TB_window").innerHTML += "<div id='TB_title'><div id='TB_ajaxWindowTitle'>" + q + "</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton' title='Close'></a></div></div><iframe frameborder='0' hspace='0' src='" + urlNoQuery[0] + "' id='TB_iframeContent' name='TB_iframeContent' style='width:" + (h + 29) + "px;height:" + (n + 17) + "px;' onload='TB_showWindow()'> </iframe>" } else { $("TB_window").innerHTML += "<div id='TB_title'><div id='TB_ajaxWindowTitle'>" + q + "</div><div id='TB_closeAjaxWindow'><a href='#' id='TB_closeWindowButton'></a></div></div><div id='TB_ajaxContent' style='width:" + h + "px;height:" + n + "px;'></div>" } $("TB_closeWindowButton").onclick = TB_remove; if (e.indexOf("TB_inline") != -1) { $("TB_ajaxContent").innerHTML = ($(s.inlineId).innerHTML); TB_position(); TB_showWindow() } else { if (e.indexOf("TB_iframe") != -1) { TB_position(); if (frames.TB_iframeContent == undefined) { $(document).keyup(function(v) { var i = v.keyCode; if (i == 27) { TB_remove() } }); TB_showWindow() } } else { var f = function() { TB_position(); TB_showWindow() }; new Request.HTML({ method: "get", update: $("TB_ajaxContent"), onComplete: f }).get(e) } } } window.onresize = function() { TB_position(); TB_load_position(); TB_overlaySize() }; document.onkeyup = function(i) { var i = new Event(i); if (i.code == 27) { TB_remove() } } } function TB_showWindow() { if (TB_doneOnce == 0) { TB_doneOnce = 1; $("TB_window").set("tween", { duration: 250, onComplete: function() { if ($("TB_load")) { $("TB_load").dispose() } } }); $("TB_window").tween("opacity", 0, 1) } else { $("TB_window").setStyle("opacity", 1); if ($("TB_load")) { $("TB_load").dispose() } } } function TB_remove() { $("TB_overlay").onclick = null; document.onkeyup = null; document.onkeydown = null; if ($("TB_imageOff")) { $("TB_imageOff").onclick = null } if ($("TB_closeWindowButton")) { $("TB_closeWindowButton").onclick = null } if ($("TB_prev")) { $("TB_prev").onclick = null } if ($("TB_next")) { $("TB_next").onclick = null } $("TB_window").set("tween", { duration: 250, onComplete: function() { $("TB_window").dispose() } }); $("TB_window").tween("opacity", 1, 0); $("TB_overlay").set("tween", { duration: 400, onComplete: function() { $("TB_overlay").dispose() } }); $("TB_overlay").tween("opacity", 0.6, 0); window.onscroll = null; window.onresize = null; $("TB_HideSelect").dispose(); TB_init(); TB_doneOnce = 0; return false } function TB_position() { $("TB_window").set("morph", { duration: 75 }); $("TB_window").morph({ width: TB_WIDTH + "px", left: (window.getScrollLeft() + (window.getWidth() - TB_WIDTH) / 2) + "px", top: (window.getScrollTop() + (window.getHeight() - TB_HEIGHT) / 2) + "px" }) } function TB_overlaySize() { $("TB_overlay").setStyles({ height: "0px", width: "0px" }); $("TB_HideSelect").setStyles({ height: "0px", width: "0px" }); $("TB_overlay").setStyles({ height: window.getScrollHeight() + "px", width: window.getScrollWidth() + "px" }); $("TB_HideSelect").setStyles({ height: window.getScrollHeight() + "px", width: window.getScrollWidth() + "px" }) } function TB_load_position() { if ($("TB_load")) { $("TB_load").setStyles({ left: (window.getScrollLeft() + (window.getWidth() - 56) / 2) + "px", top: (window.getScrollTop() + ((window.getHeight() - 20) / 2)) + "px", display: "block" }) } } function TB_parseQuery(c) { if (!c) { return {} } var e = {}; var b = c.split(/[;&]/); for (var a = 0; a < b.length; a++) { var d = b[a].split("="); if (!d || d.length != 2) { continue } e[unescape(d[0])] = unescape(d[1]).replace(/\+/g, " ") } return e };

if (!window['google']) {
    window['google'] = {};
}
if (!window['google']['loader']) {
    window['google']['loader'] = {};
    google.loader.ServiceBase = 'http://www.google.com/uds';
    google.loader.GoogleApisBase = 'http://ajax.googleapis.com/ajax';
    google.loader.ApiKey = 'ABQIAAAAIdbx_fZ0kW3pQrWZj0ShwBRNE0B0ZBOm334lfnS0pyk_nvMk8BR89WdvO1sJfd8lBkCMNEa3Ak0vBg';
    google.loader.KeyVerified = true;
    google.loader.LoadFailure = false;
    google.loader.Secure = false;
    google.loader.GoogleLocale = 'www.google.com';
    google.loader.ClientLocation = { "latitude": 53.333, "longitude": -6.249, "address": { "city": "Dublin", "region": "Dublin City", "country": "Ireland", "country_code": "IE"} };
    google.loader.AdditionalParams = '';
    (function() {
        var d = true, e = null, g = false, h = encodeURIComponent, k = window, m = google, o = undefined, p = document; function q(a, b) { return a.load = b } var r = "push", s = "replace", t = "charAt", u = "ServiceBase", v = "name", w = "getTime", x = "length", y = "prototype", z = "setTimeout", A = "loader", B = "substring", C = "join", D = "toLowerCase"; function E(a) { if (a in F) return F[a]; return F[a] = navigator.userAgent[D]().indexOf(a) != -1 } var F = {}; function G(a, b) { var c = function() { }; c.prototype = b[y]; a.T = b[y]; a.prototype = new c }
        function H(a, b) { var c = a.H || []; c = c.concat(Array[y].slice.call(arguments, 2)); if (typeof a.u != "undefined") b = a.u; if (typeof a.t != "undefined") a = a.t; var f = function() { var i = c.concat(Array[y].slice.call(arguments)); return a.apply(b, i) }; f.H = c; f.u = b; f.t = a; return f } function I(a) { a = new Error(a); a.toString = function() { return this.message }; return a } function J(a, b) { a = a.split(/\./); for (var c = k, f = 0; f < a[x] - 1; f++) { c[a[f]] || (c[a[f]] = {}); c = c[a[f]] } c[a[a[x] - 1]] = b } function K(a, b, c) { a[b] = c } if (!L) var L = J; if (!M) var M = K; m[A].v = {}; L("google.loader.callbacks", m[A].v); var N = {}, O = {}; m[A].eval = {}; L("google.loader.eval", m[A].eval);
        q(m, function(a, b, c) {
            function f(l) { var n = l.split("."); if (n[x] > 2) throw I("Module: '" + l + "' not found!"); else if (typeof n[1] != "undefined") { i = n[0]; c.packages = c.packages || []; c.packages[r](n[1]) } } var i = a; c = c || {}; if (a instanceof Array || a && typeof a == "object" && typeof a[C] == "function" && typeof a.reverse == "function") for (var j = 0; j < a[x]; j++) f(a[j]); else f(a); if (a = N[":" + i]) {
                if (c && !c.language && c.locale) c.language = c.locale; if (c && typeof c.callback == "string") {
                    j = c.callback; if (j.match(/^[[\]A-Za-z0-9._]+$/)) {
                        j = k.eval(j);
                        c.callback = j
                    } 
                } if ((j = c && c.callback != e) && !a.s(b)) throw I("Module: '" + i + "' must be loaded before DOM onLoad!"); else if (j) a.l(b, c) ? k[z](c.callback, 0) : a.load(b, c); else a.l(b, c) || a.load(b, c)
            } else throw I("Module: '" + i + "' not found!");
        }); L("google.load", m.load); m.S = function(a, b) { b ? aa(a) : P(k, "load", a) }; L("google.setOnLoadCallback", m.S); function P(a, b, c) { if (a.addEventListener) a.addEventListener(b, c, g); else if (a.attachEvent) a.attachEvent("on" + b, c); else { var f = a["on" + b]; a["on" + b] = f != e ? ba([c, f]) : c } }
        function ba(a) { return function() { for (var b = 0; b < a[x]; b++) a[b]() } } var Q = []; function aa(a) { if (Q[x] == 0) { P(k, "load", R); if (!E("msie") && !(E("safari") || E("konqueror")) && E("mozilla") || k.opera) k.addEventListener("DOMContentLoaded", R, g); else if (E("msie")) p.write("<script defer onreadystatechange='google.loader.domReady()' src=//:><\/script>"); else (E("safari") || E("konqueror")) && k[z](ca, 10) } Q[r](a) }
        m[A].N = function() { var a = k.event.srcElement; if (a.readyState == "complete") { a.onreadystatechange = e; a.parentNode.removeChild(a); R() } }; L("google.loader.domReady", m[A].N); var da = { loaded: d, complete: d }; function ca() { if (da[p.readyState]) R(); else Q[x] > 0 && k[z](ca, 10) } function R() { for (var a = 0; a < Q[x]; a++) Q[a](); Q.length = 0 }
        m[A].d = function(a, b, c) { if (c) { var f; if (a == "script") { f = p.createElement("script"); f.type = "text/javascript"; f.src = b } else if (a == "css") { f = p.createElement("link"); f.type = "text/css"; f.href = b; f.rel = "stylesheet" } (a = p.getElementsByTagName("head")[0]) || (a = p.body.parentNode.appendChild(p.createElement("head"))); a.appendChild(f) } else if (a == "script") p.write('<script src="' + b + '" type="text/javascript"><\/script>'); else a == "css" && p.write('<link href="' + b + '" type="text/css" rel="stylesheet"></link>') };
        L("google.loader.writeLoadTag", m[A].d); m[A].P = function(a) { O = a }; L("google.loader.rfm", m[A].P); m[A].R = function(a) { for (var b in a) if (typeof b == "string" && b && b[t](0) == ":" && !N[b]) N[b] = new T(b[B](1), a[b]) }; L("google.loader.rpl", m[A].R); m[A].Q = function(a) { if ((a = a.specs) && a[x]) for (var b = 0; b < a[x]; ++b) { var c = a[b]; if (typeof c == "string") N[":" + c] = new U(c); else { c = new V(c[v], c.baseSpec, c.customSpecs); N[":" + c[v]] = c } } }; L("google.loader.rm", m[A].Q); m[A].loaded = function(a) { N[":" + a.module].j(a) };
        L("google.loader.loaded", m[A].loaded); m[A].M = function() { var a = (new Date)[w](), b = Math.floor(Math.random() * 1E7); return "qid=" + (a.toString(16) + b.toString(16)) }; L("google.loader.createGuidArg_", m[A].M); J("google_exportSymbol", J); J("google_exportProperty", K); m[A].b = {}; L("google.loader.themes", m[A].b); m[A].b.B = "http://www.google.com/cse/style/look/bubblegum.css"; M(m[A].b, "BUBBLEGUM", m[A].b.B); m[A].b.D = "http://www.google.com/cse/style/look/greensky.css"; M(m[A].b, "GREENSKY", m[A].b.D); m[A].b.C = "http://www.google.com/cse/style/look/espresso.css";
        M(m[A].b, "ESPRESSO", m[A].b.C); m[A].b.G = "http://www.google.com/cse/style/look/shiny.css"; M(m[A].b, "SHINY", m[A].b.G); m[A].b.F = "http://www.google.com/cse/style/look/minimalist.css"; M(m[A].b, "MINIMALIST", m[A].b.F); function U(a) { this.a = a; this.q = []; this.p = {}; this.m = {}; this.e = {}; this.k = d; this.c = -1 }
        U[y].g = function(a, b) {
            var c = ""; if (b != o) { if (b.language != o) c += "&hl=" + h(b.language); if (b.nocss != o) c += "&output=" + h("nocss=" + b.nocss); if (b.nooldnames != o) c += "&nooldnames=" + h(b.nooldnames); if (b.packages != o) c += "&packages=" + h(b.packages); if (b.callback != e) c += "&async=2"; if (b.style != o) c += "&style=" + h(b.style); if (b.other_params != o) c += "&" + b.other_params } if (!this.k) {
                if (m[this.a] && m[this.a].JSHash) c += "&sig=" + h(m[this.a].JSHash); b = []; for (var f in this.p) f[t](0) == ":" && b[r](f[B](1)); for (f in this.m) f[t](0) == ":" && b[r](f[B](1));
                c += "&have=" + h(b[C](","))
            } return m[A][u] + "/?file=" + this.a + "&v=" + a + m[A].AdditionalParams + c
        }; U[y].z = function(a) { var b = e; if (a) b = a.packages; var c = e; if (b) if (typeof b == "string") c = [a.packages]; else if (b[x]) { c = []; for (a = 0; a < b[x]; a++) typeof b[a] == "string" && c[r](b[a][s](/^\s*|\s*$/, "")[D]()) } c || (c = ["default"]); b = []; for (a = 0; a < c[x]; a++) this.p[":" + c[a]] || b[r](c[a]); return b };
        q(U[y], function(a, b) {
            var c = this.z(b), f = b && b.callback != e; if (f) var i = new W(b.callback); for (var j = [], l = c[x] - 1; l >= 0; l--) { var n = c[l]; f && i.I(n); if (this.m[":" + n]) { c.splice(l, 1); f && this.e[":" + n][r](i) } else j[r](n) } if (c[x]) {
                if (b && b.packages) b.packages = c.sort()[C](","); for (l = 0; l < j[x]; l++) { n = j[l]; this.e[":" + n] = []; f && this.e[":" + n][r](i) } if (!b && O[":" + this.a] != e && O[":" + this.a].versions[":" + a] != e && !m[A].AdditionalParams && this.k) {
                    a = O[":" + this.a]; m[this.a] = m[this.a] || {}; for (var S in a.properties) if (S && S[t](0) == ":") m[this.a][S[B](1)] =
a.properties[S]; m[A].d("script", m[A][u] + a.path + a.js, f); a.css && m[A].d("css", m[A][u] + a.path + a.css, f)
                } else if (!b || !b.autoloaded) m[A].d("script", this.g(a, b), f); if (this.k) { this.k = g; this.c = (new Date)[w](); if (this.c % 100 != 1) this.c = -1 } for (l = 0; l < j[x]; l++) { n = j[l]; this.m[":" + n] = d } 
            } 
        });
        U[y].j = function(a) { if (this.c != -1) { X("al_" + this.a, "jl." + ((new Date)[w]() - this.c), d); this.c = -1 } this.q = this.q.concat(a.components); m[A][this.a] || (m[A][this.a] = {}); m[A][this.a].packages = this.q.slice(0); for (var b = 0; b < a.components[x]; b++) { this.p[":" + a.components[b]] = d; this.m[":" + a.components[b]] = g; var c = this.e[":" + a.components[b]]; if (c) { for (var f = 0; f < c[x]; f++) c[f].L(a.components[b]); delete this.e[":" + a.components[b]] } } X("hl", this.a) }; U[y].l = function(a, b) { return this.z(b)[x] == 0 }; U[y].s = function() { return d };
        function W(a) { this.K = a; this.n = {}; this.r = 0 } W[y].I = function(a) { this.r++; this.n[":" + a] = d }; W[y].L = function(a) { if (this.n[":" + a]) { this.n[":" + a] = g; this.r--; this.r == 0 && k[z](this.K, 0) } }; function V(a, b, c) { this.name = a; this.J = b; this.o = c; this.w = this.h = g; this.i = []; m[A].v[this[v]] = H(this.j, this) } G(V, U); q(V[y], function(a, b) { var c = b && b.callback != e; if (c) { this.i[r](b.callback); b.callback = "google.loader.callbacks." + this[v] } else this.h = d; if (!b || !b.autoloaded) m[A].d("script", this.g(a, b), c); X("el", this[v]) }); V[y].l = function(a, b) { return b && b.callback != e ? this.w : this.h }; V[y].j = function() { this.w = d; for (var a = 0; a < this.i[x]; a++) k[z](this.i[a], 0); this.i = [] };
        var Y = function(a, b) { return a.string ? h(a.string) + "=" + h(b) : a.regex ? b[s](/(^.*$)/, a.regex) : "" }; V[y].g = function(a, b) { return this.O(this.A(a), a, b) };
        V[y].O = function(a, b, c) { var f = ""; if (a.key) f += "&" + Y(a.key, m[A].ApiKey); if (a.version) f += "&" + Y(a.version, b); b = m[A].Secure && a.ssl ? a.ssl : a.uri; if (c != e) for (var i in c) if (a.params[i]) f += "&" + Y(a.params[i], c[i]); else if (i == "other_params") f += "&" + c[i]; else if (i == "base_domain") b = "http://" + c[i] + a.uri[B](a.uri.indexOf("/", 7)); m[this[v]] = {}; if (b.indexOf("?") == -1 && f) f = "?" + f[B](1); return b + f }; V[y].s = function(a) { return this.A(a).deferred }; V[y].A = function(a) { if (this.o) for (var b = 0; b < this.o[x]; ++b) { var c = this.o[b]; if ((new RegExp(c.pattern)).test(a)) return c } return this.J }; function T(a, b) { this.a = a; this.f = b; this.h = g } G(T, U); q(T[y], function(a, b) { this.h = d; m[A].d("script", this.g(a, b), g) }); T[y].l = function() { return this.h }; T[y].j = function() { }; T[y].g = function(a, b) { if (!this.f.versions[":" + a]) { if (this.f.aliases) { var c = this.f.aliases[":" + a]; if (c) a = c } if (!this.f.versions[":" + a]) throw I("Module: '" + this.a + "' with version '" + a + "' not found!"); } a = m[A].GoogleApisBase + "/libs/" + this.a + "/" + a + "/" + this.f.versions[":" + a][b && b.uncompressed ? "uncompressed" : "compressed"]; X("el", this.a); return a };
        T[y].s = function() { return g }; var ea = g, Z = [], fa = (new Date)[w](), X = function(a, b, c) { if (!ea) { P(k, "unload", ga); ea = d } if (c) { if (!m[A].Secure && (!m[A].Options || m[A].Options.csi === g)) { a = a[D]()[s](/[^a-z0-9_.]+/g, "_"); b = b[D]()[s](/[^a-z0-9_.]+/g, "_"); k[z](H($, e, "http://csi.gstatic.com/csi?s=uds&v=2&action=" + h(a) + "&it=" + h(b)), 1E4) } } else { Z[r]("r" + Z[x] + "=" + h(a + (b ? "|" + b : ""))); k[z](ga, Z[x] > 5 ? 0 : 15E3) } }, ga = function() { if (Z[x]) { $(m[A][u] + "/stats?" + Z[C]("&") + "&nc=" + (new Date)[w]() + "_" + ((new Date)[w]() - fa)); Z.length = 0 } }, $ = function(a) {
            var b = new Image,
c = ha++; ia[c] = b; b.onload = b.onerror = function() { delete ia[c] }; b.src = a; b = e
        }, ia = {}, ha = 0; J("google.loader.recordStat", X); J("google.loader.createImageForLogging", $);

    })(); google.loader.rm({ "specs": [{ "name": "books", "baseSpec": { "uri": "http://books.google.com/books/api.js", "ssl": null, "key": { "string": "key" }, "version": { "string": "v" }, "deferred": true, "params": { "callback": { "string": "callback" }, "language": { "string": "hl"}}} }, "feeds", { "name": "friendconnect", "baseSpec": { "uri": "http://www.google.com/friendconnect/script/friendconnect.js", "ssl": null, "key": { "string": "key" }, "version": { "string": "v" }, "deferred": false, "params": {}} }, "spreadsheets", "gdata", "visualization", { "name": "sharing", "baseSpec": { "uri": "http://www.google.com/s2/sharing/js", "ssl": null, "key": { "string": "key" }, "version": { "string": "v" }, "deferred": false, "params": { "language": { "string": "hl"}}} }, "search", { "name": "maps", "baseSpec": { "uri": "http://maps.google.com/maps?file\u003dgoogleapi", "ssl": "https://maps-api-ssl.google.com/maps?file\u003dgoogleapi", "key": { "string": "key" }, "version": { "string": "v" }, "deferred": true, "params": { "callback": { "regex": "callback\u003d$1\u0026async\u003d2" }, "language": { "string": "hl"}} }, "customSpecs": [{ "uri": "http://maps.google.com/maps/api/js", "ssl": null, "key": { "string": "key" }, "version": { "string": "v" }, "deferred": true, "params": { "callback": { "string": "callback" }, "language": { "string": "hl"} }, "pattern": "^(3|3..*)$"}] }, "annotations_v2", "wave", "orkut", { "name": "annotations", "baseSpec": { "uri": "http://www.google.com/reviews/scripts/annotations_bootstrap.js", "ssl": null, "key": { "string": "key" }, "version": { "string": "v" }, "deferred": true, "params": { "callback": { "string": "callback" }, "language": { "string": "hl" }, "country": { "string": "gl"}}} }, "language", "earth", "ads", "elements"] });
    google.loader.rfm({ ":feeds": { "versions": { ":1": "1", ":1.0": "1" }, "path": "/api/feeds/1.0/e291a634414cb5ef1c9f3b5424b8ac4b/", "js": "default+en.I.js", "css": "default.css", "properties": { ":JSHash": "e291a634414cb5ef1c9f3b5424b8ac4b", ":Version": "1.0"} }, ":search": { "versions": { ":1": "1", ":1.0": "1" }, "path": "/api/search/1.0/1aac947333dadc5658de188fa668170f/", "js": "default+en.I.js", "css": "default.css", "properties": { ":JSHash": "1aac947333dadc5658de188fa668170f", ":NoOldNames": false, ":Version": "1.0"} }, ":language": { "versions": { ":1": "1", ":1.0": "1" }, "path": "/api/language/1.0/007dc8a143947a38d213ea1103bda0d5/", "js": "default+en.I.js", "properties": { ":JSHash": "007dc8a143947a38d213ea1103bda0d5", ":Version": "1.0"} }, ":wave": { "versions": { ":1": "1", ":1.0": "1" }, "path": "/api/wave/1.0/6c1a0c5d2e5c4559cda97c32592213f8/", "js": "default.I.js", "properties": { ":JSHash": "6c1a0c5d2e5c4559cda97c32592213f8", ":Version": "1.0"} }, ":spreadsheets": { "versions": { ":0": "1", ":0.3": "1" }, "path": "/api/spreadsheets/0.3/8331b0bbcc74776270648505340e9200/", "js": "default.I.js", "properties": { ":JSHash": "8331b0bbcc74776270648505340e9200", ":Version": "0.3"} }, ":earth": { "versions": { ":1": "1", ":1.0": "1" }, "path": "/api/earth/1.0/adebf52d05a2cfff1db62bf5ad31980d/", "js": "default.I.js", "properties": { ":JSHash": "adebf52d05a2cfff1db62bf5ad31980d", ":Version": "1.0"} }, ":annotations": { "versions": { ":1": "1", ":1.0": "1" }, "path": "/api/annotations/1.0/00a4112600f0cbe27c3c39c9b9e70f1f/", "js": "default+en.I.js", "properties": { ":JSHash": "00a4112600f0cbe27c3c39c9b9e70f1f", ":Version": "1.0"}} });
    google.loader.rpl({ ":scriptaculous": { "versions": { ":1.8.3": { "uncompressed": "scriptaculous.js", "compressed": "scriptaculous.js" }, ":1.8.2": { "uncompressed": "scriptaculous.js", "compressed": "scriptaculous.js" }, ":1.8.1": { "uncompressed": "scriptaculous.js", "compressed": "scriptaculous.js"} }, "aliases": { ":1.8": "1.8.3", ":1": "1.8.3"} }, ":yui": { "versions": { ":2.6.0": { "uncompressed": "build/yuiloader/yuiloader.js", "compressed": "build/yuiloader/yuiloader-min.js" }, ":2.7.0": { "uncompressed": "build/yuiloader/yuiloader.js", "compressed": "build/yuiloader/yuiloader-min.js" }, ":2.8.0r4": { "uncompressed": "build/yuiloader/yuiloader.js", "compressed": "build/yuiloader/yuiloader-min.js"} }, "aliases": { ":2": "2.8.0r4", ":2.7": "2.7.0", ":2.6": "2.6.0", ":2.8": "2.8.0r4", ":2.8.0": "2.8.0r4"} }, ":swfobject": { "versions": { ":2.1": { "uncompressed": "swfobject_src.js", "compressed": "swfobject.js" }, ":2.2": { "uncompressed": "swfobject_src.js", "compressed": "swfobject.js"} }, "aliases": { ":2": "2.2"} }, ":ext-core": { "versions": { ":3.1.0": { "uncompressed": "ext-core-debug.js", "compressed": "ext-core.js" }, ":3.0.0": { "uncompressed": "ext-core-debug.js", "compressed": "ext-core.js"} }, "aliases": { ":3": "3.1.0", ":3.0": "3.0.0", ":3.1": "3.1.0"} }, ":mootools": { "versions": { ":1.2.3": { "uncompressed": "mootools.js", "compressed": "mootools-yui-compressed.js" }, ":1.1.1": { "uncompressed": "mootools.js", "compressed": "mootools-yui-compressed.js" }, ":1.2.4": { "uncompressed": "mootools.js", "compressed": "mootools-yui-compressed.js" }, ":1.2.1": { "uncompressed": "mootools.js", "compressed": "mootools-yui-compressed.js" }, ":1.2.2": { "uncompressed": "mootools.js", "compressed": "mootools-yui-compressed.js" }, ":1.1.2": { "uncompressed": "mootools.js", "compressed": "mootools-yui-compressed.js"} }, "aliases": { ":1": "1.1.2", ":1.11": "1.1.1", ":1.2": "1.2.4", ":1.1": "1.1.2"} }, ":jqueryui": { "versions": { ":1.7.2": { "uncompressed": "jquery-ui.js", "compressed": "jquery-ui.min.js" }, ":1.6.0": { "uncompressed": "jquery-ui.js", "compressed": "jquery-ui.min.js" }, ":1.7.0": { "uncompressed": "jquery-ui.js", "compressed": "jquery-ui.min.js" }, ":1.7.1": { "uncompressed": "jquery-ui.js", "compressed": "jquery-ui.min.js" }, ":1.5.3": { "uncompressed": "jquery-ui.js", "compressed": "jquery-ui.min.js" }, ":1.8.0": { "uncompressed": "jquery-ui.js", "compressed": "jquery-ui.min.js" }, ":1.5.2": { "uncompressed": "jquery-ui.js", "compressed": "jquery-ui.min.js"} }, "aliases": { ":1.8": "1.8.0", ":1.7": "1.7.2", ":1.6": "1.6.0", ":1": "1.8.0", ":1.5": "1.5.3"} }, ":chrome-frame": { "versions": { ":1.0.2": { "uncompressed": "CFInstall.js", "compressed": "CFInstall.min.js" }, ":1.0.1": { "uncompressed": "CFInstall.js", "compressed": "CFInstall.min.js" }, ":1.0.0": { "uncompressed": "CFInstall.js", "compressed": "CFInstall.min.js"} }, "aliases": { ":1": "1.0.2", ":1.0": "1.0.2"} }, ":prototype": { "versions": { ":1.6.0.2": { "uncompressed": "prototype.js", "compressed": "prototype.js" }, ":1.6.1.0": { "uncompressed": "prototype.js", "compressed": "prototype.js" }, ":1.6.0.3": { "uncompressed": "prototype.js", "compressed": "prototype.js"} }, "aliases": { ":1.6.1": "1.6.1.0", ":1": "1.6.1.0", ":1.6": "1.6.1.0", ":1.6.0": "1.6.0.3"} }, ":jquery": { "versions": { ":1.2.3": { "uncompressed": "jquery.js", "compressed": "jquery.min.js" }, ":1.3.1": { "uncompressed": "jquery.js", "compressed": "jquery.min.js" }, ":1.3.0": { "uncompressed": "jquery.js", "compressed": "jquery.min.js" }, ":1.3.2": { "uncompressed": "jquery.js", "compressed": "jquery.min.js" }, ":1.2.6": { "uncompressed": "jquery.js", "compressed": "jquery.min.js" }, ":1.4.0": { "uncompressed": "jquery.js", "compressed": "jquery.min.js" }, ":1.4.1": { "uncompressed": "jquery.js", "compressed": "jquery.min.js" }, ":1.4.2": { "uncompressed": "jquery.js", "compressed": "jquery.min.js"} }, "aliases": { ":1": "1.4.2", ":1.4": "1.4.2", ":1.3": "1.3.2", ":1.2": "1.2.6"} }, ":dojo": { "versions": { ":1.2.3": { "uncompressed": "dojo/dojo.xd.js.uncompressed.js", "compressed": "dojo/dojo.xd.js" }, ":1.3.1": { "uncompressed": "dojo/dojo.xd.js.uncompressed.js", "compressed": "dojo/dojo.xd.js" }, ":1.1.1": { "uncompressed": "dojo/dojo.xd.js.uncompressed.js", "compressed": "dojo/dojo.xd.js" }, ":1.3.0": { "uncompressed": "dojo/dojo.xd.js.uncompressed.js", "compressed": "dojo/dojo.xd.js" }, ":1.3.2": { "uncompressed": "dojo/dojo.xd.js.uncompressed.js", "compressed": "dojo/dojo.xd.js" }, ":1.2.0": { "uncompressed": "dojo/dojo.xd.js.uncompressed.js", "compressed": "dojo/dojo.xd.js" }, ":1.4.0": { "uncompressed": "dojo/dojo.xd.js.uncompressed.js", "compressed": "dojo/dojo.xd.js" }, ":1.4.1": { "uncompressed": "dojo/dojo.xd.js.uncompressed.js", "compressed": "dojo/dojo.xd.js"} }, "aliases": { ":1": "1.4.1", ":1.4": "1.4.1", ":1.3": "1.3.2", ":1.2": "1.2.3", ":1.1": "1.1.1"}} });
}
/**
* Copyright (c) 2008 Google Inc.
*
* You are free to copy and use this sample.
* License can be found here: http://code.google.com/apis/ajaxsearch/faq/#license
*/

/**
* @fileoverview A feed gadget based on the AJAX Feed API.
* @author dcollison@google.com (Derek Collison)
*/

/**
* GFdynamicFeedControl
* @param {String} feed The feed URL.
* @param {String|Object} container Either the id string or the element itself.
* @param {Object} options Options map.
* @constructor
*/

function GFdynamicFeedControl(feedUrls, container, options) {
    // node elements.
    this.nodes = {};
    this.collapseElements = [];

    // the feeds.
    this.feeds = [];
    this.results = [];

    if (typeof feedUrls == 'string') {
        this.feeds.push({ url: feedUrls });
    } else if (typeof feedUrls == 'object') {
        for (var i = 0; i < feedUrls.length; i++) {
            var entry = feedUrls[i];
            var o = {};
            var feedUrl;
            if (typeof entry == 'string') {
                o.url = feedUrls[i];
            } else if (typeof entry == 'object') {
                o = feedUrls[i];
                if (o && o.title) {
                    var s = o.title;
                    o.title = s.replace(/</g, '&lt;').replace(/>/g, '&gt;');
                }
            }
            this.feeds.push(o);
        }
    }

    if (typeof container == "string") {
        container = document.getElementById(container);
    }
    this.parseOptions_(options);
    this.setup_(container);
}

/*
* Default time in milliseconds for the feed to be reloaded.
* @type Number
*/
GFdynamicFeedControl.DEFAULT_NUM_RESULTS = 4;
/*
* Default time in milliseconds for the feed to be reloaded.
* @type Number
*/
GFdynamicFeedControl.DEFAULT_FEED_CYCLE_TIME = 1800000;
/*
* Default display time in milliseconds for each entry.
* @type Number
*/
GFdynamicFeedControl.DEFAULT_DISPLAY_TIME = 5000;
/*
* Default fadeout transition time in milliseconds for each entry.
* @type Number
*/
GFdynamicFeedControl.DEFAULT_FADEOUT_TIME = 1000;
/*
* Default time between transition steps in milliseconds
* @type Number
*/
GFdynamicFeedControl.DEFAULT_TRANSISTION_STEP = 40;
/*
* Default hover time in milliseconds for each entry.
* @type Number
*/
GFdynamicFeedControl.DEFAULT_HOVER_TIME = 100;

/**
* Setup default option map and apply overrides from constructor.
* @param {Object} options Options map.
* @private
*/
GFdynamicFeedControl.prototype.parseOptions_ = function(options) {
    // Default Options
    // TODO(dcollison) - implement Feed Cycle.
    this.options = {
        numResults: GFdynamicFeedControl.DEFAULT_NUM_RESULTS,
        feedCycleTime: GFdynamicFeedControl.DEFAULT_FEED_CYCLE_TIME,
        linkTarget: google.feeds.LINK_TARGET_BLANK,
        displayTime: GFdynamicFeedControl.DEFAULT_DISPLAY_TIME,
        transitionTime: GFdynamicFeedControl.DEFAULT_TRANSISTION_TIME,
        transitionStep: GFdynamicFeedControl.DEFAULT_TRANSISTION_STEP,
        fadeOutTime: GFdynamicFeedControl.DEFAULT_FADEOUT_TIME,
        scrollOnFadeOut: true,
        pauseOnHover: true,
        hoverTime: GFdynamicFeedControl.DEFAULT_HOVER_TIME,
        autoCleanup: true,
        transitionCallback: null,
        feedTransitionCallback: null,
        feedLoadCallback: null,
        collapseable: false,
        sortByDate: false,
        horizontal: false,
        stacked: false,
        title: null
    };

    if (options) {
        for (var o in this.options) {
            if (typeof options[o] != 'undefined') {
                this.options[o] = options[o];
            }
        }
    }

    // Cant be collapseable unless stacked
    if (!this.options.stacked) {
        this.options.collapseable = false;
    }

    // Override strange/bad options
    this.options.displayTime = Math.max(200, this.options.displayTime);
    this.options.fadeOutTime = Math.max(0, this.options.fadeOutTime);

    // Calculated
    var ts = this.options.fadeOutTime / this.options.transitionStep;
    this.fadeOutDelta = Math.min(1, (1.0 / ts));

    // Flag to start
    this.started = false;
};

/**
* Basic setup.
* @private
*/
GFdynamicFeedControl.prototype.setup_ = function(container) {
    if (container == null) return;
    this.nodes.container = container;

    // Browser fun.
    if (window.ActiveXObject) {
        this.ie = this[window.XMLHttpRequest ? 'ie7' : 'ie6'] = true;
    } else if (document.childNodes && !document.all && !navigator.taintEnabled) {
        this.safari = true;
    } else if (document.getBoxObjectFor != null) {
        this.gecko = true;
    }
    // The feedControl instance for generating entry HTML.
    this.feedControl = new google.feeds.FeedControl();
    this.feedControl.setLinkTarget(this.options.linkTarget);

    // The feeds
    this.expected = this.feeds.length;
    this.errors = 0;

    for (var i = 0; i < this.feeds.length; i++) {
        var feed = new google.feeds.Feed(this.feeds[i].url);
        feed.setResultFormat(google.feeds.Feed.JSON_FORMAT);
        feed.setNumEntries(this.options.numResults);
        feed.load(this.bind_(this.feedLoaded_, i));
    }
};

/**
* Helper method to bind this instance correctly.
* @param {Object} method function/method to bind.
* @return {Function}
* @private
*/
GFdynamicFeedControl.prototype.bind_ = function(method) {
    var self = this;
    var opt_args = [].slice.call(arguments, 1);
    return function() {
        var args = opt_args.concat([].slice.call(arguments));
        return method.apply(self, args);
    }
};

/**
* Callback associated with the AJAX Feed api after load.
* @param {Object} result Loaded result.
* @private
*/
GFdynamicFeedControl.prototype.feedLoaded_ = function(index, result) {
    if (this.options.feedLoadCallback) {
        this.options.feedLoadCallback(result);
    }
    if (result.error) {
        // Ignore failed feeds for the most part.
        // The user has control through the feedLoadCallback above
        // if they choose to do something more createive.
        // Only complain if we can't load anything.
        if (++this.errors >= this.expected) {
            this.nodes.container.innerHTML = 'Feed' + ((this.expected > 1) ? 's ' : ' ') +
                                       'could not be loaded.';
        }
        return;
    }
    // Override of title option.
    if (this.feeds[index].title) {
        result.feed.title = this.feeds[index].title;
    }
    this.results.push(result);

    if (!this.started) {
        this.createSubContainers_();
        this.displayResult_(0);
    } else if (!this.options.horizontal && this.options.stacked) {
        this.addResult_(this.results.length - 1);
    }
};

/**
* Insert blog in correct place
* @private
*/
GFdynamicFeedControl.prototype.sortByDate_ = function(resultIndex, newTitle,
                                                      newList) {
    // if sorting by date, insert it into the correct spot
    var newEntryDate = this.results[resultIndex].feed.entries[0].publishedDate;
    var newEntryDateMS = Date.parse(newEntryDate);
    var insertIndex = null;

    for (var i = 0; i < this.results.length; i++) {
        var mostRecentPost = this.results[i].feed.entries[0].publishedDate;
        var mostRecentPostMS = Date.parse(mostRecentPost);
        if (newEntryDateMS > mostRecentPostMS) {
            insertIndex = i;
            break;
        }
    }

    // If it's most stale blog, just append as usual
    if (insertIndex == null) {
        this.nodes.root.appendChild(newTitle);
        this.nodes.root.appendChild(newList);
        this.createListEntries_(resultIndex, newList);
        return;
    }

    // If it is fresher than a blog, insert to correct position
    var insertBeforeIndex = 2 + (insertIndex * 2);
    var swapToIndex = insertBeforeIndex + 2;
    var tempSwap = null;
    var myResultIndex = resultIndex + 1;

    var sectionsToChange = this.nodes.root.childNodes;
    var nodeToInsertBefore = sectionsToChange[insertBeforeIndex];

    this.nodes.root.insertBefore(newTitle, nodeToInsertBefore);
    this.nodes.root.insertBefore(newList, nodeToInsertBefore);

    this.results.splice(insertIndex, 0, this.results[resultIndex]);
    this.results.splice(myResultIndex, 1);

    var nodesToChangeClick = sectionsToChange[swapToIndex].nextSibling.childNodes;

    this.createListEntries_(insertIndex, newList);

    // Keep freshest blog open first
    if (insertIndex == 0) {
        this.displayResult_(0);
    }

    insertIndex += 1;
    // Reset all of the onmousehover listeners to highlight corect index
    for (var i = swapToIndex; i < sectionsToChange.length; i += 2) {
        var nodesToChangeClick = sectionsToChange[i].nextSibling.childNodes;
        for (var j = 0; j < nodesToChangeClick.length; j++) {
            nodesToChangeClick[j].onmouseover = this.bind_(this.listMouseOver_,
                                                     insertIndex, j);
            nodesToChangeClick[j].onmouseout = this.bind_(this.listMouseOut_,
                                                    insertIndex, j);
        }
        insertIndex++;
    }
};

/**
* Setup to display the Result for stacked mode
* @private
*/
GFdynamicFeedControl.prototype.addResult_ = function(resultIndex) {
    var result = this.results[resultIndex];
    var newTitle = this.createDiv_('gfg-subtitle');
    this.setTitle_(result.feed, newTitle);
    var newList = this.createDiv_('gfg-list');

    // add a collapseable button
    if (this.options.collapseable) {
        var collapseLink = document.createElement('div');
        newList.style.display = 'none';
        collapseLink.className = 'gfg-collapse-closed';
        newTitle.appendChild(collapseLink);
        collapseLink.onclick = this.toggleCollapse(this, newList, collapseLink);
        this.collapseElements.push({
            list: newList,
            collapse: collapseLink
        });
    }


    var clearFloat = document.createElement('div');
    clearFloat.className = 'clearFloat';
    newTitle.appendChild(clearFloat);

    // If not sorting by date, add them as usual
    if (!this.options.sortByDate) {
        this.nodes.root.appendChild(newTitle);
        this.nodes.root.appendChild(newList);
        this.createListEntries_(resultIndex, newList);
    } else {
        this.sortByDate_(resultIndex, newTitle, newList);
    }

};

/**
* Setup to display the Result
* @private
*/
GFdynamicFeedControl.prototype.displayResult_ = function(resultIndex) {
    this.resultIndex = resultIndex;
    var result = this.results[resultIndex];
    if (this.options.feedTransitionCallback) {
        this.options.feedTransitionCallback(result);
    }
    if (this.options.title) {
        this.setPlainTitle_(this.options.title);
    } else {
        this.setTitle_(result.feed);
    }
    this.clearNode_(this.nodes.entry);

    if (this.started && !this.options.horizontal && this.options.stacked) {
        this.entries = result.feed.entries;
    } else {
        this.createListEntries_(resultIndex, this.nodes.list);
    }
    this.displayEntries_();
}

/**
* Set the Title to just plaintext
* @private
*/
GFdynamicFeedControl.prototype.setPlainTitle_ = function(title, opt_element) {
    var el = opt_element || this.nodes.title;
    el.innerHTML = title;
}

/**
* Set the Title
* @private
*/
GFdynamicFeedControl.prototype.setTitle_ = function(resultFeed, opt_element) {
    var el = opt_element || this.nodes.title;
    this.clearNode_(el);
    var link = document.createElement('a');
    link.target = google.feeds.LINK_TARGET_BLANK;
    link.href = resultFeed.link;
    link.className = 'gfg-collapse-href';
    link.innerHTML = resultFeed.title;
    el.appendChild(link);
}

GFdynamicFeedControl.prototype.toggleCollapse = function(feedControl,
                                                         listReference,
                                                         collapseLink) {
    return function() {
        var els = feedControl.collapseElements;
        for (var i = 0; i < els.length; i++) {
            var el = els[i];
            el.list.style.display = 'none';
            el.collapse.className = 'gfg-collapse-closed';
        }
        listReference.style.display = 'block';
        collapseLink.className = 'gfg-collapse-open';
    }
}

/**
* Create the list Entries
* @private
*/
GFdynamicFeedControl.prototype.createListEntries_ = function(resultIndex, node) {
    var entries = this.results[resultIndex].feed.entries;
    this.clearNode_(node);
    for (var i = 0; i < entries.length; i++) {
        this.feedControl.createHtml(entries[i]);
        var className = 'gfg-listentry ';
        className += (i % 2) ? 'gfg-listentry-even' : 'gfg-listentry-odd';
        var listEntry = this.createDiv_(className);
        var link = this.createLink_(entries[i].link,
                                entries[i].title,
                                this.options.linkTarget);
        listEntry.appendChild(link);
        if (this.options.pauseOnHover) {
            listEntry.onmouseover = this.bind_(this.listMouseOver_, resultIndex, i);
            listEntry.onmouseout = this.bind_(this.listMouseOut_, resultIndex, i);
        }
        entries[i].listEntry = listEntry;
        node.appendChild(listEntry);
    }
    if (node == this.nodes.list) {
        this.entries = entries;
    }
}

/**
* Begin to display the entries.
* @private
*/
GFdynamicFeedControl.prototype.displayEntries_ = function() {
    this.entryIndex = 0;
    this.displayCurrentEntry_();
    this.setDisplayTimer_();
    this.started = true;
}

/**
* Display next entry.
* @private
*/
GFdynamicFeedControl.prototype.displayNextEntry_ = function() {
    // Check to see if we have been orphaned and need to cleanup..
    if (this.options.autoCleanup && this.isOrphaned_()) {
        this.cleanup_();
        return;
    }

    if (++this.entryIndex >= this.entries.length) {
        // End of list, see if we should rotate feeds..
        if (this.results.length > 1) {
            if (++this.resultIndex >= this.results.length) {
                this.resultIndex = 0;
            }
            this.displayResult_(this.resultIndex);
            return;
        } else {
            this.entryIndex = 0;
        }
    }

    if (this.options.transitionCallback) {
        this.options.transitionCallback(this.entries[this.entryIndex]);
    }
    this.displayCurrentEntry_();
    this.setDisplayTimer_();
}

/**
* Display current entry.
* @private
*/
GFdynamicFeedControl.prototype.displayCurrentEntry_ = function() {
    this.clearNode_(this.nodes.entry);
    this.current = this.entries[this.entryIndex].html;
    this.current.style.top = '0px';
    this.nodes.entry.appendChild(this.current);
    this.createOverlay_();

    // Expand the blog who's post is being displayed
    if (this.options.collapseable) {
        var feedTitle = null;

        for (var i = 0; i < this.results.length; i++) {
            if (this.results[i].feed.entries == this.entries) {
                feedTitle = this.results[i].feed.title;
            }
        }

        var els = this.collapseElements;

        for (var i = 0; i < els.length; i++) {
            var el = els[i];
            var divfeedTitle = el.collapse.previousSibling.innerHTML;
            var expandClicker = el.collapse;
            if (feedTitle == divfeedTitle) {
                if (this.ie) {
                    expandClicker.click();
                } else {
                    expandClicker.onclick();
                }

            }
        }
    }

    if (this.currentList) {
        var className = 'gfg-listentry ';
        className += (this.currentListIndex % 2) ?
        'gfg-listentry-even' : 'gfg-listentry-odd';
        this.currentList.className = className;
    }
    this.currentList = this.entries[this.entryIndex].listEntry;
    this.currentListIndex = this.entryIndex;
    var className = 'gfg-listentry gfg-listentry-highlight ';
    className += (this.currentListIndex % 2) ?
       'gfg-listentry-even' : 'gfg-listentry-odd';
    this.currentList.className = className;
}

/**
* Simulated mouse hover events for list entries.
* @private
*/
GFdynamicFeedControl.prototype.listMouseHover_ = function(resultIndex,
                                                          listIndex) {
    var result = this.results[resultIndex];
    var listEntry = result.feed.entries[listIndex].listEntry;
    listEntry.selectTimer = null;
    this.clearTransitionTimer_();
    this.clearDisplayTimer_();
    this.resultIndex = resultIndex;
    this.entries = result.feed.entries;
    this.entryIndex = listIndex;
    this.displayCurrentEntry_();
}

/**
* Mouse over events for list entries.
* @private
*/
GFdynamicFeedControl.prototype.listMouseOver_ = function(resultIndex,
                                                         listIndex) {
    var result = this.results[resultIndex];
    var listEntry = result.feed.entries[listIndex].listEntry;
    var cb = this.bind_(this.listMouseHover_, resultIndex, listIndex);
    listEntry.selectTimer = setTimeout(cb, this.options.hoverTime);
}

/**
* Mouse out events for list entries.
* @private
*/
GFdynamicFeedControl.prototype.listMouseOut_ = function(resultIndex, listIndex) {
    var result = this.results[resultIndex];
    var listEntry = result.feed.entries[listIndex].listEntry;
    if (listEntry.selectTimer) {
        clearTimeout(listEntry.selectTimer);
        listEntry.selectTimer = null;
    } else {
        this.setDisplayTimer_();
    }
}

/**
* Mouse over events for main entry.
* @private
*/
GFdynamicFeedControl.prototype.entryMouseOver_ = function(e) {
    this.clearDisplayTimer_();
    if (this.transitionTimer) {
        this.clearTransitionTimer_();
        this.displayCurrentEntry_();
    }
}

/**
* Mouse out events for main entry.
* @private
*/
GFdynamicFeedControl.prototype.entryMouseOut_ = function(e) {
    this.setDisplayTimer_();
}

/**
* Create the overlay div. This hack is for IE and transparency effects.
* @private
*/
GFdynamicFeedControl.prototype.createOverlay_ = function() {
    if (this.current == null) return;
    // Create div lazily and hold on to it..
    if (this.overlay == null) {
        var overlay = this.createDiv_('gfg-entry');
        overlay.style.position = 'absolute';
        overlay.style.top = '0px';
        overlay.style.left = '0px';
        this.overlay = overlay;
    }
    this.setOpacity_(this.overlay, 0);
    this.nodes.entry.appendChild(this.overlay);
}

/**
* Sets the display timer.
* @private
*/
GFdynamicFeedControl.prototype.setDisplayTimer_ = function() {
    if (this.displayTimer) {
        this.clearDisplayTimer_();
    }
    var cb = this.bind_(this.setFadeOutTimer_);
    this.displayTimer = setTimeout(cb, this.options.displayTime);
};

/**
* Class helper method for the time now in milliseconds
* @private
*/
GFdynamicFeedControl.timeNow = function() {
    var d = new Date();
    return d.getTime();
};

/**
* Transition animation for fadeout. Cleanup when finished.
* @private
*/
GFdynamicFeedControl.prototype.fadeOutEntry_ = function() {
    if (this.overlay) {
        var delta = this.fadeOutDelta;
        var ts = this.options.transitionStep;
        var now = GFdynamicFeedControl.timeNow();
        var tick = now - this.lastTick;
        this.lastTick = now;
        delta *= (tick / ts);

        var op = this.overlay.opacity + delta;
        // Overlay opacity
        this.setOpacity_(this.overlay, op);
        // Scroll down
        if (this.options.scrollOnFadeOut && (op > .5)) {
            var r = (op - .5) * 2;
            var newTop = Math.round(this.current.offsetHeight * r);
            this.current.style.top = newTop + 'px';
        }
        if (op < 1) return;
    }
    // Finished.
    this.clearTransitionTimer_();
    this.displayNextEntry_();
};

/**
* Sets the transition timer for fadeout.
* @private
*/
GFdynamicFeedControl.prototype.setFadeOutTimer_ = function() {
    this.clearTransitionTimer_();
    this.lastTick = GFdynamicFeedControl.timeNow();
    var cb = this.bind_(this.fadeOutEntry_);
    this.transitionTimer = setInterval(cb, this.options.transitionStep);
};

/**
* Clear the transition timer. Used to prevent leaks.
* @private
*/
GFdynamicFeedControl.prototype.clearTransitionTimer_ = function() {
    if (this.transitionTimer) {
        clearInterval(this.transitionTimer);
        this.transitionTimer = null;
    }
};

/**
* Clear the display timer.
* @private
*/
GFdynamicFeedControl.prototype.clearDisplayTimer_ = function() {
    if (this.displayTimer) {
        clearTimeout(this.displayTimer);
        this.displayTimer = null;
    }
};

/**
* Setup our own subcontainer to the user supplied container.
* @private
*/
GFdynamicFeedControl.prototype.createSubContainers_ = function() {
    var nodes = this.nodes;
    var container = this.nodes.container;

    this.clearNode_(container);
    if (this.options.horizontal) {
        container = this.createDiv_('gfg-horizontal-container');
        nodes.root = this.createDiv_('gfg-horizontal-root');
        this.nodes.container.appendChild(container);
    } else {
        nodes.root = this.createDiv_('gfg-root');
    }
    nodes.title = this.createDiv_('gfg-title');
    nodes.entry = this.createDiv_('gfg-entry');
    nodes.list = this.createDiv_('gfg-list');
    nodes.root.appendChild(nodes.title);
    nodes.root.appendChild(nodes.entry);

    if (!this.options.horizontal && this.options.stacked) {
        var newTitle = this.createDiv_('gfg-subtitle');
        nodes.root.appendChild(newTitle);
        this.setTitle_(this.results[0].feed, newTitle);

        if (this.options.collapseable) {
            var collapseLink = document.createElement('div');
            collapseLink.className = 'gfg-collapse-open';
            newTitle.appendChild(collapseLink);
            collapseLink.onclick = this.toggleCollapse(this, nodes.list, collapseLink);
            this.collapseElements.push({
                list: nodes.list,
                collapse: collapseLink
            });
            nodes.list.style.display = 'block';
        }

        var clearFloat = document.createElement('div');
        clearFloat.className = 'clearFloat';
        newTitle.appendChild(clearFloat);
    }

    nodes.root.appendChild(nodes.list);
    container.appendChild(nodes.root);

    if (this.options.pauseOnHover) {
        nodes.entry.onmouseover = this.bind_(this.entryMouseOver_);
        nodes.entry.onmouseout = this.bind_(this.entryMouseOut_);
    }

    // Add Branding.
    if (this.options.horizontal) {
        nodes.branding = this.createDiv_('gfg-branding');
        google.feeds.getBranding(nodes.branding, google.feeds.VERTICAL_BRANDING);
        container.appendChild(nodes.branding);
    }
};

/**
* Helper method to properly clear a node and its children.
* @param {Object} node Node to clear.
* @private
*/
GFdynamicFeedControl.prototype.clearNode_ = function(node) {
    if (node == null) return;
    var child;
    while ((child = node.firstChild)) {
        node.removeChild(child);
    }
};

/**
* Helper method to create a div with optional class and text.
* @param {String} opt_className Optional className for the div.
* @param {String} opt_text Optional text for the innerHTML.
* @private
*/
GFdynamicFeedControl.prototype.createDiv_ = function(opt_className, opt_text) {
    var el = document.createElement("div");
    if (opt_text) {
        el.innerHTML = opt_text;
    }
    if (opt_className) { el.className = opt_className; }
    return el;
};

/**
* Helper method to create a link with href and text.
* @param {String} href Href URL
* @param {String} text text for the link.
* @param {String} opt_target Optional link target.
* @private
*/
GFdynamicFeedControl.prototype.createLink_ = function(href, text, opt_target) {
    var link = document.createElement('a');
    link.href = href;
    link.innerHTML = text;
    if (opt_target) {
        link.target = opt_target;
    }
    return link;
};

/**
* Cleanup results on being orphaned.
* @private
*/
GFdynamicFeedControl.prototype.clearResults_ = function() {
    for (var i = 0; i < this.results.length; i++) {
        var result = this.results[i];
        var entries = result.feed.entries;
        for (var i = 0; i < entries.length; i++) {
            var entry = entries[i];
            entry.html = null;
            entry.listEntry.onmouseover = null;
            entry.listEntry.onmouseout = null;
            if (entry.listEntry.selectTimer) {
                clearTimeout(entry.listEntry.selectTimer);
                entry.listEntry.selectTimer = null;
            }
            entry.listEntry = null;
        }
    }
}

/**
* Check for being orphaned.
* @private
*/
GFdynamicFeedControl.prototype.isOrphaned_ = function() {
    var root = this.nodes.root;
    var orphaned = false;
    if (!root || !root.parentNode) {
        orphaned = true;
    } else if (this.options.horizontal && !root.parentNode.parentNode) {
        orphaned = true;
    }
    return orphaned;
}

/**
* Cleanup on being orphaned.
* @private
*/
GFdynamicFeedControl.prototype.cleanup_ = function() {
    this.started = false;
    // Timer Events.
    this.clearDisplayTimer_();
    this.clearTransitionTimer_();
    // Structures
    this.clearResults_();
    // Nodes
    this.clearNode_(this.nodes.root);
    this.nodes.container = null;
}

/**
* Helper method to set opacity for nodes.. Also takes into account
* visibility in general.
* @param {Element} node element.
* @param {Number} opacity alpha level.
* @private
*/
GFdynamicFeedControl.prototype.setOpacity_ = function(node, opacity) {
    if (node == null) return;
    opacity = Math.max(0, Math.min(1, opacity));
    if (opacity == 0) {
        if (node.style.visibility != 'hidden') {
            node.style.visibility = 'hidden';
        }
    } else {
        if (node.style.visibility != 'visible') {
            node.style.visibility = 'visible';
        }
    }
    if (this.ie) {
        var normalized = Math.round(opacity * 100);
        node.style.filter = 'alpha(opacity=' + normalized + ')';
    }
    node.style.opacity = node.opacity = opacity;
};

GFgadget = GFdynamicFeedControl;

function LoadDynamicFeedControl() {
    var feeds = [{ title: 'AXANI Blog', url: 'http://blog.axani.co.uk/feed/'}];
    var options = {
        stacked: false,
        horizontal: true,
        title: "",
        numResults: '2'
    }
    new GFdynamicFeedControl(feeds, 'feed-control', options);
}
google.load('feeds', '1');
google.setOnLoadCallback(LoadDynamicFeedControl);