//document.observe("dom:loaded", function() {
//  // initially hide all containers for tab content
//  $$('div.tabcontent').invoke('hide');
//});

// no-op function in case we leave in while debugging
function puts(msg) {console.log(msg)}


// what does icomment do?
function icomment(cid, form) {
  // this part isn't working, hmm...  $A($form()) or somesuch wierdness.  seems to not be able to find the form name? aah, this() is getting passed in...
  
  // works, just need to fix complete_comment to update the area below the particular inline post...
  //$(cid+'bb_add_li').innerHTML = ""
  //complete_comment(request)
  new Ajax.Request('/comment/add/' + cid, {asynchronous:true, evalScripts:true, onComplete:function(request){Element.hide(cid+'bb_add_li'); Element.clear('comment_body_'+cid);}, onFailure:function(request){comment_failure(request);}, onLoading:function(request){$(cid+'bb_add_li').innerHTML = "<p>Adding comment <img src='/s/images/wait.gif' /></p>"}, parameters:Form.serialize(form)}); 
  return false;
}

// doesn't automatically load the rest of the journal at the moment... would be cool if it did!
// do tricky stuff like only hiding when there are few comments to show?  How to paginate/etc?
// only show most recent comments, or all?
// also loads comments on this in-line item
function commentform(twisty, cid, num_comments, load_item) {
  // show inline add form, and set ajax to show other comments below the comment form...  reply form == ?
  target = "c_" + cid
  
  // if it's not open already...
  if ($(target).innerHTML.length < 10) {
    txt = "<form action='/comment/add/" + cid + "' method='post' onsubmit='icomment(" + cid + ", this); return false'>	<input type='hidden' name='inline' value='1' /><input type='hidden' name='unique' value='" + cid + "'><input type='hidden' name='comment[kind]' value='journal' /><input name='comment[item_id]' type='hidden' value='" + cid + "' />	<h2>Add comment</h2><textarea cols='52' id='comment_body_"+cid+"' name='comment[body]' onKeyPress='grow(this,event, 11, 3)' rows='3' style='width: 82%'></textarea></p>	<p><input id='submit' type='submit' value='Submit Comment' /></form><div id='"+cid+"bb_add_li'></div>"

    // inline preview is being a pain in the ass.. for now, just show twiddler
    //<ul class='comment_list'>	<li class='comment' style='display: none' id='rinterm'>
  	//	<div class='comment_by'>
  	//  	<%= image_tag(User.image(@me.id))+"<br />" if @me.has_image? -%>
  	//		<%= @me %> right now
  	//	</div>
  	//	<div class="comment_main">
  	//		<h2 id='rinterm_wait'><img src='/s/images/wait.gif' height='17' width='18'> Adding your reply:</h2>
  	//		<h3 id='rinterm_subject'></h3>
  	//		<div id='rinterm_body'></div>
  	//	</div>
  	//</li>

    // trying to include the bb_add_li div  just below the form, maybe it'll work out...
  
    //comment_controller adds to end of #{@p.unique}bb_add_li
    // was named comment_list"+cid+"
    // fuck, this loads previously made comments... where will NEW comments go?  need a <ul>...
    // currently, clicking on the '5 comments' loads a new page..
  
    // this should be abstracted better?  Or just abstracted in design, hack however in code? :)
  
  
    // this is expected to identify an ELEMENT in a list of comments... but where are the comments?, when are they loaded?  irritatingly getting complicated :( 
    if (num_comments != 0) {      
      txt += "<ul class='comment_list' id='comment_list"+cid+"'><img src='/s/images/wait.gif' /></div>"
      
      // then the result of this replaces comment_list+CID
      new Ajax.Request('/journal/load_comments/' + cid, {asynchronous:true, evalScripts:true});
    }
  
    // only do if comment form not expanded. but STILL do if num_comments is zero.
    // could try and integrate with load_comments, but leave separate for now, as thats complicated  
    if (load_item == 1 && $('journal_brief_'+cid).innerHTML.length < 1201) {
      $('journal_brief_'+cid).innerHTML+= " <img alt='Wait' id='userfind_spinner' src='/s/images/wait.gif' />"
      // scrolling it into place appears to be having problems :(
      // gets off when other display.effect things have taken effect already... moves to the OLD location on the page...
      // new Effect.ScrollToFullView('journal_brief_'+cid, {duration: 0.9, offset: 236}, {sync: true});
      new Ajax.Request('/journal/load_full/' + cid, {asynchronous:true, evalScripts:true, onLoaded:function(request){Field.focus('comment_body_'+cid)}});
    }
  
    $(target).innerHTML = txt
  }

  if ($(target).style.display == 'none') { 
    twisty.getElementsByTagName("span")[0].innerHTML = '&darr;'
    new Effect.BlindDown(target, { duration:0.2, fps:50})//, queue:'end' 

  } else {
    twisty.getElementsByTagName("span")[0].innerHTML = '&rarr;'        
    new Effect.BlindUp(target, { duration:0.2, fps:50 })    
  }
    
  return false
}




// the other way to do this (the way blockbuster does), is to have one image for each possibiliyt
// then use an AREA to onmouseover change the images.  Easier to handle leaving the 'zone'
blind_len = { duration:0.7, fps:50} // used by aph apparently?
isIE = (navigator.userAgent.indexOf('MSIE') >= 0) // make sure it's not v7?
autosave_interval = 40000 // 60k = 1 minute

Effect.DefaultOptions = {
  transition: Effect.Transitions.sinoidal,
  duration:   0.20,   // seconds
  fps:        25.0,  // max. 25fps due to Effect.Queue implementation
  sync:       false, // true for combining
  from:       0.0,
  to:         1.0,
  delay:      0.0,
  queue:      'parallel'
}

function d() {
  $A(arguments).each( function(i) {console.log(i)})
}

// onsubmit returns undef by default, not true
function check_empty_title(area) { // if we return true, it quits
  if ($F(area) !='') return true;
  return confirm('Are you sure?  You have no title chosen.'); 
}

function toggles() {
  $A(arguments).each( function(i) {Element.toggle(i)})
  return false
}
function etoggles() {
  $A(arguments).each( function(i) {Effect.toggle(i)})
  //$A(arguments).each(Effect.toggle) // doesn't work, hmm
  return false
}

// autosave if the length of the serialized paramters has changed drastically?  Or how else to tell %change?  Or if 
// save every 2 minutes assuming > 100 characters have changed?  can't tell if changed now, so just do if more
// <a href='#' onclick="autosave('item_form','/item/add'); return false">autosave</a>
var last_autosave_len = 250; // empty values have a certain amount of space.  actual=296 @ item
function autosave(form, post_to) {
	$('draft').value='1'
	serialized_form = Form.serialize($(form))
	//console.log("last autosave len = ", last_autosave_len, " len now: ", serialized_form.length)
	if (last_autosave_len + 100 > serialized_form.length) return
	last_autosave_len = serialized_form.length;
	
	new Ajax.Updater('autosave', post_to, {asynchronous:true, evalScripts:true, onLoading:function(request){Element.show('autosave'); $('autosave').innerHTML='Autosaving...'}, onFailure:function(request){$('autosave').innerHTML='Unable to autosave'}, parameters:serialized_form});
}


// container_container is middle.  outer == outer
var ljust = false
var hidden = 0
var ljust = 0
//if (disable_for_a_bit) return;	disable_for_a_bit = 1;	setTimeout( "disable_for_a_bit = 0", 200) // not as good, b/c could then miss resize events... realisticly so small that unlikely?  always miss the last one though...
// do i really need to use body instead of outer?
// remember with IE - never use a variable that's the same name as a CSS id...
function resize_edge() {
  //if (ljust == 0) return;
	//current=ie4 && !window.opera? iecompattest().scrollLeft+iecompattest().clientWidth : window.pageXOffset+window.innerWidth
	
	c = document.body; //$('outer'); //was document.body
	m = $('container_container')

	middle = m.offsetWidth
	owidth = $('outer').offsetWidth
	
	one_edge = (owidth-middle)/2
	// ugh, really want it 1/2 margin, 1/2 padding :) ==  134 -> 67 == a bit left of perfectly centered
	
	//amt = ljust/2
	// why don't I just do this for all of them?
	//if (ljust > 165) amt=0;
	amt = 0
	
	c.style.backgroundPosition = one_edge - amt + 'px 0px'
}


function old_resize_edge() {
  if (ljust == 0) return;
	current=ie4 && !window.opera? iecompattest().scrollLeft+iecompattest().clientWidth : window.pageXOffset+window.innerWidth
  
  // dduh, have to change this based on whether the right side is visible or not, just ilke before?
	if (current < max_width+ljust*2) {		
		if (hidden==0) {
		  //console.log("hiding")
			hidden = 1
			//$('right_edge').style.width=0
			Element.hide('right_edge')
		}
		return // don't do anything if it's already hidden
	}
	
	if (hidden==1) {
		hidden=0
		//$('right_edge').style.width=ljust+'px'
		Element.show('right_edge')
	}
	
	// make the bg tiling not visible... move as we resize
	half=(current - $('container_container').offsetWidth)/2
	$('outer').style.backgroundPosition = (current-ljust)/2 +'px 0px'
}


function l() {
  return
  console.log(arguments)
}

var DEVELOPMENT_MODE = false;  
  
// When logging messages with console.log()  
// if user doesn't have Firebug, write them to the DOM instead  
if (typeof console == "undefined" && DEVELOPMENT_MODE == true) {  
   
  // Create an unordered list to display log messages  
  var logsOutput = document.createElement('ul');  
  document.getElementsByTagName('body')[0].appendChild(logsOutput);  
    
  // Define console.log() function  
  console = {  
    log: function(msg) {  
      logsOutput.innerHTML += '<li>' + msg + '</li>';  
    }  
  };  
} else if (typeof console == "undefined" && DEVELOPMENT_MODE == false) { // 
  console = {  
    log: function() {} 
    // Do nothing  
  };  
}  


// puts the javascript for the images in the current image list area
var current_bg = false;
var current_edge = false;

function close_current_tab(main, tab) {
  if (main == 'edge') {
    if (current_edge && tab != current_edge) twistnow($('h'+current_edge), current_edge);
    if (tab == current_edge) {current_edge = false} else {current_edge = tab}
  } else {
    if (current_bg && tab != current_bg) twistnow($('h'+current_bg), current_bg);
    if (tab == current_bg) {current_bg = false} else {current_bg = tab}
  }
  Element.hide('bg_custom_add')
}

function btwist(area, main, twisty) {
  //console.log("btwist", area, main, twisty, "current:", current_tab)
  if (main == 'edge') { // currently changing the outer edge
    prefix = 'e_'; 
    set_color_across = false
  } else {
    prefix = 'c_'
    // also need to update the actual field... nope, sitll doesn't work
    //if (set_tile_across) {$('cdemo').style.backgroundImage = $('cdemo_parent').style.backgroundImage;}
  }
  tab = prefix + area

  close_current_tab(main, tab)  
  //console.log('opened:', current_edge, 'self:', tab)
  
  // close any others open in our main area.  boy this was a bitch to factor


  //console.log("now currents edge:", current_edge, "current bg:", current_bg)

  // put images from innerhtml in.  when it is clicked, how will we know what area it was? in function == ideal
  // otherwise check parent tree of image id somehow?
  if (area != 'plain' && !shown_images[tab] ) {
    $(tab).innerHTML = images[area]
	  shown_images[tab] = 1
  }
  
  // doesn't close when you click it again == annoying...
  if (area == 'custom') { 
    // if going to be opened, then show bg_add.  if it's going to be closed, hide it.
    if ($(tab).style.display == 'none') {Element.show('bg_custom_add')} // to be opened
    else {Element.hide('bg_custom_add')}
  }
  
  //console.log("current main:", current_main, "area:", area, "main:", main)
  if (main == 'main') {
    if (area== 'plain') { Element.show('color_across') } else { Element.hide('color_across') }
    if (area== 'tiling') { Element.show('tile_across') } else { Element.hide('tile_across') }    
  }
  // not sure why this one works this way, but the other doesn't :)
  //if (current_main == 'tiling') { Element.show('tile_across') }
  //else { Element.hide('tile_across') }
  
  return twistnow(twisty, tab)
}


