flowview = function(arg_tid, arg_container_id, arg_json_url, options)
{
  this.init = function()
  {
    elems.container = document.getElementById(container_id);

    if (mode == 'embed') {
      var h = YAHOO.util.Dom.getViewportHeight();
      if (!h) { h = 328; }
      elems.container.style.height = [ h, "px" ].join("");
    }
    
    regions.container = sz_util.getRegionWH(elems.container);

    elems.container.innerHTML = [
      '<div id="panes"></div>',
      '<div id="macro">',
      '  <div id="macro_inner">',
      '    <div id="macro_ticks"></div>',
      '    <div id="macro_thumb"></div>',
      '  </div>',
      '  <div class="extents" id="macro_min_ts"></div>',
      '  <div class="extents" id="macro_max_ts"></div>',
      '</div>',
      '<div id="popup">',
      '  <a class="msgclosebutton" href="#" onClick="flow.stopEvent(event);flow.hidePopup();">Close</a>',
      '  <div id="popup_content"></div>',
      '</div>',
      ''].join("");

    var required_divs = {
      'panes':"",
      'macro':"",
      'macro_min_ts':"",
      'macro_max_ts':"",
      'macro_inner':"",
      'macro_ticks':"",
      'macro_thumb':"",
      'popup':"",
      'popup_content':"",
      '':''
    };

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

    this.doLayout();

    YAHOO.util.Event.addListener("macro_ticks", "click", function(e) { this_obj.stopEvent(e); this_obj.handleTicksClick(e); });

    if (typeof(event_arr) != "undefined")
    {
      d.events = {};
      for (var idx in event_arr) {
        d.events[ event_arr[idx].eid ] = event_arr[idx];
      }
      this.processResponse({});
    }
    else {
      var callback = {
        success : function(o) { this_obj.processResponse(o); }, 
        failure : function(o) { this_obj.process_error(o); } 
      };
      this.request_data = YAHOO.util.Connect.asyncRequest('GET', json_url, callback, null);
    }
  }

  this.doLayout = function() {
    var padding = 8;
    var macro_height = 37;

    elems.macro.style.left   = [ padding, "px" ].join("");
    elems.macro.style.bottom = [ padding, "px" ].join("");
    elems.macro.style.width  = [ regions.container.width - (2*padding) - 4, "px" ].join("");
    elems.macro.style.height = [ macro_height, "px" ].join("");
    regions.macro = sz_util.getRegionWH(elems.macro);

    elems.macro_inner.style.left = "10px";
    elems.macro_inner.style.width = [ regions.macro.width - 20, "px" ].join("");
    elems.macro_inner.style.height = "50px";
    regions.macro_inner = sz_util.getRegionWH(elems.macro_inner);

    elems.macro_ticks.style.height = [ regions.macro_inner.height, "px"].join("");
    elems.macro_ticks.style.width = [ regions.macro_inner.width, "px"].join("");
    regions.macro_ticks = sz_util.getRegionWH(elems.macro_ticks);

    elems.panes.style.left   = elems.macro.style.left;
    elems.panes.style.top    = [ padding, "px" ].join("");
    elems.panes.style.width  = elems.macro.style.width;
    elems.panes.style.height = [ regions.container.height - macro_height - (padding * 3), "px" ].join("");
    regions.panes = sz_util.getRegionWH(elems.panes);

    centered_pane_width = parseInt(regions.panes.width / 2);
    centered_pane_height = parseInt(regions.panes.height - 10);

    centered_pane_left = Math.round( (regions.panes.width  - centered_pane_width) / 2 );
    centered_pane_top  = Math.round( (regions.panes.height - centered_pane_height) / 2 ) - 2;
  }

  this.setMacroThumbToTs = function(ts, anim_ms)
  {
    var new_left_pos = (d.meta.tick_width_px / 2) + this.macroTsToPx(ts);

    if (thumb_left_px == null || anim_ms == 0) {
      elems.macro_thumb.style.left = [ new_left_pos, "px" ].join("");
    } else {
      var anim = new YAHOO.util.Anim(elems.macro_thumb, { left: { to: new_left_pos }  }, anim_ms / 1000, YAHOO.util.Easing.easeOut); 
      anim.animate();
    }
    thumb_left_px = new_left_pos;
  }

  this.macroTsToPx = function(ts)
  {
    var ts_prop = ( ts - d.meta.event_min_ts ) / d.meta.event_ts_span;
    if (ts_prop < 0) { ts_prop = 0; }
    if (ts_prop > 1) { ts_prop = 1; }
    var px = (regions.macro_inner.width - d.meta.tick_width_px) * ts_prop;
    return px;
  }
  this.macroPxToTs = function(px)
  {
    var ts_prop =  px / regions.macro_ticks.width;
    if (ts_prop < 0) { ts_prop = 0; }
    if (ts_prop > 1) { ts_prop = 1; }
    var ts = parseInt(d.meta.event_min_ts) + (d.meta.event_ts_span * ts_prop);
    return ts;
  }

  this.processResponse = function(o) {
    if (typeof(o.responseText) != "undefined") {
      d = eval('(' + o.responseText + ')');
    }
    d.meta = {};

    var out = [];

    out.push('<ul class="panes">');

    var min_evt_ts = null;
    var max_evt_ts = null;
    var min_evt_disp_date = null;
    var max_evt_disp_date = null;

    d.event_list = [];

    for (var eid in d.events) {
      var evt = d.events[eid];
      if (typeof(evt.utc_ts) != "undefined" && evt.utc_ts != null) {
        d.event_list.push(eid);
        if (this.getOption("no_description") && evt.descrptn || evt.img_url) {
          evt.descrptn = false;
        }

        var img_height = centered_pane_height - (evt.descrptn ? 100 : 0);
        var img_width = img_height;
        if (evt.o_height) {
          img_width = (evt.o_width / evt.o_height) * img_height;
        }

        var dt = new Date(parseInt(evt.utc_ts) * 1000);
        var classes = [ 'event_pane', 'noshow' ];
        if (evt.img_url) {
          classes.push('with_img');
        }
        out.push('<li id="event_', evt.eid, '" class="', classes.join(" "), '" onClick="flow.showEventByEid(\'', evt.eid, '\', event);">');
        out.push('<div ', (evt.img_url ? [ 'style="width:', img_width, 'px; left:', (centered_pane_width / 2) - (img_width / 2), 'px;" ' ].join("") : ''), 'class="info" id="info_', evt.eid, '"><h1>');
        if (evt.link) {
          out.push('<a target="_new" href="', evt.link, '">', evt.title, "</a>");
        } else {
          out.push(evt.title);
        }
        out.push('</h1>');
        out.push(evt.disp_date);
        out.push('</div>');

        // auto-video-ize youtube
        if (evt.link && evt.link.indexOf('youtube') > 0 && !evt.media_url) {
          evt.media_url = evt.link;
        }

        if (evt.media_url) {
          out.push('<div style="text-align:center;" id="video_', evt.eid, '"></div>');
        }
        if (evt.img_url) {
          out.push('<div style="width:', centered_pane_width, 'px; height:', centered_pane_height, 'px; overflow:hidden;background:url(/images/loading_big_dark.gif) no-repeat center;">');
          var img_tag = [ '<img onLoad="flow.fixImg(this);" style="visibility:hidden;border:none;" id="img_', evt.eid, '" alt="', evt.img_url, '|', evt.title, '" xheight="', img_height, '">' ].join("");
          if (evt.link) {
            out.push('<a target="_new" href="', evt.link, '">', img_tag, '</a>');
          } else {
            out.push(img_tag);
          }
          out.push('</div>');
        }
        if (evt.descrptn) {
          var clean_desc = evt.descrptn.replace(/\<[^\>]+\>/g," ");
          //if (clean_desc.length > 120) {
          //  var clean_desc = clean_desc.substr(0,120) + "...";
          //}
          out.push('<p class="description">', clean_desc, "</p>");
        }
        out.push("</li>");

        if (min_evt_ts == null || parseInt(evt.utc_ts) < min_evt_ts) { min_evt_ts = parseInt(evt.utc_ts); min_evt_disp_date = evt.disp_date; }
        if (max_evt_ts == null || parseInt(evt.utc_ts) > max_evt_ts) { max_evt_ts = parseInt(evt.utc_ts); max_evt_disp_date = evt.disp_date;}
      }
    }
    out.push("</ul>");
    elems.panes.innerHTML = out.join("");

    d.meta.event_min_ts  = min_evt_ts;
    d.meta.event_max_ts  = max_evt_ts;

    d.meta.event_min_disp_date  = min_evt_disp_date;
    d.meta.event_max_disp_date  = max_evt_disp_date;

    d.meta.event_ts_span = max_evt_ts - min_evt_ts;
    d.meta.num_events = d.event_list.length;

    //console.log(d.meta.event_min_ts, d.meta.event_max_ts, d.meta.event_ts_span);

    this.setupMacro(this.d);

    this.showEvent(0);
  }

  this.fixImg = function(elem)
  {
    if (elem.height == 0 || elem.width == 0) { return; }
    
    img_aspect = elem.width / elem.height;
    pane_aspect = centered_pane_width / centered_pane_height;

    if (img_aspect > pane_aspect) {
      // fit width
      var orig_height = elem.height;
      var new_height = parseInt(elem.height * (centered_pane_width / elem.width));
      elem.style.height = [ new_height, 'px'].join("");
      elem.style.width  = [ centered_pane_width, 'px' ].join(""); 
      elem.style.paddingTop = [ parseInt(Math.abs(centered_pane_height - new_height) / 2), 'px' ].join("");
    } else {
      // fit height
      var orig_width = elem.width;
      var new_width = parseInt(elem.width * (centered_pane_height / elem.height));
      
/*      console.log("Elem.width[" + elem.width + "] Elem.height[" + elem.height + "]");      
      console.log("New width [" + new_width + "]");
      console.log("Centered Pane Height[" + centered_pane_height + "]"); */
      elem.style.width = [ new_width, 'px'].join("");
      elem.style.height  = [ centered_pane_height, 'px' ].join("");
    }
    
    elem.style.visibility = "inherit";
  }

  this.setupMacro = function()
  {
    elems.macro_min_ts.innerHTML = d.meta.event_min_disp_date.replace(/\d{1,2}:\d{2}(:\d{2})? (am|pm)/i, '');
    elems.macro_max_ts.innerHTML = d.meta.event_max_disp_date.replace(/\d{1,2}:\d{2}(:\d{2})? (am|pm)/i, '');

    d.meta.macro_arr = [];
    d.meta.max_in_slot = null;

    if (d.meta.event_ts_span > 0) {
      for (var eid in d.events) {
        var evt = d.events[eid];
        if (typeof(evt.utc_ts) != "undefined") {
          var macro_idx = Math.round((num_macro_ticks - 1) * (evt.utc_ts - d.meta.event_min_ts) / d.meta.event_ts_span);

          // init slot
          if (typeof(d.meta.macro_arr[macro_idx]) == "undefined") { d.meta.macro_arr[macro_idx] = 0; }

          d.meta.macro_arr[macro_idx]++;

          if (d.meta.max_in_slot == null || d.meta.macro_arr[macro_idx] > d.meta.max_in_slot) {
            d.meta.max_in_slot = d.meta.macro_arr[macro_idx];
          }
        }
      }
    }

    var num_tickstyles = 4;
    var tick_html = [];
    var tick_date_span = d.meta.event_ts_span / num_macro_ticks;
    if (d.meta.max_in_slot > 0) 
    {
      for (var i = 0; i < num_macro_ticks; i++)
      {
        d.meta.tick_width_px = (regions.macro_ticks.width - 1) / num_macro_ticks;
        var left_px = i * d.meta.tick_width_px;
        var tick_class = "level0";

        if (d.meta.macro_arr[i]) {
          var tick_level = Math.ceil(num_tickstyles * d.meta.macro_arr[i] / d.meta.max_in_slot);
          tick_class = [ "level", tick_level ].join("");
        }

        var tick_date = new Date(1000 * (parseInt(d.meta.event_min_ts) + 
                                        (i * (d.meta.event_ts_span / num_macro_ticks) )));

        tick_html.push('<div class="macro_tick ', tick_class, '" style="left:', left_px, 'px; width:', d.meta.tick_width_px, 'px;" title="', (d.meta.macro_arr[i] > 0 ? ['', d.meta.macro_arr[i], ' Events' ].join("") : ''), '"></div>');
      }
    }
    elems.macro_ticks.innerHTML = tick_html.join("");
  }

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

  this.showEventByEid = function(eid, event)
  {
    //console.log("IN showEventByEid", eid);
    if (eid != curr_eid) {
      if (event) {
        this.stopEvent(event);
      }
      for (var idx in d.event_list) {
        if (d.event_list[idx] == eid) {
          //console.log("FOUND IDX ", idx, eid);
          return this.showEvent(idx);
        }
      }
    }
  }

  this.showPopup = function(eid)
  {
    var d = new Date();
    var callback = { success : function(o) { this_obj.process_event_detail_html(o); } , 
                     failure : function(o) { this_obj.process_error(o); } };
    var url = [ "/event/", eid,
      "?rand=", d.getTime()
      ].join("");
    YAHOO.util.Connect.asyncRequest("GET", url, callback);
    
    var elem = document.getElementById("event_" + eid);
    if (elem) {
      elem_region = sz_util.getRegionWH(elem);

      var anim = new YAHOO.util.Anim(elems.popup, { 
        left:    { from:elem_region.left - regions.container.left,   to:0 },  
        top:     { from:elem_region.top - regions.container.top,    to:0 }, 
        width:   { from:elem_region.width,  to: regions.container.width - 2 }, 
        height:  { from:elem_region.height, to: regions.container.height - 2 }
        }, 0.25, YAHOO.util.Easing.backOut); 
      anim.animate();
        
      elems.popup.style.visibility = "visible";
    }
  }

  this.process_event_detail_html = function(o)
  {
    elems.popup_content.style.height = [ regions.container.height - 2 - 32, "px" ].join("");
    var obj = {};
    if (typeof(o.responseText) != "undefined") {
      obj = eval('(' + o.responseText + ')');
    }
    if (obj.content_html) {
      elems.popup_content.innerHTML = obj.content_html;
    }
  }

  this.hidePopup = function()
  {
    elems.popup_content.innerHTML = '';
    elems.popup.style.visibility = "hidden";

    // reset position
    var elem = document.getElementById("event_" + curr_eid);
    if (elem) {
      elem_region = sz_util.getRegionWH(elem);

      elems.popup.style.left = [ elem_region.left - regions.container.left, "px" ].join("");
      elems.popup.style.top = [ elem_region.top - regions.container.top, "px" ].join("");
      elems.popup.style.width = [ elem_region.width, "px" ].join("");
      elems.popup.style.height = [ elem_region.height, "px" ].join("");
    }
  }

  this.showEvent = function(sIdx) {
    var want_evt_idx = parseInt(sIdx);

    var diff = want_evt_idx - curr_evt_idx;
    var absdiff = Math.abs(diff);
    var dir_coeff = (diff < 0 ? -1 : 1);

    if (curr_evt_idx == want_evt_idx) {
      diff = 0;
      absdiff = 1;
      dir_coeff = 1;
    }
    //console.log("curr:",curr_evt_idx, " want:", want_evt_idx, " diff:", diff, " absdiff:", absdiff, " dir_coeff:", dir_coeff);

    this.flows_left = absdiff;
    this.orig_flows_left = this.flows_left;
//     this.start = new Date();
    this.flow(dir_coeff, 250);
  }


  this.showCardImg = function(eid)
  {
    var elem = document.getElementById("img_" + eid);
    if (elem && elem.alt.substr(0,4) == 'http' && elem.alt.indexOf("|")) {
      var alt_arr = elem.alt.split("|");
      elem.src = alt_arr.shift();
      elem.alt = alt_arr.join("|");
    }
  }

  this.flow = function(dir_coeff, anim_ms)
  {    
    while (this.flows_left > 0)
    {
      var do_anim = this.orig_flows_left - this.flows_left < this.max_flows || this.flows_left <= this.max_flows;

      //console.log(this.flows_left);
      var pane_step_horiz = (((regions.container.width - centered_pane_width) / 2) / num_stack) - 8;
      var pane_step_vert  = 10;

      var elem = null;
      var add_pos = curr_evt_idx + parseInt( dir_coeff * (num_stack + 1));
      if (add_pos >= 0 && add_pos < d.meta.num_events) {
          elem = document.getElementById("event_" + d.event_list[add_pos]);
      }
      if (elem) {
        // position the card and make it show up
        new_left = centered_pane_left - ((dir_coeff < 0 ? 1 : -1) * num_stack * pane_step_horiz);
        new_top = centered_pane_top + (num_stack * pane_step_vert);
        new_height = centered_pane_height - (num_stack * pane_step_vert * 2);

        elem.style.left   = [ new_left, "px" ].join("");
        elem.style.top    = [ new_top, "px" ].join("");
        elem.style.height = [ new_height, "px" ].join("");
        elem.style.width  = [ centered_pane_width, "px" ].join("");
        elem.style.zIndex = 10 - (num_stack);
        YAHOO.util.Dom.removeClass(elem, "noshow");
        if (this.flows_left < num_stack / 2 && do_anim) {
          this.showCardImg( d.event_list[add_pos] );
          if (d.event_list[add_pos + dir_coeff]) {
            this.showCardImg( d.event_list[add_pos + dir_coeff] );
          }
          if (d.event_list[add_pos + (2 * dir_coeff)]) {
            this.showCardImg( d.event_list[add_pos + (2 * dir_coeff)] );
          }
        }

        //console.log("ADD:", add_pos);
      }

      // now shift the cards, except for the last one ("last" depends on the direction of the shift)
      for (var offset = -1 * num_stack; offset <= num_stack; offset++) {
        var abs_offset = Math.abs(offset);
        var evt_idx = parseInt(curr_evt_idx) + parseInt(dir_coeff) + parseInt(offset);
        if (evt_idx >= 0 && evt_idx < d.meta.num_events) {
          // shift the cards, but skip the "last" one, 'cause it will be removed below
          var new_top = centered_pane_top + (abs_offset * pane_step_vert);
          var new_height = centered_pane_height - (abs_offset * pane_step_vert * 2);

          var new_left;
          if (offset == 0) {
            new_left = centered_pane_left;
          } else {
            new_left = centered_pane_left + ((offset < 0 ? -1 : 1) * pane_step_horiz * (num_stack - 1)) + (pane_step_horiz * 0.25 * offset);
          }

          var elem = document.getElementById("event_" + d.event_list[ evt_idx ]);
          YAHOO.util.Dom.removeClass(elem, "noshow");
          if (do_anim) {
            this.showCardImg( d.event_list[evt_idx] );
          }
          elem.style.zIndex = 10 - abs_offset;

          if (abs_offset == 0) {
            var elem_id = "event_" + d.event_list[ evt_idx ];
            YAHOO.util.Dom.addClass(elem_id, "centered");
            YAHOO.util.Dom.removeClass(elem, "right_of_center");
            YAHOO.util.Dom.removeClass(elem, "left_of_center");

            new_curr_evt_idx = evt_idx;
            new_curr_eid = d.event_list[curr_evt_idx];

            if (this.flows_left <= 1) {
              // fire event
              this.on_centered_pane.fire(d.event_list[ evt_idx ]);
              // play video in center
              var media_url = d.events[ d.event_list[ evt_idx ] ].media_url;
              if (media_url && media_url.indexOf('youtube') > 0) {
                var video_elem = document.getElementById('video_' + d.event_list[ evt_idx ]);
                var video_height = centered_pane_height - 80;
                var video_width = parseInt( 1.19 * video_height );
                if (video_width > centered_pane_width) {
                  var coeff = centered_pane_width / video_width;
                  video_width *= coeff;
                  video_height *= coeff;
                }
                video_elem.style.paddingTop = [ (centered_pane_height - video_height) / 2, 'px' ].join("");
                var matches = media_url.match(/v=([^&]+)/);
                var img_elem = document.getElementById('img_' + d.event_list[ evt_idx ]);
                if (img_elem) {
                  img_elem.style.display = 'none';
                }
                if (video_elem && matches[1]) {
                  var youtube_asset = matches[1];
                  video_elem.innerHTML = [ '<embed width="', video_width, '" height="', video_height, '" type="application/x-shockwave-flash" src="http://www.youtube.com/v/', youtube_asset, '" wmode="opaque"/>' ].join("");
                }
              }
  // 	    var finish = new Date();
  // 	    console.log("flow in " + (finish.getTime() - this.start.getTime()) + "ms");
            }
          } 
          else 
          {
            YAHOO.util.Dom.removeClass(elem, "centered");
            if (offset > 0) {
              YAHOO.util.Dom.addClass(elem, "right_of_center");
              YAHOO.util.Dom.removeClass(elem, "left_of_center");
            } else {
              YAHOO.util.Dom.addClass(elem, "left_of_center");
              YAHOO.util.Dom.removeClass(elem, "right_of_center");
            }

            var video_elem = document.getElementById('video_' + d.event_list[ evt_idx ]);
            if (video_elem && video_elem.innerHTML != '') {
              video_elem.innerHTML = '';
              var img_elem = document.getElementById('img_' + d.event_list[ evt_idx ]);
              if (img_elem) {
                img_elem.style.display = 'inline';
              }
            }
          }

          if (this.flows_left > 1) 
          {
            // no animation if there is lots to do
            if (do_anim) {
              elem.style.left = [ new_left, "px" ].join("");
              elem.style.top = [ new_top, "px" ].join("");
              elem.style.height = [ new_height, "px" ].join("");
              elem.style.width = [ centered_pane_width, "px" ].join("");
            }
          }
          else
          {
            if (anim_ms > 0)
            {
              var anim = new YAHOO.util.Anim(elem, { 
                left:   { to: new_left},
                top:    { to: new_top},
                height: { to: new_height},
                width:  { to: centered_pane_width }
                }, anim_ms / 1000, YAHOO.util.Easing.easeOut); 
              anim.animate();
            } else {
              elem.style.left = [ new_left, "px" ].join("");
              elem.style.top = [ new_top, "px" ].join("");
              elem.style.height = [ new_height, "px" ].join("");
              elem.style.width = [ centered_pane_width, "px" ].join("");
            }
          }
        }
      }

      curr_evt_idx = new_curr_evt_idx;
      curr_eid = d.event_list[curr_evt_idx];

      // now remove the card at the bottom of the pile
      var remove_idx = curr_evt_idx - parseInt( dir_coeff * num_stack );
      var elem = document.getElementById("event_" + d.event_list[ remove_idx] );
      if (elem) {
        // make sure it goes behind everything
        elem.style.zIndex = 0;
        if (!do_anim) {
          YAHOO.util.Dom.addClass(elem, "noshow");
        }
        else {
          setTimeout( function() { YAHOO.util.Dom.addClass(elem, "noshow"); }, anim_ms );
        }
        //console.log("REMOVE:", remove_idx);
      }
      
      var jump = 1;
      this.flows_left--;

      //console.log("CURRENT:", curr_evt_idx, curr_eid);
      if (d.events[curr_eid]) {
        this.setMacroThumbToTs(d.events[curr_eid].utc_ts, do_anim ? anim_ms : 0);
      }
    }
  }

  this.showPrevEvent = function() {
    this.showEvent(curr_evt_idx - 1);
  }
  this.showNextEvent = function() {
    this.showEvent(parseInt(curr_evt_idx) + 1);
  }

  this.stopEvent = function(e) {
    YAHOO.util.Event.stopEvent(e);
  }
  
  this.handleTicksClick = function(e) {
    regions.macro_ticks = sz_util.getRegionWH(elems.macro_ticks);
    var px = e.clientX - regions.macro_ticks.left;
    var ts = this.macroPxToTs(px);
    var evt_idx = this.findEventIdxForTs(ts);
    if (evt_idx == curr_evt_idx) {
      if (ts < d.events[curr_eid].utc_ts && curr_evt_idx > 0) {
        return this.showPrevEvent();
      }
      if (ts > d.events[curr_eid].utc_ts && curr_evt_idx < d.meta.num_events) {
        return this.showNextEvent();
      }
    }

    var diff = evt_idx - curr_evt_idx;
    var absdiff = Math.abs(diff);

    if (absdiff < 4) {
      for (var i = 0; i < absdiff; i++) {
        if ( diff < 0 ) {
          this.showPrevEvent();
        } else {
          this.showNextEvent();
        }
      }
    } else {
      this.showEvent(evt_idx);
    }
  }

  this.findEventIdxForTs = function(ts) {
    // find event closest to TS
    for (var idx in d.event_list) {
      if (d.events[ d.event_list[idx] ].utc_ts > ts) {
        if (idx > 0) {
          var ts_diff = d.events[ d.event_list[idx] ].utc_ts - ts;
          if (ts - d.events[ d.event_list[idx - 1] ].utc_ts < ts_diff) {
            idx = idx - 1;
          }
        }
        break;
      }
    }
    return idx;
  }

  this.getOption = function(key) {
    if (options && typeof(options[key]) != 'undefined') {
      return options[key];
    }
  }


  // constructor args
  var this_obj = this;
  var tid = arg_tid;
  var json_url = arg_json_url;
  var container_id = arg_container_id;

  // other class vars
  var elems = {};
  var regions = {};
  var curr_evt_idx = 0;
  var curr_eid = null;
  var thumb_left_px = null;

  // tunables
  var num_stack = 4;
  var num_macro_ticks = 172;
  var centered_pane_width = null;
  var centered_pane_height = null;
  var centered_pane_left = null;
  var centered_pane_top = null;
  var d = {};
  var mode = ( typeof(flowview_embed) != 'undefined' && flowview_embed == 1 ? "embed" : "page" );

  this.flows_left = 0;
  this.orig_flows_left = 0;
  this.max_flows = 6;

  this.on_centered_pane = new YAHOO.util.CustomEvent('flipbook_centered_pane');

  this.init();
}

if (document.getElementById('flow')) {
  var this_url_obj = new URL(window.location.href);
  var json_url_obj = new URL(json_url);

  var exclude_tids_arg = this_url_obj.getArg('exclude_tids');
  if (exclude_tids_arg) {
    json_url_obj.addArg('exclude_tids', exclude_tids_arg, false);
  }

  var flow = new flowview(tid, 'flow', json_url_obj.getUrlStr(), typeof(dipity_flow_options) != "undefined" ? dipity_flow_options : null);
}
