/*
 *   $Id: util_date.js 4522 2008-07-23 17:45:42Z zs $
 *
 *  Copyright (c) 2007 Underlying Inc. All rights reserved.
 */

TS.Util.Date = {};

TS.Util.Date.zoom_level = null;

TS.Util.Date.month_lookup = [ '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12' ];

TS.Util.Date.zoom_levels = [ 
    { 'name':'1sec',           'unit':'second', 'num':1,           'curr_fmt':'1sec'               },
    { 'name':'30sec',          'unit':'second', 'num':30,          'curr_fmt':'1sec'               },
    { 'name':'1min',           'unit':'minute', 'num':1,           'curr_fmt':'1sec'               },
    { 'name':'5min',           'unit':'minute', 'num':5,           'curr_fmt':'30sec'              },
    { 'name':'30min',          'unit':'minute', 'num':30,          'curr_fmt':'1min'               },
    { 'name':'1hr',            'unit':'hour',   'num':1,           'curr_fmt':'5min'               },
    { 'name':'12hr',           'unit':'hour',   'num':12,          'curr_fmt':'1hr'                },
    { 'name':'1day',           'unit':'day',    'num':1,           'curr_fmt':'1hr'                }, 
    { 'name':'7day',           'unit':'day',    'num':7,           'curr_fmt':'1day'               },
    { 'name':'1mon',           'unit':'month',  'num':1,           'curr_fmt':'7day'               },
    { 'name':'3mon',           'unit':'month',  'num':3,           'curr_fmt':'7day'               },
    { 'name':'6mon',           'unit':'month',  'num':6,           'curr_fmt':'1mon'               },
    { 'name':'1yr',            'unit':'year',   'num':1,           'curr_fmt':'1mon'               },
    { 'name':'2yr',            'unit':'year',   'num':2,           'curr_fmt':'1mon'               },
    { 'name':'5yr',            'unit':'year',   'num':5,           'curr_fmt':'6mon'               },
    { 'name':'10yr',           'unit':'year',   'num':10,          'curr_fmt':'1yr'                },
    { 'name':'25yr',           'unit':'year',   'num':25,          'curr_fmt':'1yr'                },
    { 'name':'50yr',           'unit':'year',   'num':50,          'curr_fmt':'5yr'                }, 
    { 'name':'100yr',          'unit':'year',   'num':100,         'curr_fmt':'10yr'               }, 
    { 'name':'500yr',          'unit':'year',   'num':500,         'curr_fmt':'50yr'               },
    { 'name':'1000yr',         'unit':'year',   'num':1000,        'curr_fmt':'100yr'              },
    { 'name':'5000yr',         'unit':'year',   'num':5000,        'curr_fmt':'500yr'              },
    { 'name':'10000yr',        'unit':'year',   'num':10000,       'curr_fmt':'500yr'              },
    { 'name':'50000yr',        'unit':'year',   'num':50000,       'curr_fmt':'1000yr'             },
    { 'name':'100000yr',       'unit':'year',   'num':100000,      'curr_fmt':'5000yr'             },
    { 'name':'500000yr',       'unit':'year',   'num':500000,      'curr_fmt':'10000yr'            },
    { 'name':'1000000yr',      'unit':'year',   'num':1000000,     'curr_fmt':'100000yr'           },
    { 'name':'10000000yr',     'unit':'year',   'num':10000000,    'curr_fmt':'1000000yr'          },
    { 'name':'100000000yr',    'unit':'year',   'num':100000000,   'curr_fmt':'10000000yr'         },
    { 'name':'1000000000yr',   'unit':'year',   'num':1000000000,  'curr_fmt':'100000000yr'        }
    ];

TS.Util.Date.zoom_level_name_to_id = function(zl_name)
{
  for( var i in TS.Util.Date.zoom_levels )
  {
    if (TS.Util.Date.zoom_levels[i]['name'] == zl_name) {
      return i;
    }
  }
  return -1;
}


TS.Util.Date.align_date_to_zoom_level = function(in_date, zoom_level_offset) 
{
  var use_zoom = TS.Util.Date.zoom_level + zoom_level_offset;
  if (use_zoom < 0) {
    use_zoom = 0;
  } else if (use_zoom > TS.Util.Date.zoom_levels.length) {
    use_zoom = TS.Util.Date.zoom_levels.length - 1;
  }

  var the_date = new Date(in_date);
  var unit = TS.Util.Date.zoom_levels[use_zoom].unit;
  var num  = TS.Util.Date.zoom_levels[use_zoom].num;
  if (unit == 'year') {
    the_date.setUTCFullYear(the_date.getUTCFullYear() - (the_date.getUTCFullYear() % num));
    the_date.setUTCMonth(0);
    the_date.setUTCDate(1);
    the_date.setUTCHours(0);
    the_date.setUTCMinutes(0);
    the_date.setUTCSeconds(0);
    the_date.setUTCMilliseconds(0);
  } else if (unit == 'month') {
    the_date.setUTCMonth(the_date.getUTCMonth() - (the_date.getUTCMonth() % num));
    the_date.setUTCDate(1);
    the_date.setUTCHours(0);
    the_date.setUTCMinutes(0);
    the_date.setUTCSeconds(0);
    the_date.setUTCMilliseconds(0);
  } else if (unit == 'day') {
    the_date.setUTCDate(the_date.getUTCDate() - (the_date.getUTCDate() % num));
    the_date.setUTCHours(0);
    the_date.setUTCMinutes(0);
    the_date.setUTCSeconds(0);
    the_date.setUTCMilliseconds(0);
  } else if (unit == 'hour') {
    the_date.setUTCHours(the_date.getUTCHours() - (the_date.getUTCHours() % num));
    the_date.setUTCMinutes(0);
    the_date.setUTCSeconds(0);
    the_date.setUTCMilliseconds(0);
  } else if (unit == 'minute') {
    the_date.setUTCMinutes(the_date.getUTCMinutes() - (the_date.getUTCMinutes() % num));
    the_date.setUTCSeconds(0);
    the_date.setUTCMilliseconds(0);
  } else if (unit == 'second') {
    the_date.setUTCSeconds(the_date.getUTCSeconds() - (the_date.getUTCSeconds() % num));
    the_date.setUTCMilliseconds(0);
  }

  return the_date;
}


TS.Util.Date.calc_datetime_offset = function(d, offset)
{
  var mod_date = new Date(d);
  var unit = TS.Util.Date.zoom_levels[TS.Util.Date.zoom_level].unit;
  var num = TS.Util.Date.zoom_levels[TS.Util.Date.zoom_level].num;

  if (unit == 'year') {
    mod_date.setUTCFullYear(mod_date.getUTCFullYear() + ( offset * num ));
  } else if (unit == 'month') {
    var newmonth = mod_date.getUTCMonth() + ( offset * num );
    var delta_year = Math.floor( newmonth / 12 );
    newmonth = newmonth % 12;
    mod_date.setUTCMonth(newmonth);
    mod_date.setUTCFullYear(mod_date.getUTCFullYear() + delta_year);
  } else if (unit == 'day') {
    mod_date.setUTCDate(mod_date.getUTCDate() + ( offset * num ));
  } else if (unit == 'hour') {
    mod_date.setUTCHours(mod_date.getUTCHours() + ( offset * num ));
  } else if (unit == 'minute') {
    mod_date.setUTCMinutes(mod_date.getUTCMinutes() + ( offset * num ));
  } else if (unit == 'second') {
    mod_date.setUTCSeconds(mod_date.getUTCSeconds() + ( offset * num ));
  } else {
    alert('unknown unit: ' + unit);
  }

  return mod_date;
}


TS.Util.Date.get_date_fields_for_zoomlevel = function(d, zoom_level_offset)
{
  var ret_arr = {};
  var zoom_level = TS.Util.Date.zoom_level + zoom_level_offset;

  if (zoom_level < 0 || zoom_level >= TS.Util.Date.zoom_levels.length) {
    zoom_level = TS.Util.Date.zoom_level;
  }
  var unit = TS.Util.Date.zoom_levels[zoom_level].unit;

  ret_arr.yr = d.getUTCFullYear();

  if (unit != 'year') {
    ret_arr.mo = d.getUTCMonth() + 1;

    if (unit != 'month') {
      ret_arr.dy = d.getUTCDate();

      if (unit != 'day') {
        ret_arr.hr = d.getUTCHours();

        if (unit != 'hour') {
          ret_arr.mn = d.getUTCMinutes();

          if (unit != 'minute') {
            ret_arr.sc = d.getUTCSeconds();
          }
        }
      }
    }
  }
  return ret_arr;
}

TS.Util.Date.set_currdisp_zoomlevel_id = function()
{
  var curr_fmt = TS.Util.Date.zoom_levels[TS.Util.Date.zoom_level].curr_fmt;
  TS.Util.Date.currdisp_zoomlevel_id = TS.Util.Date.zoom_level_name_to_id(curr_fmt);
}


TS.Util.Date.format_date_for_zoomlevel = function(ts, zoom_level)
{
  if (zoom_level == null) {
    return "";
  }

  var d = new Date(ts * 1000);

  if (zoom_level < 0 || zoom_level >= TS.Util.Date.zoom_levels.length) {
    zoom_level = TS.Util.Date.zoom_level;
  }
  var unit = TS.Util.Date.zoom_levels[zoom_level].unit;

  var y = d.getUTCFullYear();
  if (y < 0) {
    y += " BCE";
  }

  if  (unit == 'year') 
  { 
	 // return date_format('Y',ts);
     return y; 
  } 
  else 
  {
    var monthname = TS.Util.Date.month_lookup[ d.getUTCMonth() ]; 

    if (unit == 'month') { 
    	//return date_format('Y-m',ts);
    	//alert(ts);
      return y+"-"+monthname; 
    } else if (unit == 'day') {
    	//return date_format('Y-m-d',ts);
       return y+"-"+monthname + "-" + d.getUTCDate();
    } else {
    	//return date_format('Y-m-d H:i',ts);
      var hour = d.getUTCHours();
      //var ampm = 'am';
      //if (hour == 12) {
      //  ampm = 'pm';
      ////} else if (hour > 12) {
      //  hour -= 12;
      //  ampm = 'pm';
      //} else if (hour == 0) {
       // hour = 12;
      //}
      return y+"-"+monthname + "-" + d.getUTCDate() + " " + hour + ":" + (d.getUTCMinutes() < 10 ? "0" : "") + d.getUTCMinutes() + ":" + (d.getUTCSeconds() < 10 ? "0" : "") + d.getUTCSeconds();
      if (unit == 'hour') {
    	//return date_format('Y-m-d H:i:s',ts);
        return monthname + " " + d.getUTCDate() + ", " + y + " " + hour + ampm;
      } else if (unit == 'minute') {
        return monthname + " " + d.getUTCDate() + ", " + y + " " + hour + ":" + (d.getUTCMinutes() < 10 ? "0" : "") + d.getUTCMinutes() + " " + ampm;
      } else if (unit == 'second') {
        return monthname + " " + d.getUTCDate() + ", " + y + " " + hour + ":" + (d.getUTCMinutes() < 10 ? "0" : "") + d.getUTCMinutes() + ":" + (d.getUTCSeconds() < 10 ? "0" : "") + d.getUTCSeconds() + " " + ampm;
      }
    }
  }
}

