
var agent     = navigator.userAgent.toLowerCase();
var is_ie     = ((agent.indexOf("msie") != -1) && (agent.indexOf("opera") == -1));
var is_ie6    =  (agent.indexOf("msie 6") != -1);
var is_ie7    =  (agent.indexOf("msie 7") != -1);
var is_ie8    =  (agent.indexOf("msie 8") != -1);
var is_ie9    =  (agent.indexOf("msie 9") != -1) || (agent.indexOf("ie9") != -1);
var is_chrome = (agent.indexOf("chrome") != -1);
var is_opera  = (agent.indexOf("opera") != -1);
var is_mac    = (agent.indexOf("mac") != -1);
var is_mac_ie = (is_ie && is_mac);
var is_win_ie = (is_ie && !is_mac);
var is_safari = (agent.indexOf('safari') != -1);
var is_gecko  = (navigator.product == "Gecko");
var is_opera = (agent.indexOf("opera") != -1);
var is_firefox = (agent.indexOf("firefox") != -1);
var is_old_firefox = (agent.match(/firefox\/(...)/) ? RegExp.$1 * 1 < 1.5 : false);
var is_firefox_3_6_or_newer = (agent.match(/firefox\/(...)/) ? (RegExp.$1 * 1) >= 3.6 : false);
var is_netscape = (agent.indexOf("netscape") != -1);

var init_fns = new Array();


function addInitFunction(fn)
{
  if (init_fns instanceof Array) init_fns.push(fn);
}

function init()
{
  var i, f = document.forms['genre_styles'];

  if (f) if (genres) if (f.genres) if (f.styles)
  {
    loadCombo(f.genres, genres, 0, 'Genre');
    if (window.genre_id) setComboValue(f.genres, window.genre_id);
    handleGenre(f.genres);
    if (window.style_id) setComboValue(f.styles, window.style_id);
  }

  if (window.page_init) page_init();

  if (init_fns instanceof Array)
  {
    var i, fn;

    for (i = 0; i < init_fns.length; i++)
    {
      if ((fn = init_fns[i]) instanceof Function) fn();
    }	
  }
}

function debugging()
{
  return getCookie('debugging') ? true : false;
}

function elems(idArray, required)
{
  var elementArray = null;

  if (idArray != undefined && idArray != null)
  {
    elementArray = [];

    for (x = 0; x < idArray.length; x++)
    {
      elementArray[elementArray.length] = elem(idArray[x], required); 
    }
  }

  return (required) ? elementArray : (elementArray ? elementArray : []);
}

function elem(id, required)
{
  if (id != undefined && typeof id != 'string') return id;

  var e = document.getElementById(id);

  return required ? e : (e ? e : new Object());
}

function elemStyle(id, required)
{
  var s = elem(id).style;

  return required ? s : (s ? s : new Object());
}

function elemDisplay(id, display, required)
{
  style = elemStyle(id);

  display = (display ? '' : 'none');

  if (style.display != display) style.display = display;
}

function elemValue(id)
{
  var e = elem(id);

  if (e.type == 'checkbox') return e.checked ? e.value : '';

  return e.options ? getComboValue(e) : e.value;
}

// Return true iff the first argument is a string. 
// Adapted from http://www.planetpdf.com/developer/article.asp?ContentID=testing_for_object_types_in_ja
//
function isString(v)
{
  if (typeof v == 'string') return true;
  if (typeof v != 'object') return false;

  return v.constructor.toString().match(/string/i) != null;
}

function toggleDisplay(id, required)
{
  var s = elemStyle(id, required)

  if (s) s.display = (s.display == 'inline' ? 'none' : 'inline');

  return s ? true : false;
}

function newGecko()
{
  return navigator.product == 'Gecko' && navigator.productSub && navigator.productSub > '20041010' &&
        (navigator.userAgent.indexOf('rv:1.8') != -1 || navigator.userAgent.indexOf('rv:1.9') != -1);
}

function getRowVisibility(rowid, empty_means_none)
{
  var style = elemStyle(rowid, true);

  empty_means_none = (empty_means_none ? true : false);

  if (style)            {} else return !empty_means_none;
  if (style.visibility) {} else return !empty_means_none;

  if (style.visibility == 'collapse') return false;
  if (style.visibility == 'none')     return false;

  return true;
}

function setRowVisibility(rowid, visible)
{
  var style = elemStyle(rowid, true)

  if (style) {} else return;

  visible = (visible ? 'visible' : 'collapse');

  if (newGecko())
  {
    style.visibility = visible;
    style.display = (visible == 'visible' ? 'table-row' : 'none');
  }
  else if (visible == 'visible')
  {
    if (document.all && !window.opera) // document.compatMode == 'CSS1Compat'
    {
      style.display = 'block';
    }
    else if (document.getElementById) // && table.rows)
    // Mozilla prior to 1.8a2, Opera 7.x and MSIE 5+
    {
      style.display = 'table-row';
    }
  }
  else if (visible == 'collapse')
  {
    style.display = 'none';
  }
}

function toggleRowVisibility(rowid, empty_means_none)
{
  setRowVisibility(rowid, !getRowVisibility(rowid, empty_means_none));
}

function pixels(v)
{
  return 1 * v.toString().replace('px', '');
}

function remove_host_name(url)
{
  url = url.toString();

  return url.substring(url.indexOf(location.host) + location.host.toString().length);
}

function listen(message)
{
  message = unescapeArray(message.replace(/^\?/, ''));

  var fn = message['fn'];

  if (fn)
  {
    var i, arg = null, args = '';

    for (i = 1; (arg = message['a' + i]) != null; i++)
    {
      args += (args ? ', ' : '') + quote(arg);
    }

    fn += '(' + args + ')';

    return eval(fn);
  }
  return null;
}

function trim(s)
{
  return (''+s).toString().replace(/(^\s+|\s+$)/g, '');
}

function quote(s)
{
  return "'" + s.toString().replace('\n', '\\n').replace("'", "\\'") + "'";
}

function put(s)
{
  document.write(s);
}

function encode(s)
{
  var fn = (window.encodeURIComponent ? encodeURIComponent : escape);

  return fn(s);
}

