
var LiveBar={};var LiveWorld={};LiveBar.window_location_search=window.location.search;LiveBar.window_location_host=window.location.host;LiveBar.widgets_only=true;LiveBar.Callbacks={};LiveBar.get_tenant_id=function()
{return'24632931';};LiveBar.set_session_id=function(session_key,session_id){LiveBar.create_cookie('session_key',session_key);LiveBar.create_cookie('session_id',session_id);LiveBar.default_url_builder_options.append_callback=function(){return LiveBar.get_session_key()+"="+LiveBar.get_session_id();}}
LiveBar.get_session_id=function(){return LiveBar.read_cookie('session_id');}
LiveBar.get_session_key=function(){return LiveBar.read_cookie('session_key');}
LiveBar.Tenant={tenant_id:LiveBar.get_tenant_id(),livebar_server_domain:'curator.liveworld.com',livebar_widget_update_interval:20000,aggregate_widget_update_interval:30000,livebar_server_port:'',jsonp_callback_function:'livebar_jc',livebar_server_base_url:'',get_livebar_server_base_url:function(){return'http://curator.liveworld.com';}};LiveWorld.ga_enabled=true;LiveWorld.ga_account='UA-22975231-1';LiveWorld.tenant_metrics_url='http://curator.liveworld.com/tenants/24632931/metrics';/**
 * Put a cookie on the user's browser. If a user resizes LiveBar the new size is stored in a cookie
 * and that size setting persists as long as the cookie is present. See {@link LiveBar.Dimensions} for
 * more explanation.
 *
 * @param {String} name Cookie name.
 * @param {String} value Value to store.
 * @param {Int} days Optional - how long until it expires.
 */
LiveBar.create_cookie = function(name, value, days) {

  // if a number of days has been included in the call, calculate the expiration,
  // otherwise no expiration.
  if (days) {
    var date = new Date();
    date.setTime(date.getTime() + (days*24*60*60*1000));
    var expires = "; expires=" + date.toGMTString();
  } else {
    var expires = "";
  }
  document.cookie = name + "=" + value + expires + "; path=/";
};

/**
 * Looks for param name in browser cookies and returns value if present; null if not.
 *
 * @param {String} name Key to value to return.
 * @returns {String} or {null} Depending on success
 */
LiveBar.read_cookie = function(name) {
  var nameEQ = name + "=";
  var ca = document.cookie.split(';');
  for (var i=0;i < ca.length;i++) {
    var c = ca[i];
    while (c.charAt(0)==' ') {
      c = c.substring(1,c.length);
    }
    if (c.indexOf(nameEQ) == 0) {
      return c.substring(nameEQ.length,c.length);
    }
  }
  return null;
}

// default options for building URLs (applied as query params, except for the
// special append_callback which is called, and the result appended as a query
// param).
LiveBar.default_url_builder_options = {};

// assemble the url
LiveBar.Tenant.livebar_server_base_url = LiveBar.Tenant.get_livebar_server_base_url();

/**
 * Simple function to assemble a LiveBar URL from a hash of options.
 *
 * Optional:
 * -options.host (the fully-formed address to the server, including protocol and if needed, port)
 * -options.path (specific url path including filename, to be appended to options.host)
 * -options.query (url parameters, can be a single string or number (somefile.ext?12335) or an iteratable structure of key:value pairs
 *
 * @param Object options Required parameter to asseble URL.
 */
LiveBar.url_builder = function(options) {
  var formed_url = (typeof options.host != 'undefined') ? options.host : LiveBar.Tenant.livebar_server_base_url;  
  formed_url += (options.path) ? options.path : '';
  params = '?tenant_id=' + LiveBar.Tenant.tenant_id;
  params += '&' + LiveBar.get_session_key() + '=' + LiveBar.get_session_id();
  // merge default options
  for (i in LiveBar.default_url_builder_options) {
    if (options[i] == undefined) {
      options[i] = LiveBar.default_url_builder_options[i];
    }
  }
  // append the callback params if it's been set
  if (options.append_callback != undefined && typeof options.append_callback == 'function') {  
    params += '&' + options.append_callback();
    delete options.append_callback;    
  }
  if (options.query) {
    if (typeof options.query == 'string' || typeof options.query == 'number') {
      params += '&' + encodeURI(options.query);
    } else {
      for (i in options.query) {
        params += '&' + i + '=' + encodeURI(options.query[i]);
      }
    }
  }
  
  params += '&t=' + (+new Date());
  
  return formed_url + params;
};
widget_hide_css_node=document.createElement('link');widget_hide_css_node.type='text/css';widget_hide_css_node.rel='Stylesheet';widget_hide_css_node.href=LiveBar.url_builder({path:'/stylesheets/widgets_hide.css'});document.getElementsByTagName("head")[0].appendChild(widget_hide_css_node);/**
 * Small object to store configuration properties and methods
 */