function date_format( format, timestamp){ 
    var a, jsdate=((timestamp) ? new Date(timestamp*1000) : new Date());
    var pad = function(n, c){
        if( (n = n + "").length < c ) {
            return new Array(++c - n.length).join("0") + n;
        } else {
            return n;
        }
    };
    var txt_weekdays = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
    var txt_ordin = {1:"st",2:"nd",3:"rd",21:"st",22:"nd",23:"rd",31:"st"};
    var txt_months = ["", "January", "February", "March", "April","May", "June", "July", "August", "September", "October", "November","December"]; 
    var f = {
        // Day
            d: function(){return pad(f.j(), 2);},
            D: function(){t = f.l(); return t.substr(0,3); },
            j: function(){ return jsdate.getDate();},
            l: function(){return txt_weekdays[f.w()];},
            N: function(){return f.w() + 1;},
            S: function(){return txt_ordin[f.j()] ? txt_ordin[f.j()] : 'th'; },
            w: function(){return jsdate.getDay();},
            z: function(){return (jsdate - new Date(jsdate.getFullYear() + "/1/1")) / 864e5 >> 0;},
        // Week
            W: function(){
                var a = f.z(), b = 364 + f.L() - a;
                var nd2, nd = (new Date(jsdate.getFullYear() + "/1/1").getDay() || 7) - 1;

                if(b <= 2 && ((jsdate.getDay() || 7) - 1) <= 2 - b){
                    return 1;
                } else{
                    if(a <= 2 && nd >= 4 && a >= (6 - nd)){
                        nd2 = new Date(jsdate.getFullYear() - 1 + "/12/31");
                        return date("W", Math.round(nd2.getTime()/1000));
                    } else{
                        return (1 + (nd <= 3 ? ((a + nd) / 7) : (a - (7 - nd)) / 7) >> 0);
                    }
                }
            },

        // Month
            F: function(){return txt_months[f.n()];},
            m: function(){ return pad(f.n(), 2);},
            M: function(){ t = f.F(); return t.substr(0,3);},
            n: function(){ return jsdate.getMonth() + 1;},
            t: function(){
                var n;
                if( (n = jsdate.getMonth() + 1) == 2 ){
                    return 28 + f.L();
                } else{
                    if( n & 1 && n < 8 || !(n & 1) && n > 7 ){
                        return 31;
                    } else{
                        return 30;
                    }
                }
            },

        // Year
            L: function(){
                var y = f.Y();
                return (!(y & 3) && (y % 1e2 || !(y % 4e2))) ? 1 : 0;
            },
            //o not supported yet
            Y: function(){
                return jsdate.getFullYear();
            },
            y: function(){
                return (jsdate.getFullYear() + "").slice(2);
            },

        // Time
            a: function(){
                return jsdate.getHours() > 11 ? "pm" : "am";
            },
            A: function(){
                return f.a().toUpperCase();
            },
            B: function(){
                // peter paul koch:
                var off = (jsdate.getTimezoneOffset() + 60)*60;
                var theSeconds = (jsdate.getHours() * 3600) +
                                 (jsdate.getMinutes() * 60) +
                                  jsdate.getSeconds() + off;
                var beat = Math.floor(theSeconds/86.4);
                if (beat > 1000) beat -= 1000;
                if (beat < 0) beat += 1000;
                if ((String(beat)).length == 1) beat = "00"+beat;
                if ((String(beat)).length == 2) beat = "0"+beat;
                return beat;
            },
            g: function(){
                return jsdate.getHours() % 12 || 12;
            },
            G: function(){
                return jsdate.getHours();
            },
            h: function(){
                return pad(f.g(), 2);
            },
            H: function(){
                return pad(jsdate.getHours(), 2);
            },
            i: function(){
                return pad(jsdate.getMinutes(), 2);
            },
            s: function(){
                return pad(jsdate.getSeconds(), 2);
            },
            //u not supported yet

        // Timezone
            //e not supported yet
            //I not supported yet
            O: function(){
               var t = pad(Math.abs(jsdate.getTimezoneOffset()/60*100), 4);
               if (jsdate.getTimezoneOffset() > 0) t = "-" + t; else t = "+" + t;
               return t;
            },
            P: function(){
                var O = f.O();
                return (O.substr(0, 3) + ":" + O.substr(3, 2));
            },
            //T not supported yet
            //Z not supported yet

        // Full Date/Time
            c: function(){
                return f.Y() + "-" + f.m() + "-" + f.d() + "T" + f.h() + ":" + f.i() + ":" + f.s() + f.P();
            },
            //r not supported yet
            U: function(){
                return Math.round(jsdate.getTime()/1000);
            }
    };

    return format.replace(/[\\]?([a-zA-Z])/g, function(t, s){
        if( t!=s ){
            // escaped
            ret = s;
        } else if( f[s] ){
            // a date function exists
            ret = f[s]();
        } else{
            // nothing special
            ret = s;
        }

        return ret;
    });
}


TS.Util.Date.get_url_timestring = function(d)
{
  return Date.UTC(
    d.getUTCFullYear(),
    d.getUTCMonth(), 
    d.getUTCDate(), 
    d.getUTCHours(), 
    d.getUTCMinutes(), 
    d.getUTCSeconds()) / 1000;
}


TS.Util.Date.url_timestring_to_display_date = function(str)
{
  var d = new Date( str * 1000 );

  var year   = d.getUTCFullYear();
  var month  = d.getUTCMonth();
  var day    = d.getUTCDate();
  var hour   = d.getUTCHours();
  var minute = d.getUTCMinutes();
  var second = d.getUTCSeconds();

  var disp_date = '';
  disp_date += TS.Util.Date.month_lookup[month] + " ";

  if (day) {
    disp_date += day + ", ";
  }
  disp_date += year;

  if (hour != 0 || minute != 0 || second != 0)
  {
    if (hour || hour === 0) {
      var disp_hour = hour;
      if (hour > 12) {
        disp_hour -= 12;
      }
      if (disp_hour == 0) {
        disp_hour = 12;
      }
      disp_date += " " + (disp_hour) + ":";

      if (minute) {
        if (minute < 10) {
          disp_date += "0";
        }
        disp_date += minute;
      } else {
        disp_date += "00";
      }
      if (second) {
        if (second < 10) {
          disp_date += "0";
        }
        disp_date += ":" + second;
      }

      if (hour > 12) {
        disp_date += " PM";
      } else {
        disp_date += " AM";
      }
    }
  }
  return disp_date;
}
/*
 *   $Id: util_menu.js 6710 2009-01-28 22:31:55Z zs $
 *
 *  Copyright (c) 2007 Underlying Inc. All rights reserved.
 *
 */

var t1me_menu_open_ = 0;

// Will clean these up as soon as we need another drop down
function t1me_button_click(action, targetCode) {
  var curOpen = t1me_menu_open_;
  t1me_menu_hide_any();
  
  if (curOpen == "menu_" + targetCode) { return; }

  var aElt = document.getElementById("a_" + targetCode);
  var xOffset = YAHOO.util.Dom.getX(aElt);
  var yOffset = YAHOO.util.Dom.getY(aElt);

  var elt = document.getElementById("menu_" + targetCode);
  if (elt.style.display == 'none') {
    elt.style.display = 'block';
    YAHOO.util.Dom.setX(elt, xOffset);
    YAHOO.util.Dom.setY(elt, yOffset+15);
    setTimeout("t1me_menu_open_ = '" + elt.id + "';", 0);
  }
  else {
    elt.style.display = 'none'; 
  }
}    var callback = { success : function(o) { this_obj.process_event_edit(o); } , failure : function(o) { this_obj.process_error(o); } };


function t1me_menu_hide(targetCode) {
  var elt = document.getElementById("menu_" + targetCode);
  if (elt) {
    elt.style.display = 'none';  
  }
  t1me_menu_open_ = 0;
}

function t1me_menu_hide_any() {
  if (t1me_menu_open_) {
    var elt = document.getElementById(t1me_menu_open_);
    if (elt) {
      elt.style.display = 'none';
    }
    t1me_menu_open_ = 0;
  }
}
dipity.MiniCal = function( arg_container_elem_id, arg_get_minical_prefix)
{
  this.showCalendar = function(mon, day, year)
  {
    // roll year if out-of-bounds month is given
    if (mon || year) {
      if (mon > 12) {
        mon -= 12;
        year++;
      }
      else if (mon < 1) {
        mon = 12;
        year--;
      }
    }

    // setup defaults if null params
    var d = new Date();

    if (year == null) {
      year = d.getUTCFullYear();
    }
    if (mon == null) {
      mon = d.getUTCMonth() + 1;
    }
    if (day == null) {
      day = d.getUTCDate();
    }

    var args_str = [];
    args_str.push("get_minical_prefix=" + escape(this.get_minical_prefix));
    args_str.push("mon=" + escape(mon));
    args_str.push("year=" + escape(year));
    args_str.push("day=" + escape(day));

    // ajax request
    var callback = { success : function(o) { this_obj.displayCalendar(o); } , 
                     failure : function(o) { this_obj.displayCalendarFailure(o); } };   

    var url = "/get_minical.php?";
    this.requestingCalendar = true;
    YAHOO.util.Connect.asyncRequest('GET', url + args_str.join("&"), callback);
  }


  // Event Edit: Calendar Popup
  this.displayCalendar = function(o) 
  { 
    this.requestingCalendar = false;
    if (! o.responseText) { return; }
    var json_obj = eval('(' + o.responseText + ')');

    this.minical_elem = document.getElementById(this.minical_elem_id);
    this.minical_elem.innerHTML = json_obj['calendar'];

    this.minical_elem.style.display = 'block';
    this.showingCalendar = true;
    
    this.mcMonth = json_obj['mon'];
    this.mcYear = json_obj['year'];
  }


  this.hideCalendar = function() 
  {
    if (this.requestingCalendar) { return; }
    if (this.minical_elem) {
      this.minical_elem.style.display = 'none'; 
      this.minical_elem.innerHTML = '';
    }
    this.showingCalendar = false;
  }


  this.isDisplayed = function()
  {
    return this.showingCalendar;
  }
  
  
  this.displayCalendarFailure = function(o) { 
    console.error("minical ajax failure ", o);
  }


  this.prevYear = function() {
    this.showCalendar(this.mcMonth, 0, this.mcYear - 1);
  }
  this.prevMonth = function() {
    this.showCalendar(this.mcMonth - 1, 0, this.mcYear);
  }

  
  this.nextMonth = function() {
    this.showCalendar(parseInt(this.mcMonth) + 1, 0, this.mcYear);
  }
  this.nextYear = function() {
    this.showCalendar(this.mcMonth, 0, parseInt(this.mcYear) + 1);
  }


  this.setDate = function( mon, day, year)
  {
    this.mcMonth = mon;
    this.mcDay = day;
    this.mcYear = year;
    this.on_change.fire( mon, day, year );
  }


  // setup
  var this_obj = this;

  // obj vars
  this.requestingCalendar = false;
  this.mcMonth = 0;
  this.mcDay = 0;
  this.mcYear = 0;
  this.showingCalendar = false;

  if (arg_container_elem_id == null) {
    console.error("Must pass container element to minical constructor");
  } else {
    this.minical_elem_id = arg_container_elem_id;
    this.minical_elem = null;

    this.get_minical_prefix = arg_get_minical_prefix;
  }
  this.on_change = new YAHOO.util.CustomEvent('minical_on_change');
}
var sz_util =
{
  getRegionWH: function( elem )
  {
    var region    = YAHOO.util.Dom.getRegion(elem);
    region.width  = region.right - region.left;
    region.height = region.bottom - region.top;

    return region;
  },

  ajaxRequest: function(method, req_url, callback, args) 
  {
    if (method == "POST") {
      if (args && args.length) {
        args = [args, '&fb_sig_user=',fb_sig_user,'&fb_sig_session_key',fb_sig_session_key].join("");
      } else {
        args = ['fb_sig_user=',fb_sig_user,'&fb_sig_session_key',fb_sig_session_key].join("");
      }
    } else {
      var urlobj = new URL(req_url);

      if (typeof(fb_sig_user) != "undefined") 
      {
        urlobj.addArg('fb_sig_user', fb_sig_user, false);
        urlobj.addArg('fb_sig_session_key', fb_sig_session_key, false);
      }
      req_url = urlobj.getUrlStr();
    }

    YAHOO.util.Connect.asyncRequest(method, req_url, callback, args);
  }
};