// do the bgcolor textboxes update properly then?
//$('background_color').style.backgroundColor = $('color0').value;

// take selected bg, add to preview box, hide bg list
// to == id of bg element... used anymore?

// needs to be set to whatever it's starting with??  defaulting to ljust might work
var current_main = '';

// this needs to be cleaned up!
function bg_preview(to,color,image,ljust, area) { 
  // hide bg list & old opened images section
  //console.log($('bg_id_' + to).parentNode == 'c_tiled', 'ljust: ', ljust)  // check for tiled area
  Element.hide('color_across')
  if (!ljust) ljust=0
  //console.log("left_spacing: " + ljust)
  $('left_spacing').innerHTML = ljust
  $('left_spacing2').innerHTML = ljust
    
  // close any others in our main area, including ourselves unless we're a color?
  if (area == 'edge_bgs' || area == 'e_custom') {
    if (current_edge) twistoff($('h'+current_edge), current_edge)
    current_edge = false
  } else {
    //d("main bg.  current_bg:", current_bg)
    if (current_bg) twistoff($('h'+current_bg), current_bg)
    current_bg = false
  }
  
  //$('color3').value = '#FF0'
  //console.log('bg_preview color3 is', $('color3').value, $('color3'), $F('color3').value)
  //d("preview.  area:", area, "to:", to, "color:", color, "image:", image)

  // changing the EDGE area
	if (area == 'edge_bgs' || area == 'e_custom') {
	  // if set_tile_across is set, we need to fix some stuff
	  if (set_tile_across) {
	    set_tile_across = false;// since we're changing edge, turn off tile across
	    // put back demo, so parent doesn't tile across
	    $('cdemo').style.backgroundImage = $('cdemo_parent').style.backgroundImage
	  }
	  
	  $('edge_bg_num').value = to
	  $('cdemo_parent').style.backgroundImage = 'url(' + image + ')' // overrides any background colors usually...
	  $('cdemo_parent').style.paddingLeft = '100px'
	  $('cdemo_parent').style.paddingRight = '100px'
	  
	  $('cdemo').style.borderLeft = $('cdemo').style.borderRight = '0'
    // hack, doesn't fix in all cases... some odd spacing problems below the preview window
    $('cdemo').style.paddingBottom = '12px'
	  //console.log($('cdemo_parent').style.backgroundImage, $('cdemo_parent').style.marginLeft)
	  
  // changing the MAIN area
	} else {
	  
	  // fix edit link to point to proper bg
  	$('background_color').style.backgroundColor = color  // background treated as this color div
	  Element.show('bg_bginfo')  // un-hide background treated as this color...
	  
    $('color0').value = color
    cs0_change_update($('color0').value, true);  
  
	  $('bg_num').value = to
    $('cdemo').style.backgroundImage = 'url(' + image + ')'

    // update ljust padding to add 6 px, and default to 6?
    // so tiling images will have a paddingleft of 12 px, right?  used above to keep 'tile across' visible
    if (!ljust || ljust == 0) ljust=6
    $('cdemo').style.paddingLeft=ljust+6+"px"
    
    // put the main image on the sides, and pump up left padding to ljust, width of 'right' =ljust.  ljust always 7!
    if (ljust > 6) {
      twistoff($('he_plain'), 'e_plain')
      
      //wipe the edge_bg just in case. neeed when custom ljust set for edge, then use ljust main
      $('cdemo_parent').style.backgroundImage = ''
      $('cdemo_parent').style.paddingLeft = '0'
	    $('cdemo_parent').style.paddingRight = '0'      
          
      current_main = 'ljust';
      Element.show('he_centered'); Element.hide('he_categories'); Element.hide('tile_across')
      
      $('cdemo').style.paddingLeft = ljust + 7 + 'px'
      $('cdemo').style.borderLeft = '0' 
      $('cdemo').style.borderRight = '0'
    }
    else { // this is a tiling background in the main area
      current_main = 'tiling';
      Element.show('tile_across')
      Element.hide('he_centered'); Element.show('he_categories')      
      
      $('cdemo').style.backgroundPosition = '0 0'
      
      // but if we currently have a tiling edge bg, need to leave this... nope
      //$('cdemo_parent').style.paddingLeft = '0'
	    
	    if (set_tile_across) {
	      $('cdemo_parent').style.backgroundImage = $('cdemo').style.backgroundImage
	    }
    }
	} // edge_bgs
}

// fix demo so that it tiles across the whole thing.  main bg == blank, edge == only tile
// if set_tile_across was already true, then auto-do it?  But doesn't seem to be doing that, only set_color_across auto-works.
// this isn't currently working to auto-update to tile across.  that's fine though
var set_tile_across = false
function tile_across() {
  //if (set_tile_across) {alert('already across');return false}
  close_current_tab('edge',false) 
  
  set_tile_across = true
  $('edge_bg_num').value = $('bg_num').value
  $('bg_num').value = '' // better than 0?
  $('color0').value = '' // otherwise we can't tell this apart from a set inner color...
  
  // does this end up staying as a reference to itself, so changing one changes the other???
  //console.log('demo bg was', $('cdemo').style.backgroundImage, $('edge_bg_num').value)
  $('cdemo_parent').style.backgroundImage = $('cdemo').style.backgroundImage
  //console.log("parent now is", $('cdemo_parent').style.backgroundImage)
  
  $('cdemo').style.padding = '8px'
  //$('cdemo').style.paddingBottom = '15px'
  $('cdemo').style.backgroundImage = ''
  $('cdemo').style.backgroundColor = ''
  $('cdemo').style.border = ''
  return false
}

//set color in 2nd same as color in first + auto-update?
var set_color_across = false
function color_across() {
  close_current_tab('edge',false)
  set_color_across = true
  cs3_change_update($('color0').value, 2)
  return false
}

// CS0:: background-color
//update bgcolor/etc.  auto-updates the demo.  which would be sweet, but we lose our carefully defined demo?
// better to only have to set it in one place though... update the element ID, then call the update function...
// when this updates, it clears the existing bgs.  but it auto-updates when starting!  so fancy delay and manual settings test added
// how do I know whether this was actually a change to the background
function cs0_change_update(new_color, manual) {
  // calls automatically when we refresh, which messes things up.  how to skip?  || current_tab != 'c_plain'
  //console.log("change update with manual", manual, current_edge, current_bg)
  if (!current_bg && !current_edge && !manual) return; 
      
  if (!manual || manual == 2) {
    $('cdemo').style.backgroundImage = ''
    $('cdemo').style.backgroundColor = new_color
    $('bg_num').value = ''

    // ok, bug = change edge bg to non-color, then change main bg to color == sets edge back to color
    // now: sorta better, but changing main to tiled resets edge color to #CCC still.
    //console.log("current_main is", current_main)
    if (current_main == 'ljust') {//} || current_main == 'tiling') {
      //d("Resetting bgcolor from ljust settings")
      //Element.hide('cright')
      //$('cdemo_parent').style.backgroundImage = ''
      $('cdemo_parent').style.paddingRight = '0'
      $('cdemo_parent').style.paddingLeft = '0'
      $('cdemo').style.padding = '8px'
      $('cdemo').style.paddingBottom = '12px'
          
      // put back borders and show edge color chooser
      Element.hide('he_centered'); Element.show('he_categories')
      
      // replaces tiling outer edge with a blank color if we had a tiling edge before...
      //console.log("color3 value is", typeof $('color3').value, $('color3').value)
      
      if (typeof $('color3').value == 'undefined') $('color3').value = '#FFFFFF'
      cs3_change_update($('color3').value )
      
      //color_selects[3].setrgb(color)
      //console.log("border is now", $('cdemo').style.borderLeft)
    }
    // else if (current_main == 'tiling') {  
    //}
  }
  
  if (current_bg) { // in bg tab, not 'edge' tab.
    current_main = 'color';
    Element.hide('bg_bginfo')
  }
  
  $('color0').value = new_color
	$('link_contrast').innerHTML = test_colors(new_color, $('color2').value)		
	$('vlink_contrast').innerHTML = test_colors(new_color, $('color4').value)		
	$('font_contrast').innerHTML = test_colors(new_color, $('color1').value)		

	if (set_color_across) cs3_change_update($('color0').value, '2')
}


// CS3: EDGE COLOR
// if we were in tile_across, reset background to inner div first
function cs3_change_update(new_color, manual) {
  //console.log("change cs3 update with manual", manual, current_edge, current_bg, new_color, new_color.length) 
  if (!current_bg && !current_edge && !manual) return;
  if (new_color.length > 7) {new_color = "#CCCCCC"; color_selects[3].setrgb(new_color);}
  
  //if (!current_tab || (current_tab != 'e_plain' && current_tab != 'c_plain')) return;  
  if (!manual || manual == 2) {
    //console.log("continuing with cs3 change_update", new_color)
    $('edge_bg_num').value = ''
    if (set_color_across)
    $('cdemo_parent').style.backgroundImage = ''	
	  $('cdemo').style.borderLeft = "20px solid " + new_color;
	  $('cdemo').style.borderRight = "20px solid " + new_color;
    $('cdemo').style.padding = '8px'
    $('cdemo').style.paddingBottom = '12px'
      
  	// hide parent margin
    $('cdemo_parent').style.paddingLeft = '0'
    $('cdemo_parent').style.paddingRight = '0'	
    
    //console.log("border is now", $('cdemo').style.borderLeft, $('cdemo'))
  }

  $('color3').value = new_color
}

//CS1: FONT COLOR
function cs1_change_update(new_color) {
  $('demo_color').style.color = new_color
  $('color1').value = new_color
	$('font_contrast').innerHTML = test_colors($('color0').value, new_color)
}
function cs2_change_update(new_color) {
  $('demo_link').style.color = new_color
  $('color2').value = new_color
	$('link_contrast').innerHTML = test_colors($('color0').value, new_color)
}

function cs4_change_update(new_color) {
  $('demo_vlink').style.color = new_color
  $('color4').value = new_color
	$('vlink_contrast').innerHTML = test_colors($('color0').value, new_color)	
}

function cs5_change_update(new_color) {
  $('color5').value = new_color;
}


// for advanced author page javascript
// instead of trying an iterator, just do by hand up to 5
function showhide() {
  var a = arguments;
  Element.show(a[0])
  if (a[1]) Element.hide(a[1]);
  if (a[2]) Element.hide(a[2]);
  if (a[3]) Element.hide(a[3]);
  if (a[4]) Element.hide(a[4]);
  if (a[5]) Element.hide(a[5]);
  if (a[6]) Element.hide(a[6]);  
  return false  
}

function hideshow() {
  var a = arguments;
  Element.hide(a[0])
  if (a[1]) Element.show(a[1]);
  if (a[2]) Element.show(a[2]);
  if (a[3]) Element.show(a[3]);
  if (a[4]) Element.show(a[4]);
  if (a[5]) Element.show(a[5]);
  if (a[6]) Element.show(a[6]);  
  return false
}

function toggle() {
  var a = arguments;
  Effect.Toggle(a[0])
  if (a[1]) Effect.Toggle(a[1]);
  if (a[2]) Effect.Toggle(a[2]);
  if (a[3]) Effect.Toggle(a[3]);
  if (a[4]) Effect.Toggle(a[4]);
  return false  
}



function mood_ch(s) {
  s = $F('mood')
  //console.log("mood", s)  
  
  if (s == 'custom') {
    Element.hide('mood_img')    
    Element.show('mood_custom')
    Field.focus('mood_cust')
    return
  }
  
  v='/s/images/smile/'+s
  if (s== '') {v=v+'.png'} else {v =v+'.gif'}
  $('mood_img').src=v
  Element.hide('mood_custom')
  Element.show('mood_img')
  //console.log("The", animal, "jumped over", count, "tall buildings");
}