LiveBar.Config = {
  // switch to false to leave www in urls
  strip_www   : false,
  // switch to false to leave index.html in urls
  strip_index : true,
  
  // boolean to track whether the initialization call has been added to the client site.
  init_added : false,
  
  page_url   : '',
  bundle_url : '',
  
  set_page_url   : function() {
    this.page_url   = decodeURIComponent(document.location.href).split("?")[0]
    this.page_url   = (this.strip_www)    ? this.page_url.replace(/\/\/www\./, '//') : this.page_url;
    this.page_url   = (this.strip_index)  ? this.page_url.replace(/index\.(html|htm|php|asp|aspx|jsp|cfm)/, '') : this.page_url;
    
    if (typeof LiveBarBundleURL !== 'undefined') {      
      this.bundle_url = encodeURIComponent(LiveBarBundleURL);
    } else {
      this.bundle_url = encodeURIComponent(this.page_url); 
    }
  }
};

// set the bundle URL
LiveBar.Config.set_page_url();

LiveBar.is_IE6 = false;
LiveBar.is_IE7 = false;
LiveBar.is_IE8 = false;
LiveBar.is_FF2_Mac = false;
LiveBar.quirks_mode = false;
LiveBar.patch_fixed_position = false;

LiveBar.widget_id = 0;

// this bootstrap method is executed when the page's content is loaded
LiveBar.init = function() {
  LiveBar.test_for_patch_fixed_position();
  LiveBar.load_css();
  LiveBar.add_jQuery();
}// --------------- methods invoked during initialization; these appear in the order they are called ---------------------
/**
 * Dynamically attach all livebar stylesheets to client page.
 *
 * Loops through an array of file names and uses each to construct a path, each of which 
 * is set as the href of a new link node attached to the document head. Also uses a generated
 * timestamp to keep files fresh.
 * 
 */
LiveBar.load_css = function() { 
  var livebar_stylesheets = new Array('livebar_packaged');  
  
  // add IE 8 styles only if IE 8
  if (LiveBar.is_IE8) {
    livebar_stylesheets[livebar_stylesheets.length] = 'ie8';
  }
  
  // if quirks mode, load the IE quirks style sheet
  if (LiveBar.patch_fixed_position) {

    // add IE 6 styles only if IE 6
    if (LiveBar.is_IE6) {
      livebar_stylesheets[livebar_stylesheets.length] = 'ie6';
    }
    
    if (LiveBar.quirks_mode) {
      livebar_stylesheets[livebar_stylesheets.length] = 'ie_quirks';
      if (LiveBar.is_IE6) {
        livebar_stylesheets[livebar_stylesheets.length] = 'ie6_quirks';
      }
    }
  }

  // appending timestamp forces reload of stylesheet  
  var timestamp = parseInt(new Date().getTime()/86400000);
  var livebar_css_node;
  
  // Safari does not like the document.head.innerHTML to be modified,
  // so we need to use DOM manipulation to add elements to it
  for (i=0 ; i<livebar_stylesheets.length ; i++) {
    livebar_css_node = document.createElement('link');
    livebar_css_node.type = 'text/css';
    livebar_css_node.rel  = 'Stylesheet';    
    livebar_css_node.href = LiveBar.url_builder(
                                                 {
                                                   path  : '/stylesheets/' + livebar_stylesheets[i] + '.css',
                                                   query : timestamp
                                                 }
                                               );
    document.getElementsByTagName("head")[0].appendChild(livebar_css_node);
  }
  
  livebar_css_node = document.createElement('link');
  livebar_css_node.type = 'text/css';
  livebar_css_node.rel  = 'Stylesheet';
  livebar_css_node.href = LiveBar.url_builder(
                                               {
                                                 path  : '/stylesheets/tenant.css',
                                                 query : timestamp
                                               }
                                             );
  document.getElementsByTagName("head")[0].appendChild(livebar_css_node);
  
  livebar_css_node = document.createElement('link');
  livebar_css_node.type = 'text/css';
  livebar_css_node.rel  = 'Stylesheet';
  livebar_css_node.href = LiveBar.url_builder(
                                               {
                                                 path  : '/stylesheets/tenant_images.css',
                                                 query : timestamp
                                               }
                                             );
  document.getElementsByTagName("head")[0].appendChild(livebar_css_node);
  
};

/**
 * Attaches the livebar version of jquery to the document head.
 *
 * Creates a new script tag and sets src attribute to hit liveworld's livebar server.
 *
 * LiveBar requires it's own version of jQuery for a change on line 2659 of version 1.2.6; search for location.host 
 * in uncooked versions and change to LiveBar.location_host, which is set at the top of livebar.js
 */
LiveBar.add_jQuery = function() {
  var livebar_jquery_node  = document.createElement('script');
  livebar_jquery_node.type = 'text/javascript';
  livebar_jquery_node.src  = LiveBar.url_builder(
                                                  {
                                                    path : '/javascripts/lib/jquery.js'
                                                  }
                                                );
  if (livebar_jquery_node.addEventListener) {
    livebar_jquery_node.addEventListener("load", LiveBar.load_js, false);
  } else if ("onreadystatechange" in livebar_jquery_node) {
    livebar_jquery_node.onreadystatechange = function() {
      if (this.readyState == 'complete' || this.readyState == 'loaded') {
        LiveBar.load_js();
      }
    };
  }
  
  document.getElementsByTagName('head')[0].appendChild(livebar_jquery_node);
}

/**
 * Dynamically loads all the support libraries livebar depends on.
 *
 * Loops through an array of filenames and constructs each into the src attribute of a script tag
 * that's added to the page head. These are not removed from the DOM.
 *
 * After each script completes loading, it fires LiveBar.script_loaded() to test whether all
 * libs have completed and the bar can load.
 */