function decode(s)
{
  var fn = (window.decodeURIComponent ? decodeURIComponent : unescape);

  return fn(s);
}

function escapeArray(a)
{
  var s = '';

  for (k in a) if (k != 'indexOf') s += (s.length ? '&' : '') + encode(k) + '=' + encode(a[k]);

  return s;
}

function unescapeArray(s)
{
  var i, a = new Array;

  if (s.length)
  {
    var pairs = s.split('&');

    for (i = 0; i < pairs.length; i++)
    {
      var pair = pairs[i].split('=');

      if (pair[0]) a[unescape(pair[0])] = unescape(pair[1]);
    }
  }

  return a;
}

function indexOf(array, item)
{
  if (array.indexOf) return array.indexOf(item); else // stupid ie...
  {
    for (var i = 0; i < array.length; i++) if (array[i] == item) return i;
  }

  return -1;
}

function getCookie(name)
{
  var dc = document.cookie;

  var re = new RegExp('.*' + name + '=([^;]*).*');

  return dc.match(re) ? decode(dc.replace(re, '$1')).replace(/&sp;/g, ' ') : '';
}

function setCookie(name, value, persistent)
{
  value = '' + value;

  var s = name + '=' + encode(value.replace(/ /g, '&sp;')); // see APP.php

  if (persistent)
  {
    var d = new Date();

    d.setFullYear(d.getFullYear() + 1);

    s += '; expires=' + d.toGMTString();
  }

  document.cookie = s + '; path=/';
}

function killCookie(name)
{
  document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/';

  if (is_safari) document.cookie = name + '=';
}

function getComboValue(c, getText)
{
  c = elem(c);

  if ((c.selectedIndex >= 0) && c.options && c.options.length)
  {
    return c.options[c.selectedIndex][getText ? 'text' : 'value'];
  }
  else if (c.length)
  {
    for(var i=0;i<c.length;i++)
    {
      if (c[i].checked == true) { return c[i][getText ? 'text' : 'value']; }
    }
  }

  return -1;
}

function setComboValue(c, value)
{
  c = elem(c);

  for (var i = 0; i < c.options.length; i++)
  {
    if (c.options[i].value == value) c.selectedIndex = i;
  }
}

function addComboOption(c, value, text)
{
  c = elem(c);

  var option = document.createElement("OPTION");
  if (!is_mac_ie) if (c.options.add) c.options.add(option); else c.add(option);
  option.innerText = option.text = text;
  option.value = value;
  if (is_mac_ie) c.options.add(option);
}

function clearComboList(c)
{
  c = elem(c);

  for (i = c.options.length - 1; i >= 0; i--) c.options[i] = null;
}

function loadCombo(combo, array, extra_value, extra_label)
{
  var value = getComboValue(combo);
  clearComboList(combo);
  if (extra_label) addComboOption(combo, extra_value, extra_label);
  for (key in array) if (key != 'indexOf') addComboOption(combo, key, array[key]['name']);
  if (value >= 0) setComboValue(combo, value);
}

function handle_time_type(select)
{
  var c, b = (select.options[select.selectedIndex].value != 'specific');

  var arg = select.name.replace('type', '');

  if (c = select.form.elements[arg + 'hour']) c.disabled = b;
  if (c = select.form.elements[arg + 'minute']) c.disabled = b;
  if (c = select.form.elements[arg + 'meridiem']) c.disabled = b;
}

function handle_smart_date(select)
{
  var name = select.name;
  var type = select.name;

  name = name.replace('_mday', '');

  name = name.replace('_mon', '');

  name = name.replace('_year', '');

  type = type.replace(name+'_','');

  if(c = select.value)
  {
    if (c = select.form.elements[name + '_mday']) if(!c.value) c.value = '1';
    if (c = select.form.elements[name + '_mon'])  if(!c.value) c.value = '1';
    if (c = select.form.elements[name + '_year']) if(!c.value) c.value = (new Date()).getYear() + 1900;
  }
  else
  {
    if (c = select.form.elements[name + '_mday']) c.value = null;
    if (c = select.form.elements[name + '_mon'])  c.value = null;
    if (c = select.form.elements[name + '_year']) c.value = null;
  }

}

function date_picker_value(elem, update_hidden_field)
{
  var name = elem.name.replace('_mday', '').replace('_mon', '').replace('_year', '');

  var mon  = getComboValue(elem.form.elements[name + '_mon']);
  var mday = getComboValue(elem.form.elements[name + '_mday']);
  var year = getComboValue(elem.form.elements[name + '_year']);

  if (mday) if (mon) if (year)
  {
    var date = mon + '/' + mday + '/' + year;

    if (update_hidden_field) elem.form.elements[name].value = date;

    return new Date(date);
  }

  return null;
}

function valid_email(email)
{
  return email.value.match(/\w+@\w+\.\w+/) ? true : false;
}

function doLogin(formObject)
{
  var currentPage = document.createElement("input");

  if (document.location.toString().indexOf('ubl.com') < 0 && formObject.username.value.indexOf('@') > 0) 
  {
    doWebmailLogin(formObject);
    return false;
  }
  else
  {
    currentPage.type = "hidden";
    currentPage.name = "current_page";
    currentPage.value = document.location;
    formObject.appendChild(currentPage);
    return true;
  }
}

function doWebmailLogin(formObject)
{
  f = document.getElementById('webmail');
  f.imapuser.value = formObject.username.value;
  f.pass.value = formObject.password.value;
  f.submit();
}

function getMessages(key)
{
  var s = getCookie(key ? key : 'APP_Messages');
  killCookie(key ? key : 'APP_Messages');
  return s;
}

function handleGenre(genre, sub)
{
  var id = getComboValue(genre);

  if (sub) {} else sub = genre.form.styles;

  clearComboList(sub);

  if (id) if (genres)
  {
    var default_style = (id == 53 ? 564 : 0); // allow general choice for WAAF contest

    loadCombo(sub, genres[id] ? genres[id]['styles'] : new Array(), default_style, 'Style');
  }
}

function controlSoundslike(genre, sub)
{
  var id = getComboValue(genre);

  if (sub) {} else sub = genre.form.soundslike;

  clearComboList(sub);

  if (id) if (genre_soundslike)
  {
    loadCombo(sub, genre_soundslike[id] ? genre_soundslike[id]['prototype_bands'] : new Array(), 0, 'Sounds Like');
  }
}