// what if this is called b4 page is done loading?  Hmm.
function include_print(script_filename, skip_ad_check, item_wrapper, altad) {
  if (!hide_ads) hide_ads = false
  if (!skip_ad_check) skip_ad_check = false
  if (!skip_ad_check && hide_ads) return;
  if (window.opera) item_wrapper = false;

  if (item_wrapper) document.write("<div class='item' style='padding-left: 0'>") ;
  document.write('<' + 'script');
  document.write(' language="javascript"');
  document.write(' type="text/javascript"');
  document.write(' src="' + script_filename + '">');
  document.write('</' + 'script' + '>');
  
  //document.write('hello, world:' +altad)
  if (altad) document.write("<div class='alternateshow' style='display:none; border:1px dashed #888; width: "+google_ad_width+"px;padding:8px;margin: 6px; font-size: 0.9em'>"+altad+" relies upon your support.  Please consider <a href='/store'>purchasing a membership</a>, or occassionally disabling your adblocker to view our sponsors. Write on!</div>");
  
  if (item_wrapper) document.write("</div>");
}

function include_dom(script_filename, skip_ad_check) {
  if (!no_ads) no_ads = false
  if (!skip_ad_check) skip_ad_check = false
  if (!skip_ad_check && no_ads) return;
  
  var html_doc = document.getElementsByTagName('head').item(0);
  var js = document.createElement('script');
  js.setAttribute('language', 'javascript');
  js.setAttribute('type', 'text/javascript');
  js.setAttribute('src', script_filename);
  html_doc.appendChild(js);
  return false;
}

var skip_edge_hide = 0
function tab_active(tid, color, ljust) {
	if (active) {
		$('t_' + active).className='tab';
		Element.hide('c_' + active);
	}
	
	//alert(skip_edge_hide)
	//hide edge color when working with tiling bgs
	if (cs3 && skip_edge_hide == 0) {
	  //puts('showing cs3:' + cs3)
  	if (tid == 'tiled') {
      Element.hide('bg_edge')
    } else {
      Element.show('bg_edge')      
    }
  }
  
	$('t_' + tid).className='tab activetab';
	
	if (!shown_images[tid]) $('c_'+tid).innerHTML = images[tid]
	
	shown_images[tid] = 1
	Element.show('c_' + tid);
	active=tid
	
	if (tid == 'current') {
	  bg_move(1, current_color, current_ljust)
	}
	
	return false
}

// test this once we have updated the backgrounds
function test_colors(fore,back,fix) {
  //http://www.snook.ca/technical/colour_contrast/colour.html
	var brightnessThreshold = 100; // was 125
	var colorThreshold = 400; // was 500

  // we're given values with # on them, so skip first character
	br = parseInt(back.substr(1,2),16);
	bg = parseInt(back.substr(3,2),16);
	bb = parseInt(back.substr(5,2),16);
	fr = parseInt(fore.substr(1,2),16);
	fg = parseInt(fore.substr(3,2),16);
	fb = parseInt(fore.substr(5,2),16);

  //alert(br + " from back: " + back)
	var bY=((br * 299) + (bg * 587) + (bb * 114)) / 1000;
	var fY=((fr * 299) + (fg * 587) + (fb * 114)) / 1000;
	var brightnessDifference = Math.floor(Math.abs(bY-fY));

  var colorDifference = (Math.max (fr, br) - Math.min (fr, br)) + (Math.max (fg, bg) - Math.min (fg, bg)) + (Math.max (fb, bb) - Math.min (fb, bb));

	$("bDiff").innerHTML = brightnessDifference;
	$("cDiff").innerHTML = colorDifference;
	
	//only disable form if both are bad.
	if ((brightnessDifference < brightnessThreshold) && (colorDifference < colorThreshold)) {
	  $('color_submit').disabled = true
	  $('color_submit').value = "Please correct brightness or color"
	  //Element.show('let_me_anyways')
	  
	  return "Fix: Poor Color <" + colorThreshold + " and Brightness <" + brightnessThreshold;

  } else {
	  $('color_submit').disabled = false
	  $('color_submit').value = "Submit"
	  //Element.hide('let_me_anyways')
	  
  	//if ((brightnessDifference >= brightnessThreshold) && (colorDifference >= colorThreshold))	{} else 
  	if (brightnessDifference < brightnessThreshold) {
  	  return "Fix: Poor Brightness Contrast, <" + brightnessThreshold;

  	} else if (colorDifference < colorThreshold){
  	  return "Fix: Poor Color Contrast, <" + colorThreshold

  	}
  }
  
  return ""
}


//total, min,  moved to variables, edit with thingy
function verify_reward(amount, title, prefix, cost) {
  if (!title) title = 'Reward'
  if (!prefix) prefix = ''
  if (!cost) cost = amt
  
  fcost = prefix+'fcost'
  s = $(prefix + 'submit')
  //alert(amount)
  
  $(prefix + 'afford_amt').innerHTML= Math.floor(points/cost);
  total = amount*cost
  $(fcost).innerHTML = total
  val_item = $(prefix + 'item_id')
  if (!val_item) return; // no list shown by default == fails...
  val = val_item.value
  
  if (amount > 30) {
    s.disabled = true;    
    s.value = "Add " + title + " - 30 is the max comments to reward at once"
    
  } else if (total > points) {// grr, why do we precalculate total?
    s.disabled = true;
    s.value = "Add " + title + " - You don't have that many points"
    
  } else if (val == '0' || val == '') {
    s.disabled = true;
    s.value = "Add " + title + " - Please choose an item"   
    
  } else {    
    s.disabled = false;
    s.value = "Add " + title
  }

}

// renaming useful so that we can access storywrite's method when ap overwrites it...
var lineno = 1
function toggle_lines() {toggle_lines_default();} // poor man's alias
function toggle_lines_default() {
  if (lineno==0) {
   document.getElementsByClassName('n').each( function(i) {Element.show(i); i.style.color = '#bbb';})
  } else if (lineno == 1) {
   document.getElementsByClassName('n').each( function(i) {Element.show(i); i.style.color = '#000';})
  } else {
   document.getElementsByClassName('n').each( function(i) {Toggle.display(i)})
  }
  
  lineno += 1
  if (lineno == 3) lineno = 0
}

// what uses this?
function image_preview(title, image_url) {
  if (title == "Choose an image ->") return;
  // load the image, then update it's width property to be 200 if it's too large?
  // better yet, load @ 200 (expect too big), then update if it's smaller?  But it will only return 200 then
  $('image_preview').innerHTML = "<img id='img_preview'  src='"+image_url+"' style='clear: both; margin-top: 10px'/><br />Type to show this image:<br /> [image "+title+"]"
  setTimeout( "image_preview_check()", 100)
}

function image_preview_check() {
  i=$('img_preview')
  if (i.width != 0) {
    if (i.width > 175) i.width=175
  } else {
    setTimeout( "image_preview_check()", 200)
  }
}

// how is this different?
// no good, the expanding thing is really needed to understand it's below... 
// but it does fix the ajax thingies problem..
author_shown = 0
function twist_author() {
  poems = $('base_poems')
  b = $('base_bottom')
  d = $('full_description')  
  
  if (author_shown == 0) { 
    //b.parentNode.removeChild(b);
    //insertAfter(b, $('base_top_container'));
    //new Insertion.After($('base_top_container'), b)// snippet only :()

    Element.hide(d)
    Element.hide(poems)
    // move their full desc to the base_bottom
    b.innerHTML = d.innerHTML
    Element.show(b)    
    d.innerHTML = ''
    author_shown = 1
    new Effect.BlindDown(poems, { duration:0.7, fps:50})
    
  } else {
    
    Element.hide(b)
    d.innerHTML = b.innerHTML
    author_shown = 0
    new Effect.BlindDown(d, { duration:0.7, fps:50})
    
    //twisty.getElementsByTagName("span")[0].innerHTML = '&rarr;'
    //new Effect.BlindUp(t, { duration:0.2, fps:50 })    
  }
  return false;
}

function twistnow(twisty, target, options) {
  //console.log("twistnow:", twisty.innerHTML, "target", target)
  
  if ($(target).style.display == 'none') { 
    twisty.getElementsByTagName("span")[0].innerHTML = '&darr;'
    Element.show(target)

  } else {
    twisty.getElementsByTagName("span")[0].innerHTML = '&rarr;'
    Element.hide(target)    
  }
  
  return false;  
}

function twistoff(twisty, target, options) {
  twisty.getElementsByTagName("span")[0].innerHTML = '&rarr;'
  Element.hide(target)    
  return false;  
}

// rescue and force open?
function twist(twisty, target, options) { 
  //console.log("twist:", twisty.innerHTML, "target", target)  
  
  //console.log("twisty:", twisty.innerHTML)
  // some odd firefox bug, the display can be something other than "none", which gets really irritating!
  // trying to flip around the cases, to default to opening it...
  if ($(target).style.display == "") { 
     twisty.getElementsByTagName("span")[0].innerHTML = '&rarr;'
    new Effect.BlindUp(target, { duration:0.2, fps:50 }, options)    
  } else {
    twisty.getElementsByTagName("span")[0].innerHTML = '&darr;'
    new Effect.BlindDown(target, { duration:0.2, fps:50}, options)//, queue:'end' 
  }
  
  //setTimeout("$('r'+<%= i %>).focus()", 1000);
    
  //Effect.toggle(target, 'blind', { duration:0.2, fps:50, queue:'end' }) // 1.5+ only
    
  return false;
}


function after(nid) {
  setTimeout("$('"+nid+"').focus();", 380)
}

function twistt(target) {
  if ($(target).style.display == 'none') { 
    new Effect.BlindDown(target, { duration:0.2, fps:50})//, queue:'end' 
  } else {
    new Effect.BlindUp(target, { duration:0.2, fps:50 })    
  }
  return false
}

var rateclear
var ratebase = 0

//Usage: 	new Effect.ScrollToFullView(element, {duration: 0.6, offset: 10});
//http://www.ruby-forum.com/topic/55126
//Offset is the distance in pixel to the upper/lower viewport border.
//You need to define window.isIE as true/false somewhere prior or change the code.
// this just defines the setup delta amount, scrolLStart runs it?
Effect.ScrollToFullView = Class.create();
var offsets
Object.extend(Object.extend(Effect.ScrollToFullView.prototype,Effect.ScrollTo.prototype, offsets), {  setup: function() {
    Position.prepare();
    this.scrollStart = Position.deltaY;
    
    if (!offsets) offsets = Position.cumulativeOffset(this.element); 
    // maybe store this then?  then in im( have it jump to im, then new Position.prepare();Effect.ScrollToFullView(element, {duration: 0.6, offset: 10},  Position.deltaY);
    var rand = 0;
    if(this.options.offset) rand = this.options.offset;

    var element_kante_oben = offsets[1];
    var element_hoehe = this.element.offsetHeight;

    // L�nge und Position des dargestellten Ausschnitts relativ zumgesamten Dokument
    var screen_bottom, screen_height, screen_scrolled;
    if (isIE){
      screen_height = document.documentElement.clientHeight;
      screen_scrolled = document.documentElement.scrollTop;
    } else {
      screen_height = window.innerHeight;
      screen_scrolled = window.pageYOffset;
    }
    screen_bottom = screen_scrolled + screen_height;

    // Obere Kante des Elements sichtbar und Position des Elements +seine Hhe < screen_bottom
    // => Element wird schon komplett dargestellt
    if (element_kante_oben > screen_scrolled && element_kante_oben +element_hoehe + rand < screen_bottom ) {
      this.delta = 0;
      return;
    }

    var new_top;
    // Wenn Element her als Bildschirmhe, dann bis zur oberenKante des Elements scrollen
    if (element_hoehe + rand > screen_height) {
      new_top = element_kante_oben - rand;
    } else {
      // Mu nach oben gescrollt werden?
      if (element_kante_oben < screen_scrolled) {
        // nach oben scrollen
        new_top = element_kante_oben - rand;
      } else {
        // nach unten scrollen
        new_top = element_kante_oben + element_hoehe + rand - screen_height;
      }
    }
    
    var max = !isIE
      ? window.height - screen_height : document.body.scrollHeight - screen_height;
    this.delta  = (new_top > max ? max : new_top) - this.scrollStart;
    
    //set the 'duration' to be 1 second per 500 pixels scrolled.
    //puts(this.options.duration)
    this.options.duration = 1*(this.delta/500)
    //puts(this.options.duration)
  }
});