LiveBar.load_js = function() {
  
  LiveBar.additional_loads = 0;
  
  LiveBar.jQuery = livebar_jQuery.noConflict(true);
  LiveBar.jQuery.ajaxSettings.cache = true;
  
  LiveBar.jQuery('#livebar').addClass('livebar_minimized');
  
  LiveBar.scripts_loaded_counter = 0;
  var timestamp = parseInt(new Date().getTime()/86400000);
  
  
  
  /**
   * livebar_packaged.js varies by environment. For deployed environments it contains all the scripts
   * referenced in config/asset_packages.yml. This list is concatenated into a single file, then minified.
   * However for local development, these files need to remain distinct will formatting and comments. For
   * local versions of the site, livebar_packaged.js defines a LiveBar-namespaced array of files to pull in:
   * LiveBar.local_livebar_javascripts.
   *
   * Since there's only a single version of livebar.js that needs to function independent of environment,
   * the livebar_packaged.js file needs to be loaded, and then the presence of the local variable tested for. 
   * If the test passes all the local scripts are dynamically loaded, otherwise the json call to load
   * the bar fires.
   */
  var js_to_load = '/javascripts/livebar_packaged.js';
  if (LiveBar.widgets_only) {
    js_to_load = '/javascripts/livebar_widgets_packaged.js';
  }

  LiveBar.jQuery.getScript(
    
    LiveBar.url_builder(
      {
        path  : js_to_load,
        query : timestamp
      }
    ),
    function() {
      if (LiveBar.local_livebar_javascripts) {
        LiveBar.scripts_to_load = (LiveBar.local_livebar_javascripts.length) + LiveBar.additional_loads;
        for (i = 0; i < LiveBar.local_livebar_javascripts.length; i++) {
          LiveBar.jQuery.getScript(
            LiveBar.url_builder(
              {
                path  : '/javascripts/' + LiveBar.local_livebar_javascripts[i] + '.js',
                query : timestamp
              }
            ),
            function() {
              LiveBar.script_loaded();
            }
          );
        }
      } else {
        LiveBar.scripts_to_load = (1 + LiveBar.additional_loads);
        LiveBar.script_loaded();
      }

    }
  );

}

/**
 * Called multiple times by LiveBar.load_js. Compares the number of scripts loaded to the total
 * that will be loaded. If there's a match, makes a JSON-P call to populate the bar, stores the result
 * and triggers the process to do the actual population.
 */
LiveBar.script_loaded = function() {
  // first increment the global counter
  LiveBar.scripts_loaded_counter++;

  // since one of the query parameters for LiveBar.url_builder requires a variable value
  // for the key, pre-assemble the object here.
  var url_builder_query = {};
  url_builder_query.url = LiveBar.Config.bundle_url;
  url_builder_query[LiveBar.Tenant.jsonp_callback_function] = '?';
  if (LiveBar.get_session_key() != null) {
    url_builder_query[LiveBar.get_session_key()] = LiveBar.get_session_id();
  }
  
  // compare the global counter to the total, if a match, proceed.
  if (LiveBar.scripts_loaded_counter == LiveBar.scripts_to_load) {
    if (LiveBar.widgets_only) {
       LiveBar.PreLoad_Widgets();
       //LiveBar.PreLoad_Widgets2();    
    } else {
      // make the call to load the bar.
      
  // we're not using livebar within Phoenix -- we don't have, nor want, the bar    
//      LiveBar.jQuery.getJSON(
//        LiveBar.url_builder(
//          {
//            path : LiveBar.get_livebar_link(),
//            query : url_builder_query
//          }
//        ), 
//        function(request) { 
//  
//          // store the request in the LiveBar object so it will be available later
//          LiveBar.request = request;
//          
//          // set up an array to store setInterval calls
//          LiveBar.check_dom_intervals = [];
//  
//          // check the DOM to make sure the livebar node is present and accessible.
//          LiveBar.check_dom();
//          
//        }
//      );
    }
  }

}

/**
 * Checks to make sure JavaScript has access to the livebar node. In some cases other dynamic content is
 * manipulating the DOM and making certain browsers (and thus jQuery) unable to access the livebar div. To
 * prevent this, the check_dom call looks for the div, and if it can find it fires the render_bar call. If not
 * it recurses into itself up to 20 times, capturing the reference to the interval on each call so they can 
 * be cleared later. If at any of those iterations the livebar div becomes visible to jQuery, render_bar is fired.
 */
LiveBar.check_dom = function() {

  // check if jQuery can see the livebar div
  if (LiveBar.jQuery('#livebar').length < 1) {
  
    // the div can't be accessed, check to see if the interval is over 20 times
    if (LiveBar.check_dom_intervals.length > 20) {
    
      // it's already run the 20 times, clear the intervals and stop the check
      LiveBar.clear_dom_intervals();
    
    // the check has been running less than 20 times, load it again
    } else {
    
      // add the return from the setInterval call onto the check_dom_intervals array.
      LiveBar.check_dom_intervals.push(setInterval('LiveBar.check_dom()', 1000));
    }
  
  // the livebar div is visible, render the bar
  } else {
    LiveBar.render_bar();
  }
}