var URL = function( url_str )
{
  this.parseUrlStr = function(url_str)
  {
    var proto_arr = url_str.split("://");

    if (proto_arr.length > 0) {
      this.proto = proto_arr.shift();
    } else {
      this.proto = "http";
    }
    
    if (proto_arr.length < 1) {
      console.error("Unparsable URL ", url_str);
      return;
    }

    host_arr = proto_arr.shift().split("/");

    if (host_arr.length > 0) {
      this.host = host_arr.shift();
    }

    var post_host = '';
    if (host_arr.length > 0) {
      var post_host = host_arr.join("/"); 
    }

    var path_arr = post_host.split("?");

    var path_str = '';
    if (path_arr.length > 0) {
      path_str = path_arr.shift();
    }
    this.path = "/" + path_str;

    var query_arr = [];
    if (path_arr.length > 0) {
      query_arr = path_arr.shift().split("#");
    }

    var query_str = '';
    if (query_arr.length > 0) {
      query_str = query_arr.shift();
    }

    var hash_str = '';
    if (query_arr.length > 0) {
      hash_str = query_arr.shift();
    }
    if (hash_str && hash_str != '') {
      this.hash = "#" + hash_str;
    }
    
    var querystr_arr = query_str.split("&");
    for (var qs_idx in querystr_arr)
    {
      var pair_arr = querystr_arr[qs_idx].split("=");
      var key = pair_arr.shift();
      var val = pair_arr.shift();
      var val_arr = [];
      if (val) {
        val_arr = val.split(",");
        for (var val_idx in val_arr)
        {
          this.addArg(key, val_arr[val_idx], true);
        }
      } else if (key) {
        this.addArg(key, '', true);
      }
    }
  }

  this.getUrlStr = function()
  {
    var query_str_list = [];
    for (var key in this.query_args) 
    {
      var val_list = this.query_args[key];

      if (val_list.length > 0) 
      {
        var esc_val_list = [];
        for (var val_idx in val_list) {
          var val = val_list[val_idx];
          esc_val_list.push(escape(val));
        }
        query_str_list.push( [ escape(key), "=", esc_val_list.join(",") ].join("") );
      }
    }
    var query_str = '';
    if (query_str_list.length > 0) {
      query_str = [ '?', query_str_list.join("&") ].join("");
    }

    return [ 
        (this.proto ? this.proto : 'http') , "://" , 
        (this.host  ? this.host : "www.dipity.com" ) , 
        (this.path  ? this.path : "/") , 
        query_str , 
        this.hash 
            ].join("");
  }

  this.resetArg = function( key ) {
    this.query_args[key] = [];
  }

  this.addArg = function( key, val, allowMulti )
  {
    if (typeof(this.query_args[key]) != "undefined" && allowMulti != false) {
      this.query_args[key].push(val);
    } else {
      if (typeof(val) == "string") {
        this.query_args[key] = [ val ];
      } else if (typeof(val) != "undefined") {
        this.query_args[key] = val;
      }
    }
  }

  this.removeArg = function( key )
  {
    if (typeof(this.query_args[key]) != "undefined") {
      this.query_args[key] = null;
    }
  }

  this.getArg = function( key )
  {
    if (this.query_args[key]) {
      return this.query_args[key];
    } else {
      return "";
    }
  }

  this.proto = '';
  this.host  = '';
  this.path  = '';
  this.query_args = {};
  this.hash  = '';

  if (url_str != null) {
    this.parseUrlStr(url_str);
  }

};
var sb_slider = function( arg_parent_obj, arg_parent_elem )
{
  this.doLayout = function()
  {
    var parent_region = sz_util.getRegionWH(this.parent_elem);
    elems.sb_slider.style.width = [ parent_region.width, "px" ].join("");
  }

  this.init = function()
  {
    for (var div_id in req_divs)
    {
      if (div_id) {
        elems[div_id] = document.getElementById(div_id);
      }
    }
    this.doLayout();
    regions.sb_slider = sz_util.getRegionWH(elems.sb_slider);
    //console.log(regions.sb_slider.width);
    this.parent_obj.on_resize.subscribe(function() { this_obj.doLayout(); });
  }

  this.processResponse = function( d )
  {
    if (typeof(d.range) != 'undefined' && typeof(d.panel_width_ts) != 'undefined')
    {
      screen_width_ts = parseInt(d.panel_width_ts);
      min_utc_ts = parseInt(d.range.extents_start);
      max_utc_ts = parseInt(d.range.extents_end);
      tl_width_ts = max_utc_ts - min_utc_ts;

      elems.sb_slider_inner.style.width = [ regions.sb_slider.width * (1+( tl_width_ts / screen_width_ts )), "px" ].join("");
      regions.sb_slider_inner = sz_util.getRegionWH(elems.sb_slider_inner);

      scroll_range_px = regions.sb_slider_inner.width - regions.sb_slider.width;
      if (scroll_range_px < 0) {
        scroll_range_px = 0;
      }
    }

    if (typeof(d.ct) != 'undefined') {
      //console.log("SETTING TS", d.ct);
      this.trackEvents = false;
      this.setTS(d.ct, false);
      setTimeout( function() { this_obj.trackEvents = true; }, 1000);
    }
  }

  this.setTS = function(ts, bBroadcastChange)
  {
    //console.log("SLIDER setTS: ts=", ts, " min_utc_ts=", min_utc_ts, " max_utc_ts=", max_utc_ts);
    if (ts < min_utc_ts) {
      ts = min_utc_ts;
    } else if (ts > max_utc_ts) {
      ts = max_utc_ts;
    }
    this.curr_ts = ts;
    this.updateSliderPos(bBroadcastChange);
  }

  this.tsToPosition = function(ts)
  {
    return Math.floor( scroll_range_px * ( ts - min_utc_ts ) / tl_width_ts );
  }

  this.positionToTS = function()
  {
    //console.log("SLIDER positionToTS", Math.floor( min_utc_ts + ( elems.sb_slider.scrollLeft / scroll_range_px ) * tl_width_ts ), min_utc_ts, elems.sb_slider.scrollLeft, scroll_range_px, tl_width_ts);
    return Math.floor( min_utc_ts + ( elems.sb_slider.scrollLeft / scroll_range_px ) * tl_width_ts );
  }

  this.updateSliderPos = function(bBroadcastChange) 
  {
    this.broadcast_scroll = bBroadcastChange;
    //console.log("updateSliderPos: ts=", this.curr_ts, " pos=", this.tsToPosition(this.curr_ts));
    elems.sb_slider.scrollLeft = this.tsToPosition(this.curr_ts);
  }

  this.handleScroll = function()
  {
    //console.log("HANDLE SCROLL BS:", this.broadcast_scroll, elems.sb_slider.scrollLeft);
    this.curr_ts = this.positionToTS();
    //console.log("SCROLL TS=", this.curr_ts);
    if (this.broadcast_scroll == true) {
      //console.log("FIRE SLIDER on_move");
      this.on_move.fire( this.curr_ts );
    }
    this.broadcast_scroll = true;

    // track the slide event max once per second
    //if (this.trackTimer == null && this.trackEvents === true) {
    //  tl.trackEvent("slide","scrollbar");
    //  this.trackTimer = 1;
    //  setTimeout( function() { this_obj.trackTimer = null; }, 1000);
    //}
  }

  this.on_move     = new YAHOO.util.CustomEvent('sb_slider_move');

  var this_obj = this;
  var min_utc_ts = null;
  var max_utc_ts = null;
  var tl_width_ts = null;
  var screen_width_ts = null;
  var scroll_range_px = 0;
  this.trackTimer = null;
  this.broadcast_scroll = true;
  this.parent_obj = arg_parent_obj;
  this.parent_elem = arg_parent_elem;

  var req_divs = {
    'sb_slider':{},
    'sb_slider_inner':{},
    '':{}
  };
  var elems = {};
  var regions = {};

  this.init();

  YAHOO.util.Event.addListener(elems.sb_slider, "scroll", 
    function(e) {
      this_obj.handleScroll();
    }
  ); 
}
var sz_zoomslider = function( arg_parent_obj )
{
  this.init = function()
  {
    for (var div_id in req_divs)
    {
      if (div_id) {
        elems[div_id] = document.getElementById(div_id); }
    }

    var options_arr = [];
    var i = 0;
    var num_zls = parent_obj.zoom_levels.length;
    for(var zlid in parent_obj.zoom_levels)
    {
      elems.zoomdropdown.options[i++] = new Option(parent_obj.zoom_levels[zlid]['name'], zlid);
    }
    
    this.doLayout();
  }


  this.doLayout = function()
  {
    //console.log(elems.zoomslider);
    this.zoomslider = YAHOO.widget.Slider.getVertSlider(elems.zoomslider, elems.zoomthumb, 0, num_ticks * tick_incr, tick_incr); 
    this.zoomslider.animate = false; 

    this.zoomslider.subscribe("change", function(newX) { this_obj.handleChange(newX);    });
    YAHOO.util.Event.addListener("zoomthumb",  "mousedown",  function(e) { tl.trackEvent("zoom", "slider"); YAHOO.util.Event.stopEvent(e); slider_mousedown = true; });
    YAHOO.util.Event.addListener("zoomslider", "mousedown",  function(e) { tl.trackEvent("zoom", "slider"); YAHOO.util.Event.stopEvent(e); slider_mousedown = true; });
    YAHOO.util.Event.addListener(elems.zoomdropdown, "change",  function(e) { 
      if (slider_mousedown != true) {
        tl.trackEvent("zoom", "dropdown"); 
        this_obj.on_move.fire(elems.zoomdropdown.selectedIndex);
      }
    });
    YAHOO.util.Event.addListener(document,    "mouseup",    function(e) { 
      if (slider_mousedown == true) {
        this_obj.on_move.fire(this_obj.curr_val);
        slider_mousedown = false;
      }
    });
    YAHOO.util.Event.addListener("zoomslider_zoom_in",  "click", function(e) { YAHOO.util.Event.stopEvent(e); this_obj.zoomIncr(true);  });
    YAHOO.util.Event.addListener("zoomslider_zoom_out", "click", function(e) { YAHOO.util.Event.stopEvent(e); this_obj.zoomIncr(false); });

  }

  this.zoomIncr = function( bZoomIn )
  {
    this.curr_val += (bZoomIn ? -1 : 1);

    if (this.curr_val < 0) {
      this.curr_val = 0;
    }
    else if (this.curr_val > num_ticks) {
      this.curr_val = num_ticks;
    }
    tl.trackEvent("zoom", "plusminus");
    this.zoomslider.setValue(this.curr_val * tick_incr, false);
    this.on_move.fire(this.curr_val);
  }


  this.setZoomQuietly = function( zoom_level )
  {
    this.curr_val = zoom_level;
    this.zoomslider.setValue(this.curr_val * tick_incr, false);
  }


  this.handleChange = function( pos )
  {
    this.curr_val = pos / tick_incr;

    var dd = document.getElementById("zoomdropdown");
    dd.selectedIndex = this.curr_val;
    document.getElementById("zoomthumb").innerHTML = '<span class="zoomlabel">' + dd.options[dd.selectedIndex].innerHTML + '</span>';
  }


  /* constructor */
  var this_obj = this; // for closures

  var req_divs = {
    'zoomslider':{},
    'zoomthumb':{},
    'zoomdropdown':{},
    '':{}
  };

  var elems = {};
  var regions = {};
  var tick_incr = 10;
  var num_ticks = 6;
  var slider_mousedown = false;
  var parent_obj = arg_parent_obj;
  
  this.on_move = new YAHOO.util.CustomEvent('sz_zoomslider_move');
  this.zoomslider = null;
  this.curr_val = 0;

  this.init();
};
var sz_panelcache = function( arg_panelholder_obj )
{
  this.init = function()
  {
    cache_hash = {};
  }


  this.setPanelData = function( key, d )
  {
    //console.log("panelcache SET key=", key);
    cache_hash[key] = d;
  }


  this.clearPanelData = function( key )
  {
    //console.log("panelcache CLEAR key=", key);
    delete cache_hash[key];
  }


  this.getPanelData = function( req_obj, callback )
  {
    //console.log("GETPANELDATA:", req_obj);
    var resp_obj = { 'panels':{} };

    var server_req_obj = {};
    var bCallCallback = false;

    for (var key in req_obj) {
      if (typeof(key) == 'string' && key != 'panels') {
        server_req_obj[key] = req_obj[key];
      }
    }
    server_req_obj.panels = [];

    for ( var req_idx in req_obj['panels'] )
    {
      var panel_id = req_obj.panels[req_idx]['panel_id'];
      var seq_num  = req_obj.panels[req_idx]['seq_num'];

      if (typeof(cache_hash[seq_num]) != 'undefined')  // check if seq_num is cached
      {
        resp_obj['panels']['panel_' + panel_id] = cache_hash[seq_num];
        //console.log(panel_id, "panelcache GET key=", seq_num);
        bCallCallback = true;
        //console.log("FOUND IN CACHE");
      } else {
        server_req_obj.panels.push( req_obj.panels[req_idx] );
        //console.log("NOT IN CACHE");
      }
    }

    // request data if not all panels in cache
    if (server_req_obj.panels.length > 0) {
      this.requestData( server_req_obj, callback );
    }

    // call callback function if some panels found in cache
    //console.log("RESP OBJ=", resp_obj);
    if (bCallCallback) {
      callback(resp_obj);
    }
  }


  this.consoleLogCache = function()
  {
    console.log(cache_hash);
  }

  this.genReqSig = function( req_obj, bFull )
  {
    if (bFull) {
      return [ req_obj.ct, req_obj.z, req_obj.tid ].join("");
    } else {
      return [ req_obj.z, req_obj.tid ].join("");
    }
  }

  var req_sig = null;
  this.requestData = function( req_obj, callback )
  {
    var common_args = panelholder_obj.getCommonRequestArgs();

    for (var key in common_args) {
      if (typeof(key) == "string" && common_args[key] !== null) {
        req_obj[key] = common_args[key];
      }
    }

    // check for responses we don't need to pay attention to
    req_sig = this.genReqSig(req_obj, (typeof(req_obj.panels) == "undefined"));
    req_obj.req_sig = req_sig;
    //console.log("IN REQUEST req_sig=", req_sig);

    var yui_callback = { success : function(o) { this_obj.processResponse(o, callback); }, failure : function(o) { this_obj.processError(o); } };
//     var url = base_url + "get_event.php";
    var url = timeline_view_url ;
    var args_str = [];
    for (var key in req_obj) 
    {
      if (key == 'panels') 
      {
        var panel_pairs = [];
        for (var idx in req_obj['panels']) {
          var req_panel = req_obj['panels'][idx];
          panel_pairs.push( 
            req_panel['panel_id'] + 
            ":" + req_panel['seq_num'] + 
            ":" + escape(typeof(req_panel['oh']) != 'undefined' ? req_panel['oh'] : '') + 
            ":" + escape(typeof(req_panel['mx']) != 'undefined' ? req_panel['mx'] : '')
            );
          // tell the panel what seq_num to expect
          panelholder_obj.getPanel(req_panel['panel_id']).expect_seq_num = req_panel['seq_num'];
        }
        args_str.push("panels=" + panel_pairs.join(";"));
        req_obj.np = req_obj['panels'].length;
      } 
      else 
      {
        args_str.push(escape(key) + "=" + escape(req_obj[key]));
      }
    }
    // cache buster
    var d = new Date();
    args_str.push('rand=' + d.getTime());
    //console.log("CACHE REQUEST DATA ", url, "?", args_str.join("&"));
    YAHOO.util.Connect.asyncRequest('GET', url + "&" + args_str.join("&"), yui_callback, null);
    document.getElementById("ajax_loading").style.display = "block";
    //arg_panelholder_obj.parent_obj.trackEvent('load_panel_data', args_str.join("&"));
  }


  this.processError = function( o )
  {
    console.error(o);
  }


  this.processResponse = function( o, callback )
  {
    var d = {};

    if (typeof(o.responseText) != "undefined") {
      d = eval('(' + o.responseText + ')');
    } else {
      d=o;
    }

    // check to see if this is an out-of-order response
    //console.log("IN PROCESS req_sig=", req_sig, d.req_sig);
    if (req_sig != null && req_sig != d.req_sig) {
      //console.log("REQ_SIG_MISMSTCH");
      return;
    } else {
      req_sig = null;
    }

    for (var panel_id in d.panels)
    {
      if (typeof(d.panels[panel_id].seq_num) != 'undefined')
      {
        this.setPanelData(d.panels[panel_id].seq_num, d.panels[panel_id]);
      } 
      else 
      {
        console.log("RESPONSE ", panel_id, " has no seq_num!");
      }
    }
    callback(d);
    document.getElementById("ajax_loading").style.display = "none";
  }

  var this_obj = this;

  var cache_hash = null;
  var panelholder_obj = arg_panelholder_obj;

  this.init();
}