function single_space(fix) {
  b = $(fix).value.replace(/^<p>|<\/p>$/g, "").replace(/<br>|<br \/>/g,"\n").replace(/<p>/g,"\n\n").replace(/<\/p>/g,"").replace(/\n\n/g,"\n")
  $(fix).value = b
  if ($('fix_lines')) {
    $('fix_lines').checked = false;
  }
}

var tinyShown = [];
// = false; // start off, hmm this doesn't work w/multiple editors on a page :(
// need different name for each editor..
function toggleEditorMode(sEditorID) {
    fix = sEditorID
    e = $(fix)
    //puts(e)
    //if (e.rows < 34) e.rows = 34 // make it nice and big
    //if (e.cols < 69) e.cols = 69 // make it nice and big, done in _rich_editor now
    
    //try {
        if( tinyShown[sEditorID] ) {// removing control
            tinyMCE.execCommand("mceRemoveControl", false, sEditorID);
            tinyShown[sEditorID] = false;
            if ( !e.value.match(/<div|<p/i) ) {
              b = e.value.replace(/\n/g,"").replace(/<br[^>]*>\s*/g,"\n")
              e.value = b
            } else { // make sure </p> and <br> have \n after
              b = e.value.replace(/<\/p>[\s\r\n]*/g,"</p>\n").replace(/<br[^>]*>[\s\r\n]*/g,"<br>\n")
              e.value = b	
              Element.toggle('rich_warn_' + sEditorID)
            }
            //puts(e.value)
  					Element.toggle('rich_info_' + sEditorID)
        }
        else { // adding control.  replace \n with <br>\n if no <br> and no <p
            if ( !e.value.match(/<br|<p/i) ) {
						  b = e.value.replace(/\r/g,"").replace(/\n/g,'<br>').replace(/  /,' &nbsp;')
						  e.value = b
            }
						
						try {
						  Element.toggle('rich_info_' + sEditorID)
						  Element.hide('rich_warn_' + sEditorID)
						} catch(er) {}
            tinyMCE.execCommand("mceAddControl", false, sEditorID);
            tinyShown[sEditorID] = true;
        }
    //} catch(e) {
        //error handling
		//		alert("Sorry, rich editing doesn't work with your browser. "+ e);//" error" + e + " , " + e.message)
    //}
}

function addSpellcheck(sEditorID, options) {
	if (!options['height']) options['height']=280;
  if (!tinyShown[sEditorID]) toggleEditorMode(sEditorID);
	tinyMCE.execInstanceCommand(sEditorID, 'mceSpellCheck');
	return false
}
	
//<script>Document.write(getCookie('name'))</script> // don't store the name in a cookie just now..
function getCookie(name) {
    var dc = document.cookie;
    var prefix = name + "=";
    var begin = dc.indexOf("; " + prefix);
    if (begin == -1) {
        begin = dc.indexOf(prefix);
        if (begin != 0) return null;
    } else {
        begin += 2;
    }
    var end = document.cookie.indexOf(";", begin);
    if (end == -1) {
        end = dc.length;
    }
    return unescape(dc.substring(begin + prefix.length, end));
}


/* stars in/out */
function ratingin(eid,star,base) {
  clearTimeout(rateclear)
  ratebase = base
  if (! $(eid + '_' + 1)) {return}
  
  // hilight this star, and all to the left of it
  for (var i = 1; i <= star; i++) {
    $(eid + '_' + i).src = '/s/images/stargold.gif'
  }
  // unhilight others
  for (var i = star+1; i <= 5; i++) {
    $(eid + '_' + i).src = '/s/images/stargrey.gif'
  }
}

function ratingon(eid,star) {  
  clearTimeout(rateclear)
  new Ajax.Updater('rate_' + eid, '/comment/rate/' + eid + '?stars=' + star, {asynchronous:true, evalScripts:true, onLoading:function(request){$('rate_' + eid).innerHTML = "Rating <img border=0 src='/s/images/wait.gif'>"}}); return false
}

// on span tag covering all the images?  Hmm.
function ratingout(eid) {
  clearTimeout(rateclear)
  rateclear = setTimeout("ratingin('" + eid + "', " + ratebase + ")",200)
}

function doratingout(eid) {
  // drat, goes out betewen image elements, so delay by abit first
  if (! $(eid + '_' + 1)) {return}
  
  for (var i = 5; i > 0; i--) {
    $(eid + '_' + i).src = '/s/images/stargrey.gif'
  }
}

/* overwrite encourage function.keep it under 1 line, including Tip: */
function encourage(evt) {
  len = $('comment_body').value.length

  var e = gid('rdesc')
  if (len < 50) {
    msg = "Point out your favorite and least favorite parts."
  } else if (len < 80) {
    msg = "Which areas sound awkward?  Use line numbers."
  } else if (len < 120) {
    msg = "Try relating your emotional response."
  } else if (len < 200) {
    msg = "If you were to change one thing, what would it be?"
  } else if (len < 250) {
    msg = "Analyse the effective use of Beginning / Middle / End."
  } else if (len < 350) {
    msg = "Offer a rephrasing of an awkward area."
  } else if (len < 400) {   
    msg = "Is there another aspect this could address?"
  } else {
    msg = "Any other ideas about how this could be improved?"
  } 
  
  e.innerHTML = "<b>Tip</b>: " + msg
  grow('comment_body', evt)
}



added_to_field = ''
var def_heights = new Hash();

// works with 'this' too, since $() retunrs the object when it's already objectified! l33t!
// go to using KeyUp instead of KeyPress.  doesn't use any of these parameters anymore...
//function lengthen(field, evt, defh, max, linelen) {
//  grow(field, evt, max)
//}
// somehow this submits the form if a capital S is typed on IE?
// hmm, now this is not working at all... i swear it was!
function grow(field, evt, max, defh) {
  if (!max) max=21
  // can we load the default height automatically from the definition of the thing?  only at first, which is difficult... but otherwise should keep its height properly? hmm...
  
  f = $(field)
  linelen = f.cols // attr('cols') // resized by CSS Though..
  //console.log("name is:" + f.id + ", defh is: " + def_heights[field.id] + " rows: " + f.rows)
  
  if (!def_heights[field.id]) def_heights[field.id] = f.rows // will get messed up if no id
  defh = def_heights[field.id]
  
  lines = (f.value+'t').split(/\n/)
  count = lines.length

  for (var i = 0; i < lines.length; i++) {
    lin = lines[i]
    len = Math.floor(lin.length / linelen)
    //d("lin.length " + lin.length + ' linelen = '+ linelen + ' lin:' + lin)
    count += len
  };
  
  if (evt && evt.keyCode == Event.KEY_RETURN) count +=1
  if (isIE) count +=1
    
  //d('count=' + count + ' length=' + lines.length + ' lines:' + lines + ' value:' + f.value)
  
  if (count > max) count = max
  if (count < defh) count = defh
  f.rows = count // need 2 blank to have no scrollbar pop up, arg
}

//any way to parse this as the text arrives, rather than have the swear words flash up briefly?
// 
var swearing = new RegExp("bastard|\\bass\\b|dick\b|dickwad|cunt|f\s+u\s+c\s+k|twat|fucking|fucker|fuck|\bshit|asshole|bitch|pussy|\\bcum\\b|jiz|whore|douchebag|b!tch|faggot|\\bnigger|\\bnigga|slut|\bprick\\b|\@ss|dammit", "gi")
swearing.compile
var shown_profanity_msg = 0

function profanity(element) {
  var children = element.childNodes
  //if (element == document) t0 = new Date()
      
  for (var i = 0; i < children.length; i++) {
    var child = children[i]
    if (child.nodeName == 'SCRIPT') continue;
    
    if (child.nodeType == 3) {
      //if (child.nodeValue.length > 27) alert('checking node, length:' + child.nodeValue.length)
      // irritating that <br>s cause things to be separate nodes
      if (child.nodeValue.length > 2 &&  child.nodeValue.match(swearing) ) {
        child.nodeValue = child.nodeValue.replace(swearing, '*bunny*')
        if (shown_profanity_msg == 0) {
          Element.show('profanity_msg'); shown_profanity_msg = 1
        }
      }
    }
    
    if (child.childNodes) profanity(child)
  }
}

function imhist(i) {
  $('h_' + i).innerHTML = "<div style='padding-top: 4px'>Loading history... <img src='/s/images/wait.gif' /></div>"
  Element.hide('imr_' + i)
  twist($('imt_' + i),'imr_' + i)
  
  after('r_'+i)
  //setTimeout(function(){Field.focus('r'+i)}, 300);
  //alert($('r_' + i))
  //$('r_' + i).focus(); // not working still @ safari or IE
}

function im(name) {  
  delay = 5
    
  // twist is too slow...
  if (!Element.visible('message_box')) {
    Element.show('message_box')
    $('message_box_h').getElementsByTagName("span")[0].innerHTML = '&darr;'
    //twist($('message_box_h'), 'message_box')//, {sync: true}
    //delay += 70
  }
  
  $('cto').value = name;
  
  //firefox needs a delay before setting focus to the field?  arg.  especially with twist, since it's hidden for 200 ms.
  // still needs delay with Element.show?  wierd
  if ($('fixedcomment')) Element.hide('fixedcomment') // so it wont steal focus
  setTimeout(function(){Field.focus('cmsg')}, delay);
//  setTimeout(function(){Field.focus('cmsg')}, 500);// if fighting with movecomment
  
  // hmm, it should return false if we're returning im('user')?
  // what problem did we have with it returning false? won't move the browser to top so you can see that you're sending a message?  could use movebrowser to...
  // aah, i really want to move the screen to the IM window... as neither staying in the same place OR goign to the top is a good idea
  // what is this offset stuff?  distance before/below?
  //new Effect.ScrollToFullView('outer_message_box', {duration: 0.3, offset: 536}, {sync: true});
  //new Effect.scrollTo('outer_message_box')
  
    element = $('outer_message_box');
    var pos = Position.cumulativeOffset(element);
    //d(pos[0]);d(pos[1])
    window.scrollTo(pos[0], pos[1]-30);
    

  // how to hide 'quick comment' for a bit?
  //if ($('fixedcomment')) {
  //  Element.hide("fixedcomment")
  //  enabledfixed = setTimeout("Element.show('fixedcomment')", 2000);
  //}
  
  // http://test.to.com hi
	//return true;
	//d( "visible is now" + Element.visible('fixedcomment'))
	return false
}

function default_to() {
    if (gid('to').value == '') gid('to').value = "chat"
}

var timewait
var old_submit = 'Submit';
function pleasewait(field,msg) {
  if (timewait) clearTimeout(timewait)
    
  if (!field) field = 'submit'
	s = $(field)
	if (!s) return
	
	old_submit = s.value
  if (!msg) msg="Please Wait..."
	s.value = msg
	s.disabled = true

	timewait = setTimeout("waited('" + field + "')", 6500);
	return true;
}

function waited(field, msg) {
  clearTimeout(timewait)
  if (!field) field = 'submit'
  if (!old_submit) old_submit = 'Submit'
  if (!msg) msg = old_submit
  
  s = gid(field)
  s.value = msg
  s.disabled = false
}

function validateField(fieldId, alertMessage) {
		if (gid(fieldId).value == "") {
				alert(alertMessage);
				gid(fieldId).focus();
				return false;
		} else {
				return true;
		}
}

// validate several fields at once... doesn't work just yet.
//function validate(alertMessage, fields) {
	//for fieldId in fields {
//    if (gid(fieldId).value == "") {
 //       alert(alertMessage);
	//      gid(fieldId).focus();
	 //     return false;
		//} else {
		 //   return true;
		//}
	//}
//}
//
//function popup(url,width,height) {
//				//window.open(url,'popup','width='+width+',height='+height+',scrollbars=auto,resizable=yes,toolbar=no,directories=no,menubar=no,status=no,left=100,top=100');
//				return false;
//}