/**
 * Calls clear_dom_intervals stored by check_dom, populates the livebar div with the result of
 * the JSON-P call in script_loaded, and fires browser_specific_fixes
 */
LiveBar.render_bar = function() {
  LiveBar.clear_dom_intervals();
  LiveBar.PreLoad_Widgets();
  //LiveBar.PreLoad_Widgets2();

  
  LiveBar.jQuery('#livebar').html(LiveBar.request);  
  LiveBar.browser_specific_fixes();
  

}


/**
 * Loops through check_dom_intervals, which stores references to intervals and clears them
 */
LiveBar.clear_dom_intervals = function() {
  for (i in LiveBar.check_dom_intervals) {
    clearInterval(i);
  }
}

/**
 * Accomodates specific issues related to certain browsers and versions. Mostly applies to IE 6, though also FF2 on Mac.
 */
LiveBar.browser_specific_fixes = function() {
  
  // can put these way up here since this method doesn't fire until everything's loaded.
  LiveBar.is_FF2_Mac = LiveBar.detectMacXFF2();
  
  if (LiveBar.patch_fixed_position) {
    LiveBar.Fixed_Position_Patch.fixed_position_patch();
  }

  // delay this call to account for flash content that is dynamically added by the page's javascript;
  // even if the actual resource hasn't loaded in the first second, the DOM HTML manipulation should
  // have easily completed.
  if (LiveBar.is_FF2_Mac) setTimeout('LiveBar.fix_ff2_mac_flash()', 1000);
}


// --------------- end methods invoked during initialization ---------------------
// set the amount of time to display notifications, Selenium needs these to be quite delayed so it can detect them on its
// setTimeout loops
LiveBar.Timers = {

  notification_display : 2000,
  
  Widgets : {
  
    livebar_widget_update_interval : LiveBar.Tenant.livebar_widget_update_interval,
  
    aggregate_widget_update_interval : LiveBar.Tenant.aggregate_widget_update_interval
  
  }
  
}// --------------- utility methods ---------------------

/**
 * Grabs cookies from clients domain and sends them to the livebar instance so that facebooker has  
 * the data it needs to post items to FB from that server
 */
LiveBar.login_via_facebook = function ()
{
  LiveBar.jQuery.ajax(
    {
      url      : LiveBar.url_builder(
                   {
                     path : '/facebook_sessions'
                   }
                 ),
      data     : {
                   cookies : document.cookie,
                   _method : 'post'
                 },
      dataType : 'jsonp'
  });
};

/**
 * Checks the page URL for a passed parameter that maps onto a LiveBar state. Note that since IE restricts
 * access to the window object for dynamic script tags, the search property has been mapped to a LiveBar
 * property.
 */
LiveBar.get_livebar_link = function ()
{
  var regex = new RegExp( "livebar_link=([^&]*)" );  
  var results = regex.exec(decodeURIComponent(LiveBar.window_location_search));

  if( results == null ){
    return "";
  } else {
    return results[1];
  }
};

/**
 * Checks the page URL for a passed parameter that maps onto a LiveBar state. Note that since IE restricts
 * access to the window object for dynamic script tags, the search property has been mapped to a LiveBar
 * property.
 */
LiveBar.get_goto_url_link = function ()
{
  var regex = new RegExp( "goto_url=([^&]*)" );
  var results = regex.exec(decodeURIComponent(LiveBar.window_location_search));
  if( results == null ){
    return "";
  } else {
    return results[1];
  }
};

/**
 * Browser-independent loader to side step loading any behavior directly onto the body's load event, 
 * which can be modified by other scripts.
 *
 * Note that this is actual call is mapped onto various browser mechanisms in the following series of calls.
 *
 * Originally written by Dean Edwards/Matthias Miller/John Resig, edited by LiveBar Team
 */
LiveBar.add_load_event = function() {

  // quit if this function has already been called
  if (arguments.callee.done) return;

  // flag this function so we don't do the same thing twice
  arguments.callee.done = true;

  // kill the timer
  if (_timer) clearInterval(_timer);
  
  LiveBar.init();

};

/**
 * Maps LiveBar.add_load_event call for Internet Explorer 
 */
if (/MSIE/i.test(navigator.userAgent)) { // sniff
   document.write('<s'+'cri'+'pt id="__ie_onload" defer="true" src="javascript:void(0)"><\/script>');
   var script = document.getElementById("__ie_onload");
   script.onreadystatechange = function() {
     if (this.readyState == "complete") {
       LiveBar.add_load_event(); // call the onload handler
     }
   };
  // set a flag to make sure the call is only added once
  LiveBar.Config.init_added = true;
}

/**
 * Maps LiveBar.add_load_event call for Mozilla/Opera9
 */
if (document.addEventListener) {
  document.addEventListener("DOMContentLoaded", LiveBar.add_load_event, false);
  LiveBar.Config.init_added = true;
};

/**
 * Maps LiveBar.add_load_event call for Safari
 */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
  var _timer = setInterval(function() {
    if (/loaded|complete/.test(document.readyState)) {
      LiveBar.add_load_event(); // call the onload handler
    }
  }, 10);
  
  // set a flag to make sure the call is only added once
  LiveBar.Config.init_added = true;
};