var sz_panelholder = function( arg_parent_obj, arg_container_elem )
{
  this.init = function()
  {
    this.panelcache.init();

    for (var div_id in req_divs)
    {
      if (div_id) {
        elems[div_id] = document.getElementById(div_id);
      }
    }

    this.setupRegions();

    panelholder_pos = this.getNormalPanelholderPos();

    this.doLayout();

    // panel html
    var panel_html = [];
    var panel_width_pct = [ 100 / this.num_panels, "%" ].join("");
    for (var i = 0; i < this.num_panels; i++) {
      panel_html.push( [ 
        '<div style="width:', panel_width_pct, '" class="panel" id="panel_', i, '">',
        '</div>'].join(""));
    }
    elems.panelholder.innerHTML = panel_html.join("");

    // panel elements
    for (var i = 0; i < this.num_panels; i++)
    {
      var panel_id = 'panel_' + i;
      panel_order.push(i);
      elems[panel_id] = document.getElementById(panel_id);

      panels[i] = new sz_panel(this_obj, panel_id, elems.container);
    }
    this.setPanelPos();
  }


  this.requestAllData = function( req_obj, no_reset )
  {
    //debugger;
    //console.log("REQUEST ALL DATRA", panel_width, panelholder_pos);
    if (no_reset) {
      this.panelcache.requestData( req_obj, function(d) { 
        this_obj.parent_obj.processResponse(d); 
        } );
    }
    else {
      this.panelcache.init();
      this.panelcache.requestData( req_obj, function(d) { 
        this_obj.resetPanelOrder(); 
        this_obj.resetForReqAllData(); 
        this_obj.parent_obj.processResponse(d); 
        } );
    }
  }

  this.handleResize = function() 
  { 
    var orig_ph_width = panel_width * this.num_panels;
    var orig_cp = this.getCenteredPos();
    var orig_prop = orig_cp / orig_ph_width;

    this.setupRegions(); // get new panel_width and container_region

    panelholder_pos = Math.floor((regions.container.width / 2) - (panel_width * this.num_panels * orig_prop));

    this.doLayout();

    this.on_resize.fire();
  }

  this.resetForReqAllData = function()
  {
    this.setupRegions(); // get new panel_width and container_region
    panelholder_pos = this.getNormalPanelholderPos();
    this.doLayout();
  }

  this.getNormalPanelholderPos = function()
  {
    //console.log("GNPP", this.num_panels, panel_width, regions.container.width, (this.num_panels * panel_width) / 2, regions.container.width / 2, -1 * (((this.num_panels * panel_width) / 2) - (regions.container.width / 2)));
    return -1 * (((this.num_panels * panel_width) / 2) - (regions.container.width / 2));
  }

  this.setupRegions = function()
  {
    regions.container = sz_util.getRegionWH( elems.container );
    //panel_width = regions.container.width;
    panel_width = fixed_panel_width;
  }


  // set up panelholder min/max, position, and width
  this.doLayout = function()
  {
    var normal_panelholder_pos = this.getNormalPanelholderPos();
    min_panelholder_pos = normal_panelholder_pos - (0.5 * panel_width); 
    max_panelholder_pos = normal_panelholder_pos + (0.5 * panel_width);

    //console.log(normal_panelholder_pos, min_panelholder_pos, max_panelholder_pos, panelholder_pos);

    elems.panelholder.style.width = [ (panel_width * this.num_panels), 'px' ].join("");
    elems.panelholder.style.height = [ regions.container.height, 'px' ].join("");

    if (!isNaN(panelholder_pos)) {
      elems.container.scrollLeft = -1 * panelholder_pos;
    }
  }


  // sets the panel position within the panelholder based on panel_order[]
  this.setPanelPos = function()
  {
    for (var i = 0; i < this.num_panels; i++)
    {
      var panel_id = "panel_" + panel_order[i];
      if (panels[panel_order[i]].max_utc_ts <= min_utc_ts) {
        elems[panel_id].style.zIndex = 0;
      } else {
        elems[panel_id].style.zIndex = this.num_panels - i + 1;
      }
      elems[panel_id].style.left = [ 100 * (i / this.num_panels), "%" ].join("");
    }
  }


  // handler for container drag events
  this.doSlide = function( deltaX, bUpdateCurrTS )
  {
    if (Math.abs(deltaX) > panel_width) { deltaX = (deltaX / Math.abs(deltaX)) * (panel_width); }
    
    // HACK: Reduces timeline disappearance by avoiding big shifts
    if (deltaX > panel_width) { deltaX = panel_width; }
    if (deltaX < -1 * panel_width) { deltaX = -1 * panel_width; }
    //console.log(deltaX, bUpdateCurrTS, this.curr_utc_ts, min_utc_ts, max_utc_ts);

    panelholder_pos += parseInt(deltaX);

    var shifted_id = false;

    //console.log("DX:", deltaX, "PW:", panel_width, "PP:", panelholder_pos, "MNPP:", min_panelholder_pos, "MXPP:", max_panelholder_pos);

    if (panelholder_pos < min_panelholder_pos) {
      panel_order.push(panel_order.shift());
      shifted_id = panel_order[ this.num_panels - 1 ];
      panelholder_pos += panel_width;
      //console.log("SHIFT L->R", panel_order, shifted_id);
    } else if (panelholder_pos > max_panelholder_pos) {
      panel_order.unshift(panel_order.pop());
      shifted_id = panel_order[0];
      panelholder_pos -= panel_width;
      //console.log("SHIFT R->L", panel_order, shifted_id);
    }
    
    if (shifted_id !== false) 
    {
      this.setPanelPos();
      panels[shifted_id].youGotShifted( (deltaX > 0 ? -1 : 1) * this.num_panels );

      var panel_req_obj = {
        'panel_id':shifted_id, 
        'seq_num':panels[shifted_id].getSeqNum()
      };

      if (deltaX > 0) {
        // shifted R->L, need matrix str of next panel
        panel_req_obj['mx'] = panels[ (shifted_id + 1) % this.num_panels ].getMatrixStr();
        console.log(panel_req_obj['mx'], (shifted_id + 1) % this.num_panels);
      } else {
        // shifted L->R, need overhang str of prev panel
        panel_req_obj['oh'] = panels[ (shifted_id - 1 + this.num_panels) % this.num_panels ].getOverhangStr();
      }

      this.panelcache.getPanelData( { 'panels':[ panel_req_obj ] }, function(d) { this_obj.parent_obj.processResponse(d); } );
      // console.log( "SHIFT:", shifted_id, ( deltaX > 0 ? "RIGHT" : "LEFT"), panels[ shifted_id ].panel_req_offset); 
    }

    elems.container.scrollLeft = -1 * panelholder_pos;

    if (bUpdateCurrTS) {
      var cent_ts = this.getCenteredTS();
      this.setCurrTS(cent_ts);
      if (cent_ts > max_utc_ts) {
        this.setCurrTS(max_utc_ts);
        this.slideToTS(max_utc_ts, false);
      } else if (this.getCenteredTS() < min_utc_ts) {
        this.setCurrTS(min_utc_ts);
        this.slideToTS(min_utc_ts, false);
      }
    }
    elems.curr_datetime_val.innerHTML = TS.Util.Date.format_date_for_zoomlevel(parseInt(this.curr_utc_ts) + parseInt(this.parent_obj.gmtoffset), TS.Util.Date.currdisp_zoomlevel_id);
  }


  this.position_nowline = function()
  {
    var d = new Date();
    var now_utc_ts = parseInt(d.getTime() / 1000);
    now_utc_ts += d.getTimezoneOffset() * 60; // adjust for client tz
    now_utc_ts += this.parent_obj.gmtoffset; // adjust to TL tz
    //console.log("NOWLINE off:", this.parent_obj.gmtoffset);

    if (now_utc_ts >= holder_min_utc_ts && now_utc_ts < holder_max_utc_ts)
    {
      for (var i = 0; i < this.num_panels; i++)
      {
        if (now_utc_ts >= panels[i].min_utc_ts && now_utc_ts < panels[i].max_utc_ts)
        {
          // now is somewhere within panel[i]
          if (!elems.nowline) 
          {
            elems.nowline = document.createElement("DIV");
            elems.nowline.setAttribute("id", "nowline");
          } 
          var left_pos = Math.round( 100 * ( (now_utc_ts - panels[i].min_utc_ts)/(panels[i].max_utc_ts - panels[i].min_utc_ts)));
          if (elems.nowline.parentNode != elems["panel_" + i])
          {
            elems["panel_" + i].appendChild(elems.nowline);
          }
          elems.nowline.style.left = [ left_pos, '%' ].join("");
        }
      }
    } else {
      if (elems.nowline && elems.nowline.parentNode) {
        elems.nowline.parentNode.removeChild(elems.nowline);
      }
    }
  }


  this.animateSlide = function( delta_x, frames, ms_per_frame )
  {
    var incr_x = Math.floor(delta_x / frames);
    if (incr_x < 0) { incr_x += 1; }
    for (var i = 0; i < frames; i++) {
      window.setTimeout( function() { 
        this_obj.doSlide(incr_x, true, true); 
      }, ms_per_frame * i );
      delta_x = delta_x - incr_x;
    }
    window.setTimeout( function() { 
      this_obj.doSlide(delta_x, true, true);  
      this_obj.parent_obj.setCurrUtcTS(this_obj.getCenteredTS()); 
    }, ms_per_frame * (i + 1) );
  }
  
  var kineticSlideTerminated = 0;
  this.terminateKineticSlide = function() {
    kineticSlideTerminated = 1;
  }
  
  this.kineticSlide = function ( speed, friction ) {
    // now let's not go too crazy here!
    if (speed > 100) { speed = 100; }
    if (speed < -100) { speed = -100; }
      
    var absSpeed = Math.abs(speed);
    if (!friction) {
      // drop out if there isn't enough momentum
      if (absSpeed < 3) { 
        return; 
      }
    
      // set the friction based on the initial speed
      if (absSpeed > 50) { friction = 0.1; }
      else { friction = 0.15; }
      
      kineticSlideTerminated = 0;
    }
    
    if (this_obj.curr_utc_ts <= min_utc_ts || this_obj.curr_utc_ts >= max_utc_ts) {
      speed = -0.3 * speed;
    }
  
    if (kineticSlideTerminated || absSpeed < 0.2) {
      // we slowed down enough, finish the slide
      return; 
    }
    
    var ms_per_frame = 20;
    if (absSpeed > 0.2 && absSpeed < 1.0) {
      ms_per_frame = Math.floor((1.0 / absSpeed) * 20);
    }

    var slideX = 0;
    if (speed > 0) { slideX = Math.ceil(speed); }
    else { slideX = Math.floor(speed); }

    // console.log("utc[" + this_obj.curr_utc_ts + "] min[" + min_utc_ts + "] max[" + max_utc_ts + "] slideX [" + slideX + "]");
    this_obj.doSlide(slideX, true, true);
    this_obj.parent_obj.setCurrUtcTS(this_obj.getCenteredTS()); 
    this_obj.parent_obj.slider.setTS(this_obj.curr_utc_ts, false); 

    window.setTimeout(
      function() {
        this_obj.kineticSlide(speed * (1.0 - friction), friction);
      }, ms_per_frame);    
  }


  this.setCurrTS = function( ts )
  {
    this.curr_utc_ts = ts;
  }


  this.animateZoom = function( delta_zoom, frames, ms_per_frame, run_when_done )
  {
    if (delta_zoom < 1) {
      delta_zoom = 1 - delta_zoom;
    }

    var orig_vp_width = this.num_panels * panel_width;
    var new_vp_width  = this.num_panels * panel_width * delta_zoom;

    var incr_zoom = (new_vp_width - orig_vp_width) / frames;

    //console.log("ANIMATEZOOM", delta_zoom, orig_vp_width, new_vp_width, incr_zoom);

    for (var i = 0; i < frames; i++) {
      window.setTimeout( function() { this_obj.zoomIncr(incr_zoom); }, ms_per_frame * i );
      delta_zoom = delta_zoom / incr_zoom;
    }
    window.setTimeout( function() { this_obj.zoomIncr(delta_zoom); }, ms_per_frame * (i + 1) );
    window.setTimeout( function() { run_when_done(); }, ms_per_frame * (i + 2));
  }


  // zoom panelholder some increment
  this.zoomIncr = function( zoom_amt )
  {
    var orig_ph_width = this.num_panels * panel_width;
    var new_ph_width = orig_ph_width + zoom_amt;

    panel_width = new_ph_width / this.num_panels;

    panelholder_pos -= Math.floor(( this.getCenteredPos() / orig_ph_width ) * ((this.num_panels * panel_width) - orig_ph_width));

    this.doLayout();
  }


  // return panelholder pixel position of where the panelholder intersects the middle of the container
  this.getCenteredPos = function() 
  {
    return Math.round((regions.container.width / 2) - panelholder_pos);
  }


  // return panel id of panel closest to middle of container
  this.getCenteredPanelIdx = function()
  {
    return panel_order[ Math.floor(this.getCenteredPos() / panel_width) ];
  }


  this.pxToTS = function(vp_pos)
  {
    //console.log(vp_pos-panelholder_pos, (vp_pos-panelholder_pos) / panel_width, panels[panel_order[0]].getWidthTS(), panels[panel_order[0]].min_utc_ts);
    return panels[panel_order[0]].min_utc_ts + ( ( (vp_pos-panelholder_pos) / panel_width ) * panels[0].getWidthTS());
  }


  this.getCenteredTS = function()
  {
    var centeredPanelIdx = this.getCenteredPanelIdx();

    var centeredTS = null;

    if (typeof(panels[centeredPanelIdx]) != "undefined" && panels[centeredPanelIdx].min_utc_ts != null)
    {
      centeredTS = Math.floor( parseInt(panels[centeredPanelIdx].min_utc_ts) + ( ( (this.getCenteredPos() % panel_width) / panel_width ) * panels[centeredPanelIdx].getWidthTS()));
    }

    //console.log("getCenteredTS PANEL=", centeredPanelIdx, " POS=", this.getCenteredPos(), " TS=", centeredTS, " PWTS:", panel_width_ts, " PW:", panel_width, panels[centeredPanelIdx].min_utc_ts);

    return centeredTS;
  }


  this.slideToTS = function( desired_ts, bUpdateCurrTS )
  {
    if (holder_min_utc_ts == null || holder_max_utc_ts == null) {
      this.setHolderMinMax();
    }
    //console.log("SLIDE TO TS", desired_ts, holder_min_utc_ts, holder_max_utc_ts);
    desired_ts = parseInt(desired_ts);
    if ((holder_min_utc_ts == null || desired_ts >= holder_min_utc_ts) && 
        (holder_max_utc_ts == null || desired_ts <= holder_max_utc_ts))
    {
      if (this.timeout_jumpToTS != null) {
        clearTimeout(this.timeout_jumpToTS);
        this.timeout_jumpToTS = null;
      }
      if (this.hide_panelholder_for_jump == true) {
        this.hide_panelholder_for_jump = false;
        //elems.panelholder.style.visibility = "visible";
      }
      
      var centered_pos = this.getCenteredPos();

      for (var i = 0; i < this.num_panels; i++) 
      {
        var the_panel = panels[panel_order[i]];
        if ( the_panel.max_utc_ts > desired_ts ) 
        {
          // desired_ts is in this panel
          var panel_prop = ( desired_ts - the_panel.min_utc_ts ) / ( the_panel.getWidthTS() );
          var desired_pos = Math.floor((i + panel_prop) * panel_width);
          //console.log("SLIDE THIS MANY PX ", centered_pos - desired_pos, "cp:", centered_pos, "dp:", desired_pos, "dts:", desired_ts, "cts:", this.getCenteredTS(), "pw:", panel_width);
          this.doSlide(centered_pos - desired_pos, bUpdateCurrTS);
          break;
        }
      }
    }
    else 
    {
      //console.log("ABOUT TO JUMP TO TS", desired_ts);
      //console.log("UP IN HERE", desired_ts, holder_min_utc_ts, holder_max_utc_ts, desired_ts >= holder_min_utc_ts, desired_ts <= holder_max_utc_ts);
      if (this.hide_panelholder_for_jump == false) {
        this.hide_panelholder_for_jump = true;
        //elems.panelholder.style.visibility = "hidden";
      }
      if (bUpdateCurrTS) {
        this.setCurrTS(desired_ts);

        if (this.hide_panelholder_for_jump) {
          if (this.timeout_jumpToTS != null) {
            clearTimeout(this.timeout_jumpToTS);
            this.timeout_jumpToTS = null;
          }
          this.timeout_jumpToTS = setTimeout( function() { this_obj.jumpToTS(this_obj.curr_utc_ts, bUpdateCurrTS); }, 500); 
        }
      }
    }
  }


  this.jumpToTS = function (desired_ts, bUpdateCurrTS, bogus)
  {
    if (desired_ts >= holder_min_utc_ts && 
        desired_ts <= holder_max_utc_ts)
    {
      this.slideToTS(desired_ts, bUpdateCurrTS );
    } else {
      this.panelcache.requestData( { 'ct':desired_ts }, function(d) { 
        this_obj.resetPanelOrder(); 
        this_obj.parent_obj.processResponse(d); 
        } );
    }
  }


  this.resetPanelOrder = function()
  {
    //console.log("RESET PANEL ORDER");
    for (var i = 0; i < this.num_panels; i++) 
    {
      panel_order[i] = i;
    }
    this.setPanelPos();
  }


  this.getPanelWidth = function()
  {
    return panel_width;
  }


  this.getNumPanels = function()
  {
    return this.num_panels;
  }

  this.getPanel = function(panel_id) {
    return panels[panel_id];
  }

  this.processResponse = function( d )
  {
    eventData = null;

    //console.log(panelholder_pos, this.curr_utc_ts, d.ct);
    if (typeof(d.ct) != "undefined") {
      this.curr_utc_ts = parseInt(d.ct);
    }

    if (typeof(d.panel_width_ts) != "undefined") {
      panel_width_ts = parseInt(d.panel_width_ts);
    }

    if (typeof(d.range) != "undefined") {
      min_utc_ts = parseInt(d.range.extents_start);
      max_utc_ts = parseInt(d.range.extents_end);
    }

    // prevent jumpy panelholder
    //elems.panelholder.style.visibility = 'hidden';
    for (var panel_key in d.panels)
    {
      var panel_idx = panel_key.split("_")[1];
      //console.log("SUCHARETARD", d, "IDX:", panel_idx, panel_key, d.panels[panel_key].start_date);
      panels[panel_idx].processResponse(d.panels[panel_key]);
    }
    this.setHolderMinMax();

    for (var panel_key in d.panels)
    {
      var panel_idx = panel_key.split("_")[1];
      panels[panel_idx].processResponse2(d.panels[panel_key]);
    }
    this.setPanelPos();
    this.position_nowline();

    if (typeof(d.ct) != 'undefined') {
      //console.log("PANELHOLDER processResponse d.ct=", d.ct);
      this.slideToTS(d.ct, true);
    }

  }

  // get event data set in a template for an event in one of our panels
  this.getEventData = function(eid)
  {
    if (!eventData) {
      eventData = new Array();
      for (var i = 0; i < panels.length; i++) {
	var dataObj = panels[i].getEventData();
	if (dataObj) {
	  for (var attr in dataObj) {
	    eventData[attr] = dataObj[attr];
	  }
	}
      }
    }

    if (typeof eventData[eid] != "undefined") {
      return eventData[eid];
    }

    return null;
  }

  setInterval(function() { this_obj.position_nowline(); }, 10000);


  // sets the currnet min/max TS values for the panelholder
  this.setHolderMinMax = function()
  {
    holder_min_utc_ts = panels[ panel_order[0] ].min_utc_ts;
    holder_max_utc_ts = panels[ panel_order[this.num_panels - 1] ].max_utc_ts;
  }


  this.getHolderExtents = function()
  {
    return { 'min_utc_ts':holder_min_utc_ts, 'max_utc_ts':holder_max_utc_ts };
  }


  this.getCommonRequestArgs = function()
  {
    regions.container = sz_util.getRegionWH(elems.container);
    return {
      'pw':fixed_panel_width,
      'ph':regions.container.height,
      'np':this.num_panels,
      'z':this.parent_obj.zoom_level_name,
      'tid':this.parent_obj.current_tid,
      'exclude_tids':this.parent_obj.exclude_tids.join(","),
      'bgimg':this.parent_obj.bgimg,
      'bgcolor':this.parent_obj.bgcolor
    };
  }

  /* constructor */
  var this_obj = this;

  var min_utc_ts = null;
  var max_utc_ts = null;
  var holder_min_utc_ts = null;
  var holder_max_utc_ts = null;

  var panel_order = [];
  var panels = [];
  this.num_panels = 4;
  var half_panels = Math.round(this.num_panels / 2);
  var panel_width = fixed_panel_width = 600;
  var panel_width_ts = null;
  var min_panelholder_pos = 0;
  var max_panelholder_pos = 0;
  var panelholder_pos = 0;
  var startX = 0;
  var eventData = null;

  this.panelcache = new sz_panelcache( this_obj );
  this.timeout_jumpToTS = null;

  var elems = {};
  var regions = {};

  var req_divs = {
    'panelholder':{},
    'curr_datetime_val':{},
    'curr_datetime':{},
    '':{}
  };
  elems.container = arg_container_elem;

  this.on_resize = new YAHOO.util.CustomEvent('sz_panelholder_resize');
  this.on_change_utc_ts = new YAHOO.util.CustomEvent('sz_change_utc_ts');
  this.hide_panelholder_for_jump = false;

  arg_parent_obj.on_resize.subscribe(function() { this_obj.handleResize(); } );
  this.parent_obj = arg_parent_obj;

  this.curr_utc_ts = null;

  this.init();
}
var sz_panel = function( arg_parent_obj, arg_panel_id, arg_container_elem )
{
  this.init = function()
  {
    elems.panel  = document.getElementById(panel_id);
    elems.panel.innerHTML = [
        '<div class="events"     id="', panel_id, '_events"></div>',
        '<div class="ticks"      id="', panel_id, '_ticks"></div>',
        '<div class="bumper_right" id="', panel_id, '_bumper_right"></div>',
        ''].join("");

    elems.events     = document.getElementById(panel_id + "_events")
    elems.ticks      = document.getElementById(panel_id + "_ticks")
    this.doLayout();
  }

  this.doLayout = function() {
    regions.container = sz_util.getRegionWH(elems.container);
    elems.panel.style.height = [ regions.container.height, 'px' ].join("");
  }

  this.getSeqNum = function() {
    return this.seq_num;
  }
  this.setSeqNum = function( seqnum ) {
    this.seq_num_changed = 0;
    if (this.seq_num != seqnum) { 
      this.seq_num_changed = 1;    
    }
    this.seq_num = seqnum;
  }

  this.setExtents = function(arg_min_utc_ts, arg_max_utc_ts)
  {
    this.min_utc_ts = parseInt(arg_min_utc_ts);
    this.max_utc_ts = parseInt(arg_max_utc_ts);
    //elems.extents.innerHTML = this.min_utc_ts + " - " + this.max_utc_ts + " (seq:" + this.seq_num + " pid:" + panel_id + ")";
    //console.log("panel extents #", panel_id, this.min_utc_ts, this.max_utc_ts);
  }


  this.processResponse = function( d )
  {
    if (this.expect_seq_num !== null && d.seq_num != this.expect_seq_num) {
      return;
    }

    this.expect_seq_num = null;
    //console.log("PANEL PROCESS RESPONSE d=", d);
    this.setSeqNum(d.seq_num);
    this.setExtents(d.start_date, d.end_date);
    this.setTickHtml(d.ticks_html + '<div class="mainlabel">' + d.mainlabel + '</div>');
    //this.setMainlabel(d.mainlabel);
    // this.setGraphImg(d.graph_img);
    overhang_str = d.overhang;
    matrix_str = d.matrix;    
  }
  this.processResponse2 = function( d )
  {
    this.transitionHtml(d.event_html);
    event_data = d.event_json;    
  }

  this.getEventData = function()
  {
    return event_data;
  }

  this.setGraphImg = function(src)
  {
    if (src && src != '') {
      elems.graph.src = src;
    }
  }

  
  this.setMainlabel = function(str)
  {
    elems.mainlabel.innerHTML = str;
  }


  this.youGotShifted = function ( shifted_num_panels )
  {
    this.waiting_for_content = true;
    overhang_str = '';
    matrix_str = '';
    //console.log("OLD:", this.seq_num, this.max_utc_ts, this.min_utc_ts);
    this.seq_num += parseInt(shifted_num_panels);
    this.setEventHtml("LOADING...");
    this.setTickHtml("");
    var offset = parseInt( shifted_num_panels * this.getWidthTS() );
    this.max_utc_ts += offset;
    this.min_utc_ts += offset;
  }
  

  this.getOverhangStr = function()
  {
    return overhang_str;
  }
  this.getMatrixStr = function()
  {
    return matrix_str;
  }

  this.getWidthTS = function()
  {
    //console.log("WIDTH TS:", this.max_utc_ts, this.min_utc_ts);
    return this.max_utc_ts - this.min_utc_ts;
  }

  
  this.setEventHtml = function( html )
  {
    elems.events.innerHTML = html;
  }

  this.fadeIn = function(fraction) {
    fraction += 0.25;
    if (fraction > 1.0) {
      fraction = 1.0;
    }
    
    elems.events.style['opacity'] = fraction;
    elems.events.style['-moz-opacity'] = fraction;
    if (fraction >= 1.0) { return; }
    
    window.setTimeout( function() { this_obj.fadeIn(fraction); }, 10);
  }
  
  this.transitionHtml = function ( html ) {
    if (this.seq_num_changed) {
      elems.events.style['opacity'] = 0;
      elems.events.style['-moz-opacity'] = 0;
    }
    
    this_obj.setEventHtml(html);
    
    if (this.seq_num_changed) {
      this_obj.fadeIn(0.0);    
      this.seq_num_changed = 0;
    }    
  }
  

  this.setTickHtml = function( html )
  {
    elems.ticks.innerHTML = html;
  }


  /* constructor */
  var this_obj = this;
  var panel_id = arg_panel_id;

  var elems = {};
  var regions = {};
  var overhang_str = '';
  var matrix_str = '';
  var event_data = null;

  this.on_resize = new YAHOO.util.CustomEvent('sz_panel_resize');
  this.min_utc_ts = null;
  this.max_utc_ts = null;
  this.panel_req_offset = 0;
  this.seq_num = null;
  this.expect_seq_num = null;
  this.seq_num_changed = 0;
  this.waiting_for_content = true;
  elems.container = arg_container_elem;

  arg_parent_obj.on_resize.subscribe(function() {
    this_obj.doLayout();
    this_obj.on_resize.fire();
    });

  this.init();
}
/*
 *  $Id: sz_viewport.js 7806 2009-10-08 18:24:42Z bag $
 *
 *  Copyright (c) 2007 Underlying Inc. All rights reserved.
 */