function setSearchFields(type, keywords)
{
  var e, f = document.forms['search'];

  if (f)
  {
    if (e = f.elements['type']) setComboValue(e, type);
    if (e = f.elements['keywords']) e.value = keywords;
  }
}

function nav(url)
{
  // this lets the media player drive the main window to
  // add_to_watch.php without appearing to be the referrer
  setTimeout('location = "'+url+'";', 50);
}

var mpwin = 0;
var mpcount = 0;
function mediaPlayer(cls, id)
{
  if (mpwin) mpwin.close();
  var  args = cls + "', '" + id;
  if(is_safari)
  {
    mpcount++;
    mpPopup(cls, id);
  } else {
    mpPopup(cls, id);
  }
}

var pwin = 0;
var pcount = 0;
function launch_db_picker(source, key, value, s_name, element_name, element_label, extra_key, extra_value)
{
  var args = 'source='+source+'&key='+key+'&value='+value+'&element_name='+element_name+'&element_label='+element_label;

  if (extra_key) args += '&' + escape(extra_key) + '=' + escape(extra_value);

  if(pwin) pwin.close();

  if(is_safari) pcount++;

  if(s_name.match(/\?/)) s_name = s_name + '&';
  else s_name = s_name + '?';

  s_name = s_name + args;

  pwin =  window.open(s_name, 'pwin'+pcount,
                      'toolbar=no,location=no,directories=no,status=no,menubar=no,titlebar=0,' +
                      'scrollbars=yes,resizable=yes,width=400,height=300');
}

function choose_picker_value(element_name, key, element_label, value)
{
  var key_field   = document.getElementById(element_name);  
  var value_field = document.getElementById(element_label);  

  key_field.value   = key;
  value_field.value = value;
  return true;
}

function mpPopup(cls, id)
{
  mpwin = window.open('/mediaplayer/class/' + cls + '/id/' + id + '/index.php', 'mpwin'+mpcount,
		      'toolbar=no,location=no,directories=no,status=no,menubar=no,titlebar=0,' +
		      'scrollbars=no,resizable=no,width=400,height=416');
}

var popup = 0;

function openPopup(url, requireLogin, windowWidth, windowHeight)
{
  if (popup) popup.close();

  if (requireLogin) if (have_user()) {} else
  {
    if (confirm('To use this feature please login or signup for a free membership.'))
    {
      if (window.opener) { window.opener.document.location = '/signup'; window.close(); }

      else document.location = '/signup';
    }

    return;
  }

  if (url.toLowerCase().indexOf('http') != 0) if (url.toLowerCase().indexOf('/') != 0) url = '/' + url;

  // Set the "default" window width/height (if the values aren't passed in)
  windowWidth = (windowWidth != undefined && windowWidth != null && !isNaN(windowWidth)) ? Number(windowWidth) : 0;
  windowHeight = (windowHeight != undefined && windowHeight != null && !isNaN(windowHeight)) ? Number(windowHeight) : 0;

  // Adjust the window width/height if they are invalid value(s)
  if (windowWidth <= 0) { windowWidth = 640; }
  if (windowHeight <= 0) { windowHeight = 480; }

  // Open the 'popup'
  popup = window.open(url, 'popup', 'toolbar=no,location=no,directories=no,status=no,menubar=no,titlebar=0,scrollbars=no,resizable=no,width=' + windowWidth + ',height=' + windowHeight);

  if (is_mac)
  {
    setTimeout('window.popup.document.location = "'+ url+'";', 90);
  }
}


function openScrollingPopup(url, requireLogin, windowWidth, windowHeight)
{
  if (popup) popup.close();
 
  if (requireLogin) if (have_user()) {} else
  {
    if (confirm('To use this feature please login or signup for a free membership.'))
    {
      if (window.opener) { window.opener.document.location = '/signup'; window.close(); }
    
      else document.location = '/signup';
    }
   
    return;
  }

  if (url.toLowerCase().indexOf('http') != 0) if (url.toLowerCase().indexOf('/') != 0) url = '/' + url;
   
  // Set the "default" window width/height (if the values aren't passed in)
  windowWidth = (windowWidth != undefined && windowWidth != null && !isNaN(windowWidth)) ? Number(windowWidth) : 0;
  windowHeight = (windowHeight != undefined && windowHeight != null && !isNaN(windowHeight)) ? Number(windowHeight) : 0;
     
  // Adjust the window width/height if they are invalid value(s)
  if (windowWidth <= 0) { windowWidth = 640; }
  if (windowHeight <= 0) { windowHeight = 480; }
 
  // Open the 'popup'
  popup = window.open(url, 'popup', 'toolbar=no,location=no,directories=no,status=no,menubar=no,titlebar=0,scrollbars=yes,resizable=yes,width=' + windowWidth + ',height=' + windowHeight);

  if (is_mac)
  {
    setTimeout('window.popup.document.location = "'+ url+'";', 90);
  }
}

// hopefully the last popup function needed - others should use this one or replaced with direct calls to it.
//
// if an old_popup window is provided it is first closed
// options to override the defaults defined within can be passed as an object for example: { toolbar:'yes' }
// the opener argument can be provided to specify a diferent opening window than the caller
//
function popup_window(url, old_popup, options, opener)
{
  if (old_popup) old_popup.close();

  if (window.old_popup) window.old_popup.close();

  if (is_safari) popup_window.count++;

  var s = '', defaults =
  {
    toolbar:'no',
    location:'no',
    directories:'no',
    status:'no',
    menubar:'no',
    titlebar:'no',
    scrollbars:'yes',
    resizable:'yes',
    width:640,
    height:480
  };

  if (options instanceof Object) for (option in options) if (option != 'indexOf') defaults[option] = options[option];

  for (option in defaults) if (option != 'indexOf') s += ',' + option + '=' + defaults[option];

  window.old_popup = window.open(url, 'popup' + (popup_window.count ? popup_window.count : ''), s.substring(1));

  if (window.old_popup) {} else alert('Warning: Popup Blocker Suspected.');

  if (opener) {} else opener = window;

  if (popup.opener != opener) popup.opener = opener;

  return window.old_popup;
}