var imgsrv = '/s/images';
// new funs for bulletin board
function collapse(num, dbl) {
	var it = gid('reply_' + num);
	var img = gid('exp_' + num);
	//alert("Collapsing " + it + ", with image: " + img)

	if (it) {
		if (it.style.display == 'none') {
			it.style.display = 'block';
			img.src = imgsrv + '/minus.gif';
		} else {
			it.style.display = 'none';
			img.src = imgsrv + '/plus.gif';
		}
	} else {
		//alert("Couldn't find it " + num);
	}

	// if double, go down any children and open (close = just close first?)
	// double doesn't work yet :(
	if (dbl) {
		// open submenus, and change images
		var submenu = it.getElementsByTagName("ul");
		for (var i = 0; i < submenu.length; i++) {
			//alert("on " + submenu[i].id);
			submenu[i].style.display = 'block';
		}

		var submenu = it.getElementsByTagName("img");
		for (var i = 0; i < submenu.length; i++) {
			//alert("src is " + img.src);
			if (img.src == imgsrv + '/plus.gif') {
				img.src = imgsrv + '/minus.gif';
			}
		}
		//alert("in doubleclick");
		return false;// stop processing second click?
	}
}

// crappy maxlength script from http://www.experts-exchange.com/Web/Web_Languages/HTML/Q_20781420.html
//~ <textarea name="name" id="name" onkeypress="LimitMultiLineLength(this)" onbeforepaste="LimitMultiLineLength(this)" maxLength="255" ErrorMessage="The maximum allowance of 255 characters has been reached." style="height:108px;width:400px;"></textarea>
// doesn't appear to work, at least with safari
// safari lets you return false to onkeydown, but not firefox apparently
// odd firefox bug, moves cursor to end of textarea @ element.hide/show
//shown_bad = false
function maxlen(e, evt, max, newlines)
{
  if (!newlines) newlines = 0
  l = e.value.length
  if (evt.keyCode == 8) l -= 1
  $(e.id+'_mnum').innerHTML = l // setting the current number of chars
  
  if (evt.keyCode == 8 || evt.keyCode == 9 || (evt.keyCode >= 63232 && evt.keyCode <= 63235) || (evt.keyCode >= 37 && evt.keyCode <= 40)) return true
  m = $(e.id + "_max")
  bad = e.value.length > max-1
  // also count newlines if requested
  if (newlines != 0 && e.value.split("\n").length > newlines) bad = true
  
  if (bad) {
    Element.show(m)
    //shown_bad = true
    return false
  } else {
    //if (shown_bad) 
    Element.hide(m)
    return true
  }
}

/* from http://www.blakems.com/archives/000087.html, my top javascripts */
function expandCollapse() {
    for (var i=0; i<expandCollapse.arguments.length; i++) {
    var element = gid(expandCollapse.arguments[i]);
    element.style.display = (element.style.display == "none") ? "block" : "none";
    }
		return false;
}

//http://simon.incutio.com/archive/2004/05/26/addLoadEvent
// dammit, doesn't work with multiple..
// much faster if we use dom:loaded observer instead

function addLoadEvent(func) {
  // newer faster method, but requires the new prototype, which doesn't work with the old scriptaculus + the new scriptaculus causes errors on IE when they try to add backgrounds.  phew!
  //document.observe("dom:loaded", func);
    
  var oldonload = window.onload;
  if (typeof window.onload != 'function') {
    window.onload = func;
  } else {
    window.onload = function() {
      oldonload();
      func();
    }
  }
}

// stub method to avoid errors?
function t(name) {
    //gid('to').value == name;
    //gid('msg').focus();
}

// for the comment box...
// move the bb form to the end of the current id
// can parts of this move to the prototype module?
function bb_reply_new(id, unique) {
  if (!unique) unique='r'
  var form = $(unique+'bb_add_li')
  var it = $('bb_' + id)
  if ($('rep_' + id)) return false

  
  new Insertion.After(it, "<li id='rep_" + id + "'>" + form.innerHTML + '</li>')
  return false
}

//does this work in IE in old ap or 
function bb_reply(id,unique) {
  if (!unique) unique='r'
	var form = $(unique+'bb_add_li');
	  
	// when topic is closed, won't have label...
	// some people are still getting this.  why wouldn't they have the reply form?
	if (!form) {	
	  alert('unable to find reply form');
	  return false; 
	}
	
	Element.show(form) // unhide it for size tests

	var it = $('bb_' + id);
	var submenu = it.getElementsByTagName("ul");

  // update width of text field to fit within the space provided.
  // update to be width of main area, minus indent?  Arg, different width on each browser, irritating
  // try leaving this alone to always be 95% of the available space in css?
  //if ($('main')) { 
  //  posit = Position.page(it) // relative to each browser, but not each other.  damn!
  //  xpos = Number(posit[0])
  //  siz = (625 - (xpos))
  //  if (/Firefox\/1.5/.test(navigator.userAgent)) siz = siz//+50
  //  if (/MSIE/.test(navigator.userAgent)) siz = siz-100
  //  if (siz > 540) siz = 540
  //  $(unique+'comment_body').style.width = siz +'px'; // 769-200-some + space from left side
  //  //alert(gid('review_body').style.width)
  //}
	
	Element.hide(form);
	form.parentNode.removeChild(form);

  // the way it's put before it in IE adds some left spacing to the label unfortunately...
	if (submenu.length > 0) {
	  //alert('putting in submenu')
		it.insertBefore(form, submenu[0]);
	} 
	else {
		insertAfter(form, it);
	}
	
	//Element.show(form)
	new Effect.BlindDown(form, {duration:0.3} );//,
	//alert('showed' + form)
	if ($(unique+'bb_form_label')) $(unique+'bb_form_label').innerHTML = 'Reply to comment';
	
	if (/MSIE/.test(navigator.userAgent)) $(unique+'bb_form_label').style.marginLeft="-12px"
	
	$(unique+'comment_parent').value = id;
	
	// why don't we focus the field anymore?  set a delay on it i guess so that it happens after the adding of it?
  setTimeout("Field.focus('rcomment_body')", 400)
	//alert('done')
	return false;
}

//add history support?  for tabs, and background preview detection?  http://www.urlgrey.org/wordpress/history.php
// big arg = links need to have no href, so use onMouseUp
// document.location='#{url}?bg=#{b.id}

// plain calls bg_move(1), others call bg_move(#{b.id},'#{b.bgcolor}',#{b.ljust})
function bg_move(to,color,ljust) {
      
  b = $('bg_colors')
  bitem = $('bg_id_' + to)
  $('bg_num').value = to
  if (to == 1) $('bg_num').value = current_bg
    
  Element.hide(b)
	b.parentNode.removeChild(b);
	insertAfter(b, bitem);	
	
  if (color) {
    $('cdemo').style.backgroundImage = bitem.style.backgroundImage
    Element.hide('bg_colorinfo');
    
    // any way to only show bg_bginfo if this is NOT a system background? hard2 know what area we're in    
    // also want to show it when it's 'current' and it is our custom or we are a mod.  could do one-time though
    if (active == 'custom') Element.show('bg_bginfo')
    Element.show('choose_text');
    
    $('background_color').style.backgroundColor = color
    $('color0').value = color
    
    if (cs3) { // ap doesn't use edge color anymore
      //puts("showing cs3, it's" + cs3)
      cs3_change_update(color);
      color_selects[3].setrgb(color)
    }
    
    new Effect.BlindDown(b, { duration:0.3, fps:50, queue:'end' })
    //Element.show(b)  
    
  } else { // resetting for plain color
    $('cdemo').style.backgroundImage = 'none'
    $('background_color').style.backgroundColor = $('color0').value;
    Element.hide('bg_bginfo','choose_text');
    Element.show('bg_colorinfo');
    
    Element.show(b)  
  }
  
  if (!ljust || ljust == 0) ljust=6
  $('cdemo').style.paddingLeft=ljust+6+"px"
  
  cs0_change_update($('color0').value);
}

// better to just link to object with ?theme=0 ?  oi!
// b/c sidebar and headers don't get fixed
function remove_background() { 
  //document.write('<style type='text/css'>body { bgcolor: green; }</style>') // prob doesn't play happy with history.js
  //return false;
  b = document.body.style;
  b.backgroundColor ='#666666'
  b.color='#000000'
  // linkcolors don't work. headings will be rough as well...
  document.linkColor='#1984c1'
  document.vlinkColor='#19A1B2'
  c=$('container_container');
  c.style.backgroundImage = 'none'
  c.style.backgroundColor = '#EEEEEE'
  return false
}

function insertAfter(newChild,refChild)
//Post condition: if childNodes[n] is refChild, than childNodes[n+1] is newChild.
{
  var parent=refChild.parentNode;
  if(parent.lastChild==refChild) return parent.appendChild(newChild);
  else return parent.insertBefore(newChild,refChild.nextSibling);
}

function gid(id) {
  return document.getElementById(id)
}

function jinspect(obj) { var s = ""; for(var f in obj) { s += "field "+f+" = "+obj[f]+"\n"; } puts(s); }

// could find location of cursor by storing value @ onKeyDown, then checking vs value@ onKeyUp to find where \n was added - split by \n, iterate over previous checking with same index on secondary, start 'back' from i
function autorhyme() {
  if (gid('autorhyme').checked != true) return;
	lines_back = gid('rhyme_back').value
	var t = gid('item_text').value.replace(/\r/g,"").replace(/\s*$/,'').split("\n");
  //alert( gid('Story_body').selectionStart || document.selection.createRange().length-1 )
  
	var line = t[t.length - lines_back];
	if (!line) {
	  line = t[t.length - lines_back - 1]; // try one farther back, if its a blank line..
	  if (!line) { //alert("no line found back " + lines_back);inspect(t);
  	  return;
  	}
	}
	
	var word = line.match(/([^\s]+)$/)[0]
	word = word.replace(/\d+$/,"").replace(/\W$/,"");
	$('rhyme').value = word
	$('rhyme_form').onsubmit()
}


/* functions for line numbering.  beautiful.  we use toggle_lines now though */
var lines = 2
function removeLines() {
  lines = 0
  c = gid('content')
  c.innerHTML = c.innerHTML.replace(/<p>/gi,'<br>').replace(/<li>|<ol class="linenos">|<\/ol>|<\/p>/gi,'')
//alert(c.innerHTML)

  if (gid('togglelines')) gid('togglelines').firstChild.data = 'Line numbers';
}

//if (lines == 2) {showLines();}
function showLines() {
  lines = 1
  c = gid('content')

	// go throught the text and create the <div> fields.  this isn't the slow part?  maybe
	// can't we use <ol> instead somehow?  just replace all <br>&<p> with <li>?
	//replace(/(<br>\r?\n<br>/gi,'<p>').
  htm = c.innerHTML
  htm = "<ol class=\"linenos\"><li>" + htm.replace(/<\/p>|(<br>\s*)+\s*\Z|\A\s*(<br>\s*)+/,'').replace(/(<br\s*\/?>\r?\n?\s*){2,}/gi,'<p>').replace(/(<br>|<br \/>|<p>)/gi, "$1<li>") + "</ol>"
  c.innerHTML = htm
//alert(htm) // result still has BR's in it too in IE? aah, by design, strange
  if (gid('togglelines')) gid('togglelines').firstChild.data = 'Hide numbers';

  //width = Element.getDimensions('content').width
  //$('content').style.width = (width-250)+'px'
  //alert($('content').style.width)
  //c.style.width = '' // try to force a re-evaluation of table width?
}

function old_removeLines() {
  lines = 0
  c = gid('content')
  c.innerHTML = c.innerHTML.replace(/<div class="?linenum"?>[^>]+>/gi,'')
  if (gid('togglelines')) gid('togglelines').firstChild.data = 'Line numbers';
}