TS.Timeline = function(arg_container_elem_id, arg_page, url_tid, url_time, url_zoom, hide_tl_info, url_display, mode)
{
  this.requestAllData = function( req_obj, no_reset )
  {
    this.panelholder.requestAllData( req_obj, no_reset );
  }

  this.stopEvent = function(e) {
    YAHOO.util.Event.stopEvent(e);
  }

  var first = true;
  
  this.processResponse = function(d)
  {
    if (typeof(d.refresh) != 'undefined' && d.refresh == 1) {
      console.log("Refresh request...");
    }
  
    if (typeof(d.zl) != 'undefined') {
      this.zoom_level_name = d.zl;
      TS.Util.Date.zoom_level = TS.Util.Date.zoom_level_name_to_id(d.zl);
      this.updateZoomlevel(true);
    }

    if (typeof(d.panel_width_ts) != 'undefined') {
      vp_width_ts = (this.panelholder.getPanelWidth() / regions.vp.width) * parseInt(d.panel_width_ts);
    }
    if (typeof(d.ct) != 'undefined') {
      this.setCurrUtcTS(parseInt(d.ct));
    }
    if (typeof(d.tid) != 'undefined') {
      this.current_tid = d.tid;
    }

    if (typeof(d.bgcolor) != 'undefined') {
      this.bgcolor = d.bgcolor;
    }
    if (typeof(d.bgimg) != 'undefined') {
      this.bgimg = d.bgimg;
    }

    if (this.gmtoffset == 0 && typeof(d.gmtoffset) != 'undefined') {
      this.gmtoffset = d.gmtoffset;
    }

    var timelineHeaderCanCreateIndicator = document.getElementById('timeline_can_create');
/*    if (timelineHeaderCanCreateIndicator && timelineHeaderCanCreateIndicator.innerHTML == '1') {
      console.log("Page frame indicates that timeline should be editable!");
    } */
    
    if (typeof(d.can_create_tids) != 'undefined') {
      if (d.can_create_tids.length > 0 || (timelineHeaderCanCreateIndicator && timelineHeaderCanCreateIndicator.innerHTML == '1')) {
        this.can_create_tids = d.can_create_tids;
        YAHOO.util.Event.removeListener(elems.create_event_btn,  "click");
        YAHOO.util.Event.addListener(elems.create_event_btn,  "click",  function(e) { 
          YAHOO.util.Event.stopEvent(e); 
          this_obj.start_event_edit(); 
          });
        YAHOO.util.Event.addListener(elems.manage_feeds_btn,  "click",  function(e) { 
          YAHOO.util.Event.stopEvent(e);
          if (typeof(dialog_feeds)=="undefined") {
            dialog_feeds = new PopupDialog( {
              "url":feeds_href,
              "onclose":"",
              "windowclass":"standard_with_header",
              "windowstyle":"","anchor":"",
              "receiverurl":"",
              "ismodal":true,
              "hash":"feeds"
              });
          }
          dialog_feeds.prepareOpen(); 
          return false;
          });

        YAHOO.util.Dom.replaceClass(elems.create_event_btn, "deact", "active");
        YAHOO.util.Dom.replaceClass(elems.manage_feeds_btn, "deact", "active");
      } 
      else {
        this.can_create_tids = [];
        YAHOO.util.Event.removeListener(elems.create_event_btn,  "click");
        YAHOO.util.Event.removeListener(elems.manage_feeds_btn,  "click");
        YAHOO.util.Dom.replaceClass(elems.create_event_btn, "active", "deact");
        YAHOO.util.Dom.replaceClass(elems.manage_feeds_btn, "active", "deact");
      }
    }

    this.panelholder.processResponse(d);
    this.slider.processResponse(d);

    if (first) {
      this.panelholder.kineticSlide(5, 0.04);
      first = false;
    }

    if (typeof(d.popup_eid) != "undefined" && d.popup_eid != '') {
      this.show_event_detail_popup(d.popup_eid);
      url_eid = ''; // just do once per req
    }
    else if (typeof(url_eid) != "undefined" && url_eid) {
      this.show_event_detail_popup(url_eid);
      url_eid = ''; // just do once per req
    }

    if (d.still_processing) {
      this.still_processing_percent = parseInt(d.still_processing_percent);
      this.still_processing = 1;
      
      dt = new Date();
      var now_time = dt.valueOf();

      // THIS IS A CRAPPY CRAPPY HACK, I WILL FIX EVENTUALLY
      //console.log("Diff [" + (now_time - this.last_request_time) + "] NowTime [" + now_time + "] Last Requst Time [" + this.last_request_time + "]");
      if (now_time - this.last_request_time < (d.still_processing_wait / 2)) { 
        this.last_request_time = now_time;
        return; 
      }
      
      this.last_request_time = now_time;
      //console.log("Scheduling request [" + d.still_processing_wait + "]");
      if (this.refresh_count < this.max_refresh_count) {
        this.refresh_count++;
        window.setTimeout( function() { this_obj.refresh(); }, d.still_processing_wait);
      }
      else {
        console.log("Max refresh exceeded");
      }
    }
    else {
      this.still_processing = 0;
    }
  }


  this.updateZoomlevel = function(bUpdateSlider)
  {
    TS.Util.Date.set_currdisp_zoomlevel_id();
    curr_zl_name = TS.Util.Date.zoom_levels[TS.Util.Date.zoom_level].name;

    var i = 0;
    for (var zl_name in this.zoom_levels) 
    {
      if (zl_name == curr_zl_name) 
      {
        if (bUpdateSlider) {
          this.zoomslider.setZoomQuietly(i);
        }
        break;
      }
      i++;
    }
  }

  this.setCurrUtcTS = function( arg_curr_utc_ts )
  {
    this.curr_utc_ts = arg_curr_utc_ts;
    elems.curr_datetime_val.innerHTML = TS.Util.Date.format_date_for_zoomlevel(parseInt(this.curr_utc_ts) + parseInt(this.gmtoffset), TS.Util.Date.currdisp_zoomlevel_id);
  }


  this.handleZoomSliderMove = function(e, args)
  {
    var i = 0;
    for (var zl_name in this.zoom_levels) {
      if (i == args[0]) {
        break;
      }
      i++;
    }
    this.handleZoomToLevel(zl_name);
  }


  var start_mouse_pos = 0;
  this.startDrag = function(e) 
  { 
    if (this.is_dragging === false)
    {
      this.panelholder.terminateKineticSlide();
      this.is_dragging = true;
      this.slider.trackEvents = false;
      start_mouse_pos = e.clientX;
      if (navigator.userAgent.toLowerCase().indexOf("msie") < 0) {
        // prevent error log spew from IE
        elems.vp.style.cursor='-moz-grabbing';
      }
      // prevent IE text selection
      document.body.ondrag = function () { return false; };
      document.body.onselectstart = function () { return false; };
    }
  }
  var lastSlideX = 0;
  var lastSlideTime = 0;
  var didDrag = false;
  
  this.onDrag = function(e) { 
    if (this.is_dragging === true) 
    {
      this.show_curr_datetime_disp();
      if (this.notified_drag === false) {
        this.trackEvent("slide", "drag");
        this.notified_drag = true;
      }

      var curr_mouse_pos = e.clientX;

      var delta_x = curr_mouse_pos - start_mouse_pos; //(mouse_drag_factor * (curr_mouse_pos - start_mouse_pos));

      if (delta_x != 0) 
      {
        this.panelholder.doSlide(delta_x, true, true); 
        lastSlideX = delta_x;
        
        d = new Date();
        lastSlideTime = d.valueOf();
      }
      this.slider.setTS(this.panelholder.curr_utc_ts, false); 

      start_mouse_pos = curr_mouse_pos;
      didDrag = true;
    }
  };
  
  this.endDrag = function(e) { 
    if (this.is_dragging === true)
    {
      if (didDrag) {
        this.setCurrUtcTS(this.panelholder.curr_utc_ts); 
        this.is_dragging = false;
        this.notified_drag = false;
        // re-enable IE text selection
        document.body.ondrag = function () { return true; };
        document.body.onselectstart = function () { return true; };
        this.hide_curr_datetime_disp();
        elems.vp.style.cursor='move';
        this.slider.trackEvents = true;

        d = new Date();
        nowTime = d.valueOf();
        if (nowTime - lastSlideTime < 200) {
        //console.log("Now [" + nowTime + "] Last Slide Time [" + lastSlideTime + "] Diff [" + (nowTime - lastSlideTime) + "]");
          this.panelholder.kineticSlide(lastSlideX);
        }
        
        lastSlideX = 0; lastSlideTime = 0;
        didDrag = false;
      } else {
        this.handleClickedElem(e);
      }
    }
    this_obj.is_dragging = false;
  }

  this.handleClickedElem = function(e)
  {
    this.stopEvent(e); 
    var target = (e.target ? e.target : e.srcElement);

    var comments = false;
    var votelink = false;
    var voteup = false;

    do {
      // if the comments bubble was somewherez in the chain
      if (target.className && target.className.indexOf('comments') >= 0) {
        comments = true;
      }
      if (target.className && target.className.indexOf('votelink') >= 0) {
        votelink = true;
        if (target.className && target.className.indexOf('voteup') >= 0) {
          voteup = true;
        }
      }

      if (target.nodeName.toUpperCase() == "A") 
      {
        var payload_elems = YAHOO.util.Dom.getElementsByClassName('payload', 'span', target);
        if (payload_elems[0]) {
          var payload = null;
          try {
            payload = eval('(' + payload_elems[0].innerHTML + ')');
          } catch(err) {
            console.log("error parsing ", payload_elems[0].innerHTML);
          }
        }

        if (target.className && target.className.indexOf('zoom') >= 0) {
          if (payload != null) {
            this.trackEvent('zoom','flag');
            this.zoomToSegment(payload.utc_ts);
          }
          return false;
        }
        
        if (target.className && target.className.indexOf('zone')  >= 0) { // zone1 zone2 zone3
          var eid = target.id.substr(5);

          if (votelink) {
            this.event_vote(e,eid,payload.tid,payload.vote_sig, voteup);
          } else {
            var smashed = target.title.replace(/\s+/g,'-');
            smashed = smashed.replace(/[^a-zA-Z0-9\-]/g,'');
            smashed = smashed.replace(/-+/g,'-');
            //console.log(target, target.title);
            this.show_event_detail_popup_click(eid, e, smashed, (comments ? 'comments' : '') );
          }
          return false;
        }
        break; 
      } else { 
        target = target.parentNode; 
      } 
    } while (target && (!target.className || target.className.indexOf('events') == -1));

    return false;
  }
  

  this.doLayout = function() {
    regions.container = sz_util.getRegionWH(elems.container);
    elems.vp.style.width  = [ regions.container.width,  "px" ].join("");
    elems.vp.style.height = [ regions.container.height - 15, "px" ].join("");

    elems.curtain.style.width = elems.vp.style.width;
    elems.curtain.style.height = elems.vp.style.height;
  }

  this.doProgress = function(initial) {
    var bar = document.getElementById('progress_bar'); 
    var percent = parseInt(bar.style.width);
    if (percent >= 100 || this.still_processing == 0) { 
      // raise the curtain!
      fraction = 1.0;
      if (initial == 1) { fraction = 0.0; }
      this.raiseCurtain(fraction);
      return 1; 
    }
    else {
      if (initial == 1) {
        elems.curtain.style.display = 'block';
      }
    }
    
    var base_speed = 100;
    if (percent < this.still_processing_percent) {
      base_speed = 25;
    }
    else if (percent - this.still_processing_percent > 10) {
      base_speed = 300;
    }
    
    bar.style.width = (percent + 1) + '%'; 
    window.setTimeout( function() { this_obj.doProgress(0) } , base_speed);
    return 0;
  }
  
  this.raiseCurtain = function(fraction) {
    fraction -= 0.1;
    if (fraction <= 0.0) {
      elems.curtain.style.display = 'none';   
      fraction = 0.0;
    }
    
    elems.curtain.style['opacity'] = fraction;
    elems.curtain.style['-moz-opacity'] = fraction;
    if (fraction <= 0.0) { return; }
    
    window.setTimeout( function() { this_obj.raiseCurtain(fraction); }, 10);
  }
  
  this.init = function()
  {
    // current theme/skin
    var this_url = new URL(window.location.href);
    skin = this_url.getArg("skin");

    elems.container = document.getElementById(this.container_elem_id);
    elems.container.innerHTML = [
      '<div id="vp"></div>',
      '<div id="tltoplinks">',
      '  <div id="page_left">',
      '    <a id="manage_feeds_btn" class="widget_top_button styled_button styled_button_standard deact" target="_top" href="#"><div class="rightedge"></div>Add a Source</a>',
      '    <a id="create_event_btn" class="widget_top_button styled_button styled_button_standard deact" href="#"><div class="rightedge"></div>Add an Event</a>',
      '  </div>',
      '  <div id="zoomslider_outer"><a href="#" id="zoomslider_zoom_out" class="zoomslider_mag" title="缩小">缩小</a><a href="#" id="zoomslider_zoom_in" class="zoomslider_mag" title="放大">放大</a><div id="zoomslider"><div id="zoomthumb" title="拖动缩放"></div></div><select id="zoomdropdown"></select></div>',
      //'    <a id="zoom_all_btn" class="widget_top_button styled_button styled_button_standard" style="margin-right:0px;" href="#"><div class="rightedge"></div>Show All</a>',
      '  <div id="page_right">',
      '  </div>',
      '</div>',
      '<div id="sb_slider" style="hegiht:0px;"><div id="sb_slider_inner"></div></div>',
      '<div id="curr_datetime" class="curr_datetime_off"></div>',
      '<div id="curr_datetime_val"></div>',
      '<div id="ajax_loading">Loading...</div>',
      '<div id="curtain"><div id="loading_badge_centerpoint"><div id="loading_badge"><div id="loading"><div id="progress_bar" style="width:0%"></div></div></div></div></div>',
      '<div id="popup_anchor"></div>',
      '' ].join("");

   for (var div_id in req_divs)
    {
      if (div_id) {
        elems[div_id] = document.getElementById(div_id);
      }
    }

    if (typeof(buttons) == "string") {
      if (buttons === '0') {
        elems.manage_feeds_btn.style.display = 'none';
        elems.create_event_btn.style.display = 'none';
      }
    }

    this.doLayout();

    regions.vp = sz_util.getRegionWH(elems.vp);

    if (typeof(tl_bgimg) != "undefined" && tl_bgimg != '') {
      elems.vp.style.background = tl_bgcolor + " url(" + tl_bgimg + ") repeat-x bottom";
    }
    else if (typeof(tl_bgcolor) != "undefined" && tl_bgcolor != '') {
      elems.vp.style.backgroundColor = tl_bgcolor;
    }

    elems.vp.innerHTML = [
        '<div id="tl_floor"></div>',
        '<div id="panelholder"></div>',
        '' ].join("");

    this.panelholder = new sz_panelholder(this_obj, elems.vp);
    this.slider = new sb_slider(this_obj, elems.vp);
    this.zoomslider = new sz_zoomslider(this_obj);

    // vp dragging
    //YAHOO.util.Event.addListener("vp",     "dblclick",  function(e) { this_obj.stopEvent(e);this_obj.handleDoubleClickZoom(e); });
    YAHOO.util.Event.addListener("vp",     "mousedown", function(e) { this_obj.startDrag(e); });
    YAHOO.util.Event.addListener("vp",     "mousemove", function(e) { this_obj.onDrag(e); });
    YAHOO.util.Event.addListener(document, "mouseup",   function(e) { this_obj.endDrag(e); });

    elems.curr_datetime.style.height = [ regions.vp.height, "px" ].join("");
    document.getElementById("tl_floor").style.top = [ 46 * (Math.floor( (regions.vp.height - 40) / 46 ) - 1), "px"].join("");

    if (this.page) {
      this.page.on_resize.subscribe(function() { 
        this_obj.on_resize.fire();
        });
    } else {
      YAHOO.util.Event.addListener(window, "resize", function(e) { this_obj.handleResize(); });
    }

    this.slider.on_move.subscribe( function(e, args) {
        //console.log("on_move", args[0]);
        this_obj.setCurrUtcTS(args[0]);

        this_obj.show_curr_datetime_disp();
        //console.log("SLIDER ONMOVE viewport.curr_utc_ts=", this_obj.curr_utc_ts);
        this_obj.panelholder.slideToTS(this_obj.curr_utc_ts, true);
        if (this_obj.hide_curr_datetime_disp_timeout != null) {
          clearTimeout(this_obj.hide_curr_datetime_disp_timeout);
        }
        this_obj.hide_curr_datetime_disp_timeout = setTimeout( function() { this_obj.hide_curr_datetime_disp() }, 1000);
      });

    this.zoomslider.on_move.subscribe( function(e, args) { this_obj.handleZoomSliderMove(e, args); } );

    //if (window.addEventListener) {
    //  /** DOMMouseScroll is for mozilla. */
    //  elems.vp.addEventListener('DOMMouseScroll', this.wheel, false);
    //} else {
    //  /** IE/Opera. */
    //  elems.vp.onmousewheel = this.wheel;
    //}
    if (this.still_processing == 1 && this.doProgress(1)) { 
      this.panelholder.kineticSlide(-5, 0.08); 
    } 
    
    if (this.has_event_payload()) {
      this.panelholder.panelcache.processResponse( this.get_event_payload(), function(d) { 
        this_obj.processResponse(d); 
        } );
    }
    else if (this.curr_utc_ts != null && TS.Util.Date.zoom_level != null) {
      this.requestAllData( { 'full':1, 'ct':this.curr_utc_ts, 'z':TS.Util.Date.zoom_levels[TS.Util.Date.zoom_level]['name']} );
    }
    else if (this.curr_utc_ts != null) {
      this.requestAllData( { 'full':1, 'az':1, 'ct':this.curr_utc_ts } );
    } 
    else 
    {
      this.requestAllData( { 'full':1, 'az':1 } );
    } 
  }

  var pendingResize = null;
  var firstResize = true;
  this.handleResize = function() 
  {
    if (firstResize) { 
      firstResize = false;
      return;
    }
    if (widget_fixed != '1') 
    {
      if (pendingResize != null) {
        window.clearTimeout(pendingResize);
      }
      pendingResize = window.setTimeout( function() { this_obj.actuallyResize(); }, 250 );
    }
  }

  this.actuallyResize = function() 
  {
    this.doLayout(); 
    this.on_resize.fire(); 
    this.requestAllData( {'ct':this_obj.curr_utc_ts } );
  }
  
  this.refresh = function() 
  {
    this.requestAllData( {'ct':this_obj.curr_utc_ts, 'refresh':1}, 1 );
  }

  this.slide_to_event = function(event_id) 
  {
    var event_region = YAHOO.util.Dom.getRegion('event' + event_id); 

    var delta_x = 0;

    //console.log( event_region, regions.vp );
    //if (event_region.left < (regions.vp.left + 50)) {
    //  delta_x = (regions.vp.left + 50) - event_region.left;
    //} else if (event_region.right > (regions.vp.right - (50 + this.ref_event_width))) {
    //  delta_x = (regions.vp.right - (50 + this.ref_event_width)) - event_region.right;
    //}
    delta_x = (regions.vp.left + (regions.vp.width / 2)) - event_region.left
    //console.log(delta_x);

    //var delta_x = (vp_x_center - event_region.left) + 10; 
    if (delta_x != 0) {
      this.panelholder.animateSlide(delta_x, 25/*frames*/, 20/*ms_per_frame*/); 
    }
  }


  this.show_event_detail_popup_click = function(event_id, e, smashed_title, tab)
  {
    YAHOO.util.Event.stopEvent(e); 
    if (this.show_popup_click ) { return; }

    this.show_popup_click = true; 

    var options = {
      'grow_from_elem':["event", event_id].join(""),
      'smashed_title':smashed_title,
      'default_tab':tab
    };

    this.show_event_detail_popup(event_id, options);
  }

  this.show_event_detail_popup = function(event_id, options)
  {
	this.show_popup_click=false;

	var e=event_id.split('_');
	switch(e[1]){
		case 'comic':
			window.open('http://www.u17.com/comic/'+e[2]+'.html');
			break;
		case 'chapter':
			window.open('http://www.u17.com/comic_show/c'+e[2]+'_m0.html');
			break;	
		case 'image':
			window.open('http://www.u17.com/comic_show/c'+e[2]+'_m0_i'+e[3]+'.html');
			break;				
	}
    //if (!options) { options = {}; }

    //active_event_id = event_id;

    //var width = Math.min(parseInt(elems.vp.style.width), 575);
    //var d = new Date();
    //var url = [ dipity.view_url, "/event/", 
    //  (options.smashed_title ? options.smashed_title : ''),
     // "?", "eid=" + escape(event_id),
    //  (mode == 'embed' ? "&width=" + width : ''),
    //  "&mode=", mode,
     // (options.default_tab ? "&default_tab=" + options.default_tab : ''),
    //  ].join("");

    //dialog_event.setUrl(url);
    //dialog_event.prepareOpen();
  }


  this.event_vote = function(e, eid, tid, sig, bVotePlus)
  {
    YAHOO.util.Event.stopEvent(e); 

    active_event_id = eid;
    var callback = { success : function(o) { this_obj.requestAllData( { 'ct':this_obj.curr_utc_ts } ); this_obj.hide_popup(); },
                     failure : function(o) { this_obj.process_error(o); } };
    var args = [ 
        'tid=' + escape(tid),
        'sig=' + escape(sig),
        'vote=' + escape( bVotePlus ? "1" : "-1" ) 
        ];
    YAHOO.util.Connect.asyncRequest('GET', [ base_url, 'event/', escape(eid), '/vote', "?", args.join("&") ].join(""), callback);
  } 


  this.hide_popup = function()
  {
    this.show_popup_click = false;
  }

  this.process_error = function(o)
  {
    console.error(o);
  }

  this.zoomToSegment = function(new_ts)
  {
    this.curr_utc_ts = new_ts;
    this.panelholder.slideToTS(new_ts, true);
    var zoom_id = TS.Util.Date.zoom_level;
    var new_zoom_name = this.zoom_levels[this.zoom_level_name]['seg'];

    if (new_zoom_name != this.zoom_name) {
      this.handleZoomToLevel(new_zoom_name);
    }
  }

  this.handleZoomToLevel = function(zoom_name)
  {
    var zoom_id = TS.Util.Date.zoom_level_name_to_id(zoom_name);
    if (zoom_id > -1)
    {
      TS.Util.Date.zoom_level = zoom_id;
    } else {
      console.error("Invalid zoom name '", zoom_name, "' passed to tl.handleZoomToLevel()");
    }

    var curr_zoom_name = this.zoom_level_name;
    var curr_zoom_level = this.zoom_levels[this.zoom_level_name]['dur'];
    var new_zoom_level = this.zoom_levels[zoom_name]['dur'];

    //console.log( "HANDLEZOOMTOLEVEL", curr_zoom_level / new_zoom_level);

    this.zoom_level_name = zoom_name;

    this.slider.broadcast_scroll = false;
    this.panelholder.animateZoom( 
      curr_zoom_level / new_zoom_level, 
      20, // steps
      10, // ms per step
      function() { 
            this_obj.requestAllData( { 'ct':this_obj.curr_utc_ts, 
              'trk_zoom_new':zoom_name, 
              'trk_zoom_old':curr_zoom_name, 
              'trk_zoom_type':'slider' } ); 
      } // run_when_done
    );
  }

  /////////////////////////////////////////////////////////////////////////////////
  // APPROVE EVENT
  this.start_event_approve = function(event_id)  {
    var callback = { success : function(o) { this_obj.hide_popup();this_obj.requestAllData( { 'ct':this_obj.curr_utc_ts } ); } ,
                     failure : function(o) { this_obj.process_error(o); } };
    if (confirm("Really approve this event?"))
    { 
      YAHOO.util.Connect.asyncRequest('GET', [base_url, 'event/', event_id, '/approve' ].join(""), callback);
    } 
  }   

  /////////////////////////////////////////////////////////////////////////////////
  // DELETE EVENT
  this.start_event_del = function(event_id)
  {
    var callback = { success : function(o) { this_obj.hide_popup();this_obj.requestAllData( { 'ct':this_obj.curr_utc_ts } ); } , 
                     failure : function(o) { this_obj.process_error(o); } };
    if (confirm("Really delete this event?"))
    {
      YAHOO.util.Connect.asyncRequest('GET', [base_url, 'event/', event_id, '/delete', "?tid=", this.current_tid].join(""), callback);
    }
  }


  /////////////////////////////////////////////////////////////////////////////////
  // EDIT HANDLERS
  this.start_event_edit = function(event_id, focus_field)
  {
    var path = "create/event";

    var args_arr = new Array();
    if (event_id) {
      path = "event/" + event_id + "/edit";
      mode = 'edit';
    } else {
      mode = 'add';
    }
    
    args_arr.push("tid=" + escape(this.current_tid));
    args_arr.push("skin=" + escape(skin));

    var url = [ base_url, path ].join("") + "?" + args_arr.join("&");
    console.log(url);

    dialog_event.setUrl(url);
    dialog_event.setWidth(577);
    dialog_event.setHeight(490);
    dialog_event.prepareOpen();
  }

  this.finish_event_edit_ajax = function(response)
  {
    var ct = this.curr_utc_ts;
    if (typeof(response.event_utc_ts) != "undefined") {
      ct = response.event_utc_ts;
    }
    if (typeof(response.eid) != "undefined") {
      active_event_id = response.eid;
    }

    if (response.fields.addmore.value != '') {
      this.requestAllData( { 'ct':ct } );
      this.event_addmore = 0;
      this.start_event_edit();
    } else {
      if (response.eid) {
        this.requestAllData( { 'ct':ct, 'popup_eid':response.eid } );
      } 
    }
  }

  this.has_event_payload = function() {
    if (event_payload) { return 1; }
    return 0;
  }
  
  this.get_event_payload = function() {
    return event_payload;
  }

  this.show_curr_datetime_disp = function() {
    YAHOO.util.Dom.replaceClass(elems.curr_datetime, "curr_datetime_off", "curr_datetime_on");
    YAHOO.util.Dom.replaceClass(elems.curr_datetime_val, "curr_datetime_off", "curr_datetime_on");
  }
  this.hide_curr_datetime_disp = function() {
    YAHOO.util.Dom.replaceClass(elems.curr_datetime, "curr_datetime_on", "curr_datetime_off");
    YAHOO.util.Dom.replaceClass(elems.curr_datetime_val, "curr_datetime_on", "curr_datetime_off");
    this_obj.hide_curr_datetime_disp_timeout = null;
  }

  var zone3img_height = 138;
  var zone3img_width  = 195;
  this.zone3img_load = function(elem, eid)
  {
    if (elem.height > zone3img_height)
    {
      elem.style.bottom = [ (zone3img_height - elem.height) / 2, 'px' ].join(''); 
    }
    if (elem.width < zone3img_width) {
      var padding_px = [ (zone3img_width - elem.width) / 2, 'px' ].join('');
      elem.style.paddingLeft = padding_px;
      elem.style.paddingRight = padding_px;
    }
    elem.style.visibility='inherit'; 
  }

  /** Event handler for mouse wheel event.
   */
  this.wheel = function(event) {
    var delta = 0;
    if (!event) /* For IE. */
      event = window.event;
    if (event.wheelDelta) { /* IE/Opera. */
      delta = event.wheelDelta/120;
      /** In Opera 9, delta differs in sign as compared to IE.
       */
      if (window.opera)
        delta = -delta;
    } else if (event.detail) { /** Mozilla case. */
      /** In Mozilla, sign of delta is different than in IE.
       * Also, delta is multiple of 3.
       */
      delta = -event.detail/3;
    }
    /** If delta is nonzero, handle it.
     * Basically, delta is now positive if wheel was scrolled up,
     * and negative, if wheel was scrolled down.
     */
    if (delta) {
      this_obj.handleWheelMove(delta);
    }
    /** Prevent default actions caused by mouse wheel.
     * That might be ugly, but we handle scrolls somehow
     * anyway, so don't bother here..
     */
    if (event.preventDefault)
      event.preventDefault();
    event.returnValue = false;
  }

  this.trackWheel = true;
  this.handleWheelMove = function(delta)
  {
    this.panelholder.doSlide((delta < 0 ? 50 : -50), true, true); 
    this.slider.setTS(this.panelholder.curr_utc_ts, false); 
    //if (this.trackWheel) {
    //  this.trackEvent("slide", "wheel");
    //  setTimeout( function() { this_obj.trackWheel = true; }, 1000);
    //  this.trackWheel = false;
    //}
  }

  this.handleDoubleClickZoom = function(event)
  {
    var click_ts = this.panelholder.pxToTS(event.clientX - regions.vp.left);
    this.trackEvent("zoom", "dblclick");
    this.zoomToSegment(click_ts);
  }

  this.trackEvent = function( action, label, number )
  {
    trackEvent("timeline", action, label, number); // trackEvent() is in common_inline_js.template
  }

  this.excludeChildTls = function (exclude_list) {
    this.exclude_tids = exclude_list;
    this.requestAllData( {'ct':this_obj.curr_utc_ts } );
  }

  /* api funcs -- keep these defined in whatever form this becomes */
  this.switchTimeline = function(tid) {
    this.requestAllData( { 'tid':tid, 'full':1, 'az':1 } );
  }
  
  this.zoomToExtents = function()
  {
    this.requestAllData( { 'full':1, 'az':'all' } );
  }

  this.slideToTS = function(ts)
  {
    this.panelholder.slideToTS(ts, true);
  }

  this.showEID = function(eid)
  {
  }

  this.zoomIn = function()
  {
  }

  this.zoomOut = function()
  {
  }

  this.scrollLeft = function(amt)
  {
  }

  this.scrollRight = function(amt)
  {
  }

  // invoke a callback if it is specified by the server.  e.g. when
  // this function is called from hover_event_on, 'name' should be passed
  // as 'hover_event_on', and this function will check to see if the
  // server-side template specified a function name to be called when
  // hover_event_on is called.  the name of the function to call is
  // given as the value of the 'hover_event_on_callback' json property.
  // callbacks are defined in app_embed.js in the dipity_callbacks
  // object literal.
  this.doCallbacks = function(name, event_id)
  {
    var newArgs = new Array();
    for (var i = 1; i < arguments.length; i++) {
      newArgs.push(arguments[i]);
    }

    var event_data = this.panelholder.getEventData(event_id);
    keyName = name + '_callback';
    if (event_data && event_data[keyName]) {
      funcName = event_data[keyName];
      if (typeof dipity_callbacks[funcName] == "undefined") {
	console.log(funcName + " is not defined in dipity_callbacks");
	return;
      }

      dipity_callbacks[funcName].apply(this, newArgs);
    }
  }

  /* constructor */
  var this_obj = this; // for closures

  var req_divs = {
    'curtain':{},
    'vp':{},
    'curr_ts':{},
    'curr_datetime':{},
    'curr_datetime_val':{},
    'create_event_btn':{},
    'manage_feeds_btn':{},
    'zoomlist':{},
    '':{}
  };

  var elems = {};
  var regions = {};

  var vp_width_ts = null;
  var titlebar_height = 0;
  var active_event_id = null;
  var last_request_time;
  var skin = '';

  var feeds_href = [timeline_view_url, '/feeds', (fullscreen == '1' ? "?done=" + escape( timeline_view_url + "/embed_tl?fs=1" ) : "")].join("");
  var feeds_button_href = '#';
  if (typeof(dipity.curr_login) != 'undefined' && dipity.curr_login) {
    feeds_button_href = feeds_href;
  }

  this.still_processing = tl_still_processing;
  this.still_processing_percent = 100;
  this.refresh_count = 0;
  this.max_refresh_count = 5;

  this.zoom_level_name = '7day';
  this.curr_utc_ts = null;
  this.page = arg_page;
  this.is_dragging = false;
  this.notified_drag = false;

  this.on_resize = new YAHOO.util.CustomEvent('sz_resize');
  this.panelholder = null;
  this.slider = null;
  this.zoomslider = null;
  this.popup_mode = null;
  this.show_popup_click = false;
  this.current_tid = null;
  this.exclude_tids = [];
  this.container_elem_id = arg_container_elem_id;
  this.minical = null;
  this.hide_curr_datetime_disp_timeout = null;
  this.last_request_time = 0;
  this.bgcolor = tl_bgcolor;
  this.bgimg = tl_bgimg;
  this.gmtoffset = 60*60*8;

  if (url_tid) {
    this.current_tid = url_tid;
  }
  if (url_zoom) {
    TS.Util.Date.zoom_level = TS.Util.Date.zoom_level_name_to_id(url_zoom);
  }
  if (url_time) {
    this.curr_utc_ts = url_time;
  }

  this.zoom_levels = {
    '1hr':  { 'dur':60*60,            'name':'小时',      'seg':'1hr' },
    '1day': { 'dur':60*60*24,         'name':'天',       'seg':'1hr' },
    '7day': { 'dur':60*60*24*7,       'name':'周',      'seg':'1day' },
    '1mon': { 'dur':60*60*24*30,      'name':'月',     'seg':'7day' },
    '6mon': { 'dur':60*60*24*30*6,    'name':'半年',  'seg':'1mon' },
    '1yr':  { 'dur':60*60*24*365,     'name':'一年',    'seg':'6mon' },
    '2yr':  { 'dur':60*60*24*365*2,   'name':'两年',   'seg':'1yr' }//,
    //'5yr':  { 'dur':60*60*24*365*5,   'name':'5 Years',   'seg':'6mon' },
    //'10yr': { 'dur':60*60*24*365*10,  'name':'10 Years',  'seg':'1yr'  },
    //'25yr': { 'dur':60*60*24*365*25,  'name':'25 Years',  'seg':'5yr'  },
    //'100yr':{ 'dur':60*60*24*365*100, 'name':'100 Years', 'seg':'10yr' },
    //'500yr':{ 'dur':60*60*24*365*500, 'name':'500 Years', 'seg':'100yr' }
  };

  this.init();

  // needs to be after init()
  var dialog_event = new PopupDialog( { 
    "url":"about:blank",
    "onclose":"tl.show_popup_click=false",
    "windowclass":"standard_with_header eventdetail",
    "windowstyle":"",
    "anchor":"popup_anchor",
    "popup_align":{ "vertical":"middle", "horizontal":"center" },
    "receiverurl":"",
    "ismodal":true,
    "showloading":(skin != '' ? false : true),
    "hash":"event"
    }); 
};
sourceList = function()
{
  this.init = function() 
  {
    elems.source_list = document.getElementById('source_list');
    elems.input_nodes = YAHOO.util.Dom.getElementsByClassName('sourcebutton', 'a', elems.source_list);

    var curr_url = new URL(window.location.href);
    var exclude_list = curr_url.getArg('exclude_tids');
      
    for (var idx in elems.input_nodes) {
      if (idx == parseInt(idx)) {
        var tid = elems.input_nodes[idx].id.substr(7);

        // uncheck sources excluded in the URL
        for (var i in exclude_list) {
          if (exclude_list[i] == tid) {
            YAHOO.util.Dom.addClass(elems.input_nodes[idx], "source_disabled");
          }
        }
      }
    }
  }

  this.toggleSource = function(e, id)
  {
    YAHOO.util.Event.stopEvent(e);
    if (YAHOO.util.Dom.hasClass(id, "styled_button_standard")) {
      YAHOO.util.Dom.replaceClass(id, "styled_button_standard", "styled_button_cancel");
    } else {
      YAHOO.util.Dom.replaceClass(id, "styled_button_cancel", "styled_button_standard");
    }
    this.handleSourceChange();
  }

  this.handleSourceChange = function() {
    var exclude_list = [];
    for (var idx in elems.input_nodes) {
      if (idx == parseInt(idx) && YAHOO.util.Dom.hasClass(elems.input_nodes[idx], "styled_button_cancel")) {
        exclude_list.push(elems.input_nodes[idx].id.substr(7));
      }
    }

    if (typeof(tl) == "object") {
      tl.excludeChildTls(exclude_list);
    }
    else {
      // reload with exclude list arg
      var curr_url = new URL(window.location.href);
      curr_url.resetArg('exclude_tids');
      curr_url.addArg('exclude_tids', exclude_list, false);
      window.location.href = curr_url.getUrlStr();
    }
  }

  var this_obj = this;
  var elems = {};
};