function content_popup(content_block, title, ok_callback, cancel_callback, mode)
{
  if (mode) {} else mode = 'confirm';

  var confirm = (ok_callback || cancel_callback) ? '&' + mode + '=true' : '';

  var dir = (location.pathname.match(/\/dashboard/) ? '/dashboard' : '/nrp/content');

  var win = popup_window(dir + '/pop_content.php?content=' + content_block + '&title=' + escape(title) + confirm);

  if (win)
  {
    win.ok_callback = ok_callback;
    win.cancel_callback = cancel_callback;
  }
}

function have_user()
{
  return getCookie('login_id') ? true : false;
}

function canUseCORS()
{
  if (window.XDomainRequest) return true;

  if (window.XMLHttpRequest) return 'withCredentials' in new XMLHttpRequest();

  return false;
}

function postRequest(url, data, method, successCallback, failureCallback, useCorsInIe)
{
  if (is_ie9 && window.NJQ) return NJQ.ajax(
  {
    type: method,
    url: url,
    data: data,
    success: successCallback,
    error: failureCallback,
    dataType: 'text'
  });

  var req = false, xdr = false;

  if (data)   {} else data = ''; 
  if (method) {} else method = "POST";

  // IE8's CORS support works for asynchronous
  // calls only so require a successCallback
  //
  if (successCallback && window.XDomainRequest && useCorsInIe)
  {
    if (xdr = new XDomainRequest())
    {
      if (successCallback) xdr.onload  = function() { successCallback(xdr.responseText) };
      if (failureCallback) xdr.onerror = failureCallback;

      xdr.open(method, url);
      xdr.send(data);
      return;
    }
  }

  if (window.XMLHttpRequest) // safari, mozilla
  {
    // causes dialog to popup but is only necessary when running this file locally
    // for example, off your desktop, where the address bar might read:
    // file:///e:/Documents%20and%20Settings/Administrator/Desktop/SoundsLike.htm
    //
    //netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");

    try { req = new XMLHttpRequest(); }

    catch(e) { req = false; } finally {}
  }
  else if (window.ActiveXObject) // msie
  {
    try { req = new ActiveXObject("Msxml2.XMLHTTP"); } catch(e)
    {
       try { req = new ActiveXObject("Microsoft.XMLHTTP"); }

       catch(e) { req = false; } finally {}
    }
  }

  if (req)
  {
    req.open(method, url, successCallback ? true : false); // false for synchronous call
    req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    req.setRequestHeader("Content-length", data.length);
    req.setRequestHeader("Connection", "close");

    if (successCallback) req.onreadystatechange = function()
    {
      if (req.readyState == 4)
      {
        if (req.status == 200) successCallback(req.responseText);

        else if (failureCallback) failureCallback(req.status);
      }
    }

    req.send(data);

    return successCallback ? null : req.responseText;
  }

  return "Unable to Post Request";
}

var g_weekday   = '';
var g_monthname = '';
var g_monthday  = '';
var g_year      = '';

function getCalendarDate()
{
   var months = getMonthsArray();

   var days = getDaysArray();

   var now         = new Date();
   var monthnumber = now.getMonth();
     g_weekday     = days[now.getDay()];
     g_monthname   = months[monthnumber];
     g_monthday    = now.getDate();
     g_year        = now.getYear();
   if(g_year < 2000) { g_year = g_year + 1900; }
   var dateString = g_monthname + 
                    ' ' + 
                    g_monthday + 
                    ', ' + 
                    g_year;
   return dateString;
}

function getMonthsArray()
{
   var months = new Array(13);

   months[0]  = "January";
   months[1]  = "February";
   months[2]  = "March";
   months[3]  = "April";
   months[4]  = "May";
   months[5]  = "June";
   months[6]  = "July";
   months[7]  = "August";
   months[8]  = "September";
   months[9]  = "October";
   months[10] = "November";
   months[11] = "December";

   return months;
}

function getShortMonthsArray()
{
   var months = new Array(13);

   months[0]  = "Jan";
   months[1]  = "Feb";
   months[2]  = "Mar";
   months[3]  = "Apr";
   months[4]  = "May";
   months[5]  = "Jun";
   months[6]  = "Jul";
   months[7]  = "Aug";
   months[8]  = "Sep";
   months[9]  = "Oct";
   months[10] = "Nov";
   months[11] = "Dec";

   return months;
}

function getDaysArray()
{
   var days = new Array(7);

   days[0] = "Sunday";
   days[1] = "Monday";
   days[2] = "Tuesday";
   days[3] = "Wednesday";
   days[4] = "Thursday";
   days[5] = "Friday";
   days[6] = "Saturday";

   return days;
}

function getDateWithSuffix(date)
{
  var d = date.getDate();

  switch (d)
  {
    case  1: return d += 'st';
    case  2: return d += 'nd';
    case  3: return d += 'rd';
    case 21: return d += 'st';
    case 22: return d += 'nd';
    case 23: return d += 'rd';
    case 31: return d += 'st';
    default: return d += 'th';
  }

  return d;
}

function format_date(date)
{
  var year = date.getYear();

  if (year < 2000) year += 1900;

  return getMonthsArray()[date.getMonth()] + ' ' + date.getDate() + ', ' + year;
}

function formatTime(t) // epoch used is aribitrary as the choice of date matters not
{
  return (new Date('Jan 1, 1970 ' + t)).toLocaleTimeString().replace(/:00 /, '');
}

getCalendarDate();

function ucwords(s)
{
  return (''+s).toLowerCase().replace(/\b[a-z]/g, function() { return arguments[0].toUpperCase(); });
}

// macromedia rollover functions
//
function MM_swapImgRestore() { //v3.0
  var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc;
}

function MM_preloadImages() { //v3.0
  var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array();
    var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++)
    if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}}
}

function MM_findObj(n, d) { //v4.01
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document);
  if(!x && d.getElementById) x=d.getElementById(n); return x;
}

function MM_swapImage() { //v3.0
  var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3)
   if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];}
}