function old_showLines() {
  lines = 1
  c = gid('content')

	// go throught the text and create the <div> fields.  this isn't the slow part?  maybe
	// can't we use <ol> instead somehow?  just replace all <br>&<p> with <li>?
  htm = c.innerHTML
  htm = "<div class='linenum'></div>" + htm.replace(/(<br>|<br \/>)/gi, "$1<div class='linenum'></div>")
  c.innerHTML = htm.replace(/<\/p>/gi,'').replace(/(<p>)/gi, "$1<div class='linenum'></div>")
	
	// faster to replace innerHTML with the new div characters, all at once?
	
  rows = c.getElementsByTagName('div')
  n = 1
  for (var i = 0; i < rows.length; i++) {
    if (rows[i].className == 'linenum') {
      if (rows[i].nextSibling) if (!rows[i].nextSibling.nodeValue || rows[i].nextSibling.nodeValue.match(/^\s+$/) ) continue;
      rows[i].innerHTML = n++
    }
  }
  
  if (gid('togglelines')) gid('togglelines').firstChild.data = 'Hide numbers';
  gid('Story_table').width = '100%'
  c.style.width = '' // try to force a re-evaluation of table width?
}

// copy it onto the clipboard for safekeeping in case anything goes wrong
function spell_copy() {
  // how to check for ie first?  how to use createTextRange on a textarea field?
  if (navigator.userAgent.indexOf('MSIE')  >= 0) {
    txt = gid('Story_body')
    copied = txt.createTextRange();
    copied.execCommand("Copy");
  }
}

// hmm, actually trying this huh?
function to_clipboard(textarea) {
  return; // I'm worried this will giv ea security error b/c of recent MS patches.  try again l8r
  if (navigator.userAgent.indexOf('MSIE') >= 0) {
    txt = gid(textarea)
    copied = txt.createTextRange();
    copied.execCommand("Copy");
  }	
}

// eval'd by ajax result?  Hmm...should we use our 'old' ajax process?
// just eval script fragment
// we'll just leave the simple ajax-javascript stuff for two weeks and they'll do it...
var word_index
var word_current
var spelling = new Object()
var words = ["spel", "spel2"]

spelling["spel"] = ["test1","test2"]
spelling["spel2"] = ["test1","test2"]

function spell_start() { 
  word_index = -1
  spell_next()
  // make sure the spellcheck is visible
  Toggle.display('spell_window')
  Effect.Highlight('spell_window')
}

function spell_change() {
  // default to first spelling choice
  options = gid('spell_suggestions')
  if ( gid('spell_word').value == word_current ) gid('spell_word').value = options[options.selectedIndex].value
  
  // replace words in the textarea with our replacement
  alert(gid('Story_body').value)
  gid('Story_body').value = gid('Story_body').value.replace(new RegExp('\\b' + word_current + '\\b', 'g'), gid('spell_word').value )  //new RegExp('blah')
  
  //alert( gid('Story_body').value.replace(/\bspel\b/,'testing regex') )
  spell_next();
}

function spell_next() {
  word_index += 1
  if (!words[word_index]) {Toggle.display('spell_window'); return; }
  
  word = words[word_index]
  gid('spell_word').value = word_current = word
  gid('spell_suggestions').options.length = 0
  
  for (i=0; i < spelling[word].length; i++) {
    gid('spell_suggestions').options[i] = new Option( spelling[word][i], spelling[word][i] )
  }
}

// keyhandlers to thesaurus (T) if any selected word + t, d=define, r=rhyme
// use a popup window?  Hmm.
//document.onkeypress = keyhandler;

function findSelection()
{
	if (document.getSelection) txt = document.getSelection();
	else if (document.selection) txt = document.selection.createRange().text;
	else return "";
	return txt;
};

function keyhandler(e) {
    if (window.event) 
    	Key = window.event.keyCode;
    else 
        Key = e.which;

    if (Key == 100) { 
    	var result = findSelection();
    	result.replace(/\s*$/,'');
    	
        if (result.length && result.length < 125 && result.indexOf(' ') == -1) 
        	var toast = window.open('/word/'+escape(result),'0','toolbar=1,scrollbars=1,location=0,statusbar=1,menubar=1,resizable=1,width=510,height=510,left=280,top=80');
     }
};

// correctly handle PNG transparency in Win IE 5.5 or higher. added IE7 skip.  requires height/width
// should have a .gif or a .png before we call this?
var arVersion = navigator.appVersion.split("MSIE")
var version = parseFloat(arVersion[1])
function fixPNG(myImage) 
{
    if ((version >= 5.5) && (version < 7) && (document.body.filters) && isIE) { // if (isIE) { // indow.ie55up
     var imgID = (myImage.id) ? "id='" + myImage.id + "' " : ""
     var imgClass = (myImage.className) ? "class='" + myImage.className + "' " : ""
     var imgTitle = (myImage.title) ? "title='" + myImage.title + "' " : "title='" + myImage.alt + "' "
     var imgStyle = "display:inline-block;" + myImage.style.cssText 
     var strNewHTML = "<span " + imgID + imgClass + imgTitle
     strNewHTML += " style=\"" + "width:" + myImage.width + "px; height:" + myImage.height + "px;" + imgStyle + ";"
     strNewHTML += "filter:progid:DXImagetransform.Microsoft.AlphaImageLoader"
     strNewHTML += "(src=\'" + myImage.src + "\', sizingMethod='scale');\"></span>" 
     myImage.outerHTML = strNewHTML
  }
}


/* comment failure functions */
function complete_comment(request, p) {	
  if (!p) p=''
	waited(p + 'submit');
	
	if (request.status == 200) {
	  //new Effect.BlindDown($('comment_list').lastChild);// to just move the new comment
		Element.hide(p + 'interm')
		
		// what is this from?  !p won't match anymore, since it's =='', doesn't work, no easy way2 access it?
		//if ( p == '' && $(p+'comment_list') ) {
  	//  Element.cleanWhitespace(p + 'comment_list');
		//  new Effect.Highlight($(p + 'comment_list').firstChild);  //hilight the new comment?
		//  //if ($('rating_p')) {// no div around ratings anymore?  odd...
		//    //Element.hide('rating_p','rdesc')
		//    //Effect.BlindUp('rating_p')
		//    //Effect.BlindUp('rdesc')
		//  //}
	  //}
	  
	  // only if we're on an item vs. contest/etc, how to tell...?
	  //if ($('newcomment_msg') && $F('comment_kind') == 'item') {
	  //  len = $F('comment_body').length
	  //  if (len != 0) {
    //    Element.show('newcomment_msg');	  
    //    $('newcomment_size').innerHTML = len
    //	  if ($F('comment_body').length > 100 ) {
    //	    Element.show('newcomment_points');
    //	  } else {
    //	    Element.show('newcomment_short');
    //	  }
    //	}
    //}
    
    if (comment_error==0) {
		  Field.clear(p + 'comment_subject')
		  Field.clear(p + 'comment_body')
		  // resize box... doesn't seem to be working?
		  //console.log('resizing comment body')
      grow('comment_body', false, 5, 3) 
      grow('qc', false, 5, 3)
      //console.log($('comment_body').rows)
	  }
	
		// perhaps change the item's div id or something so that it doesn't move along with us?
	};
}

// is it even calling this?  WTF!
// where does it know where to move it?
var comment_error=0;
function interm_comment(p) {
  if (!p) p=''  
  comment_error=0
	pleasewait(p + 'submit');
	//puts('showing ' + p+'interm_wait' + $(p+'interm_wait'))
	
	// use their pic even when we're cached
	if ($('interm_by_src')) {	$('interm_by').innerHTML = $('interm_by_src').innerHTML }
	
	// show it before we set the content for it? odd
	Element.show(p + 'interm_wait')
	// speed of scroll should be porportional to distance, arg...
	if (p == '') new Effect.ScrollToFullView(p + 'comment_list', {duration: 0.9, offset: 236}, {sync: true});
	$(p + 'interm_subject').innerHTML = $(p + 'comment_subject').value
	body = $(p + 'comment_body').value
	
	body = body.replace(/\r|\n|\r\n/g,'<br>') // not working...

	$(p + 'interm_body').innerHTML = body
	// when blinddown is over, then it's alignment is off...

	new Effect.BlindDown(p + 'interm');
	
	// dont show evil msg about featured items, if we were going to
	//window.onbeforeunload = function () { return "You have not saved your ..
  window.onbeforeunload = null	
}

function comment_failure(request, p) {
  if (!p) p=''  
  waited(p + 'submit')  
	Element.hide(p + 'interm_wait')

	$(p + 'interm_subject').innerHTML = 'Error adding comment, please try again.'
	$(p + 'interm_body').innerHTML = "Error number is " + request.status + ". "
	if (request.status == '500') $(p + 'interm_body').innerHTML += "This error was automatically recorded for fixing.";
		
	new Effect.Highlight(p + 'interm', {duration: 5.0})
}

function logsize(num) {
  logConsole.outputElement.style.height = num+'px'
}
Position.Window = {
    //extended prototypes position to return
    //the scrolled window deltas
    getDeltas: function() {
        var deltaX =  window.pageXOffset
            || document.documentElement.scrollLeft
            || document.body.scrollLeft
            || 0;
        var deltaY =  window.pageYOffset
            || document.documentElement.scrollTop
            || document.body.scrollTop
            || 0;
        return [deltaX, deltaY];
    },
    //extended prototypes position to
    //return working window's size, 
    //copied this code from the tooltip.js library
    size: function() {
        var winWidth, winHeight, d=document;
        if (typeof window.innerWidth!='undefined') {
            winWidth = window.innerWidth;
            winHeight = window.innerHeight;
        } else {
            if (d.documentElement && typeof d.documentElement.clientWidth!='undefined' && d.documentElement.clientWidth!=0) {
                winWidth = d.documentElement.clientWidth
                winHeight = d.documentElement.clientHeight
            } else {
                if (d.body && typeof d.body.clientWidth!='undefined') {
                    winWidth = d.body.clientWidth
                    winHeight = d.body.clientHeight
                }
            }
        }
        return [winWidth, winHeight];
    }
}


//new Effect.KeepFixed('hypv-feedback', -25, -25);http://wiki.script.aculo.us/scriptaculous/revision/show/2/Effect.KeepFixed
var lastscroll = -1;
var elementDimensions;

// this isn't staying on the rightmost edge of the screen like I wanted it to...
// could a) rewrite using position: absolute (wont work quite right for IE6), or fix this somehow...
Effect.KeepFixed = function(element, offsetx, offsety, skip, altX) {
    var _scroll = Position.Window.getDeltas();
    // 40 is height we need to be from top to start showing?  moving to 20
    if (_scroll[1] == lastscroll || _scroll[1] < 5) return [false];
    lastscroll = _scroll[1];
    
    //puts("newscroll:" + lastscroll)
    var _window = Position.Window.size();
    var elementDimensions = Element.getDimensions(element);
    //if (!elementDimensions) elementDimensions = Element.getDimensions(element);    
    var eWidth = elementDimensions.width;
    //var eHeight = 88//elementDimensions.height;//this is bigger at first?  odd!
    var eHeight = elementDimensions.height;
    var moveX = _window[0] - eWidth + _scroll[0] + offsetx - 19; // -19 was perfect at edge of sidebar
    // try moving Y up higher, hard to guess based on screen size, but a few hundred... was -19
    var moveY = _window[1] - eHeight + _scroll[1] + offsety; // - 159;
    //d("_window[1]=" + _window[1] + ", eHeight " + eHeight + ", scroll[1]" + _scroll[1] + ", offsety:" + offsety)
    
    //console.log(_window[0]);

    altX = Position.page($('container_container'))[0]
    storysize=Element.getDimensions($('container_container'))
    moveX = altX + storysize.width - 230;
      
    // hmm, on second thought, better aligned flush with the right of the page
    // altered this to use container_container from main before...  much better!
    if (false) {
      altX = Position.page($('container_container'))[0]
      storysize=Element.getDimensions($('container_container'))
      moveX = altX + storysize.width - eWidth - 9;
    }
    
    
    newsize = 215 + altX; // 218 in defaults.  yay, perfect finally!
    if (newsize > 300) newsize = 300;
    $('fixedcomment').style.width = newsize+'px';
  
    if (!skip) new Effect.Move(element, { x: moveX, y: moveY, mode: 'absolute', duration: 0.3, fps: 50 });
    return [moveX, moveY]
}