/**
 * Maps LiveBar.add_load_event call for other browsers, first checks to make sure
 * LiveBar.Config.init_added has not been set to true by a previous match.
 */
if (!LiveBar.Config.init_added) {
  var oldonload = window.onload; 
  if (typeof window.onload != 'function') { 
    window.onload = func; 
  } else { 
    window.onload = function() { 
      if (oldonload) { 
        oldonload(); 
      } 
      func(); 
    } 
  }
  
  LiveBar.add_load_event();
};

// --------------- end utility methods ---------------------// --------------- browser-specific methods ---------------------
/**
 * Firefox 2 on Mac has issues with Flash showing through a CSS-positioned layer, even if it's an iframe, even if it's not transparent.
 * the following 2 functions determine if the user agent is FF2 on a Mac and if so examines the client page for embedded flash and hides
 * any it finds.
 */
LiveBar.fix_ff2_mac_flash = function() {
  if (LiveBar.is_FF2_Mac) {
    htmlObjects = document.getElementsByTagName('object');
    for (i=0 ; i < htmlObjects.length ; i++) {
      if (htmlObjects[i].getAttribute('codebase').indexOf('flash') > -1) {
        htmlObjects[i].style.visibility = 'hidden';        
      }
    }
    htmlIFrames = document.getElementsByTagName('iframe');
    for (i=0 ; i < htmlIFrames.length ; i++) {
      if (htmlIFrames[i].id != 'everett_iframe' && htmlIFrames[i].id != 'livebar_iframe') {
        htmlIFrames[i].style.visibility = 'hidden';
      }
    }
  }
}

/**
 * Need to hide all Flash in FF2 on Mac as they show through the iframe
 */
LiveBar.detectMacXFF2 = function() {
  var userAgent = navigator.userAgent.toLowerCase();
  if (/firefox[\/\s](\d+\.\d+)/.test(userAgent)) {
    var ffversion = new Number(RegExp.$1);
    if (ffversion < 3 && userAgent.indexOf('mac') != -1) {
      return true;
    }
  }
}

/**
 * IE 6 shows select menus through CSS-positioned layers, even through the everett iframe. loop through all select menus and hide them. 
 */
LiveBar.toggle_select_menus = function(visiblity_to_set) {
  var select_menus_to_toggle = document.getElementsByTagName('select');
  for (i=0 ; i < select_menus_to_toggle.length ; i++) {
    select_menus_to_toggle[i].style.visibility = visiblity_to_set;
  }
}


/**
 * IE 7 in quirks mode and IE 6 in both quirks and strict lack support for position: fixed. This is a lightweight object to hold methods
 * and properties specific to emulate fixed positioning through dynamic absolute positioning.
 */
LiveBar.Fixed_Position_Patch = {
  
  /**
   * When the document is scrolled, need to recalculate where in the document the bottom of the viewport
   * is so the bar can be positioned there.
   */
  fixed_scroll_position : '0px',
  
  /**
   * Height of the overall bar; set via CSS and/or user resizing.
   */
  livebar_height : '0px',
  
  /**
   * Returns the height of the bar with the 'px' stripped off.
   */
  get_livebar_height : function() {
    LiveBar.Fixed_Position_Patch.livebar_height = parseInt(LiveBar.jQuery('#livebar').height());
  },
  
  /**
  * Calculate the bottom of the viewport minus the height of the bar. Returns an integer
  */
  set_fixed_scroll_position : function() {
    if (LiveBar.patch_fixed_position) {
      LiveBar.Fixed_Position_Patch.get_livebar_height();

      // document.documentElement['clientHeight'] == the height of the viewport (borrowed from prototype)
      // window.document.documentElement['scrollTop'] == vertical scroll offset from top of document
      // heightString == the height of the bar
      LiveBar.Fixed_Position_Patch.fixed_scroll_position = (LiveBar.jQuery(window).height() + LiveBar.jQuery(document).scrollTop()) - LiveBar.Fixed_Position_Patch.livebar_height + 'px';
    }
  },

  /**
  * Reposition bar on IE 6 window onScroll. Switches positioning from bottom to top and calls get_fixed_scroll_position() 
  * to determine the new position. 
  */
  fix_scroll_position : function() {
    if (LiveBar.patch_fixed_position) {
      LiveBar.Fixed_Position_Patch.set_fixed_scroll_position();
      LiveBar.jQuery('#livebar').css('bottom', 'auto');
      LiveBar.jQuery('#livebar').css('top', LiveBar.Fixed_Position_Patch.fixed_scroll_position);
      LiveBar.has_scrolled_quirks = true;
    }
  },

  /**
  * Reposition bar on IE 6 window onResize. Switches positioning from top to bottom, which IE consistently renders properly.
  */
  fix_resize_position : function() {
    LiveBar.Fixed_Position_Patch.get_livebar_height();
    LiveBar.Fixed_Position_Patch.set_fixed_scroll_position();
    if (LiveBar.patch_fixed_position) {
      LiveBar.jQuery('#livebar').css('bottom', 'auto');
      LiveBar.jQuery('#livebar').css('top', LiveBar.Fixed_Position_Patch.fixed_scroll_position);
      LiveBar.jQuery('#livebar').css('width', LiveBar.jQuery(window).width());
    }
  },

  /**
  * Foundation work for the repositioning calls to work: sets document.domain, makes the initial function call to reposition
  * and then attaches positioning calls to the window's onresize and onscroll events.
  */
  fixed_position_patch : function() {
    if (LiveBar.patch_fixed_position) {

      // first one is for the equivalent of onload, though since the page has loaded and this is 
      // being appended to the DOM we have to sort of pretend...
      LiveBar.Fixed_Position_Patch.fix_resize_position();

      // attach to window scroll and resize events
      LiveBar.jQuery(window).bind('scroll', function() { LiveBar.Fixed_Position_Patch.fix_scroll_position() });
      LiveBar.jQuery(window).bind('resize', function() { LiveBar.Fixed_Position_Patch.fix_resize_position() });
    }
  }
}