function toggle_tabs(img, key, state)
{

  if(state == undefined)
    s = (document.getElementById(key).style.display == 'none');
  else
    s = state;
 
  try
  {
    document.getElementById(key).style.display = (s ?'inline':'none');
    document.getElementById(img).src = (s ? '/images/arrowD.gif':'/images/arrowL.gif');
  }
  catch(e) {} finally {}
}

function hide_message()
{
  if (!window.NJQ) show_message(''); else
  {
    var e = top.elem('message_box');

    NJQ(e).fadeOut(1000, function() { show_message(''); NJQ(e).fadeIn(0); });
  }
}

function show_message(s, duration)
{
  hideLoadingDialog();

  top.elem('message_box').innerHTML = s;

  if (duration) setTimeout(hide_message, duration);

  if (s) if (window.refresh_editor) try
  {
    refresh_editor();
  }
  catch(e) {} finally {}
}

function stop_event(event)
{
  if (event)
  {
    if (event.stopPropagation) event.stopPropagation(); else event.cancelBubble = true;
  }
}

function add_event(element, event, fn, useCapture)
{
  element = elem(element);

  if (element.addEventListener) element.addEventListener(event, fn, useCapture);

  else if (element.attachEvent) element.attachEvent('on' + event, fn);
}

function get_event(evt)  { return evt ? evt : window.event; }   // the latter is ie
function get_target(evt) { return evt ? (evt.target ? evt.target : evt.srcElement) : null; } // the latter is ie

function window_size(win)
{
  if (win) {} else win = window;

  var body = win.document.body;
  var elem = win.document.documentElement;

  if (win.innerHeight)   return { y: win.innerHeight,   x: win.innerWidth   };
  if (body.clientHeight) return { y: body.clientHeight, x: body.clientWidth };
  else                   return { y: elem.clientHeight, x: elem.clientWidth };
}

function content_size(win)
{
  if (win) {} else win = window;

  var body = win.document.body;
  var elem = win.document.documentElement;

  if (body.scrollHeight) return { y: body.scrollHeight, x: body.scrollWidth };
  else                   return { y: elem.scrollHeight, x: elem.scrollWidth };
}

function auto_adjust_height(div, win)
{
  if (win) {} else win = window;

  if (typeof div == 'string') div = win.document.getElementById(div);

  if (div) {} else return;

  var other_content_height = content_size(win).y - div.scrollHeight;

  div.style.overflowY = 'auto';

  var fn = function()
  {
    var h = window_size(win).y - other_content_height;

    div.style.height = (h < 0 ? 0 : h) + 'px';
  }

  add_event(win, 'resize', fn);

  fn();
}

function auto_adjust_height2(div, diff, win)
{
  if (win) {} else win = window;

  if (typeof div == 'string') div = win.document.getElementById(div);

  if (div) {} else return;

  div.style.overflowY = 'auto';

  var fn = function()
  {
    var h = content_size(win).y - div.offsetTop - diff;

    div.style.height = (h < 0 ? 0 : h) + 'px';
  }

  add_event(win, 'resize', fn);

  fn();
}

var htmlarea_textarea = null;
var htmlarea_window   = null;
var htmlarea_title    = null;

function open_htmlarea(textarea, title)
{
  if (htmlarea_window) htmlarea_window.close();

  htmlarea_textarea = textarea;

  htmlarea_window = window.open('/nrp/includes/htmlarea.php', 'htmlarea',
    "toolbar=no,location=no,directories=no,status=no,menubar=no," +
    "scrollbars=no,resizable=yes,width=640,height=480");

  htmlarea_title = title;
}

function draw_htmlarea_button(input_name, title)
{
  if (is_win_ie || is_gecko)
  {
    var s = 'open_htmlarea(this.form.' + input_name + ', \'' + title + '\')';

    document.write('<br><input type="button" class="btn" value="HTML Editor..." onclick="' + s + '">&nbsp;Supported by IE 5.5, Mozilla 1.3, Netscape 4.7 or greater.');
  }
}

function format_money(price)
{
    price += 0;
    price  = (Math.round(price*100))/100;
    price  = (price == Math.floor(price)) ? price + '.00' 
              : ( (price*10 == Math.floor(price*10)) ? 
                       price + '0' : price);
    return '$' + price;
}

function normalize_upc(upc)
{
  upc = ('' + upc).replace(/[^\d]/g, '');

  return upc.length == 12 ? '0' + upc : upc;
}

function valid_upc(upc)
{
  upc = normalize_upc(upc);

  if (upc.length != 13) return false;

  var a = upc.split('');

  for (var i in a) if (i != 'indexOf') a[i] = 1 * a[i];

  var even = a[0] + a[2] + a[4] + a[6] + a[8] + a[10];
  var odd  = a[1] + a[3] + a[5] + a[7] + a[9] + a[11];

  var i = 3 * odd + even;

  return (Math.ceil(i / 10) * 10) % i == a[12];
}

// useful since their value property is read only
//
function reset_file_chooser(file)
{
  file = elem(file);

  var copy = document.createElement('input');
  copy.setAttribute('type', 'file');
  copy.setAttribute('id', file.id);
  copy.setAttribute('name', file.name);
  copy.setAttribute('disabled', file.disabled);

  var parent = file.parentNode;
  parent.removeChild(file);
  parent.appendChild(copy);

  return copy;
}

// Utility to dump an object or array to an alert box
//
function dump(o)
{
  var s = '';

  for (k in o) if (k != 'indexOf') if (!(o[k] instanceof Function)) s += k + ' = ' + o[k] + '\n';

  alert(s);
}

// Remove all of a dom element's children
//
function emptyElem(e)
{
  if (e) if (e = elem(e)) while (e.lastChild) e.removeChild(e.lastChild);
}

// Enacpsulates delayed method invocation
//
function setObjectTimeout(object, method, delay)
{
  if (delay) {} else delay = 50;

  return eval('setTimeout(function() { object.' + method + '(); }, delay)');
}

// Disable user selection of text across browsers
//
function disableUserSelect(e)
{
  if (e) if (e = elem(e))
  {
    if (is_ie) add_event(e, 'selectstart', function() { return false; }); else
    {
      e.style.MozUserSelect = e.style.webkitUserSelect = e.style.khtmlUserSelect = 'none';
    }
  }
}