// http://groups.google.com/group/prototype-scriptaculous/browse_thread/thread/e902934f3590e4fe
// now fucking safari refuses to show it again. what the heck! // now it doesnt show it at all :)
function movecomment() {
  //d("movecomment")
 //nterval ( 'document.layers.divID.top=window.pageYOffset;', 100 ); }
 // hide it if real comment form is visible
 //|| !Element.visible('fixedcomment')
 // can disable with visibility=='hidden'
  element=$('fixedcomment')
  if (!element || element.style.visibility=='hidden') return
  //if () return
  
  //puts( 0-Position.page($('main'))[0] )
  
  // hmm, moves to 0,0 within it's current div box, want to move releative to the whole window!
  // now that we have ie7, possible to just do this in CSS?  Easier?  Hmm...
  
  // moving to my own css-based solution?
  coords = new Effect.KeepFixed(element, 0, 0, false, true) // isIE, -24
  if (!coords[0]) return
  
  // start how many pixels down from the top of the window?
  // can I do this with relative positioning?
  //element.style.position = 'relative'
  //element.style.top = window.scrollTop+500+ "px"
  //element.style.right = "5px"
  //d("element top: ", element.style.top)
  //return; // aah, detection of where to move it requires coords too.  hmm, maybe 

  
  //d(Position.positionedOffset($('comment_body'))[1] + ' vs ' + coords[1] + ' or' + coords)
  
  // if our destination is past the comment box, hide us
  //puts('pos=' + Position.positionedOffset($('comment_body'))[1] + ' vs coords:' + coords[1] + ' vis: ' + Element.visible(element))
  
  // hide it if we're alongside the regular comment box...  was +230
  // 100 is too small, increasing some again
  if (Position.positionedOffset($('comment_body'))[1] < coords[1]+170) {
    if (Element.visible(element)) {
      //puts('hiding')
      bod = $('comment_body')
      grow(bod, false)
      Field.focus(bod)
      // what is this doing, setting the scroll of the window to the end of the long comment being entered?
      //bod.scrollTop = bod.scrollHeight;      
      bod.scrollTop = bod.scrollHeight - bod.clientHeight;
      
      new Effect.Fade(element, {duration:0.15})      
      if ($F('qc') != '') new Effect.Highlight('comment_body')// probs with firefox ==lines
      
      // automatically copies our value into the main comment box.  but this one might be out of date! how do we keep then synchronized?  a) test for which is bigger?  b) update this one when we change that one, or c) update that one when we change this one (prob best, since this can dissapear then...)
      //$('comment_body').value = $F('qc')  

    }
    
  } else {    
    if (!Element.visible(element)) {
      element.style.top = "0px"
      //element.style.left = coords[0]+'px'; element.style.top=coords[1]+'px';// doesn't really work?
      $('qc').value = $F('comment_body')
      new Effect.Appear(element)
      
      // somehow gets moved to y=6000, fucking A  Position.page($('fixedcomment')) 
      //puts('done showing, vis' +Element.visible(element) + ' loc:' + Position.page(element) )
    }
  }  
}

// damn, now need to make this work with multiple applause forms on the same page?  prob avoid counting frees since will get off?  back2inline!
function app_cst(num) {
	cost = num-freeleft
	
	if (cost < 0) {
		freeleftnow = freeleft - num
		if (freeleftnow < 0) freeleftnow = 0 
	
		Element.hide('acst')
		Element.show('afree')		
		$('afreen').innerHTML = freeleftnow
	} else {
		Element.hide('afree')
		Element.show('acst')
		$('acstn').innerHTML=cost*app_amt	
	}
	
	// what is this part for?
  //console.log(document.comment_form.applause[num])	
	document.comment_form.applause[num].checked = true // array works like that?	
}

function app_inline(sid, num) {
  app = $(sid + '_' + num)
  app.checked = true
	$(sid + "_cost").innerHTML=num*app_amt
}

// regex in javascript is so frustrating!
function tag_in(col, val) {
  v = $(col)
  if (v.value.length + val.length > 85) return false;// max size
  
  if (!v.value.match(val + ',')) {
    if (v.value && !v.value.match(/, $/)) v.value += ', ';
    v.value += val + ', '
  }
  return false
}


//http://tinymce.moxiecode.com/tinymce/docs/plugin_spellchecker.html
var tiny_options = {
	//relative_urls : true, convert_urls : true,
	theme : 'advanced',
	// what is this for? needed to avoid it converting urls oddly...  but breaks spellchecker!
  //relative_urls : false,  remove_script_host : false,	document_base_url : 'http://' + location.hostname + "/s/javascripts/tiny_mce",
  convert_urls : false, // trying this, since it doesn't seem to break spellcheck...
  
	verify_html : true, 
	entities : "160,nbsp", 	// don't fuck with other chars
	extended_valid_elements : 'hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style],b,center,a[href|title|alt|showhide|hideshow|toggle|target|rel],style[type]',
	//,td[style|colspan|rowspan|width|height|bgcolor] // causes problems
	//auto_resize : true,// makes it expand down, infinitely.  wish there was a way to limit it?		
	plugins : 'inlinepopups,emotions,paste,fullscreen,table,spellchecker,searchreplace',
	theme_advanced_toolbar_location : 'top',
	theme_advanced_toolbar_align : 'left',	
	// pretty good list by default, but more are fairly safe, damn, doesn't like this
	theme_advanced_fonts : 'Andale Mono=Andale Mono;Arial=Arial;Arial Black=Arial Black,Sans-serif;Book Antiqua=Book Antiqua,Sans-serif;Bookmark Old Style=Bookmark Old Style,Arial,Sans-serif;Century Gothic=Century Gothic,Sans-serif;Century Schoolbook=Century Schoolbook,Sans-serif;Comic Sans MS=Comic Sans MS,Sans-serif;Courier New=Courier New,Monospace;Garamond=Garamond;Georgia=Georgia;Helvetica=Helvetica;Impact=Impact;Monospace=Monospace;Palatino=Palatino;Sans-serif=Sans-serif;Serif=Serif;Tahoma=Tahoma,Sans-serif;Terminal=Terminal,Monospace;Times New Roman=Times New Roman,Serif;trebuchet MS=trebuchet MS,Serif;Verdana=Verdana,Sans-serif;Webdings=Webdings;Wingdings=Wingdings',
	/* available buttons: 
	 			bold,italic,underline,strikethrough,justifyleft,justifycenter,justifyright,justifyfull,
	 			styleselect,formatselect bullist,numlist,outdent,indent,
	 			undo,redo,link,unlink,anchor,image,cleanup,help,code,
	 			hr,removeformat,visualaid,sub,sup,charmap,separator,code */
	theme_advanced_buttons1 : 'spellchecker, bold,italic,underline,strikethrough,separator,table,row_after,col_after,delete_row, delete_col,separator,justifyleft,justifycenter,justifyright,justifyfull,fontselect,fontsizeselect',
	theme_advanced_buttons2 : 'hr,bullist,numlist,outdent,indent,separator,link,unlink,image,separator,fullscreen,removeformat,code,separator,forecolor, backcolor,emotions,searchreplace,separator,cut,paste,pasteword',	
	theme_advanced_buttons3 : '',
	content_css : '/s/stylesheets/tinymce.css',
	fullscreen_settings : {
		theme_advanced_path_location : "top",
		content_css : '/s/stylesheets/tinymce.css'
	}
	//undo,redo,cleanup
	//,height:'500px'
	, width:'97%' // better to use textarea size, this baad 4 comments, and appears to have problems?
	//... but we don't change editor size anymore?  sure... 600px
}

var free_options = {
	theme : 'advanced',
	//verify_html : true, 
	entities : "160,nbsp",
	plugins : 'inlinepopups, spellchecker',
	theme_advanced_buttons1 : '', //'spellchecker', // just start it automatically...
	theme_advanced_buttons2 : '', theme_advanced_buttons3 : '',	
	content_css : '/s/stylesheets/tinymce.css',
	width:'97%'
}

var silver_options = {
	theme : 'advanced',
	verify_html : true, 
	entities : "160,nbsp",
	plugins : 'inlinepopups, spellchecker, fullscreen',
	theme_advanced_buttons1 : 'spellchecker,bold,italic,underline,strikethrough, fullscreen',
	theme_advanced_buttons2 : '', theme_advanced_buttons3 : '',	
	theme_advanced_toolbar_location : 'top',	
	theme_advanced_toolbar_align : "left",	
	content_css : '/s/stylesheets/tinymce.css',
	fullscreen_settings : {
		theme_advanced_path_location : "top",
		content_css : '/s/stylesheets/tinymce.css'
	},
	width:'97%'
}

function check_all(classname) {
  set = document.getElementsByClassName(classname)
  checked = !set[0].checked
  set.each( function(i) {i.checked = checked} )
  return false
}

function im_show_dates() {
  document.getElementsByClassName('imdate').each( function(i) { Element.show(i) } )
  return false
}

function im_open(classname) {
  document.getElementsByClassName('ir').each( function(i) { Element.show(i) } )
  return false
}

// changed 2/26/10 to reference form w/getelementbyid rather than this, due to bug
function im_reply(id) {
  new Ajax.Request('/chat/say', {asynchronous:true, evalScripts:true, onLoaded:function(request){waited('ims_'+id, 'Your message was sent');$('imm_'+id).innerHTML=' &nbsp; <b>Replied to '+Form.getInputs($('f_'+id),'hidden','to')[0].value+'</b>'; twist($('imt_'+id),'imr_'+id)}, onLoading:function(request){pleasewait('ims_'+id)}, parameters:Form.serialize($('f_'+id))}); return false;
}

function im_del(id) {
  //new Ajax.Updater('rate_' + eid, '/comment/rate/' + eid + '?stars=' + star, {asynchronous:true, evalScripts:true, onLoading:function(request){$('rate_' + eid).innerHTML = "Rating <img border=0 src='/s/images/wait.gif'>"}}); return false
    
  new Ajax.Request('/im/delete/'+id, {asynchronous:true, evalScripts:true, onLoaded:function(request){}, onLoading:function(request){new Effect.Fade('im_' + id)} }); return false;
}

//http://radio.javaranch.com/pascarello/2006/08/17/1155837038219.html
var ChatScroll = new Object();
ChatScroll.Pane = function(scrollContainerId) {
    this.bottomThreshold = 50;
    this.scrollContainerId = scrollContainerId;
}

// prob not used, keep it the 255 pixels from the lower end of the screen..
ChatScroll.Pane.prototype.resize =
function()    {
    var scrollDiv           = document.getElementById(this.scrollContainerId);
    scrollDiv.style.height  = (document.documentElement.clientHeight - 225) + 'px';
    scrollDiv               = null;
    
    this.scrollToEnd();
}

ChatScroll.Pane.prototype.scrollToEnd =
function()    {
    var scrollDiv       = document.getElementById(this.scrollContainerId);
    scrollDiv.scrollTop = scrollDiv.scrollHeight;
    scrollDiv           = null;
}

ChatScroll.Pane.prototype.isScrollable = 
function()    {
    var scrollDiv = document.getElementById(this.scrollContainerId);
    var currentHeight = 0;
    
    if (scrollDiv.scrollHeight > 0)
        currentHeight = scrollDiv.scrollHeight;
    else 
        if (objDiv.offsetHeight > 0)
            currentHeight = scrollDiv.offsetHeight;

            // so scrollDiv.scrollHeight - scrollDiv.scrollTop - (scrollDiv.style.pixelHeight) ? scrollDiv.style.pixelHeight : scrollDiv.offsetHeight) > 50 == minimum scrolled by
    var Result = (currentHeight - scrollDiv.scrollTop - ((scrollDiv.style.pixelHeight) ? scrollDiv.style.pixelHeight : scrollDiv.offsetHeight) < this.bottomThreshold);
    scrollDiv  = null;
    
    return Result;
}

// if we have window resizing problems? damn, two things want to be notified @ window resizing!
// disabled for now, we'll see if it's really necessary, but it shouldn't be
//window.onresize = resizeEvent;
//function resizeEvent(){    chatScroller.resize(); }