LiveBar.test_for_patch_fixed_position = function() {
    // these values are always the same in all browsers when in standards mode, but always different in quirks mode
    // IE 6 always needs the positioning patch. IE 6 detection runs before jQuery loads, so have to do it the old way.
    LiveBar.is_IE6 = (navigator.appName == 'Microsoft Internet Explorer') && (navigator.appVersion.indexOf('MSIE 6') > 0);
    LiveBar.quirks_mode = (document.body.clientWidth != document.body.offsetWidth && navigator.appName == 'Microsoft Internet Explorer');
    LiveBar.patch_fixed_position = (LiveBar.quirks_mode || LiveBar.is_IE6);
    
    // check if IE 7, which has it's own set of rendering issues
    LiveBar.is_IE7 = (navigator.appVersion.indexOf('MSIE 7') > 0);
    
    // check if IE 8, which has it's own set of rendering issues
    LiveBar.is_IE8 = (navigator.appVersion.indexOf('MSIE 8') > 0);  
}

// --------------- end browser specific methods ---------------------
/*
    http://www.JSON.org/json2.js
    2009-09-29

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    See http://www.JSON.org/js.html
*/
// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

if (!this.JSON) {
    this.JSON = {};
}

(function () {
    function f(n) {
        // Format integers to have at least two digits.
        return n < 10 ? '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function (key) {

            return isFinite(this.valueOf()) ?
                   this.getUTCFullYear()   + '-' +
                 f(this.getUTCMonth() + 1) + '-' +
                 f(this.getUTCDate())      + 'T' +
                 f(this.getUTCHours())     + ':' +
                 f(this.getUTCMinutes())   + ':' +
                 f(this.getUTCSeconds())   + 'Z' : null;
        };

        String.prototype.toJSON =
        Number.prototype.toJSON =
        Boolean.prototype.toJSON = function (key) {
            return this.valueOf();
        };
    }

    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
        gap,
        indent,
        meta = {    // table of character substitutions
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        },
        rep;


    function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

        escapable.lastIndex = 0;
        return escapable.test(string) ?
            '"' + string.replace(escapable, function (a) {
                var c = meta[a];
                return typeof c === 'string' ? c :
                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
            }) + '"' :
            '"' + string + '"';
    }


    function str(key, holder) {

// Produce a string from holder[key].

        var i,          // The loop counter.
            k,          // The member key.
            v,          // The member value.
            length,
            mind = gap,
            partial,
            value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

        if (value && typeof value === 'object' &&
                typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }

// What happens next depends on the value's type.

        switch (typeof value) {
        case 'string':
            return quote(value);

        case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

            return isFinite(value) ? String(value) : 'null';

        case 'boolean':
        case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.

            return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.

        case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.

            if (!value) {
                return 'null';
            }

// Make an array to hold the partial results of stringifying this object value.

            gap += indent;
            partial = [];

// Is the value an array?

            if (Object.prototype.toString.apply(value) === '[object Array]') {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || 'null';
                }

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

                v = partial.length === 0 ? '[]' :
                    gap ? '[\n' + gap +
                            partial.join(',\n' + gap) + '\n' +
                                mind + ']' :
                          '[' + partial.join(',') + ']';
                gap = mind;
                return v;
            }

// If the replacer is an array, use it to select the members to be stringified.

            if (rep && typeof rep === 'object') {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    k = rep[i];
                    if (typeof k === 'string') {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            } else {

// Otherwise, iterate through all of the keys in the object.

                for (k in value) {
                    if (Object.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
                        }
                    }
                }
            }

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

            v = partial.length === 0 ? '{}' :
                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
                        mind + '}' : '{' + partial.join(',') + '}';
            gap = mind;
            return v;
        }
    }

// If the JSON object does not yet have a stringify method, give it one.

    if (typeof JSON.stringify !== 'function') {
        JSON.stringify = function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

            var i;
            gap = '';
            indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.

            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }

// If the space parameter is a string, it will be used as the indent string.

            } else if (typeof space === 'string') {
                indent = space;
            }

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
                    (typeof replacer !== 'object' ||
                     typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.

            return str('', {'': value});
        };
    }


// If the JSON object does not yet have a parse method, give it one.

    if (typeof JSON.parse !== 'function') {
        JSON.parse = function (text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.

            var j;

            function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.

                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }


// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.

            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return '\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.

// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.

            if (/^[\],:{}\s]*$/.
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                j = eval('(' + text + ')');

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.

                return typeof reviver === 'function' ?
                    walk({'': j}, '') : j;
            }