// Returns an array of js objects derived from the json
// encoded output of APP_Database::complex_results, ex:
//
// input  = { rows:[[1, 'item 1'], [2, 'item2']], cols:['id', 'name'], types:['int4', 'varchar'] }
//
// output = [ { id:1, name:'item 1' }, { id:2, name:'item 2' } ];
//
// The input format is used to reduce the amount of data transferred by listing property names only once.
// Instances of the optional entity_class will be returned if one is provided.
//
function objectsFromData(data, entity_class)
{
  var array = [];

  if (entity_class) {} else entity_class = Object;

  while (row = data.rows.shift())
  {
    var obj = new entity_class;

    for (col in data.cols) if (col != 'indexOf')
    {
      var value = row[col];
      var type = data.types[col];

      if (type == 'bool') value = (value == 't');

      obj[data.cols[col]] = value;
    }

    array.push(obj);
  }

  return array;
}

// Issue an asynchronous request for the json encoded output of a call to APP_Database::complex_results or similar.
// The search parameter may be a urlencoded string or a hash or properties that the function will encode.
// Upon success, invokes the callback with the resulting data as an array of js objects returned by objectsFromData.
// If a window is specified, it will be automatically closed upon success.
// NOTE: requires YUI includes, yahoo/yahoo.js & connection/connection.js
//
function requestData(url, search, callback, entity_class, win, method)
{
  var callback_wrapper =
  {
    success: function(response)
    {
      if (is_firefox) if (win) win.close();

      if (response.responseText !== undefined)
      {
        if (callback)
        {
          var data = null;

          eval('data = ' + response.responseText);

          callback(objectsFromData(data, entity_class));
        }
      }
      //else alert('Empty!');
    },
    failure: function(response)
    {
      //alert('Failure!');
    }
  }

  if (search) search = '?' + ((search instanceof Array) || (search instanceof Object) ? escapeArray(search) : search);

  //prompt('', url + search);

  var request = YUI.util.Connect.asyncRequest(method ? method : 'GET', url + search, callback_wrapper);

  if (!is_firefox) if (win) win.close();
}

// Similar to above, but allow the caller to process the data
//
function request(url, data, callback, failure_callback, scope, headers)
{
  YAHOO.util.Connect.initHeader('Accept', 'application/json');

  // an associative array of complete header lines
  if (headers)
  {
    for (lbl in headers) if (lbl != 'indexOf')
    {
      YAHOO.util.Connect.initHeader(lbl, headers[lbl]);
    }
  }

  // an associative array of complete header lines
  YAHOO.util.Connect.asyncRequest('POST', url,
  {
    success: function (o)
    {
      var r = null;

      try { r = YUI.lang.JSON.parse(o.responseText); } catch(e)
      {
        try { r = eval('(' + o.responseText + ')'); } catch(e) {}
      }

      if (!r)
      {
        if (failure_callback) failure_callback(o.responseText); else alert(o.responseText);
      }
      else
      {
        if ((r.success == 'true') || (r.success == true))
        {
          if (callback) return scope ? callback.call(scope, r.data) : callback(r.data);
        }
        else if (r.error) alert(r.error); //else alert(o.responseText);
      }
    },
    failure: function (o)
    {
      if (failure_callback) failure_callback(o.responseText); else if (debugging()) alert(o.statusText);
    },
    scope:scope
  }, (data instanceof Object) ? escapeArray(data) : data);
}

function callModel(model, method, id, data, callback, failure_callback, scope)
{
  data || (data = {});

  data['models'] = model;
  data['task'] = method;
  data['id'] = id;

  request('/nrp/services/ajax_controller.php', data, callback, failure_callback, scope);
}

function callRelax(model, method, id, data, successCallback, failureCallback)
{
  id || (id = 0);
  data || (data = {});

  var force_jsonp = !!data.jsonp;

  // require nrp/includes/javascript/json2min.js to make sure we've got JSON in all browsers!
  //
  if (!isString(data)) data = stringifyJSON(data);

  // allow method/action to be specified either as explicit arg or request envelope attribute
  //
  if (method) data.action || (data.action = method); else method = data.action;

  var url = nimbitUrl('nrp/relax/' + model + '/' + id + '/' + method);

  var callback = function(json)
  {
    var o;

    try { eval('o = ' + json); } catch(e)
    {
      if (failureCallback) failureCallback(200, json);
    };

    if (successCallback) successCallback(o);
  }

  // use XMLHttpRequest if the current page originates from the same host as this script
  // otherwise use jsonp, but note that this limits data to about 2k as it is a get
  //
  if ((onNimbitPage() || (canUseCORS() && !is_ie9)) && !force_jsonp) postRequest(url, data, 'POST', callback, failureCallback, true); else
  {
    if (successCallback)
    {
      var i = callRelax.jsonpCallCount = (callRelax.jsonpCallCount || 0) + 1;

      callRelax['callback' + i] = successCallback;

      url += '?callback=callRelax.callback' + i;
    }

    append_dom(document.body, ['script', { type:'text/javascript', src:url + '&request=' + data }], false, document.body.firstChild);
  }
}

function blink(element, times)
{
  var style = elemStyle(element);

  if (style.visibility == 'hidden') times--;

  style.visibility = (style.visibility == 'hidden' ? '' : 'hidden');

  if (times) setTimeout(function() { blink(element, times); }, 500);
}

function empty_elem(e)
{
  for (e = elem(e); e.firstChild;) e.removeChild(e.firstChild);
}

function append_children(node, children)
{
  node = elem(node);

  for (var i = 0; i < children.length; i++) node.appendChild(children[i]);
}

function prepend_children(node, children, before_node)
{
  node = elem(node);

  if (before_node) {} else before_node = node.firstChild;

  for (var i = 0; i < children.length; i++) node.insertBefore(children[i], before_node);
}