// CHAT FUNCTIONS

	function go()	{
		connection = new AFLAX.Socket(aflax, server, 4442, "onConnectEvent", "onDataEvent", "onCloseEvent");
		scroll_now('chatroom')	// doesnt seem to scroll it all the way for some reason in IE?
	}	
	
	function ch_go()	{
		ch_connection = new AFLAX.Socket(ch_aflax, ch_server, 4442, "ch_onConnectEvent", "ch_onDataEvent", "ch_onCloseEvent");
		scroll_now('ch_chatroom')		
	}	
	
	function onConnectEvent(val)	{
	  scroll_now('chatroom')	  
	  
    if(val) {
			connection.send("join%%" + room + "%%" + join_str)
			connected = 1
			if (send_msg) connection.send("say%%" + room + "%%" + send_msg)
		} else {
			onDataEvent("Could not connect to server.");
		}
	}
	
	function scroll_now(chat_id) {
	  // push it by a bit, since it seems to be a bit short still?  No, must just be a timer prob
	  $(chat_id).scrollTop = $(chat_id).scrollHeight + 100
	}
	
	function onDataEvent(str)	{ parse_message(str, 'chatroom') }

	function onCloseEvent()	{
		onDataEvent("Connection lost- <a href='#' onclick='connection.connect(server, 4442); return false'>Reconnect</a>?");
		connected = 0
	}

	function send(str)	{
		scroll_now('chatroom')
		connection.send("say%%" + room + "%%" + str);
		$('livechat_input').focus()
	}
		
	var set_height_under = 0 // 265 if we want it to grow
	var beep_first_enter = 0
	var last_beep = 0 // not used
	
	// WTF is the diff btwn scroll_down and scroll_now?
	function scroll_down(chatroom_id) {
	  s = $(chatroom_id)
	  diff = s.scrollHeight - s.scrollTop - ((s.style.pixelHeight) ? s.style.pixelHeight : s.offsetHeight)
	  //console.log("diff:", diff)
	  //console.log('scrollheight:', s.scrollHeight, 'scrolltop:', s.scrolltop, 'pixelheight:', s.style.pixelHeight)
	  
		if (diff < 82) { // 21 == always, 41 = one line
		  s.scrollTop = s.scrollHeight + 100
		  setTimeout("$('" + chatroom_id + "').scrollTop = $('" + chatroom_id + "').scrollHeight", 300) // always do it twice? hmm
		  return true
		  //console.log('scrolling down')
		} else {
		  
		  //console.log("not scrolling down")
		  return false
		}
	}
	
	// just returns true/false, checks whether it should scroll down
	function to_scroll_down(chatroom_id) {
	  s = $(chatroom_id)
	  diff = s.scrollHeight - s.scrollTop - ((s.style.pixelHeight) ? s.style.pixelHeight : s.offsetHeight)

		if (diff < 82) { // 21 == always, 41 = one line
		  return true
		} else {
		  return false
		}
	}
	
  // hmm, really want to allow js=click to IM w/names?  bold AND linked? no... just link with u('name')
  //if (set_height_under != 0 && chat.scrollHeight > set_height_under) { chat.style.height = set_height_under+'px'}
  //var buffer;// ugg, need a buffer for each chat_id?  not really, since only will be one connected at a time... but better to not require that
  var buffer = new Object()
  //spelling["spel"] = ["test1","test2"]

  var parse_timeout = false;
  
  // only let this be called every 200 ms; else add to buffer.  when user returns to chat, all is processed immediately.  should avoid wierd lag scenario
	function parse_message(str, chat_id)	{
	  c = $(chat_id)
	  //console.log("got data", str, "chat id:", chat_id, c)  //substring(str,0,2)
	  
	  if (str.substring(0,2) == '%%') {
	    //console.log("cmd = '", cmd, "', msg= '", msg, "'")
      // chrome hates this?
			//[skip, cmd, msg, msg2] = str.split('%%')
			my_arr = str.split('%%')
	    skip = my_arr[0]; cmd = my_arr[1]; msg = my_arr[2]; msg2 = my_arr[3];

	    if (cmd == 'clear') {
	      c.innerHTML = 'Cleared<br />'

	    } else if (cmd == 'im') { // %%im%%kevin%%hey how are you?
  		  s = "<a href='/"+msg+"' onMouseOver=\"userdrop(this, event, '"+msg+"')\" onMouseout='delayhidemenu()'>"+msg+"</a>: "+msg2+"<br>"
  		  add_and_shorten(s, 'new_ims', 1000, 200)
        $('new_ims').innerHTML = h
        
      } else if (cmd == 'noti') {
        
      } else if (cmd == 'chat') { // user-to-user real-time chat.  different from ims=how?  no storage really
        // chat server keeps track of which ones you've replied to and re-sends @ connect until X minutes or you've responded?
        // now that we've put the parse_timeout code on the chatroom only, this will have the same problem...
        c = get_chat_div(msg) // make sure its created
        add_and_shorten(msg2, 'chatw_'+user_name, 1000, 200)
        scroll_down('chatw_'+user_name)
	    } else {
	      // show some error message
	      //console.log("unknown cmd:", cmd)
	    }
	  } else {
	    //console.log("msg:", str) //, "parse_timeout:", parse_timeout, "buffer:", buffer[chat_id])
	    // not solving the delay problem.  skip this then for now, and revisit later?
  	  if (parse_timeout) { 
  	    if (!buffer[chat_id]) buffer[chat_id]=''; 
  	    buffer[chat_id] += str + "<br>"; 
  	    //console.log("buffer now:", buffer[chat_id])
  	    return
  	  } 
  	    	  
  	  parse_timeout=true
  	  setTimeout("clear_chat_buffer('"+chat_id+"')", 180); // longer than usual for testing.  200
  	  if (buffer[chat_id] && buffer[chat_id] != ''){ str = buffer[chat_id] + str; buffer[chat_id] = '' }
      
      to_scroll = to_scroll_down(chat_id)
      
      // shouldn't it be the other way around?  cbox is small, chatroom is big... ch_chatroom else
      if (chat_id == 'chatroom') {
	      add_and_shorten(str, chat_id, 4500, 500)
	    } else {
	      add_and_shorten(str, chat_id, 9500, 500)
	    }
	    
  		if (to_scroll) {
  		  //scroll_now(chat_id)
  		  scroll_down(chat_id)  		  
  		}
	  }
	}
	
	// new drop down menu will give us the option to send this?	
	function get_chat_div(user_name) {
	  return
	  c = $('chatw_'+user_name)
	  if (c) return c
	  // make sure aux chat window is open.  use bottom after all now?  doesnt really matter where we put it
	  if (!Element.visible('aux_chats')) new Effect.BlindDown('aux_chats')
	  // needs it's own div for the input box, or not?
	  $('aux_chats').innerHTML += "<div id='chatw_"+user_name+"'></div><div id='chatm_"+user_name+"'><input type='text' style='width:100%' onkeypress=\"if (evt.keyCode == Event.KEY_RETURN) {send_user_chat('"+user_name+"',this.value)\"} /></div>"
	  return $('chatw'+user_name)
	}
	
	function send_user_chat(user_name, msg) {
		ch_connection.send("uchat%%" + user_name + "%%" + msg)
		scroll_down('chatw_'+user_name)
	}
	
	// not being used right now
	function clear_chat_buffer(chat_id) { // single threaded, don't worry too much
	  parse_timeout = false; 
	  if (!buffer[chat_id] || buffer[chat_id] == '') {return}
	  
	  console.log('clearing buffer:', buffer[chat_id])	  
	  v = $(chat_id).innerHTML 
	  v += buffer[chat_id]
	  $(chat_id).innerHTML = v // less flicker when we do it like this?
	  buffer[chat_id] = ''
	  scroll_down(chat_id)
	}
	
	// avoid problem of chopping off text and leaving an empty html tag
	function add_and_shorten(message, chat_id, max_size, remove_amount) {
	  h = $(chat_id).innerHTML + message + "<br>"
	  //console.log(h.length, " vs ", max_size)
	  if (h.length > max_size) { 
	    // remove more if it's longer
	    if (h.length > (max_size+remove_amount)) { remove_amount = h.length-max_size-remove_amount;}
	    h = h.substring(remove_amount)
	    lookfor = '<a ';  mat = h.match(/<a /mi); if (mat) lookfor = mat[0]; // could go back to <br> now
	    where = h.indexOf(lookfor) // might it change quotes too??? assume links mostly same+safe
	    //console.log("Where is ", where, ", lookfor is:", lookfor, ", start is:", h.substring(0,75))
	    //where = h.indexOf('<br>')+4
	    //if (where == -1) {where = h.indexOf('<BR>')+4}
	    //if (where == -1) {where = h.indexOf('<BR />')+4}
	    //if (where == -1) {where = h.indexOf('<br />')+4}	//arg!
	    if (where > 800 || where == -1) {where = 0; }
	    
	    h = h.substring(where) // strip up to <br>. case matters!
	  }
	  
	  $(chat_id).innerHTML = h
	}	
	
	function ch_onConnectEvent(val)	{
    if(val) {
			ch_connection.send("join%%" + ch_room + "%%" + join_str)
			ch_connected = 1
			if (ch_send_msg) setTimeout("ch_connection.send('say%%' + ch_room + '%%' + ch_send_msg)", 500)
		} else {
			ch_onDataEvent("Could not connect to server.")
		}
	}
	
	
	function ch_onDataEvent(str)	{ parse_message(str, 'ch_chatroom') }
	
	function ch_onCloseEvent()	{
		ch_onDataEvent("Connection lost- <a href='#' onclick='ch_connection.connect(ch_server, 4442); return false'>Reconnect</a>?");
		ch_connected = 0
	}

	function ch_send(str)	{
		ch_connection.send("say%%" + ch_room + "%%" + str)
		scroll_now('ch_chatroom')
	}

  var num_posts = 0
	var ch_set_height = 0
	
	
/* mp3 player stuff */
	function thisMovie(movieName) {
	  // does this not match anymore?  never alerts...
	  if(navigator.appName.indexOf("Microsoft") != -1) {
			return window[movieName];
		} else {
			return document[movieName];
		}
	};
	
	function sendEvent(typ,prm) {
	  //alert("sending " + typ + prm)
		thisMovie("mediaplayer").sendEvent(typ,prm);
	};	
	
	// looks like we get a state: 0 call when it first initalizes?
  var first_volume = 0;
	function getUpdate(typ,pr1,pr2) {
    //var id = document.getElementById('output');
		//id.innerHTML += "<br>" + typ+ ": "+Math.round(pr1);
		if (typ == "volume" && first_volume == 0 && $("song")) {first_volume=1;sendEvent("playitem",$("song").value)}

		//puts("'" + typ  + ": " + pr1  + ": " +pr2)
		if (first_volume == 1 && typ == "item") $("song").value = pr1
	};
	
	//can we just point our music player at a playlist.com music list?  I doubt it!
	function openMusic(autostart, addVars) {
    if (!autostart) autostart = 'false'
    Element.show('player2');
    
		var FU = {movie:"/s/images/mediaplayer.swf",id:"mediaplayer",name:"mediaplayer",width:"305",height:"300",majorversion:"7",build:"0",bgcolor:"#FFFFFF",	flashvars:"file=/s/music/music.xml&displayheight=0&repeat=true&lightcolor=0xCC9900&backcolor=0x000000&frontcolor=0xCCCCCC&shuffle=false&enablejs=true&"+autostart+"=false"+addVars };
		UFO.create(FU, "player2");
		
		Element.show('music_info')
		Element.hide("show_player")
		$('use_music').checked = true //'checked'
	}
	
	function playitem(num) {
	  // this may be messing up IE, so it stops any execution?  Hmm..
	  // hopefully this is long enough for people over a medium connection? 400 worked 3 me
	  // 550 wasn't enough in AP production, hmm...perhaps we need a better way to handle this?  just skip it and default music_id?
	//  setTimeout("sendEvent(\"playitem\",num)", 950)
	}