// If the text is not JSON parseable, then a SyntaxError is thrown.

            throw new SyntaxError('JSON.parse');
        };
    }
}());

// --------------- widgets methods ---------------------

LiveBar.widget_counter = 0;

/**
 * Builds the actual widget from the javascript call in the client page.
 *
 * IMPORTANT IMPORTANT IMPORTANT NOTE!!!!!!!
 * IE limits the lang attribute, which is where the widget URL is stored, to 129 characters. If the fully-formed URL
 * exceeds this IE will simply truncate it, which strips the json-p callback parameter causing jquery to attempt
 * a cross domain ajax call, which will fail horribly.
 *
 * @param {JSON Object} options = { 
 *                                   'widget_action' : 'url',                                 // call to pass to JSON request
 *                                   'query'         : 'parameters to pass',                  // parameters to pass to the call
 *                                   'css_classname  : 'name of css class to apply to widget' // additional class name to enable styling of widgets
 *                                   'title'         : 'override for the title of the widget' // string to display as the widget's title
 *                                   'data_livebar_properties : comma delimited list of name:value pairs //will end up as query paramters on the livebar url.
 *                                 }
 */
LiveBar.widget = function(resource, options) {
  
  // if no options passed in, create an empty object.
   if (!options) options = {};
  
  // create empty properties for options not passed in; this will avoid undefined script errors
  options.widget_action = options.widget_action ? ('/' + options.widget_action) : '';
  options.query = options.query ? (options.query) : '';
  options.css_classname = (options.css_classname) ? ' ' + options.css_classname : '';
  options.data_livebar_properties = options.data_livebar_properties ? ''+ options.data_livebar_properties : '';
   if (options.data_livebar_properties && !options.data_livebar_properties == '') {
    options.data_livebar_properties = ' data-livebar-properties="' + options.data_livebar_properties +'"';
  }
  
  // define this so that the query options can be conditionally added and use variable value as key
  var url_builder_query = {};
  
  // checks to see if there was a query set in the initial widget call and if so processes the string
  // into key/value pairs in the url_builder_query hash
  if (options.query != '') {
    var key_pair = [];
    if (options.query.indexOf('&') > -1) {
      query_pairs = options.query.split('&');
      for (i = 0 ; i < query_pairs.length ; i++) {
        key_pair = query_pairs[i].split('=');
        url_builder_query[key_pair[0]] = key_pair[1];
      }
    } else {
      key_pair = options.query.split('=');
      url_builder_query[key_pair[0]] = key_pair[1];
    }
  }
  
  if (options.title) {
    attribute_title = 'title="'+options.title+'"';
  } else {
    attribute_title = '';
  }
  
  url_builder_query.widget_id = LiveBar.widget_id;
  
  url_builder_query.url = LiveBar.Config.bundle_url;
  url_builder_query[LiveBar.Tenant.jsonp_callback_function] = '?';
  
  widget_lang_attribute = LiveBar.url_builder(  
                                               {
                                                 host  : '',
                                                 path  : '/widgets/' + resource + options.widget_action,
                                                 query : url_builder_query
                                               }
                                             );

  // inject the widget HTML into the document. When the LiveBar.Widgets object loads, these will
  // be populated by the response of a JSON-P call to the URL stored in the lang attribute.
  document.write( '<div class="livebar_widgets livebar_widgets_' + resource + options.css_classname + '" ' +
                  'id="livebar_widget_' + LiveBar.widget_id + '" ' + attribute_title +
                  'lang="' + widget_lang_attribute + '"' + options.data_livebar_properties + '></div>');

};


/**
 * For each widget on the page set up to use WidgetLoader, a javascript object containing the object definition is created
 * and passed back to the Preload_Widget api call.
 */
LiveBar.load_widget_json_definition = function(resource, options) {
  
  var json_object = new Object();
  // if no options passed in, create an empty object.
   if (!options) options = {};
  
  // create empty properties for options not passed in; this will avoid undefined script errors
  // hangles both passing in of obfuscated widget id and the resource name for LiveBar widgets
  if (parseInt(resource) > 0) {
    json_object["id"] = resource; // maps onto the obfuscated widget id
    json_object["resource"] = 'twitter_search'; // TODO: this needs to not be hardcoded once there are additional types of aggregate widgets - kcallahan 3/19/10
  } else {
    json_object["resource"] = resource;
    json_object["widget_action"] = options.widget_action;
  }
  options.query = options.query ? ('&' + options.query) : '';
  options.css_classname = (options.css_classname) ? ' ' + options.css_classname : '';
  options.data_livebar_properties = options.data_livebar_properties ? ''+ options.data_livebar_properties : '';
  
   if (options.data_livebar_properties && !options.data_livebar_properties == '') {
        local_props = options.data_livebar_properties.split(",");
       if (local_props && local_props.length > 0)
       for (var i = 0; i < local_props.length; i++){ 
         prop_item = local_props[i].split(":");
       // seperate the name value pairs from the string
         if (prop_item && prop_item.length > 0) {
           prop_key = prop_item[0].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
           prop_value = prop_item[1].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
           json_object[prop_key] = prop_value
         }
       }
  } 
  // checks to see if there was a query set in the initial widget call and if so processes the string
  // into key/value pairs in the url_builder_query hash
  if (options.query != '') {
    var key_pair = [];
    if(options.query.indexOf('&') == 0) {
        options.query= options.query.substring(1)
    }
    if (options.query.indexOf('&') > -1) {
      query_pairs = options.query.split('&');
      for (i = 0 ; i < query_pairs.length ; i++) {
        key_pair = query_pairs[i].split('=');
        json_object[key_pair[0].replace(/^\s\s*/, '').replace(/\s\s*$/, '')] = key_pair[1].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
      }
    } else {
      key_pair = options.query.split('=');
      json_object[key_pair[0].replace(/^\s\s*/, '').replace(/\s\s*$/, '')] = key_pair[1].replace(/^\s\s*/, '').replace(/\s\s*$/, '');
    }
  }  
  if (options.title) {
    attribute_title = 'title="'+options.title+'"';
    json_object["title_override"] = options.title;
  } 
  // Return the json_object which contains the widget definition.  
  // PreLoad_Widgets is called during the livebar load to load all widgets at once.

 return json_object;

};
// Legacy Widget Load
LiveBar.Widget = function(resource, options) {
  return LiveBar.widget(resource, options);
};