// given a list of node definition attributes builds and returns a dom fragment
//
// the first element in the array is always the root tag name
// the second element may be a literal javascript object defining the tag's attributes
// the last element in the array is the textual content OR a list of additional child node definitions
//
// for example...
///
// ['h3', 'Welcome']
//
// ['a', { href:'http://www.nimbit.com' }, 'Visit Nimbit']
//
// ['div', { className:'header' }, ['a', { href:'http://www.nimbit.com' }, 'Visit Nimbit']]
//
// ['div', {       cls:'header' }, ['a', { href:'http://www.nimbit.com' }, 'Visit Nimbit']]
//
// note option of abbreviating the css className attribute as cls
//
function build_dom(node_definitions)
{
  var nodes = new Array();

  for (i = 0; i < arguments.length; i++)
  {
    var def = arguments[i];

    if (def) {} else continue;

    if (!(def instanceof Object)) nodes.push(document.createTextNode(def)); else
    {
      if (def instanceof Array) if (def.length)
      {
	var node = def.shift();
	var props = new Object;

	if (def.length) if (def[0] instanceof Object) if (!(def[0] instanceof Array))
	{
	  props = def.shift();

	  if (is_ie && !is_ie9) if (props.name) node = '<' + node + ' name="' + props.name + '"/>';
	}

	try { node = document.createElement(node); }

	catch(e) { alert(e + '\n\n' + node); }

	for (prop in props) if (prop != 'indexOf')
	{
	  if (prop != 'style') node[prop == 'cls' ? 'className' : prop] = props[prop]; else
	  {
	    for (attrib in props[prop]) node.style[attrib] = props[prop][attrib];
	  }
	}

        for (var i = 0; i < def.length; i++) append_children(node, build_dom(def[i]));

	nodes.push(node);
      }
    }					   
  }

  return nodes;
}

// Convenience wrapper to build_dom and append it to an existing element
// that can optionally first remove any exisitng child nodes.
// Optional insertBeforeChild argument causes the new element to be so inserted.
//
function append_dom(element, definition, removeChildren, insertBeforeChild)
{
  element = elem(element);

  var child = build_dom(definition).pop();

  if (removeChildren) while (element.lastChild) element.removeChild(element.lastChild);

  if (insertBeforeChild) element.insertBefore(child, elem(insertBeforeChild)); else element.appendChild(child);

  return child;
}

function append_style(styles)
{
  var css = document.createElement('style');

  css.type = 'text/css';

  if (css.styleSheet) css.styleSheet.cssText = styles;

  else css.appendChild(document.createTextNode(styles));

  document.getElementsByTagName("head")[0].appendChild(css);
}

// install cross-browser scroll event handler
//
function addScrollHandler(fn, scroll)
{
  var element = window; // MSIE 6, 7 and MSIE 8

  if (window.addEventListener) {} // Firefox 1+, Opera 9, Safari 3+, etc.

  else if (document.addEventListener) element = document; // Opera 7, Opera 8

  add_event(element, scroll ? scroll : 'scroll', fn);
}

// install cross-browser resize event handler
//
function addResizeHandler(fn)
{
  addScrollHandler(fn, 'resize');
}

function javascriptPath(tail)
{
  return '/nrp/includes/javascript/' + tail;
}

function yuiPath(tail)
{
  return javascriptPath('yui/build/' + tail);
}