if (document.getElementById('source_list')) {
  var sl = new sourceList();
  sl.init();
}
embed = function()
{
  this.init = function()
  {
    for (var div_id in req_divs)
    {
      if (div_id) {
        elems[div_id] = document.getElementById(div_id);
      }
    }
    elems.container = document.getElementById(container_id);

    var chrome_height = 0;

    var h = YAHOO.util.Dom.getViewportHeight();
    var w = YAHOO.util.Dom.getViewportWidth();
    if (!h) { h = 328; }

    elems.container.style.height = [ h - chrome_height, "px" ].join("");
    elems.container.style.width = [ w, "px" ].join("");
    elems.container.style.left = [ 0, "px" ].join("");
    elems.container.style.marginTop = [ chrome_height, "px" ].join("");
  }

  var this_obj = this;

  var req_divs = {
    'chrome':{},
    '':{}
  };
  var elems = {};
  var regions = {};

  this.init();
};

if (document.getElementById('chrome')) { 
  var embed = new embed();
}
/*
 *   $Id: app_embed.js 6048 2008-10-06 23:07:53Z eric $
 *
 *  Copyright (c) 2007 Underlying Inc. All rights reserved.
 */
if (document.getElementById('emb_tl') && typeof(url_tid) != 'undefined') {
  var tl = new TS.Timeline('emb_tl', null, url_tid, url_time, url_zoom, 1, url_display, tl_mode);
  if (typeof(url_add) != 'undefined' && url_add) {
    tl.start_event_edit();
  }

  var dipity_callbacks = {
    // hook into event_hover_on to setup an iframe that is loaded
    // with digg's compact badge skin.  this provides the current
    // digg count for a digg event.
    digg_iframe_hover: function(event_id) {
      var event_data = tl.panelholder.getEventData(event_id);
      var digg_votelink_iframe = document.getElementById('digg' + event_id);

      if (digg_votelink_iframe != null) {
	if (digg_votelink_iframe.src != "about:blank") { return; } // already loaded

	// initialize the iframe with a loading message
	var doc = digg_votelink_iframe.contentDocument;
	if (doc == undefined || doc == null) {
	  doc = digg_votelink_iframe.contentWindow.document;
	}
	doc.open();
	var html = [
          '<html>',
	  '  <body style="margin:2px 2px;padding:0;font-family:Helvetica,Arial,sans-serif;font-size:12px;font-weight:bold">',
	  '     Loading...',
	  '  </body>',
	  '</html>'
	].join('');
	doc.write(html);
	doc.close();

	// now load from digg, template specifies the source
	digg_votelink_iframe.src = event_data.digg_iframe_src;
      }
    }
  };
}

// start poller for queued_update stuff
if (typeof(tl) != 'undefined' && typeof(queued_update) != 'undefined' && queued_update == 1)
{
  pollQueuedUpdate();
}