//Single call widget loader
LiveBar.WidgetLoader = function(resource, options) {
    return LiveBar.load_widget_json_definition(resource, options);
}
LiveBar.WidgetLoader2 = function(id, obj) {
  if(!obj) obj = {};
  obj['id'] = id;
  return obj;
}

/**
 *   Loads the widgets on the load of LiveBar.  If the widget is loaded with LiveBar.WidgetLoad, then it is loaded in deferred mode. 
 *   If the widget is loaded with LiveBar.WidgetLoader, then a single call with all of the widget definitions is passed to the server and render via rails
 *   Legacy Widgets are loaded via LiveBar.Widget
*/
LiveBar.PreLoad_Widgets = function() {
  var widgets  = new Object();
  var widgets_to_load = new Object()
  var main_widget_loader = new Object()
  
  LiveBar.jQuery(".lwd_widget_container").each(function(i) {
    cell_id = "livebar_widget_" + LiveBar.widget_counter;
    LiveBar.jQuery(this).attr("id", cell_id);
    if (LiveBar.jQuery(this).text().indexOf("WidgetLoader") > 0) {
      widgets[cell_id] = eval( LiveBar.jQuery(this).text() );
      widgets[cell_id]["div_id"] = cell_id
      LiveBar.jQuery(this).attr('class', 'lwd_widget_container '+ 'livebar_widget_'+ widgets[cell_id]["resource"].replace(' ', '_'))
      LiveBar.jQuery(this).text("");
    } 
    LiveBar.widget_counter++; 
  });
  
  LiveBar.jQuery.each(widgets, function(key, value) {
    widgets_to_load[key] = value;
  });
  
  main_widget_loader["bundle"] = LiveBar.Config.bundle_url;
  main_widget_loader[LiveBar.get_session_key()] = LiveBar.get_session_id();
  main_widget_loader["tenant_id"] = LiveBar.Tenant.tenant_id
  main_widget_loader["widgets"] = widgets_to_load
  
  var myurl =  LiveBar.url_builder(
    {
      path: '/widgets/multi_widget',
      query: 'format=html&widgets='+JSON.stringify(widgets_to_load)
    }
  );
  
  main_widget_loader["url"] = myurl;    
  LiveBar.WidgetData.widgets =  main_widget_loader;
  LiveBar.Widgets.reload();
  LiveBar.jQuery(".lwd_widget_container").css('display', "block")
};



/**
 *   Loads the widgets on the load of LiveBar.  If the widget is loaded with LiveBar.WidgetLoad, then it is loaded in deferred mode. 
 *   If the widget is loaded with LiveBar.WidgetLoader, then a single call with all of the widget definitions is passed to the server and render via rails
 *   Legacy Widgets are loaded via LiveBar.Widget
*/
LiveBar.PreLoad_Widgets2 = function() {
  var widgets = new Object;
  var main_widget_loader = new Object()
  
  LiveBar.jQuery(".livebar_widget").each(function(i) {
    div_id = "livebar_widget_" + LiveBar.widget_counter;
    LiveBar.jQuery(this).attr("id", div_id); // set div ID
    if(LiveBar.jQuery(this).text().indexOf("WidgetLoader2") > 0) {
      widgets[div_id] = eval(LiveBar.jQuery(this).text());
      LiveBar.jQuery(this).text("");
    }
    LiveBar.widget_counter++; 
  });
  
  main_widget_loader["bundle"] = LiveBar.Config.bundle_url;
  main_widget_loader[LiveBar.get_session_key()] = LiveBar.get_session_id();
  main_widget_loader["tenant_id"] = LiveBar.Tenant.tenant_id
  main_widget_loader["widgets"] = widgets
  
  var url = LiveBar.url_builder(
    {
      path: '/widgets/multi',
      query: 'format=html&widgets='+JSON.stringify(widgets)
    }
  );
  
  main_widget_loader["url"] = url;    
  LiveBar.WidgetData.widgets = main_widget_loader;
  LiveBar.Widgets.reload();
  LiveBar.jQuery(".livebar_widget").css('display', "block");
};

// --------------- end widgets methods ---------------------