function parseUrl(url) // parses components of valid urls
{
  var o = { url:'' + url, args:{} }; // coerce url to string so document.location may be passed directly

  this.re1 || (this.re1 = /^([^:]*):?\/\/([^\/:]+)(:\d+)?\/([^\#?]*)(\#[^\?]*)?([?].*)?/);

  if (o.url.match(this.re1))
  {
    o.protocol = RegExp.$1 ? RegExp.$1 : '';
    o.host     = RegExp.$2 ? RegExp.$2 : '';
    o.port     = RegExp.$3 ? RegExp.$3.substr(1) : '';
    o.pathname = RegExp.$4 ? RegExp.$4 : '';
    o.hash     = RegExp.$5 ? RegExp.$5.substr(1) : '';
    o.search   = RegExp.$6 ? RegExp.$6.substr(1) : '';
    o.args     = unescapeArray(o.search);

    this.re2 || (this.re2 = /(store|artist)(s|data)\/([^\/]+)/);

    if (o.pathname.match(this.re2)) o.dirname = RegExp.$3 ? RegExp.$3 : '';
  }

  o.assemble = function()
  {
    var s = (this.protocol ? this.protocol + ':' : '') + '//' + o.host;

    s += (this.port ? this.portl + ':' : '') + '/' + this.pathname;

    if (this.args) s += '?' + escapeArray(this.search);

    if (this.hash) s += '#' + hash;

    return s;
  };

  return o;
}

function scriptInfo(scriptIndex)
{
  var scripts = document.getElementsByTagName('script');

  if (scriptIndex) if (scriptIndex < 0) scriptIndex = scripts.length + scriptIndex;

  return scripts.length > scriptIndex ? parseUrl(scripts[scriptIndex].src) : {};
}

// Utility for pulling in scripts to use yui
// Requires YAHOO.util.YUILoader already be included...
//
function yuiLoader(modules, callback)
{
  var requires = ['yahoo-dom-event'];

  var loader = new YAHOO.util.YUILoader();

  for (var i = 0; i < modules.length; i++) if (modules[i] == 'NIMBIT.DataTable')
  {
    loader.addModule({ name:'yui.css',       type:'css', fullpath:'/dashboard/yui.css' });
    loader.addModule({ name:'campaigns.css', type:'css', fullpath:'/dashboard/campaigns.css' });
    loader.addModule(
    {
      name:'NIMBIT.DataTable',
      type:'js',
      fullpath:javascriptPath('DataTable.js'),
      requires:requires = ['yahoo-dom-event', 'connection', 'container', 'json', 'datatable', 'yui.css', 'campaigns.css']
    });
  }

  loader.filter = 'raw';
  loader.loadOptional = true;
  loader.require(requires.concat(modules));
  loader.insert(callback ? { onSuccess:callback } : null);
  return loader;
}

function hideLoadingDialog()
{
  if (loadingDialog.dialog) loadingDialog.dialog.hide();
}

// requires YAHOO.widget.Panel
//
function loadingDialog(task, wait_to_show)
{
  hideLoadingDialog();

  var settings =
  {
    width:"240px", 
    fixedcenter:true, 
    close:false, 
    draggable:false, 
    zindex:4,
    modal:true,
    visible:false
  };
 
  var dialog = new YAHOO.widget.Panel("wait", settings);
  dialog.setHeader((task ? task : 'Loading') + ', please wait...');
  dialog.setBody('<img src="/images/interstitial_loading.gif"/>');
  dialog.render(document.body);
  if (! wait_to_show) {
    dialog.show();
  }

  return loadingDialog.dialog = dialog;
}

// Turns a numeric value into a string with commas for thousands and preserving decimal
function numToString(no)
{
  no += '';
  x = no.split('.');
  x1 = x[0];
  x2 = x.length > 1 ? '.' + x[1] : '';
  var rgx = /(\d+)(\d{3})/;
  while (rgx.test(x1)) {
    x1 = x1.replace(rgx, '$1' + ',' + '$2');
  }
  return x1 + x2;
}

function in_array(a, e)
{
  for (i in a) if (a[i] == e) return true;

  return false;
}

function joinPath(parts)
{
  var s = '';

  if (parts && parts.length)
  {
    s = parts.shift();

    for (var i = 0; i < parts.length; i++)
    {
      s = s.replace(/[/]+$/, '') + '/' + parts[i].replace(/^[/]+/, '');
    }
  }

  return s;
}

function imageUrl(suffix, images)
{
  images || (images = 'images');

  var s = window.client_settings;

  if (s) if (s.useS3ForAlbumArt)
  {
    return joinPath([s.cloudfrontBaseUrl ? s.cloudfrontBaseUrl : (s.s3BaseUrl + s.albumArtBucket), s.albumArtBucketPrefix, images, suffix]);
  }

  if (s) {} else
  {
    if (imageUrl.warned) {} else
    {
      imageUrl.warned = true;

      alert('Warning: Sourcing media from Nimbit in lieu of explicit client settings.');
    }
  }

  return nimbitUrl(joinPath([images, 'db', suffix]));
}

function mediaUrl(suffix)
{
  return imageUrl(suffix, 'media');
}

function productImageSrc(product, size)
{
  size || (size = 'square');

  var isMusic = product.type.match(/^(CD|Vinyl LP|MP3 Album|Vinyl 45)$/) ? true : false;

  return product.imageId ? imageUrl(size + '/' + product.imageId + '.jpg') : nimbitUrl('images/' + (isMusic ? 'no_album_art.jpg' : 'no_merch_art.jpg'));
}

// return a url rooted at nimbit
//
function nimbitUrl(suffix)
{
  if (nimbitUrl.host) return nimbitUrl.host + (suffix ? suffix : '');

  if (window.nimbitUrlHost) return nimbitUrl.host = nimbitUrlHost;

  var scripts = document.getElementsByTagName('script');

  for (var i = scripts.length; i > 0; i--)
  {
    if (scripts[i - 1].src.match(/^(https?:\/\/.*?nimbitmusic.*?com\/)/)) return nimbitUrl.host = RegExp.$1;
  }

  for (var i = scripts.length; i > 0; i--)
  {
    if (scripts[i - 1].src.match(/^(https?:\/\/.*?nco.*?nimbit.*?com\/)/)) return nimbitUrl.host = RegExp.$1;
  }

  for (var i = scripts.length; i > 0; i--)
  {
    if (scripts[i - 1].src.match(/^(https?:\/\/.*?nimbit.*?com\/)/)) return nimbitUrl.host = RegExp.$1;
  }
  
  for (var i = scripts.length; i > 0; i--)
  {
    if (scripts[i - 1].src.match(/^(https?:\/\/.*?nimbit.*?net\/)/)) return nimbitUrl.host = RegExp.$1;
  }  

  // accomodate ie returning the raw src value which is sometimes root-relative with no host name
  //
  for (var i = scripts.length; i > 0; i--)
  {
    if (scripts[i - 1].src.match(/^\/nrp\/includes\/javascript\/common.js/))
    {
      if (document.location.toString().match(/^(https?:\/\/.*?nimbit.*?com\/)/)) return nimbitUrl.host = RegExp.$1;
    }
  }
}
//
nimbitUrl(); // initialize the host name while this is the most recent script being loaded

function membersUrl(suffix)
{
  if (membersUrl.host) {} else if (nimbitUrl.host)
  {
    if (nimbitUrl.host.match(/nimbitmusic.com/))
    {
      membersUrl.host = nimbitUrl.host.replace(/\/\/.*?nimbitmusic.*?com/, 'members.nimbit.com');
    }
    else
    {
      membersUrl.host = nimbitUrl.host.replace(/nco[.]/, 'members.');
    }
  }

  return membersUrl.host + (suffix ? suffix : '');
}

function onNimbitPage()
{
  return document.location.toString().indexOf(nimbitUrl()) == 0;
}

// These wrappers exist to defend against other libraries on sites that
// decide to trounce upon the native implementations for whatever reason.
// The two json2 fallback functions are defined in json2min.js
//
function stringifyJSON(data)
{
  // not sure why they feel it necessary but the mootools library breaks both the
  // native JSON.stringify and json2's stringify and makes a useable encode instead
  //
  if (window.JSON && JSON.encode) return JSON.encode(data);

  return (window.JSON && JSON.stringify && JSON.stringify.toString().match(/native code/) && (JSON.stringify([]) == json2stringify([]))) ? JSON.stringify(data) : json2stringify(data);
}

function parseJSON(data)
{
  return (window.JSON && JSON.parse && JSON.parse.toString().match(/native code/)) ? JSON.parse(data) : json2parse(data);
}

function cloneObject(objectToClone) 
{
  return parseJSON(stringifyJSON(objectToClone));
}

function parseDate(dateString)
{
  if (('' + dateString).match(/(\d\d\d\d)-(\d\d?)-(\d\d?)/))
  {
    return new Date(RegExp.$1, RegExp.$2 - 1, RegExp.$3, 0, 0, 0, 0);
  }
  else
  {
    return new Date(dateString);
  }
}

// Firefox has the odd behaviour of passing the delta from the delay as an arg to the callback
// This function filters it out...
//
function setTimeoutWithNoArgs(fn, delay)
{
  setTimeout(function() { fn(); }, delay);
}
