
var _proxy_jslib_SCRIPT_NAME= "/nph-proxy.cgi" ;
var _proxy_jslib_PROXY_GROUP= [] ;
var _proxy_jslib_ALL_TYPES= ['', 'application/x-javascript', 'application/x-ecmascript', 'application/x-vbscript', 'application/x-perlscript', 'application/javascript', 'application/ecmascript', 'text/javascript', 'text/ecmascript', 'text/jscript', 'text/livescript', 'text/vbscript', 'text/vbs', 'text/perlscript', 'text/tcl', 'text/x-scriptlet', 'text/scriptlet', 'application/hta', 'text/css', 'text/xml'] ;
var _proxy_jslib_MIME_TYPE_ID= {'':0, 'text/javascript':7, 'application/x-javascript':1, 'text/xml':19, 'application/x-perlscript':4, 'application/x-vbscript':3, 'text/tcl':14, 'text/vbs':12, 'text/jscript':9, 'text/ecmascript':8, 'application/javascript':5, 'text/perlscript':13, 'text/livescript':10, 'application/ecmascript':6, 'application/x-ecmascript':2, 'text/vbscript':11, 'text/x-scriptlet':15, 'text/css':18, 'text/scriptlet':16, 'application/hta':17} ;


function _proxy_jslib_proxy_encode(URL) {
    URL= URL.replace(/^([\w\+\.\-]+)\:\/\//, '$1/') ;
//    URL= URL.replace(/(.)/g, function (s,p1) { return p1.charCodeAt(0).toString(16) } ) ;
//    URL= URL.replace(/([a-mA-M])|[n-zN-Z]/g, function (s,p1) { return String.fromCharCode(s.charCodeAt(0)+(p1?13:-13)) }) ;

    return URL ;
}

function _proxy_jslib_proxy_decode(enc_URL) {
//    enc_URL= enc_URL.replace(/([a-mA-M])|[n-zN-Z]/g, function (s,p1) { return String.fromCharCode(s.charCodeAt(0)+(p1?13:-13)) }) ;
//    enc_URL= enc_URL.replace(/([\da-fA-F]{2})/g, function (s,p1) { return String.fromCharCode(eval('0x'+p1)) } ) ;
    enc_URL= enc_URL.replace(/^([\w\+\.\-]+)\//, '$1://') ;
    return enc_URL ;
}

function _proxy_jslib_cookie_encode(cookie) {
//    cookie= cookie.replace(/(.)/g, function (s,p1) { return p1.charCodeAt(0).toString(16) } ) ;
//    cookie= cookie.replace(/([a-mA-M])|[n-zN-Z]/g, function (s,p1) { return String.fromCharCode(s.charCodeAt(0)+(p1?13:-13)) }) ;
    cookie= cookie.replace(/(\W)/g, function (s,p1) { return '%'+p1.charCodeAt(0).toString(16) } ) ;
    return cookie ;
}

function _proxy_jslib_cookie_decode(enc_cookie) {
    enc_cookie= enc_cookie.replace(/%([\da-fA-F]{2})/g, function (s,p1) { return String.fromCharCode(eval('0x'+p1)) } ) ;
//    enc_cookie= enc_cookie.replace(/([a-mA-M])|[n-zN-Z]/g, function (s,p1) { return String.fromCharCode(s.charCodeAt(0)+(p1?13:-13)) }) ;
//    enc_cookie= enc_cookie.replace(/([\da-fA-F]{2})/g, function (s,p1) { return String.fromCharCode(eval('0x'+p1)) } ) ;
    return enc_cookie ;
}




var _proxy_jslib_RE_FULL_URL ;
var _proxy_jslib_url_start, _proxy_jslib_url_start_inframe, _proxy_jslib_url_start_noframe,
    _proxy_jslib_is_in_frame, _proxy_jslib_packed_flags, _proxy_jslib_URL ;
var _proxy_jslib_base_url, _proxy_jslib_base_scheme, _proxy_jslib_base_host, _proxy_jslib_base_path, _proxy_jslib_base_file ;
var _proxy_jslib_cookies_are_banned_here, _proxy_jslib_doing_insert_here, _proxy_jslib_SESSION_COOKIES_ONLY,
    _proxy_jslib_COOKIE_PATH_FOLLOWS_SPEC, _proxy_jslib_RESPECT_THREE_DOT_RULE,
    _proxy_jslib_default_script_type, _proxy_jslib_default_style_type ;
var _proxy_jslib_RE, _proxy_jslib_needs_jslib ;
var _proxy_jslib_write_buffers= [ {doc:document, has_js:true} ] ;
var _proxy_jslib_wins= new Array() ;
var _proxy_jslib_ret ;

_proxy_jslib_init() ;


//---- first, the initialization functions -----------------------------

// set _proxy_jslib_URL, _proxy_jslib_url_start, _proxy_jslib_packed_flags,
//   _proxy_jslib_is_in_frame, _proxy_jslib_url_start_inframe, _proxy_jslib_url_start_noframe
// _proxy_jslib_base_url must be set elsewhere, to handle possibly coming from
//   HTTP headers.
function _proxy_jslib_init() {
    _proxy_jslib_set_RE() ;

    // create global regex that matches a full URL, needed for _proxy_jslib_parse_full_url()
    var RE_SCRIPT_NAME= _proxy_jslib_global_replace(_proxy_jslib_SCRIPT_NAME, /(\W)/,
						    function (p) { return '\\'+p[1] } ) ;
    _proxy_jslib_RE_FULL_URL= new RegExp('^('+RE_SCRIPT_NAME+')\\/?([^\\/]*)\\/?(.*)') ;

    // Mozilla sometimes adds 'wyciwyg://' to the URL
    var URL= document.URL.replace(/^wyciwyg:\/\/\d+\//i, '') ;

    var u= _proxy_jslib_parse_full_url(URL) ;
    if (_proxy_jslib_PROXY_GROUP.length) {
	_proxy_jslib_url_start= _proxy_jslib_PROXY_GROUP[Math.floor(Math.random()*_proxy_jslib_PROXY_GROUP.length)]
				+'/'+u[1]+'/' ;
    } else {
	_proxy_jslib_url_start= u[0]+'/'+u[1]+'/' ;
    }
    var flags= _proxy_jslib_unpack_flags(u[1]) ;
    _proxy_jslib_is_in_frame= flags[5] ;
    flags[5]= 1 ;    // that's the frame flag
    _proxy_jslib_url_start_inframe= u[0]+'/'+_proxy_jslib_pack_flags(flags)+'/' ;
    flags[5]= 0 ;
    _proxy_jslib_url_start_noframe= u[0]+'/'+_proxy_jslib_pack_flags(flags)+'/' ;

    _proxy_jslib_packed_flags= u[1] ;
    _proxy_jslib_URL=          u[2] ;

    // this begins life as the hostname
    window._proxy_jslib_document_domain= _proxy_jslib_parse_url(_proxy_jslib_URL)[4] ;
    _proxy_jslib_wins[0]= window ;

    // call _proxy_jslib_onload() and possibly an existing window.onload()
    // make sure _proxy_jslib_onload() is called even if window.onload() fails.
    var old_onload= window.onload ;
    window.onload= function() {
		       try { if (old_onload) old_onload() } catch(e) {} ;
		       _proxy_jslib_onload() ;
		   }

//alert('end of init; _p_j_URL=\n['+_proxy_jslib_URL+']') ;
}


// set variables passed in from Perl program.
function _proxy_jslib_pass_vars(base_url, cookies_are_banned_here, doing_insert_here, SESSION_COOKIES_ONLY, COOKIE_PATH_FOLLOWS_SPEC, RESPECT_THREE_DOT_RULE, default_script_type, default_style_type) {
    // set base_ vars from base_url
    _proxy_jslib_base_url= base_url.replace(/^\s+|\s+$/g, '')
				   .replace(/^([\w\+\.\-]+\:\/\/[^\/\?]+)\/?/, "$1/") ;
    _proxy_jslib_base_scheme= _proxy_jslib_base_url.match(/^([\w\+\.\-]+\:)\/\//)[1] ;
    _proxy_jslib_base_host=   _proxy_jslib_base_url.match(/^([\w\+\.\-]+\:\/\/[^\/\?]+)/)[1] ;
    _proxy_jslib_base_path=   _proxy_jslib_base_url.match(/^([^\?]*\/)/)[1] ;
    _proxy_jslib_base_file=   _proxy_jslib_base_url.match(/^([^\?]*)/)[1] ;

    // other settings
    _proxy_jslib_cookies_are_banned_here=  cookies_are_banned_here ;
    _proxy_jslib_doing_insert_here=        doing_insert_here ;
    _proxy_jslib_SESSION_COOKIES_ONLY=     SESSION_COOKIES_ONLY ;
    _proxy_jslib_COOKIE_PATH_FOLLOWS_SPEC= COOKIE_PATH_FOLLOWS_SPEC ;
    _proxy_jslib_RESPECT_THREE_DOT_RULE=   RESPECT_THREE_DOT_RULE ;

    _proxy_jslib_default_script_type=      default_script_type.toLowerCase() ;
    _proxy_jslib_default_style_type=       default_style_type.toLowerCase() ;
}


// lastly, do what's needed after the document fully loads
function _proxy_jslib_onload() {
    _proxy_jslib_mark_as_proxified(window.document) ;

    // if we're in frames, then try to update the URL in the top form
    if (_proxy_jslib_is_in_frame && (window.parent===window.top) && top._proxy_jslib_insertion_frame)
	top._proxy_jslib_insertion_frame.document.URLform.URL.value= _proxy_jslib_URL ;
}



//---- the general handler routines _proxy_jslib_handle() and _proxy_jslib_assign() ----

// This is used when the property in question IS NOT being assigned to.
function _proxy_jslib_handle (o, property, cur_val) {
//alert('starting handle; o, property, cur_val, URL=['+o+']['+property+']['+cur_val+']\n['+_proxy_jslib_URL+']') ;
    // guess when the window object is implied; this only matters with Window's
    //   properties that we handle below
    if ((o===null)  && property.match(/^(location|open|setInterval|setTimeout|frames|parent|top|opener|execScript|navigate|showModalDialog|showModelessDialog|parentWindow)$/) && (window[property]===cur_val)) o= window ;

    // handle eval() specially-- it (oddly) can be a property of any object
    if (property=='eval')
	return function (code) {
		   if (o!=null) return o.eval(_proxy_jslib_proxify_js(code, 0)) ;
		   else         return   eval(_proxy_jslib_proxify_js(code, 0)) ;
	       } ;

    // if object is still null, merely return property value
    if (o==null) return cur_val ;

    // assure that object is correctly marked as proxified,
    //   including when the document may still be loading
    // jsm-- this whole subsystem should be reworked at some point
    if (!o._proxy_jslib_is_proxified && _proxy_jslib_node_is_in_HTML_document(o))
	_proxy_jslib_mark_as_proxified(o) ;

    var otype= _proxy_jslib_object_type(o) ;

    // handle any non-Type-specific properties first, or properties that may
    //   apply to different object types (e.g. the properties of Node)
    switch (property) {
	case 'insertAdjacentHTML':
	    return function (where, text) {
		       if (this!==window) o= this ;
		       if (o._proxy_jslib_is_proxified)
			   return o.insertAdjacentHTML(where, _proxy_jslib_proxify_html(text, false, o.document)[0]) ;
		       return o.insertAdjacentHTML(where, text) ;
		   } ;
	case 'setAttribute':
	    return function (name, value) {
		       if (this!==window) o= this ;
		       if (o._proxy_jslib_is_proxified)
			   return o.setAttribute(name.toLowerCase(), _proxy_jslib_proxify_attribute(name, value)) ;
		       return o.setAttribute(name, value) ;
		   }
	case 'setAttributeNode':
	    return function (newAttr) {
		       if (this!==window) o= this ;
		       if (o._proxy_jslib_is_proxified)
			   newAttr.nodeValue= _proxy_jslib_proxify_attribute(newAttr.nodeName, newAttr.nodeValue) ;
		       return o.setAttributeNode(newAttr) ;
		   }
	case 'appendChild':
	    return function (newChild) {
		       if (this!==window) o= this ;
		       var ret ;
		       if (o._proxy_jslib_is_proxified && !newChild._proxy_jslib_is_proxified) {
			   ret= o.appendChild(_proxy_jslib_proxify_element(newChild)) ;
			   newChild._proxy_jslib_is_proxified= true ;
		       } else {
			   ret= o.appendChild(newChild) ;
		       }
		       return ret ;
		   }
	case 'insertBefore':
	    return function (newChild, refChild) {
		       if (this!==window) o= this ;
		       var ret ;
		       if (o._proxy_jslib_is_proxified && !newChild._proxy_jslib_is_proxified) {
			   ret= o.insertBefore(_proxy_jslib_proxify_element(newChild), refChild) ;
			   newChild._proxy_jslib_is_proxified= true ;
		       } else {
			   ret= o.insertBefore(newChild, refChild) ;
		       }
		       return ret ;
		   }
	case 'replaceChild':
	    return function (newChild, oldChild) {
		       if (this!==window) o= this ;
		       var ret ;
		       if (o._proxy_jslib_is_proxified && !newChild._proxy_jslib_is_proxified) {
			   ret= o.replaceChild(_proxy_jslib_proxify_element(newChild), oldChild) ;
			   newChild._proxy_jslib_is_proxified= true ;
		       } else {
			   ret= o.replaceChild(newChild, oldChild) ;
		       }
		       return ret ;
		   }
	case 'cloneNode':
	    return function (deep) {
		       if (this!==window) o= this ;
		       var ret= o.cloneNode(deep) ;
		       ret._proxy_jslib_is_proxified= o._proxy_jslib_is_proxified ;
		       return ret ;
		   }

	case 'insertRule':
	    return function (rule, index) {
		       if (this!==window) o= this ;
		       return o.insertRule(_proxy_jslib_proxify_css(rule), index) ;
		   }

	case 'innerHTML':
	case 'outerHTML':
	case 'outerText':
	    return _proxy_jslib_proxify_html(o[property], false, o.document, true)[0] ;  // unproxifies


	// because some sites modify these in place, we must un-proxify these
	//   when retrieving the value.
	// for Location and Link objects, return the object, but handle
	//   toString() below to unproxify it when needed.
	// jsm-- this will still leave Location or Link proxified when
	//   toString() is called implicitly.
	case 'src':
	case 'href':
	case 'background':
	case 'lowsrc':
	case 'action':
	case 'useMap':
	case 'longDesc':
	case 'cite':
	case 'codeBase':
	case 'location':
	    var u= (o!=void 0) ? o[property] : cur_val ;
	    if (u==void 0) return void 0 ;
	    // return unchanged if u is a non-String object
	    if (u && (typeof u=='object') && (u.toLowerCase==void 0))
		return u ;
	    var pu= _proxy_jslib_parse_full_url(u) ;
	    if (pu==void 0) return u ;   // if it's not a URL
	    // if o is a node, then deproxify only if it's proxified or is an Image
	    if ((o.nodeName!==void 0) && (o.nodeType!==void 0) && (o.nodeValue!==void 0)) {
		if (o._proxy_jslib_is_proxified || (otype=='Image'))
		    return pu[2] ;
		else return u ;
	    }
//if (u=='') alert('in handle, first switch; typeof, o, property, u, caller=['+typeof(o)+']['+o+']['+property+']['+u+']\n['+arguments.callee.caller+']') ;
	    return pu[2] ;
    }


    // note use of closures to remember the object o
    // note also that in returned functions, we use "this" if it is available;
    //   see comments above proxify_js() (Perl routine)
    switch (otype+'.'+property) {
	// Store new windows in a list so we can insert JS later if needed.
	// Store windows instead of documents, because docs may not be created yet.
	case 'Window.open':
	    return function (url, name, features, replace) {
		       if (this!==window) o= this ;
		       var full_url= _proxy_jslib_full_url(url) ;
		       var win= o.open(full_url, name, features, replace) ;
		       if (url) win._proxy_jslib_document_domain=
			   _proxy_jslib_parse_url(_proxy_jslib_parse_full_url(full_url)[2])[4] ;
		       _proxy_jslib_wins[_proxy_jslib_wins.length]= win ;
		       return win ;
		   } ;
	case 'Document.open':
	    return function(arg1, name, features, replace) {
		       // arg1 should default to "text/html", but it doesn't
		       //   always in Firefox, so we force it
		       if (arg1==void 0) arg1= 'text/html' ;
		       if (this!==window) o= this ;
		       if (arguments.length<=2) {
//alert('about to Document.open; win=['+_proxy_jslib_doc2win(o,_proxy_jslib_wins)+']') ;
			   return o.open(arg1, name) ;
		       } else {
			   // MSIE-specific
			   return o.open(_proxy_jslib_full_url(arg1), name, features, replace) ;
		       }
		   }
	case 'Document.write':
	    // buffer the output by document
	    // no return value
	    return function () {
		       if (this!==window) o= this ;
		       for (var i= 0 ; i<arguments.length ; i++)
//if (confirm('write ['+arguments[i]+']?'))
			   _proxy_jslib_add_to_write_buffer(o, arguments[i]) ;
		   } ;
	case 'Document.writeln':
	    return function () {
		       if (this!==window) o= this ;
		       for (var i= 0 ; i<arguments.length ; i++)
			   _proxy_jslib_add_to_write_buffer(o, arguments[i]) ;
		       _proxy_jslib_add_to_write_buffer(o, '\n') ;
		   } ;
	case 'Document.close':
	    return function() {
		       if (this!==window) o= this ;
//alert('starting Document.close(); # buffers='+_proxy_jslib_write_buffers.length) ;  //  jsm-- all alerts and confirms
		       var buf, i, p ;
		       for (i in _proxy_jslib_write_buffers) {
			   if (_proxy_jslib_write_buffers[i].doc===o) {
			       buf= _proxy_jslib_write_buffers[i] ;
			       if (buf.buf==void 0) break ;
			       p= _proxy_jslib_proxify_html(buf.buf, !buf.has_js, o) ;
			       if (p[2]) return ;   // found frame document
//if (confirm('flushing one buffer;\nhas_js=['+p[1]+']\nout=['+p[0]+']'))
			       buf.has_js= buf.has_js || p[1] ;
			       buf.buf= void 0 ;
			       o.write(p[0]) ;
			       _proxy_jslib_mark_as_proxified(o) ;
			       break ;
			   }
		       }
//alert('about to o.close()') ;
		       o.close() ;
//alert('ending Document.close()') ;
		   }
	case 'Document.URL':
	case 'Document.referrer':
	    var pu= _proxy_jslib_parse_full_url(o[property]) ;
	    return (pu==void 0)  ? void 0  : pu[2] ;
	case 'Document.body':
	    var ret= o.getElementById('_proxy_css_main_div') ;
	    return ret  ? ret  : o.body ;
	case 'Location.replace':
	    return function (url) {
		       if (this!==window) o= this ;
		       var u= _proxy_jslib_parse_full_url(o.toString()) ;
		       if (u!=void 0 && u[1]!='') {
			   return o.replace(_proxy_jslib_full_url_by_frame(url, _proxy_jslib_unpack_flags(u[1])[5])) ;
		       } else {
			   return o.replace(_proxy_jslib_full_url(url)) ;
		       }
		   } ;
	case 'Link.toString':
	case 'Location.toString':
	    return function () {
		       if (this!==window) o= this ;
		       return _proxy_jslib_parse_full_url(o.toString())[2] ;
		   }
	case 'Window.setInterval':
	    var oldsetInterval= o.setInterval ;
	    return function (codefunc, interval) {
		       if (this!==window) o= this ;
		       if (typeof(codefunc)=='function') {
			   // Function.apply() not available in MSIE 5.0  :P
			   return oldsetInterval.apply(o, arguments) ;
		       } else {
			   return oldsetInterval.call(o, _proxy_jslib_proxify_js(codefunc), interval) ;
		       }
		   } ;
	case 'Window.setTimeout':
	    var oldsetTimeout= o.setTimeout ;
	    return function (codefunc, delay) {
		       if (this!==window) o= this ;
		       if (typeof(codefunc)=='function') {
			   // Function.apply() not available in MSIE 5.0  :P
			   return oldsetTimeout.apply(o, arguments) ;
		       } else {
			   return oldsetTimeout.call(o, _proxy_jslib_proxify_js(codefunc), delay) ;
		       }
		   } ;
	case 'Document.cookie':
	    return _proxy_jslib_cookie_from_client(o) ;
	case 'Document.domain':
	    return _proxy_jslib_doc2win(o,_proxy_jslib_wins)._proxy_jslib_document_domain ;
	case 'Window.frames':
	    var f, ret= [], useret ;
	    if (_proxy_jslib_document_domain==void 0) _proxy_jslib_init_domain(window) ;
	    for (f=0 ; f<o.frames.length ; f++) {
		try {
		    if (o.frames[f]._proxy_jslib_document_domain==void 0) _proxy_jslib_init_domain(o.frames[f]) ;
		    if ((o.frames[f]._proxy_jslib_document_domain!=_proxy_jslib_document_domain)
			&& (o.frames[f]._proxy_jslib_document_domain!=void 0))
		    {
//alert('frame differs in domain; f, domains of window, o.frames[f]=['+f+']['+_proxy_jslib_document_domain+']['+o.frames[f]._proxy_jslib_document_domain+']') ;  // jsm-- test a bunch, then remove
			// include both the numbered frame and the (non-standard) named frame
			ret[f]= _proxy_jslib_dup_window_safe(o.frames[f]) ;
			if (o.frames[f].name) ret[o.frames[f].name]= ret[f] ;
			useret= true ;
		    } else {
			ret[f]= o.frames[f] ;
			if (o.frames[f].name) ret[o.frames[f].name]= ret[f] ;
		    }
		} catch (e) {
//var _proxy_s= '' ; while (_proxy_s= prompt('Window.frames error: '+e, _proxy_s)) {try{alert(eval(_proxy_s))}catch(e){alert(e)}} ;
		}
	    }
	    return useret  ? ret  : o.frames ;
	case 'Window.parent':
	    var w= (o.top._proxy_jslib_main_frame===o)  ? o  : o.parent ;
	    if (_proxy_jslib_document_domain==void 0) _proxy_jslib_init_domain(window) ;
	    if (w._proxy_jslib_document_domain==void 0) _proxy_jslib_init_domain(w) ;
	    return ((w._proxy_jslib_document_domain==_proxy_jslib_document_domain)
		    || (w._proxy_jslib_document_domain==void 0))
		? w  : _proxy_jslib_dup_window_safe(w) ;
	case 'Window.top':
	    // if window uses frames, translate "top" to "top._proxy_jslib_main_frame".
	    var w= (o.top._proxy_jslib_main_frame!==void 0)  ? o.top._proxy_jslib_main_frame  : o.top ;
	    if (_proxy_jslib_document_domain==void 0) _proxy_jslib_init_domain(window) ;
	    if (w._proxy_jslib_document_domain==void 0) _proxy_jslib_init_domain(w) ;
//alert('in Window.top; o, o.name, w, w.name=\n['+o+']['+o.name+']\n['+w+']['+w.name+']') ;  // jsm-- all alerts
	    return ((w._proxy_jslib_document_domain==_proxy_jslib_document_domain)
		    || (w._proxy_jslib_document_domain==void 0))
		? w  : _proxy_jslib_dup_window_safe(w) ;
	case 'Window.opener':
	    if (!o.opener) return null ;
	    if (_proxy_jslib_document_domain==void 0) _proxy_jslib_init_domain(window) ;
	    if (o.opener._proxy_jslib_document_domain==void 0) _proxy_jslib_init_domain(o.opener) ;
	    return ((o.opener._proxy_jslib_document_domain==_proxy_jslib_document_domain)
		    || (o.opener._proxy_jslib_document_domain==void 0))
		? o.opener  : _proxy_jslib_dup_window_safe(o.opener) ;

	//  _proxy_jslib_parse_url() returns full_match, protocol, authentication, host, hostname, port, pathname, search, hash
	case 'Link.protocol':
	case 'Location.protocol':
	    return _proxy_jslib_parse_url(_proxy_jslib_parse_full_url(o.href)[2])[1] ;
	case 'Link.host':
	case 'Location.host':
	    return _proxy_jslib_parse_url(_proxy_jslib_parse_full_url(o.href)[2])[3] ;
	case 'Link.hostname':
	case 'Location.hostname':
	    return _proxy_jslib_parse_url(_proxy_jslib_parse_full_url(o.href)[2])[4] ;
	case 'Link.port':
	case 'Location.port':
	    return _proxy_jslib_parse_url(_proxy_jslib_parse_full_url(o.href)[2])[5] ;
	case 'Link.pathname':
	case 'Location.pathname':
	    return _proxy_jslib_parse_url(_proxy_jslib_parse_full_url(o.href)[2])[6] ;
	case 'Link.search':
	case 'Location.search':
	    return _proxy_jslib_parse_url(_proxy_jslib_parse_full_url(o.href)[2])[7] ;


	// DOM methods in this block (and above, before this switch/case block)
	case 'Document.getElementById':
	    // Hack-- if element isn't in doc yet but is in output buffer, flush
	    //   buffer and try again.
	    return function (elementId) {
		       if (this!==window) o= this ;
		       var e, i, buf, p ;
		       e= o.getElementById(elementId) ;
		       if (e!=null) return e ;
		       for (i= 0 ; i<_proxy_jslib_write_buffers.length ; i++)
			   if (_proxy_jslib_write_buffers[i]  &&
			       _proxy_jslib_write_buffers[i].doc===o) break ;
		       if (i>=_proxy_jslib_write_buffers.length) return null ;
		       buf= _proxy_jslib_write_buffers[i] ;
		       if (buf.buf==void 0) return null ;
		       if (buf.buf.match(new RegExp('id\\s*=\\s*[\'"]?\\s*'+elementId+'\\s*[\'"]?', 'i'))) {
			   p= _proxy_jslib_proxify_html(buf.buf, false, o) ;
			   if (p[2]) return ;   // found frame document
			   buf.has_js= buf.has_js || p[1] ;
			   buf.buf= void 0 ;
			   o.write(p[0]) ;
			   _proxy_jslib_mark_as_proxified(o) ;
		       }
		       return o.getElementById(elementId) ;
		   }
	case 'Node.getElementsByTagName':     // actually Element
	case 'Document.getElementsByTagName':
	    return function (tagname) {
// jsm-- for some reason this alert() makes gmail's single-message-view work,
//   usually.  I absolutely detest site-specific fixes, but for now let's
//   make gmail work and address the problem correctly later.
if (document.URL.match(/\/mail\.google\.com\/mail\//) && tagname=='INPUT') alert('Hit OK to continue...') ;
		       if (this!==window) o= this ;
		       var i, buf, pi, doc ;
		       doc= (o.ownerDocument || o) ;
		       for (i= 0 ; i<_proxy_jslib_write_buffers.length ; i++)
			   if (_proxy_jslib_write_buffers[i]  &&
			       _proxy_jslib_write_buffers[i].doc===doc) break ;
		       if (i>=_proxy_jslib_write_buffers.length) return o.getElementsByTagName(tagname) ;
		       buf= _proxy_jslib_write_buffers[i] ;
		       if (buf.buf==void 0) return o.getElementsByTagName(tagname) ;
		       if (buf.buf.match(new RegExp('<\\s*'+tagname+'\\b', 'i'))) {
			   p= _proxy_jslib_proxify_html(buf.buf, false, doc) ;
			   if (p[2]) return ;   // found frame document
			   buf.has_js= buf.has_js || p[1] ;
			   buf.buf= void 0 ;
			   doc.write(p[0]) ;
			   _proxy_jslib_mark_as_proxified(doc) ;
		       }
		       return o.getElementsByTagName(tagname) ;
		   }

	case 'Range.insertNode':
	    return function (newNode) {
		       if (this!==window) o= this ;
		       if (!newNode._proxy_jslib_is_proxified)
			   return o.insertNode(_proxy_jslib_proxify_element(newNode)) ;
		       return o.insertNode(newNode) ;
		   }
	case 'Range.surroundContents':
	    return function (newParent) {
		       if (this!==window) o= this ;
		       if (!newParent._proxy_jslib_is_proxified)
			   return o.surroundContents(_proxy_jslib_proxify_element(newParent)) ;
		       return o.surroundContents(newParent) ;
		   }
	case 'NamedNodeMap.setNamedItem':
	    return function (node) {
		       if (this!==window) o= this ;
		       node.nodeValue= _proxy_jslib_proxify_attribute(node.nodeName, node.nodeValue) ;
		       return o.setNamedItem(node) ;
		   }

	case 'CSSPrimitiveValue.setStringValue':
	    return function (type, value) {
		       if (this!==window) o= this ;
		       if (type==CSSPrimitiveValue.CSS_URI)
			   return o.setStringValue(type, _proxy_jslib_full_url(value)) ;
		       return o.setStringValue(type, value) ;
		   }
	case 'CSSStyleDeclaration.setProperty':
	    return function (name, value, priority) {
		       if (this!==window) o= this ;
		       return o.setProperty(name, _proxy_jslib_proxify_css(value), priority) ;
		   }


	// Netscape-specific in this block
	case 'Layer.load':
	    if (!o.load) return undefined ;
	    return function (url, width) {
		       if (this!==window) o= this ;
		       return o.load(_proxy_jslib_full_url(url), width) ;
		   } ;


	// MSIE-specific in this block
	case 'Window.execScript':
	    if (!o.execScript) return undefined ;
	    return function(code, language) {
		       if (this!==window) o= this ;
		       if (language.match(/^\s*(javascript|jscript|ecmascript|livescript|$)/i))
			   return o.execScript(_proxy_jslib_proxify_js(code), language) ;
		       // disallow scripts we don't support
		       return ;
		   }
	case 'Window.navigate':
	    if (!o.navigate) return undefined ;
	    return function (url) {
		       if (this!==window) o= this ;
		       return o.navigate(_proxy_jslib_full_url(url)) ;
		   } ;
	case 'Window.showModalDialog':
	    if (!o.showModalDialog) return undefined ;
	    return function(url, args, features) {
		       if (this!==window) o= this ;
		       return o.showModalDialog(_proxy_jslib_full_url(url), args, features) ;
		   } ;
	case 'Window.showModelessDialog':
	    if (!o.showModelessDialog) return undefined ;
	    return function(url, args, features) {
		       if (this!==window) o= this ;
		       return o.showModelessDialog(_proxy_jslib_full_url(url), args, features) ;
		   } ;
	// don't need to handle Document.parentWindow, do we?


	// non-standard but supported by both Mozilla and MSIE
	case 'XMLHttpRequest.open':
	    return function(method, url, asyncflag, username, password) {
		       if (this!==window) o= this ;
		       // if absolute URL, verify domain is same as current page
		       if (url.match(/^[\w\+\.\-]*\:/)) {
			   var h1= (_proxy_jslib_parse_url(_proxy_jslib_URL))[4] ;
			   var h2= (_proxy_jslib_parse_url(url))[4] ;
//alert('h1,h2,url=['+h1+']['+h2+']\n['+url+']') ;
			   var d1= (h1.match(/(^|\.)(\w+\.\w+)$/))[2].toLowerCase() ;
			   var d2= (h2.match(/(^|\.)(\w+\.\w+)$/))[2].toLowerCase() ;
			   if (d1!=d2) return ;   // unallowed domain
		       }

		       // proxify the URL using 'text/xml' as the expected type
		       var flags= _proxy_jslib_unpack_flags(_proxy_jslib_packed_flags) ;
		       flags[5]= 1 ;  // because of how this is used, don't insert the top form
		       flags[6]= 'text/xml' ;

		       var old_url_start= _proxy_jslib_url_start ;
		       _proxy_jslib_url_start= _proxy_jslib_SCRIPT_NAME + '/' + _proxy_jslib_pack_flags(flags) + '/' ;
		       url= _proxy_jslib_full_url(url) ;
		       _proxy_jslib_url_start= old_url_start ;

		       return o.open(method, url, asyncflag, username, password) ;
		   }


	default:
	    if (typeof(o[property])=='function') {
		var fn= o[property] ;
		var ret= function () {
			     // Function.apply() not available in MSIE 5.0  :P
			     if (this!==window) {
				 return fn.apply(this, arguments) ;
			     } else {
				 return fn.apply(o, arguments) ;
			     }
			 } ;
		// must copy all other properties too, in case anything's dereferenced
		for (var p in o[property]) ret[p]= o[property][p] ;
		return ret ;
	    } else {
		return o[property] ;
	    }

    }
}



// This is used when the property in question IS being assigned to, WITH an object.
function _proxy_jslib_assign (prefix, o, property, op, val) {
    var new_val, otype ;

    // guess when the window object is implied
//    if ((o===null)  && (window[property]!==void 0) && (window[property]===cur_val)) o= window ;

    // handle prefix
    if (prefix=='delete') return delete o[property] ;
    if (prefix=='++') {
	val= o[property]+1 ;
	op= '=' ;
    } else if (prefix=='--') {
	val= o[property]-1 ;
	op= '=' ;
    }

// sanity check
if (o==null) alert('in assign, o is null, property, caller=\n['+property+']\n['+arguments.callee.caller+']') ;   // jsm-- remove in production release?

    // assure that object is correctly marked as proxified,
    //   including when the document may still be loading
    // jsm-- this whole subsystem should be reworked at some point
    if (!o._proxy_jslib_is_proxified && _proxy_jslib_node_is_in_HTML_document(o))
	_proxy_jslib_mark_as_proxified(o) ;

    otype= _proxy_jslib_object_type(o) ;

    // Simple variable assignment if o is a Node but not proxified yet.
    // Don't do this with Image objects, because they can load a URL even
    //   when not in a document.  Not very elegant here.
    // Mozilla chokes on some "o.node{Name,Type,Value}", so use try/catch block
    try {
	if ((o.nodeName!==void 0) && (o.nodeType!==void 0) && (o.nodeValue!==void 0) && (otype!='Image')) {
	    if (!o._proxy_jslib_is_proxified)
		return (op=='++' || op=='--')  ? eval('o[property]'+op)  : eval('o[property]'+op+'val') ;
	}
    } catch (e) {
    }


    var opmod= op.match(/=/)  ? op.replace(/=$/, '')  : '' ;

    // For unknown object types, transform common URL properties such as "src".
    //   It's better to proxify a property too much than to open a privacy hole,
    //   which is what happens if such a property is a URL that does not get
    //   proxified.  This also protects against when _proxy_jslib_object_type()
    //   doesn't ID an object correctly.
    // Don't do this if the value it's being assigned to is a non-String object.
    //   This helps when variables have the same name as properties.
    // We don't cover all combinations of properties and operators here; e.g.
    //   URL-like properties are unlikely to use ++ or --, and other
    //   combinations don't usually make sense.  We can revisit if needed.
    switch (property) {
	// A little hack-- handle CSS2Properties.background differently.
	case 'background':
	    if (otype=="CSS2Properties") {
		o[property]= _proxy_jslib_proxify_css(val) ;
		return val ;
	    }   // else drop through to next block

	case 'src':
	case 'href':
	case 'lowsrc':
	case 'action':
	case 'useMap':
	case 'longDesc':
	case 'cite':
	case 'codeBase':
	case 'location':
	    // test if val is a non-String object
	    if (val && (typeof val=='object') && (val.toLowerCase==void 0))
		return eval('o[property]'+op+'val') ;
	    if (opmod!='') {
		new_val= _proxy_jslib_parse_full_url(o[property])[2] ;
		eval('new_val' + op + 'val')
	    } else {
		new_val= val ;
	    }
	    // this won't catch e.g. "top.location.href=u"... :P
	    if ((property=='location') && (o.top===o)) {
		o[property]= _proxy_jslib_full_url_by_frame(new_val, false) ;
	    } else {
		o[property]= _proxy_jslib_full_url(new_val) ;
	    }
	    if (otype=='Window') _proxy_jslib_init_domain(o) ;
	    // return unproxified value
	    return new_val ;

	case 'profile':
	    var u= val.split(/\s+/) ;
	    for (var i= 0 ; i<u.length ; i++)
		u[i]= _proxy_jslib_full_url(u[i]) ;
	    o[property]= u.join(' ') ;
	    return val ;

	case 'cssText':
	    o[property]= _proxy_jslib_proxify_css(val) ;
	    return val ;

	// these are properties of HTMLElement, i.e. could be one of many object types
	case 'innerHTML':
	case 'outerHTML':
	case 'outerText':
	    // unproxify it first by calling _proxify_html() with reverse=true
	    if (op!='=') new_val= _proxy_jslib_proxify_html(o[property], false, (o.ownerDocument || o), true)[0] ;
	    eval('new_val' + op + 'val') ;
	    o[property]= _proxy_jslib_proxify_html(new_val, false, (o.ownerDocument || o))[0] ;
	    return new_val ;

	// same for properties of Node
	case 'nodeValue':
	    if (opmod!='') { eval('new_val= o[property]' + opmod + 'val') }
	    else           { new_val= val }
	    o[property]= _proxy_jslib_proxify_attribute(property, new_val) ;
	    return new_val ;

	default:
	    var fu, u ;
	    if (otype=='Link' || otype=='Location') {
		fu= _proxy_jslib_parse_full_url(o.href) ;
		u=  _proxy_jslib_parse_url(fu[2]) ;
	    }
	    // u[] has full_match, protocol, authentication, host, hostname, port, pathname, search, hash
	    switch (otype+'.'+property) {
		// here we ignore case of "+=", etc.; revisit later if needed
		case 'Link.protocol':
		case 'Location.protocol':
		    val.toLowerCase() ;
		    o.href= _proxy_jslib_full_url(val+'//'+(u[2]!='' ? u[2]+'@' : '')+u[3]+u[6]+u[7]+u[8]) ;
		    return val ;
		case 'Link.host':
		case 'Location.host':
		    val.toLowerCase() ;
		    o.href= _proxy_jslib_full_url(u[1]+'//'+(u[2]!='' ? u[2]+'@' : '')+val+u[6]+u[7]+u[8]) ;
		    return val ;
		case 'Link.hostname':
		case 'Location.hostname':
		    o.href= _proxy_jslib_full_url(u[1]+'//'+(u[2]!='' ? u[2]+'@' : '')+val+(u[5]!='' ? ':'+u[5] : '')+u[6]+u[7]+u[8]) ;
		    return val ;
		case 'Link.port':
		case 'Location.port':
		    o.href= _proxy_jslib_full_url(u[1]+'//'+(u[2]!='' ? u[2]+'@' : '')+u[4]+(val!='' ? ':'+val : '')+u[6]+u[7]+u[8]) ;
		    return val ;
		case 'Link.pathname':
		case 'Location.pathname':
		    o.href= _proxy_jslib_full_url(u[1]+'//'+(u[2]!='' ? u[2]+'@' : '')+u[3]+val+u[7]+u[8]) ;
		    return val ;
		case 'Link.search':
		case 'Location.search':
		    o.href= _proxy_jslib_full_url(u[1]+'//'+(u[2]!='' ? u[2]+'@' : '')+u[3]+u[6]+val+u[8]) ;
		    return val ;
		case 'Document.cookie':
		    return (_proxy_jslib_cookies_are_banned_here
			    ? ''
			    : o.cookie= _proxy_jslib_cookie_to_client(val) ) ;
		case 'Document.domain':
		    var w= _proxy_jslib_doc2win(o,_proxy_jslib_wins) ;
		    // new domain must be suffix of old domain, must contain a
		    //   ".", and must be a complete domain suffix of old value
		    //   (tested here by prefixing with "." before suffix check,
		    //   but allowing if strings are equal).
		    if ( ( (('.'+val)==w._proxy_jslib_document_domain.slice(-val.length-1))
			   || (val==w._proxy_jslib_document_domain) )
			 && val.match(/\./) )
			return (w._proxy_jslib_document_domain= val) ;
//		    else alert('Warning: tried to set document.domain to illegal value: ['+val+'] old value: ['+w._proxy_jslib_document_domain+']') ;  // jsm
		    break ;
		case 'Attr.value':
		    o.value= _proxy_jslib_proxify_attribute(o.name, val) ;
		    return val ;
//		case 'CSS2Properties.background':   // handled above
		case 'CSS2Properties.backgroundImage':
		case 'CSS2Properties.content':
		case 'CSS2Properties.cursor':
		case 'CSS2Properties.listStyle':
		case 'CSS2Properties.listStyleImage':
		    o[property]= _proxy_jslib_proxify_css(val) ;
		    return val ;

		default:
		    return (op=='++' || op=='--')  ? eval('o[property]'+op)  : eval('o[property]'+op+'val') ;
	    }
    }
}



// This is used when the property in question IS being assigned to, WITHOUT an object.
// The value returned is the value to set the variable to.
function _proxy_jslib_assign_rval (prefix, property, op, val, cur_val) {

    // handle prefix
    if (prefix=='delete') return undefined ;  // not quite the same as delete, but close enough
    if (prefix=='++') {
	val= 1 ;
	op= '+=' ;
    } else if (prefix=='--') {
	val=  1 ;
	op= '-=' ;
    }

    if (val && (typeof val=='object') && (val.toLowerCase==void 0))
	return val ;
    var new_val= cur_val ;
    eval('new_val' + op + 'val') ;

    switch (property) {
	// when there's no object, "location" is the only property that needs proxification
	case 'location':
	    return _proxy_jslib_full_url(new_val) ;
	default:
	    return new_val ;
    }
}



// Next two routines are used when in a with() block.
function _proxy_jslib_with_handle (with_objs, property, cur_val) {
    for (var i= with_objs.length-1 ; i>=0 ; i--)
	for (var j in with_objs[i])
	    if (j==property) return _proxy_jslib_handle(with_objs[i], j, with_objs[i][j]) ;
    return _proxy_jslib_handle(null, property, cur_val) ;
}

function _proxy_jslib_with_assign_rval (with_objs, prefix, property, op, val, cur_val) {
    for (var i= with_objs.length-1 ; i>=0 ; i--)
	for (var j in with_objs[i])
	    if (j==property) return _proxy_jslib_assign(prefix, with_objs[i], j, op, val) ;
    return _proxy_jslib_assign_rval(prefix, property, op, val, cur_val) ;
}



//---- below are used to support the API functions above ---------------


function _proxy_jslib_add_to_write_buffer(doc, html) {
    var i ;
    for (i= 0 ; i<_proxy_jslib_write_buffers.length ; i++) {
	if (_proxy_jslib_write_buffers[i].doc===doc) break ;
    }
    if (i==_proxy_jslib_write_buffers.length || _proxy_jslib_write_buffers[i].doc!==doc) {
	_proxy_jslib_write_buffers[_proxy_jslib_write_buffers.length]= { doc: doc, buf: html } ;
    } else {
	if (_proxy_jslib_write_buffers[i].buf==void 0) _proxy_jslib_write_buffers[i].buf= '' ;
	_proxy_jslib_write_buffers[i].buf+= html ;
    }
}


// careful-- output of document.write() may be (erroneously?) parsed and
//   executed immediately after document.write() statement.  To help with
//   that, we clear the buffer before calling document.write().
// Hack here for JS insertions-- if document was created and nothing written on
//   it yet, then insert the JS library if needed.
// Another hack-- since _proxy_jslib_write_buffers may be reset if what's
//   written includes jslib, we exit the loop if that happens.
function _proxy_jslib_flush_write_buffers() {
    var buf, i, p ;

    for (i= 0 ; (_proxy_jslib_write_buffers!=void 0) && (i<_proxy_jslib_write_buffers.length) ; i++) {
	buf= _proxy_jslib_write_buffers[i] ;
	if (buf.buf==void 0) continue ;

	p= _proxy_jslib_proxify_html(buf.buf, !buf.has_js, buf.doc) ;
	if (p[2]) return ;   // found frame document
//var w= _proxy_jslib_doc2win(buf.doc,_proxy_jslib_wins) ; if (w!=void 0) w= w.name ;
//if (confirm('flushing buffer;\nwin=['+w+']\nhas_js=['+p[1]+']\nout=['+p[0]+']')) ;
	buf.has_js= buf.has_js || p[1] ;
	buf.buf= void 0 ;
	buf.doc.write(p[0]) ;
	_proxy_jslib_mark_as_proxified(buf.doc) ;
    }
}



function _proxy_jslib_new_function() {
    arguments[arguments.length-1]= _proxy_jslib_proxify_js(arguments[arguments.length-1]) ;
    // MSIE 5.0 doesn't support Function.apply  :P
    return Function.apply(null, arguments) ;  // Function() same w/ or w/o "new"
}


function _proxy_jslib_doc2win(d, wins) {
    var f ;
    for (var i= 0 ; i<wins.length ; i++) {
	if (wins[i].document===d) return wins[i] ;
	if (wins[i].frames.length && (f= _proxy_jslib_doc2win(d, wins[i].frames))) return f ;
    }
    return null ;
}


// include fields needed for type ID, plus any other "authorized" fields.
function _proxy_jslib_dup_window_safe(w) {
    return { navigator:     w.navigator,
	     clearInterval: w.clearInterval,
	     moveBy:        w.moveBy,
	     self:          w,

	     location:      w.location } ;
}


function _proxy_jslib_init_domain(w) {
    if (w.document.URL=='about:blank') {
	w._proxy_jslib_document_domain= void 0 ;
	return ;
    }
    var URL= w.document.URL.replace(/^wyciwyg:\/\/\d+\//i, '') ;
    URL= _proxy_jslib_parse_full_url(URL)[2] ;
    URL= decodeURIComponent(URL) ;
    if (URL=='about:blank') {
	w._proxy_jslib_document_domain= void 0 ;
	return ;
    }
    w._proxy_jslib_document_domain= _proxy_jslib_parse_url(URL)[4] ;
}



function _proxy_jslib_full_url(uri_ref, reverse) {
    var script, r_l ;

    if (uri_ref==null) return '' ;
//if (uri_ref.match(/\/[01]{6}[A-Z]\//)) alert('in full_url; uri_ref, caller=\n['+uri_ref+']\n['+arguments.callee.caller+']') ;   // jsm

    if (reverse) return _proxy_jslib_parse_full_url(uri_ref)[2] ;

    uri_ref= uri_ref.replace(/^\s+|\s+$/g, '') ;
    if (/^x\-proxy\:\/\//i.test(uri_ref))  return '' ;

    if (/^(javascript|livescript)\:/i.test(uri_ref)) {
	script= uri_ref.replace(/^(javascript|livescript)\:/i, '') ;
	r_l= _proxy_jslib_separate_last_js_statement(script) ;
	return 'javascript:' + _proxy_jslib_proxify_js(r_l[0], 1)
			     + '; _proxy_jslib_proxify_html(' + _proxy_jslib_proxify_js(r_l[1], 0) + ')[0]' ;
    }

    var uf= uri_ref.match(/^([^\#]*)(\#.*)?/) ;
    var uri= uf[1] ;
    var frag=  uf[2]  ? uf[2]  : '' ;
    if (uri=='')  return uri_ref ;

    uri= uri.replace(/[\r\n]/g, '') ;

    var absurl ;
    if      (/^[\w\+\.\-]*\:/.test(uri))  { absurl= uri               }
    else if (/^\/\//.test(uri))           { absurl= _proxy_jslib_base_scheme + uri }
    else if (/^\//.test(uri))             { absurl= _proxy_jslib_base_host   + uri }
    else if (/^\?/.test(uri))             { absurl= _proxy_jslib_base_file   + uri }
    else                                  { absurl= _proxy_jslib_base_path   + uri }

    return _proxy_jslib_url_start + _proxy_jslib_wrap_proxy_encode(absurl) + frag ;
}


function _proxy_jslib_full_url_by_frame(uri_ref, is_frame, reverse) {
    var old_url_start= _proxy_jslib_url_start ;
    _proxy_jslib_url_start= is_frame  ? _proxy_jslib_url_start_inframe  : _proxy_jslib_url_start_noframe ;
    var ret= _proxy_jslib_full_url(uri_ref, reverse) ;
    _proxy_jslib_url_start= old_url_start ;
    return ret ;
}


function _proxy_jslib_wrap_proxy_encode(URL) {
    var uf= URL.match(/^([^\#]*)(\#.*)?/) ;
    var uri= uf[1] ;
    var frag=  uf[2]  ? uf[2]  : '' ;

    uri= _proxy_jslib_proxy_encode(uri) ;
    uri= uri.replace(/\=/g, '=3d').replace(/\?/g, '=3f').replace(/\#/g, '=23').replace(/\%/g, '=25') ;
    while (uri.match(/\/\//)) uri= uri.replace(/\/\//g, '/=2f') ;

    return uri + frag ;
}

function _proxy_jslib_wrap_proxy_decode(enc_URL) {
    var uf= enc_URL.match(/^([^\?\#]*)([^\#]*)(.*)/) ;
    var uri= uf[1] ;
    var query= uf[2] ;
    var frag=  uf[3]  ? uf[3]  : '' ;

    uri= uri.replace(/\=(..)/g, function (s,p1) { return String.fromCharCode(eval('0x'+p1)) } ) ;
    uri= _proxy_jslib_proxy_decode(uri) ;

    return uri + query + frag ;
}



function _proxy_jslib_cookie_to_client(cookie) {
    if (_proxy_jslib_cookies_are_banned_here) return '' ;

    var u= _proxy_jslib_parse_url(_proxy_jslib_URL) ;
    if (u==null) {
	alert("CGIProxy Error: Can't parse URL <"+_proxy_jslib_URL+">; not setting cookie.") ;
	return '' ;
    }
    var source_server= u[4] ;
    var source_path= u[6] ;
    if (source_path.substr(0,1)!='/') source_path= '/' + source_path ;

    var name, value, expires_clause, path, domain, secure_clause ;
    var new_name, new_value, new_cookie ;

    name= value= expires_clause= path= domain= secure_clause=
	new_name= new_value= new_cookie= '' ;

    if (/^\s*([^\=\;\,\s]*)\s*\=?\s*([^\;]*)/.test(cookie)) {
	name= RegExp.$1 ; value= RegExp.$2 ;
    }
    if (/\;\s*(expires\s*\=[^\;]*)/i.test(cookie))        expires_clause= RegExp.$1 ;
    if (/\;\s*path\s*\=\s*([^\;\,\s]*)/i.test(cookie))    path= RegExp.$1 ;
    if (/\;\s*domain\s*\=\s*([^\;\,\s]*)/i.test(cookie))  domain= RegExp.$1 ;
    if (/\;\s*(secure\b)/i.test(cookie))                  secure_clause= RegExp.$1 ;

    if (path=='') path= _proxy_jslib_COOKIE_PATH_FOLLOWS_SPEC  ? source_path  : '/' ;

    if (domain=='') {
	domain= source_server ;
    } else {
	domain= domain.replace(/\.+$/, '') ;
	domain= domain.replace(/\.{2,}/g, '.') ;
	if ( (source_server.substr(source_server.length-domain.length)!=domain.toLowerCase()) && ('.'+source_server!=domain) )
	    return '' ;
	var dots= domain.match(/\./g) ;
	if (_proxy_jslib_RESPECT_THREE_DOT_RULE) {
	    if (dots.length<3 && !( dots.length>=2 && /\.(com|edu|net|org|gov|mil|int)$/i.test(domain) ) )
		return '' ;
	} else {
	    if (dots.length<2) {
		if (domain.match(/^\./)) return '' ;
		domain= '.'+domain ;
		if (dots.length<1) return '' ;
	    }
	}
    }

    new_name=  _proxy_jslib_cookie_encode('COOKIE;'+name+';'+path+';'+domain) ;
    new_value= _proxy_jslib_cookie_encode(value+';'+secure_clause) ;

    if (_proxy_jslib_SESSION_COOKIES_ONLY && (expires_clause!='')) {
	/^expires\s*\=\s*(.*)$/i.test(expires_clause) ;
	var expires_date= RegExp.$1.replace(/\-/g, ' ') ;  // Date.parse() can't handle "-"
	if ( Date.parse(expires_date) > (new Date()).getTime() ) expires_clause= '' ;
    }

    new_cookie= new_name+'='+new_value ;
    if (expires_clause!='') new_cookie= new_cookie+'; '+expires_clause ;
    new_cookie= new_cookie+'; path='+_proxy_jslib_SCRIPT_NAME+'/' ;
    if (secure_clause!='')  new_cookie= new_cookie+'; '+secure_clause ;

    return new_cookie ;
}


function _proxy_jslib_cookie_from_client(doc) {
    if (_proxy_jslib_cookies_are_banned_here) return '' ;
    if (!doc.cookie) return '' ;

    var target_path, target_server, target_scheme ;
    var u= _proxy_jslib_parse_url(_proxy_jslib_URL) ;
    if (u==null) {
	alert("CGIProxy Error: Can't parse URL <"+_proxy_jslib_URL+">; not using cookie.") ;
	return ;
    }
    target_scheme= u[1] ;
    target_server= u[4] ;
    target_path= u[6] ;
    if (target_path.substr(0,1)!='/') target_path= '/' + target_path ;

    var matches= new Array() ;
    var pathlen= new Object() ;
    var cookies= doc.cookie.split(/\s*;\s*/) ;
    for (var c in cookies) {
	var nv= cookies[c].split(/=/, 2) ;
	var name=  _proxy_jslib_cookie_decode(nv[0]) ;
	var value= _proxy_jslib_cookie_decode(nv[1]) ;
	var n= name.split(/;/) ;
	if (n[0]=='COOKIE') {
	    var cname, path, domain, cvalue, secure ;
	    cname= n[1] ; path= n[2] ; domain= n[3].toLowerCase() ;
	    var v= value.split(/;/) ;
	    cvalue= v[0] ; secure= v[1] ;
	    if (secure!='' && secure!=null && target_scheme!='https:') continue ;
	    if ( ((target_server.substr(target_server.length-domain.length)==domain)
		  || (domain=='.'+target_server))
		&& target_path.substr(0, path.length)==path )
	    {
		matches[matches.length]= cname  ? cname+'='+cvalue  : cvalue ;
		pathlen[cname+'='+cvalue]= path.length ;
	    }
	}
    }

    matches.sort(function (v1,v2) { return (pathlen[v2]-pathlen[v1]) } ) ;

    return matches.join('; ') ;
}




// returns [new_html, needs_jslib, found_frameset]
// call with reverse=true to un-proxify a block of HTML-- convenient but kinda hacky
function _proxy_jslib_proxify_html(html, is_full_page, doc, reverse) {
    var out= '' ;
    var m1, m2, m3, rem ;
    var html_pos, head_pos ;

    if (is_full_page) _proxy_jslib_needs_jslib= false ;

    if (html==void 0) return [void 0, false, false] ;

    while (html!='') {
	var start= html.match(/^[^\<]*/) ;
	out+= start[0] ;
	html= html.substr(start[0].length) ;

	// because not all browsers support non-greedy matching, next six
	//   blocks emulate it.
	if (m1= html.match(/^\<\!\-\-/)) {
	    rem= html.substr(4) ;
	    if (rem.match(/\-\-\>/)) {
		m2= rem.match(/\-\-\s*\>/) ;
	    } else if (m2= rem.match(/\>/)) {
	    } else {
		html= '' ;
		break ;
	    }
	    var comment= html.substr(0, 4+m2.index+m2[0].length) ;
	    html= html.substr(comment.length) ;
	    out+= _proxy_jslib_proxify_comment(comment, reverse) ;
	    continue ;
	}

	if (m1= html.match(/^\<\s*script\b/i)) {
	    rem= html.substr(m1[0].length) ;
	    if (m2= rem.match(/\<\s*\/script\b/i)) {
		rem= html.substr(m1[0].length+m2.index+m2[0].length) ;
		if (m3= rem.match(/\>/)) {
		    var script_block= html.substr(0, m1[0].length+m2.index+m2[0].length+m3.index+1) ;
		    html= html.substr(script_block.length) ;
		    out+= _proxy_jslib_proxify_script_block(script_block, reverse) ;
		    continue ;
		}
	    }
	}

	if (m1= html.match(/^\<\s*style\b/i)) {
	    rem= html.substr(m1[0].length) ;
	    if (m2= rem.match(/\<\s*\/style\b/i)) {
		rem= html.substr(m1[0].length+m2.index+m2[0].length) ;
		if (m3= rem.match(/\>/)) {
		    var style_block= html.substr(0, m1[0].length+m2.index+m2[0].length+m3.index+1) ;
		    html= html.substr(style_block.length) ;
		    out+= _proxy_jslib_proxify_style_block(style_block, reverse) ;
		    continue ;
		}
	    }
	}

	if (m1= html.match(/^\<\![^\>]*\>?/)) {
	    out+= _proxy_jslib_proxify_decl_bang(m1[0], reverse) ;
	    html= html.substr(m1[0].length) ;
	    continue ;
	}

	if (m1= html.match(/^\<\?[^\>]*\>?/)) {
	    out+= _proxy_jslib_proxify_decl_question(m1[0], reverse) ;
	    html= html.substr(m1[0].length) ;
	    continue ;
	}

	// gmail has a bug where a <body> tag is missing the closing ">",
	//   so disallow "<" in tag here to avoid including following tag.
	//if (m1= html.match(/^\<[^\>]*\>?/)) {
	if (m1= html.match(/^\<[^\<>]*\>?/)) {
	    var tag_name= '' ;
	    // For JS insertions, and <frameset> tags.  Ignore declarations for now.
	    if (m2= m1[0].match(/^\<\s*([A-Za-z][\w\.\:\-]*)/)) {
		tag_name= m2[1].toLowerCase() ;
		if ((tag_name=='frameset') && _proxy_jslib_doing_insert_here && !_proxy_jslib_is_in_frame && !reverse) {
		    _proxy_jslib_return_frame_doc(_proxy_jslib_wrap_proxy_encode(_proxy_jslib_URL), doc) ;
		    return ['', false, true] ;
		}
	    }

	    out+= _proxy_jslib_proxify_element(m1[0], reverse) ;
	    html= html.substr(m1[0].length) ;

	    if      (tag_name=='html') { html_pos= out.length }
	    else if (tag_name=='head') { head_pos= out.length }

	    continue ;
	}

	break ;
    }

    if (reverse) _proxy_jslib_needs_jslib= false ;

    // Don't worry about top insertion.  Hacky.
    if (is_full_page && _proxy_jslib_needs_jslib && !reverse) {

	var jslib_block= '<script type="text/javascript" src="'
		       + _proxy_jslib_html_escape(_proxy_jslib_url_start+_proxy_jslib_wrap_proxy_encode('x-proxy://scripts/jslib'))
		       + '"><\/script>\n' ;
	var base_url_jsq= _proxy_jslib_global_replace(_proxy_jslib_base_url, /(["\\])/,
						      function (p) { return '\\'+p[1] } ) ;
	var insert_string= '<script type="text/javascript">_proxy_jslib_pass_vars("'
			 + base_url_jsq + '",'
			 + _proxy_jslib_cookies_are_banned_here + ','
			 + _proxy_jslib_doing_insert_here + ','
			 + _proxy_jslib_SESSION_COOKIES_ONLY + ','
			 + _proxy_jslib_COOKIE_PATH_FOLLOWS_SPEC + ','
			 + _proxy_jslib_RESPECT_THREE_DOT_RULE + ',"'
			 + _proxy_jslib_default_script_type + '","'
			 + _proxy_jslib_default_style_type + '");<\/script>\n' ;
	var insert_pos= head_pos || html_pos || 0 ;
	out= out.substring(0,insert_pos) + jslib_block + insert_string + out.substring(insert_pos) ;
    }

    return [out, _proxy_jslib_needs_jslib] ;
}



function _proxy_jslib_proxify_comment(comment, reverse) {
    var m= comment.match(/^\<\!\-\-(.*?)(\-\-\s*)?>$/) ;
    var contents= m[1] ;
    var end= m[2] ;
    contents= _proxy_jslib_proxify_html(contents, false, null, reverse)[0] ;
    comment= '<!--' + contents + end + '>' ;
    return comment ;
}


function _proxy_jslib_proxify_decl_bang(decl_bang, reverse) {
    var q ;
    var inside= decl_bang.match(/^\<\!([^>]*)/)[1] ;
    var words= inside.match(/\"[^\"\>]*\"?|\'[^\'\>]*\'?|[^\'\"][^\s\>]*/g) ;
    for (var i=0 ; i<words.length ; i++) {
	words[i]= words[i].replace(/^\s*/, '') ;
	if (words[i].match(/^[\"\']?[\w\+\.\-]+\:\/\//)) {
	    if      (words[i].match(/^'/))  { q= "'" ; words[i]= words[i].replace(/^\'|\'$/g, '') }
	    else if (words[i].match(/^"/))  { q= '"' ; words[i]= words[i].replace(/^\"|\"$/g, '') }
	    else                            { q= '' }
	    words[i]= q + _proxy_jslib_full_url(words[i], reverse) + q ;
	}
    }
    decl_bang= '<!' + words.join(' ') + '>' ;
    return decl_bang ;
}


function _proxy_jslib_proxify_decl_question(decl_question, reverse) {
    return decl_question ;
}


function _proxy_jslib_proxify_script_block(script_block, reverse) {
    var m1, m2, tag, script, attrs, attr, name ;
    attr= new Object() ;

    m1= script_block.match(/^(\<\s*script\b[^\>]*\>)((.|\s)*)\<\s*\/script\b[^\>]*\>$/i) ;
    var o_n_j= _proxy_jslib_needs_jslib ;   // hack hack
    tag= _proxy_jslib_proxify_html(m1[1], reverse)[0] ;
    _proxy_jslib_needs_jslib= o_n_j ;
    script= m1[2] ;
    attrs= tag.match(/^\<\s*script\b([^\>]*)\>/i)[1] ;

    while (m2= attrs.match(/([A-Za-z][\w\.\:\-]*)\s*(\=\s*(\"([^\"\>]*)\"?|\'([^\'\>]*)\'?|([^\'\"][^\s\>]*)))?/)) {
	attrs= attrs.substr(m2[0].length) ;
	name= m2[1].toLowerCase() ;
	if (attr[name]!=null) continue ;
	attr[name]= m2[4]  ? m2[4]  : m2[5]  ? m2[5]  : m2[6]  ? m2[6]  : '' ;
	attr[name]= _proxy_jslib_html_unescape(attr[name]) ;
    }
    if (attr.type!=null) attr.type= attr.type.toLowerCase() ;
    if (!attr.type && attr.language) {
	attr.type= attr.language.match(/javascript|ecmascript|livescript|jscript/i)
						     ? 'application/x-javascript'
		 : attr.language.match(/css/i)       ? 'text/css'
		 : attr.language.match(/vbscript/i)  ? 'application/x-vbscript'
		 : attr.language.match(/perl/i)      ? 'application/x-perlscript'
		 : attr.language.match(/tcl/i)       ? 'text/tcl'
		 : '' ;
    }
    if (!attr.type) attr.type= _proxy_jslib_default_script_type ;

    // For now, don't worry about "</script" inside JS-written scripts.

    script= _proxy_jslib_proxify_block(script, attr.type, 1, reverse) ;

    return tag+script+'<\/script>' ;
}


function _proxy_jslib_proxify_style_block(style_block, reverse) {
    var m1, m2, tag, stylesheet, attrs, type ;
    m1= style_block.match(/^(\<\s*style\b[^\>]*\>)((.|\s)*)\<\s*\/style\b[^\>]*\>$/i) ;
    var o_n_j= _proxy_jslib_needs_jslib ;   // hack hack
    tag= _proxy_jslib_proxify_html(m1[1], reverse)[0] ;
    _proxy_jslib_needs_jslib= o_n_j ;
    stylesheet= m1[2] ;
    attrs= tag.match(/^\<\s*style\b([^\>]*)\>/i)[1] ;

    while (m2= attrs.match(/([A-Za-z][\w\.\:\-]*)\s*(\=\s*(\"([^\"\>]*)\"?|\'([^\'\>]*)\'?|([^\'\"][^\s\>]*)))?/)) {
	attrs= attrs.substr(m2[0].length) ;
	if (m2[1].toLowerCase()=='type') {
	    type= m2[4]!=null  ? m2[4]  : m2[5]!=null  ? m2[5]  : m2[6]!=null  ? m2[6]  : '' ;
	    type= _proxy_jslib_html_unescape(type).toLowerCase() ;
	    break ;
	}
    }
    if (!type) type= _proxy_jslib_default_style_type ;
    stylesheet= _proxy_jslib_proxify_block(stylesheet, type, 1, reverse) ;

    return tag+stylesheet+'<\/style>' ;
}


// the property tests are to distinguish from XML documents
function _proxy_jslib_node_is_in_HTML_document(node) {
    // Mozilla chokes on some "node instanceof Node", so wrap in a try block
    // MSIE chokes on simply "Node", so avoid "instanceof Node" altogether.  :P
    try {
//	if (!(node instanceof Node)) return false ;
	if (!((node.nodeName!==void 0) && (node.nodeType!==void 0) && (node.nodeValue!==void 0)) ) return false ;
	var d= node.ownerDocument ;
	return ( (node.nodeType==9 && node.anchors && node.applets && node.getElementsByName)
	      || (d && d.anchors && d.applets && d.getElementsByName) ) ;
    } catch(e) {
	return false ;
    }
}


function _proxy_jslib_mark_as_proxified(node) {
    // MSIE breaks if properties are added to Text or Comment nodes, so
    //   don't mark them.
    if ((node.nodeType==3) || (node.nodeType==8))  return ;
    node._proxy_jslib_is_proxified= true ;
    for (var i= 0 ; i<node.childNodes.length ; i++)
	_proxy_jslib_mark_as_proxified(node.childNodes[i]) ;
}


function _ostring(o, depth, filter) {
    var ret= '' ;
    if (depth>0)
	for (var p in o) {
try {
	    if (filter && !p.match(filter)) continue ;
//	    if (o[p]&&(typeof(o[p])!='function'))
		ret+= p + ':'
		      + ( (o[p]&&(typeof(o[p])=='object'))
			  ? _ostring(o[p],depth-1)
			  : ('"'+o[p]+'"') )
		      + ', ' ;
} catch(e) { ret+= p+':<<error: '+e+'>>, ' }
	}
    return '{' + ret + '}' ;
}

function _nodestring(n) {
    if (!n) return '' ;
    var ret= '' ;
    ret+= '<' + n.nodeName ;
    if (n.attributes)
	for (var i= 0 ; i<n.attributes.length ; i++)
	    ret+= ' ' + n.attributes[i].nodeName + '="' + n.attributes[i].nodeValue+'"' ;
    ret+= '>' ;
    ret+= n.innerHTML + '</' + n.nodeName + '>' ;
    return ret ;
}

function _node_is_in_document(node) {
    for ( ; (node!=null) && (node.nodeType!=9) ; node= node.parentNode) ;   // Node.DOCUMENT_NODE==9
    return node!=null ;
}

function _ancestorsof(node) {
    var ret= '' ;
    for ( ; (node!=null) && (node.nodeType!=9) ; node= node.parentNode)
	ret+= '['+node.nodeType+']['+node+']['+_node_is_in_document(node)+']\n' ;
   return ret ;
}

function _object_type(o) { return _proxy_jslib_object_type(o) }



// used for tags, element nodes (nodes+children are modified in place), and
//   DocumentFragment nodes.
function _proxy_jslib_proxify_element(element, reverse) {
    // Unfortunately, attr{} may have extra properties if a Web page changes
    //   anything in the Object prototype.  Thus, we use names[] to keep track
    //   of the tag's attributes.  We do this elsewhere too.
    var m1, m2, tag_name, attrs, attr, names, name, i, rebuild, end_slash,
	old_url_start, flags ;
    attr= new Object() ;
    names= new Array() ;

//sanity check
if (element._proxy_jslib_is_proxified && !reverse) alert('called _proxy_jslib_proxify_element() on a proxified element; caller=['+arguments.callee.caller+']') ;

    // handle either tag strings or Node objects
    if (typeof element=='string') {
	if (!(m1= element.match(/^\<\s*([A-Za-z][\w\.\:\-]*)\s*([^\>]*)/))) return element ;
	tag_name= m1[1].toLowerCase() ;
	attrs= m1[2] ;
	// ignore possibility of <frameset> tag
	if (attrs=='') return element ;

	while (m2= attrs.match(/([A-Za-z][\w\.\:\-]*)\s*(\=\s*(\"([^\"\>]*)\"?|\'([^\'\>]*)\'?|([^\'\"][^\s\>]*)))?/)) {
	    attrs= attrs.substr(m2.index+m2[0].length) ;
	    name= m2[1].toLowerCase() ;
	    if (attr[name]!=null) { rebuild= 1 ; continue }
	    attr[name]= (m2[4]!='' && m2[4]!=void 0) ? m2[4]
		      : (m2[5]!='' && m2[5]!=void 0) ? m2[5]
		      : (m2[6]!='' && m2[6]!=void 0) ? m2[6]
		      : '' ;
	    attr[name]= _proxy_jslib_html_unescape(attr[name]) ;
	    names[names.length]= name ;
	}

// work around Mozilla bug when taking typeof of HTMLObjectElement
//    } else if (typeof element=='object') {
    } else if ((typeof element=='object') || (typeof element=='function')) {
	// don't proxify Image objects, since they're already proxified
	if (element._proxy_jslib_is_proxified || _proxy_jslib_object_type(element)=='Image')
	    return element ;

	if (element.nodeType==1) {           // Node.ELEMENT_NODE
	    tag_name= element.nodeName.toLowerCase() ;
	    for (i= 0 ; i<element.attributes.length ; i++) {
		name= element.attributes[i].nodeName.toLowerCase() ;
		attr[name]= element.attributes[i].nodeValue ;
		names[names.length]= name ;
	    }
	} else if (element.nodeType==11) {   // Node.DOCUMENT_FRAGMENT_NODE
	    for (i= 0 ; i<element.childNodes.length ; i++)
		_proxy_jslib_proxify_element(element.childNodes[i], reverse) ;
	    return element ;
	} else if (element.nodeType==3) {     // Node.TEXT_NODE
	    return element ;
	} else {
	    alert('Error: unhandled node type==['+element.nodeType+']\ncaller=[\n'+arguments.callee.caller+']') ;
	    return ;
	}
    } else {
	alert('Error: unhandled typeof==['+(typeof element)+ '];\nelement=['+element+']\ncaller=['+arguments.callee.caller+']') ;
	return ;
    }


    // Now we have tag_name, attr[], and names[] set.

//    for (name in attr) {
    for (i= 0 ; i<names.length ; i++) {
	name= names[i] ;
	// for now, simply delete attributes with script macros
	if (attr[name].match(/\&\{.*\}\;/)) { delete attr[name] ; rebuild= 1 ; continue }

	if (name.match(/^on/)) {
	    attr[name]= _proxy_jslib_proxify_block(attr[name], _proxy_jslib_default_script_type, 1, reverse) ;
	    rebuild= 1 ;
	}
    }

    if (attr.style!=null) {
	if (attr.style.match(/(expression|function)\s*\(/i ))
	    attr.style= _proxy_jslib_global_replace(attr.style, /\b((expression|function)\s*\()([^\)]*)/i,
						    function (p) { return p[1]+_proxy_jslib_proxify_js(p[3], void 0, void 0, reverse) } ) ;

	attr.style= _proxy_jslib_proxify_block(attr.style, _proxy_jslib_default_style_type, 1, reverse) ;
	rebuild= 1 ;
    }

    // huge simplification of tag-specific block
    if (attr.href!==void 0)        { attr.href=        _proxy_jslib_full_url(attr.href,reverse) ;        rebuild= 1 }
    if (attr.src!==void 0)         {
	if (tag_name=='frame' || tag_name=='iframe') {
				     attr.src=         _proxy_jslib_full_url_by_frame(attr.src,1,reverse) ; rebuild= 1 ;
	} else if (tag_name=='script') {   // messy  :P
	    var old_url_start= _proxy_jslib_url_start ;
	    var flags= _proxy_jslib_unpack_flags(_proxy_jslib_packed_flags) ;
	    flags[6]= (attr.type!==void 0)  ? attr.type  : _proxy_jslib_default_script_type ;
	    _proxy_jslib_url_start= _proxy_jslib_SCRIPT_NAME + '/' + _proxy_jslib_pack_flags(flags) + '/' ;
				     attr.src=         _proxy_jslib_full_url(attr.src,reverse) ;         rebuild= 1 ;
	    _proxy_jslib_needs_jslib= true ;
	    _proxy_jslib_url_start= old_url_start ;
	} else                     { attr.src=         _proxy_jslib_full_url(attr.src,reverse) ;         rebuild= 1 }
    }
    if (attr.lowsrc!==void 0)      { attr.lowsrc=      _proxy_jslib_full_url(attr.lowsrc,reverse) ;      rebuild= 1 }
    if (attr.dynsrc!==void 0)      { attr.dynsrc=      _proxy_jslib_full_url(attr.dynsrc,reverse) ;      rebuild= 1 }
    if (attr.action!==void 0)      { attr.action=      _proxy_jslib_full_url(attr.action,reverse) ;      rebuild= 1 }
    if (attr.background!==void 0)  { attr.background=  _proxy_jslib_full_url(attr.background,reverse) ;  rebuild= 1 }
    if (attr.usemap!==void 0)      { attr.usemap=      _proxy_jslib_full_url(attr.usemap,reverse) ;      rebuild= 1 }
    if (attr.cite!==void 0)        { attr.cite=        _proxy_jslib_full_url(attr.cite,reverse) ;        rebuild= 1 }
    if (attr.longdesc!==void 0)    { attr.longdesc=    _proxy_jslib_full_url(attr.longdesc,reverse) ;    rebuild= 1 }
    if (attr.codebase!==void 0)    { attr.codebase=    _proxy_jslib_full_url(attr.codebase,reverse) ;    rebuild= 1 }
    if (attr.pluginspage!==void 0) { attr.pluginspage= _proxy_jslib_full_url(attr.pluginspage,reverse) ; rebuild= 1 }

    if ((tag_name=='meta') && attr['http-equiv'].match(/^\s*refresh\b/i)) {
	attr.content= _proxy_jslib_global_replace(
			  attr.content,
			  /(\;\s*URL\=)\s*(\S*)/i,
			  function (a) { return a[1] + _proxy_jslib_full_url(a[2],reverse) } ) ;
	rebuild= 1 ;
    }

    // Now attr[] has been modified correctly.


    if (typeof element == 'object') {
	if (rebuild)
	    for (i= 0 ; i<element.attributes.length ; i++)
		element.attributes[i].nodeValue= attr[element.attributes[i].nodeName.toLowerCase()] ;
	for (i= 0 ; i<element.childNodes.length ; i++) {
	    if (element.childNodes[i].nodeType==1) {
		_proxy_jslib_proxify_element(element.childNodes[i], reverse) ;
	    }
	}
	element._proxy_jslib_is_proxified= true ;
	return element ;
    }

    if (!rebuild) return element ;

    attrs= '' ;
//    for (name in attr) {
    for (i= 0 ; i<names.length ; i++) {
	name= names[i] ;
	if (attr[name]==null) continue ;
	if (attr[name]=='')  { attrs+= ' '+name ; continue }
	if (!attr[name].match(/\"/) || attr[name].match(/\'/)) {
	    attrs+= ' '+name+'="'+_proxy_jslib_html_escape(attr[name])+'"' ;
	} else {
	    attrs+= ' '+name+"='"+_proxy_jslib_html_escape(attr[name])+"'" ;
	}
    }

    end_slash= element.match(/\/\s*>?$/)  ? ' /'  : '' ;
    return '<'+tag_name+attrs+end_slash+'>' ;
}



function _proxy_jslib_element2tag (e) {
    var ret= '', i ;
if (e.nodeType!=1) alert('in element2tag; nodeType=['+e.nodeType+']') ;
    for (i= 0 ; i<e.attributes.length ; i++)
	ret+= ' '+e.attributes[i].nodeName+'="'+e.attributes[i].nodeValue+'"' ;
    ret= '<'+e.tagName+ret+'>' ;
    for (i=0 ; i<e.childNodes.length ; i++)
	if      (e.childNodes[i].nodeType==1) ret+= '\n'+_proxy_jslib_element2tag(e.childNodes[i]) ;
	else if (e.childNodes[i].nodeType==3) ret+= '\n'+e.childNodes[i].nodeValue ;
    return ret ;
}



// This mimics much of _proxy_jslib_proxify_element(), above.
function _proxy_jslib_proxify_attribute(name, value, reverse) {
    if (/\&\{.*\}\;/.test(value)) return ;

    name= name.toLowerCase() ;

    // when proxifying URL, assume it's in a frame, since most of the time this
    //   routine is called it will be in a frame... not perfect....
    if (/^(href|src|lowsrc|dynsrc|action|background|usemap|cite|longdesc|codebase)$/i.test(name)) {
	//return _proxy_jslib_full_url(value, reverse) ;
	return _proxy_jslib_full_url_by_frame(value, true, reverse) ;
    } else if (/^on/i.test(name)) {
	return _proxy_jslib_proxify_block(value, _proxy_jslib_default_script_type, 1, reverse)
    } else if (/^style$/i.test(name)) {
	if (/(expression|function)\s*\(/i.test(value)) return ;
	else return value ;
    } else {
	return value ;
    }
}



function _proxy_jslib_proxify_block(s, type, unknown_type_ok, reverse) {
    type= type.toLowerCase() ;

    if (type=='text/css') {
	return _proxy_jslib_proxify_css(s, reverse) ;

    } else if (type.match(/^(application\/x\-javascript|application\/x\-ecmascript|application\/javascript|application\/ecmascript|text\/javascript|text\/ecmascript|text\/livescript|text\/jscript)$/)) {
	return _proxy_jslib_proxify_js(s, 1, void 0, reverse) ;

    } else {
	return unknown_type_ok ? s : '' ;
    }
}



function _proxy_jslib_proxify_css(css, reverse) {
    var out= '', m1 ;
    while (m1= css.match(/url\s*\(\s*(([^\)]*\\\))*[^\)]*)(\)|$)/i)) {
	out+= css.substr(0,m1.index) + 'url(' + _proxy_jslib_css_full_url(m1[1], reverse) + ')' ;
	css= css.substr(m1.index+m1[0].length) ;
    }
    out+= css ;

    css= out ;
    out= '' ;
    while (m1=css.match(/\@import\s*(\"[^"]*\"|\'[^']*\'|[^\;\s\<]*)/i)) {
	if (!m1[1].match(/^url\s*\(/i)) {   // to avoid use of "(?!...)"
	    out+= css.substr(0,m1.index) + '@import ' + _proxy_jslib_css_full_url(m1[1], reverse) ;
	} else {
	    out+= css.substr(0,m1.index) + m1[0] ;
	}
	css= css.substr(m1.index+m1[0].length) ;
    }
    out+= css ;

    css= out ;
    out= '' ;
    while (m1= css.match(/((expression|function)\s*\()([^)]*)/i)) {
	out+= css.substr(0,m1.index) + m1[1] + _proxy_jslib_proxify_js(m1[3], reverse) ;
	css= css.substr(m1.index+m1[0].length) ;
    }
    out+= css ;

    return out ;
}


function _proxy_jslib_css_full_url(url, reverse) {
    var q= '' ;
    url= url.replace(/\s+$/, '') ;
    if      (url.match(/^\"/)) { q= '"' ; url= url.replace(/^\"|\"$/g, '') }
    else if (url.match(/^\'/)) { q= "'" ; url= url.replace(/^\'|\'$/g, '') }
    url= url.replace(/\\(.)/, "$1").replace(/^\s+|\s+$/g, '') ;
    url= _proxy_jslib_full_url(url, reverse) ;
    url= _proxy_jslib_global_replace(url, /([\(\)\,\s\'\"\\])/,
				     function (p) { return '\\'+p[1] } ) ;
    return q+url+q ;
}



function _proxy_jslib_return_frame_doc(enc_URL, doc) {
    var top_URL= _proxy_jslib_html_escape(_proxy_jslib_url_start_inframe
					  + _proxy_jslib_wrap_proxy_encode('x-proxy://frames/topframe?URL='
								      + encodeURIComponent(enc_URL) ) ) ;
    var page_URL= _proxy_jslib_html_escape(_proxy_jslib_url_start_inframe + enc_URL) ;
    doc.open();
    doc.write('<html>\n<frameset rows="80,*">\n'
	    + '<frame src="'+top_URL+'">\n<frame src="'+page_URL+'" name="_proxy_jslib_main_frame">\n'
	    + '</frameset>\n</html>') ;
    doc.close() ;
//alert('in return_frame_doc, after writing doc; top_URL, page_URL=\n['+top_URL+']\n['+page_URL+']') ;
}



//---- everything needed to handle proxify_js() ------------------------


// currently this only returns the proxified string, not the remainder
function _proxy_jslib_proxify_js(s, top_level, with_level, reverse) {
    if ((s==void 0) || (s=='')) return s ;
    if (with_level==void 0) with_level= 0 ;

    // for now, don't support un-proxifying script blocks
    if (reverse) return s ;

    // hack for eval()-- return unchanged if it's not a string or String object
    if (!s.match) return s ;

    var RE= _proxy_jslib_RE ;


    var out, element, token, last_token, new_last_token, newline_since_last_token, div_ok,
	term_so_far= '', prefix= '', sub_expr, op, new_val, cur_val_str, inc_by,
	does_write, in_braces= 0, in_func= false, expr,
	var_decl, varname, eq, value, skip1, skip2, funcname, with_obj, code,
	match, m2, o_p, o, p, ex_s ;
    out= new Array() ;


    // s is constantly trimmed from the front
  OUTER:
    while(1) {
	if (div_ok) {
	    if (!(match= s.match(RE.InputElementDiv))) break ;
	} else {
	    if (!(match= s.match(RE.InputElementRegExp))) break ;
	}
	s= s.slice(match.index+match[0].length) ;

	element= match[0] ;
	token= match[3] ;

	if (token) {
	    div_ok= /^(\)|\]|\+\+|\-\-)$|^([a-zA-Z\$\_\\\d'"]|\.\d|\/..)/.test(token) ;
	    if (/^(case|delete|do|else|in|instanceof|new|return|throw|typeof|void)$/.test(token)) div_ok= false ;
	}

	if (/^[\x0a\x0d]$/.test(element)) newline_since_last_token= true ;
	new_last_token= '' ;

	if (token=='{') {
	    in_braces++ ;
	} else if (token=='}') {
	    if (--in_braces==0) in_func= false ;
	}

	if (!token) {
	    if (term_so_far) term_so_far+= element ;
	    else out[out.length]= element ;

	} else if (match= token.match(/^\_proxy(\d*)(\_.*)/))   {
	    // the "-0" is to typecast match[1] to a number
	    term_so_far+= '_proxy'+(match[1]-0+1)+match[2] ;

	} else if (RE.N_S_RE.test(token)) {
	    out[out.length]= prefix + term_so_far ;
	    prefix= '' ;
	    term_so_far= token ;


	} else if (/^(\+\+|\-\-|delete)$/.test(token)) {
	    if (token=='--' && (match= s.match(/^\s*\>/))) {
		s= s.slice(match.index+match[0].length) ;
		out[out.length]= prefix + term_so_far + '-->' ;
		prefix= term_so_far= '' ;
	    } else if (term_so_far!='' && !newline_since_last_token) {
		out[out.length]= prefix + term_so_far + token ;
		prefix= term_so_far= '' ;
	    } else {
		out[out.length]= prefix + term_so_far ;
		prefix= term_so_far= '' ;
		o_p= _proxy_jslib_get_next_js_term() ;
		o= o_p[0] ;
		p= o_p[1] ;
		if (p==void 0) break ;
		if (o!='') {
		    out[out.length]= "_proxy_jslib_assign('" + token + "', ("
				   + _proxy_jslib_proxify_js(o, 0, with_level) + "), ("
				   + _proxy_jslib_proxify_js(p, 0, with_level) + "), '')" ;
		} else {
		    p= p.match(/^'(.*)'$/)[1] ;
		    out[out.length]= "(" + p + "= _proxy_jslib_assign_rval('"
				   + token + "', '" + p + "', '', '', " + p + "))" ;
		}
	    }


	} else if (token=='eval' && (match= s.match(RE.SKIPTOPAREN))) {
	    s= s.slice(match.index+match[0].length) ;
	    _proxy_jslib_needs_jslib= true ;
	    ex_s= _proxy_jslib_get_next_js_expr(s, 1) ;
	    s= ex_s[1] ;
	    term_so_far+= token + match[1] + '_proxy_jslib_proxify_js(('
			+ _proxy_jslib_proxify_js(ex_s[0], 0, with_level)
			+ '), 0, ' + with_level + ') )' ;
	    if (!(match= s.match(/^\)/))) break ;
	    s= s.slice(match.index+match[0].length) ;
	    div_ok= true ;


	} else if (/^(open|write|writeln|close|replace|load|eval|setInterval|setTimeout|toString|src|href|background|lowsrc|action|location|URL|referrer|useMap|longDesc|cite|codeBase|profile|cssText|insertRule|setStringValue|setProperty|backgroundImage|content|cursor|listStyleImage|host|hostname|pathname|port|protocol|search|insertNode|surroundContents|setNamedItem|getElementById|getElementsByTagName|innerHTML|outerHTML|outerText|insertAdjacentHTML|setAttribute|setAttributeNode|appendChild|insertBefore|replaceChild|nodeValue|cloneNode|value|cookie|domain|frames|parent|top|opener|execScript|navigate|showModalDialog|showModelessDialog)$/.test(token)) {
	    _proxy_jslib_needs_jslib= true ;
	    does_write= does_write || (token=='write') || (token=='writeln') || (token=='eval') ;
	    if ( newline_since_last_token
		 &&   /^(\)|\]|\+\+|\-\-)$|^([a-zA-Z\$\_\\\d'"]|\.\d|\/..)/.test(last_token)
		 && ! /^(case|delete|do|else|in|instanceof|new|typeof|void|function|var)$/.test(last_token) )
	    {
		out[out.length]= prefix + term_so_far ;
		prefix= term_so_far= '' ;
	    }
	    term_so_far= term_so_far.replace(RE.DOTSKIPEND, '') ;

	    if (/^[\{\,]/.test(last_token) && (match= s.match(RE.SKIPTOCOLON))) {
		s= s.slice(match.index+match[0].length) ;
		out[out.length]= prefix + term_so_far + token + match[1] ;
		prefix= term_so_far= '' ;
		new_last_token= ':' ;
		div_ok= false ;

	    } else if (prefix!='') {
		if (term_so_far=='') {
		    out[out.length]= (with_level
				      ? (token+"= _proxy_jslib_with_assign_rval(_proxy_jslib_with_objs, '"+prefix+"', '"+token+"', '', '', "+token+")")
				      : (token+"= _proxy_jslib_assign_rval('"+prefix+"', '"+token+"', '', '', "+token+")") ) ;
		} else {
		    term_so_far= "_proxy_jslib_assign('"+prefix+"', "+term_so_far+", '"+token+"', '', '')" ;
		}
		prefix= '' ;
		new_last_token= ')' ;
		div_ok= true ;
	    } else if (match= s.match(RE.NEXTISINCDEC)) {
		s= s.slice(match.index+match[0].length) ;
		op= match[3] ;
		if (term_so_far=='') {
		    out[out.length]= (with_level
				      ? (token+"= _proxy_jslib_with_assign_rval(_proxy_jslib_with_objs, '', '"+token+"', '"+op+"', '', "+token+")")
				      : (token+"= _proxy_jslib_assign_rval('', '"+token+"', '"+op+"', '', "+token+")") ) ;
		} else {
		    term_so_far= "_proxy_jslib_assign('', "+term_so_far+", '"+token+"', '"+op+"', '')" ;
		}
		new_last_token= ')' ;
		div_ok= true ;
	    // use charAt() to avoid use of (?!...) construct in regex
	    } else if ((match= s.match(RE.NEXTISASSIGN)) && (s.charAt(match[0].length)!='=')) {
		s= s.slice(match.index+match[0].length) ;
		op= match[3] ;
		ex_s= _proxy_jslib_get_next_js_expr(s, 0) ;
		s= ex_s[1] ;
		new_val= _proxy_jslib_proxify_js(ex_s[0], 0, with_level) ;
		if (term_so_far=='') {
		    out[out.length]= (with_level
				      ? (token+"= _proxy_jslib_with_assign_rval(_proxy_jslib_with_objs, '', '"+token+"', '"+op+"', ("+new_val+"), "+token+")")
				      : (token+"= _proxy_jslib_assign_rval('', '"+token+"', '"+op+"', ("+new_val+"), "+token+")") ) ;
		} else {
		    term_so_far= "_proxy_jslib_assign('', "+term_so_far+", '"+token+"', '"+op+"', ("+new_val+"))" ;
		}
		new_last_token= ')' ;
		div_ok= false ;
	    } else {
		if (term_so_far=='') {
		    term_so_far= (with_level
				  ? ("_proxy_jslib_with_handle(_proxy_jslib_with_objs, '"+token+"', "+token+")")
				  : ("_proxy_jslib_handle(null, '"+token+"', "+token+")") ) ;
		} else {
		    term_so_far= "_proxy_jslib_handle("+term_so_far+", '"+token+"', '')" ;
		}
		if (last_token=='new') term_so_far= "("+term_so_far+")" ;
		new_last_token= ')' ;
		div_ok= true ;
	    }


	// Skip these for the JS version-- they require %IN_CUSTOM_INSERTION
	//   etc. and would be rare anyway.  Revisit later if needed.
	//} else if (/^(applets|embeds|forms|ids|layers|anchors|images|links)$/.test(token)) {

	} else if (/^(if|while|for|switch)$/.test(token)) {
	    out[out.length]= prefix + term_so_far + token ;
	    prefix= term_so_far= '' ;
	    if (!(match= s.match(RE.SKIPTOPAREN))) break ;
	    s= s.slice(match.index+match[0].length) ;
	    ex_s= _proxy_jslib_get_next_js_expr(s, 1) ;
	    s= ex_s[1] ;
	    out[out.length]= match[1] + _proxy_jslib_proxify_js(ex_s[0], 0, with_level) + ')' ;
	    if (!(match= s.match(/^\)/))) break ;
	    s= s.slice(match.index+match[0].length) ;
	    div_ok= false ;

	} else if (token=='catch') {
	    out[out.length]= prefix + term_so_far + token ;
	    prefix= term_so_far= '' ;
	    if (!(match= s.match(RE.SKIPTOPAREN))) break ;
	    s= s.slice(match.index+match[0].length) ;
	    ex_s= _proxy_jslib_get_next_js_expr(s, 1) ;
	    s= ex_s[1] ;
	    out[out.length]= match[1] + ex_s[0] + ')' ;
	    if (!(match= s.match(/^\)/))) break ;
	    s= s.slice(match.index+match[0].length) ;
	    div_ok= false ;

	} else if (token=='function') {
	    out[out.length]= prefix + term_so_far + token ;
	    prefix= term_so_far= '' ;
	    //if (!(match= s.match('^(('+RE.SKIP+')*)('+RE.IdentifierName+')?(('+RE.SKIP+')*\\()')))
	    if (!(match= s.match('^(('+RE.SKIP+')*)('+RE.IdentifierName+'(\\.('+RE.IdentifierName+'))*)?(('+RE.SKIP+')*\\()')))
		break ;
	    s= s.slice(match.index+match[0].length) ;
	    //skip1= match[1] ; funcname= match[4] ; skip2= match[7] ;
	    skip1= match[1] ; funcname= match[4] || '' ; skip2= match[11] ;
	    if (m2= funcname.match(/^_proxy(\d*)_/))
		funcname= '_proxy' + (m2[1]-0+1) + funcname.replace(/^_proxy(\d*)/, '') ;
	    ex_s= _proxy_jslib_get_next_js_expr(s, 1) ;
	    s= ex_s[1] ;
	    out[out.length]= skip1 + funcname + skip2 + ex_s[0] + ') {' ;
	    if (!(match= s.match(/^\)\s*\{/))) break ;
	    s= s.slice(match.index+match[0].length) ;
	    in_braces++ ;
	    in_func= true ;
	    div_ok= false ;


	} else if (token=='with') {
	    out[out.length]= prefix + term_so_far ;
	    prefix= term_so_far= '' ;
	    if (!(match= s.match('^(('+RE.SKIP+')*)\('))) break ;
	    s= s.slice(match.index+match[0].length) ;
	    skip1= match[1] ;
	    ex_s= _proxy_jslib_get_next_js_expr(s, 1) ;
	    s= ex_s[1] ;
	    with_obj= _proxy_jslib_proxify_js(ex_s[0], 0, with_level) ;
	    if (!(match= s.match('^\)(('+RE.SKIP+')*)'))) break ;
	    s= s.slice(match.index+match[0].length) ;
	    skip2= match[1] ;
	    if (match=s.match(/^\{/)) {
		s= s.slice(match.index+match[0].length) ;
		ex_s= _proxy_jslib_get_next_js_expr(s, 1) ;
		s= ex_s[1] ;
		code= '{' + _proxy_jslib_proxify_js(ex_s[0], 0, with_level+1) + '}' ;
		if (!(match= s.match(/^\}/))) break ;
		s= s.slice(match.index+match[0].length) ;
	    } else {
		ex_s= _proxy_jslib_get_next_js_expr(s, 0) ;
		s= ex_s[1] ;
		code= _proxy_jslib_proxify_js(ex_s[0], 0, with_level+1) ;
		while (match=s.match(/^,/)) {
		    s= s.slice(match.index+match[0].length) ;
		    ex_s= _proxy_jslib_get_next_js_expr(s, 0) ;
		    s= ex_s[1] ;
		    code+= ',' + _proxy_jslib_proxify_js(ex_s[0], 0, with_level+1) ;
		}
	    }
	    out[out.length]= (with_level  ? ''  : 'var _proxy_jslib_with_objs= [] ;') ;
	    out[out.length]= 'with'+skip1+'(_proxy_jslib_with_objs[_proxy_jslib_with_objs.length]= ('+with_obj+'))'+skip2+code ;
	    out[out.length]= '; _proxy_jslib_with_objs.length-- ;' ;
	    div_ok= false ;


	} else if (token=='var') {
	    out[out.length]= prefix + term_so_far + token ;
	    prefix= term_so_far= '' ;
	    while (1) {
		ex_s= _proxy_jslib_get_next_js_expr(s, 0) ;
		s= ex_s[1] ;
		var_decl= ex_s[0] ;
		if (!(match= var_decl.match('^(('+RE.SKIP+')*)('+RE.IdentifierName+'('+RE.SKIP+')*)(\\=|in)?((x|[^x])*)$')))
		    break OUTER ;
		skip1= match[1] ; varname= match[4] ; eq= match[9] ; value= match[10] ;
		if (m2= varname.match(/^_proxy(\d*)_/))
		    varname= '_proxy' + (m2[1]-0+1) + varname.replace(/^_proxy(\d*)/, '') ;
		out[out.length]= skip1 + varname ;
		if (eq) out[out.length]= eq + _proxy_jslib_proxify_js(value, 0, with_level) ;
		if (!(match= s.match(/^\,/))) break ;
		s= s.slice(match.index+match[0].length) ;
		out[out.length]= ',' ;
	    }
	    div_ok= false ;

	} else if (token=='new') {
	    out[out.length]= prefix + term_so_far ;
	    prefix= term_so_far= '' ;
	    if (match= s.match('^('+RE.SKIP+')*Function\\b')) {
		s= s.slice(match.index+match[0].length) ;
		out[out.length]= '_proxy_jslib_new_function' ;
	    } else {
		out[out.length]= token ;
	    }

	} else if ((token=='return') && !in_func && top_level) {
	    out[out.length]= prefix + term_so_far ;
	    prefix= term_so_far= '' ;
	    _proxy_jslib_needs_jslib= true ;
	    ex_s= _proxy_jslib_get_next_js_expr(s, 0) ;
	    s= ex_s[1] ;
	    expr= ex_s[0] ;
	    while (match=s.match(RE.SKIPTOCOMMASKIP)) {
		s= s.slice(match.index+match[0].length) ;
		ex_s= _proxy_jslib_get_next_js_expr(s, 0) ;
		s= ex_s[1] ;
		expr+= ', ' + ex_s[0] ;
	    }
	    expr= _proxy_jslib_proxify_js(expr, 0, with_level) ;
	    out[out.length]= 'return ((_proxy_jslib_ret= ('+expr+')), _proxy_jslib_flush_write_buffers(), _proxy_jslib_ret)' ;
	    div_ok= false ;


	} else if (/^(abstract|boolean|break|byte|case|char|class|const|continue|debugger|default|delete|do|else|enum|export|extends|final|finally|float|goto|implements|in|instanceof|int|interface|long|native|package|private|protected|return|short|static|synchronized|throw|throws|transient|try|typeof|void|volatile)$/.test(token)) {
	    out[out.length]= prefix + term_so_far + token ;
	    prefix= term_so_far= '' ;

	} else if (token.match('^('+RE.IdentifierName+')$')) {
	    if ( newline_since_last_token
		 &&   /^(\)|\]|\+\+|\-\-)$|^([a-zA-Z\$\_\\\d'"]|\.\d|\/..)/.test(last_token)
		 && ! /^(case|delete|do|else|in|instanceof|new|typeof|void|function|var)$/.test(last_token) )
	    {
		out[out.length]= prefix + term_so_far ;
		prefix= '' ;
		term_so_far= token ;
	    } else {
		term_so_far+= token ;
	    }

	} else if (token=='.') {
	    term_so_far+= '.' ;

	} else if (token=='(') {
	    does_write= 1 ;
	    ex_s= _proxy_jslib_get_next_js_expr(s, 1) ;
	    s= ex_s[1] ;
	    term_so_far+= '(' + _proxy_jslib_proxify_js(ex_s[0], 0, with_level) + ')' ;
	    if (!(match= s.match(/^\)/))) break ;
	    s= s.slice(match.index+match[0].length) ;
	    new_last_token= ')' ;
	    div_ok= true ;


	} else if (token=='[') {
	    ex_s= _proxy_jslib_get_next_js_expr(s, 1) ;
	    s= ex_s[1] ;
	    sub_expr= _proxy_jslib_proxify_js(ex_s[0], 0, with_level) ;
	    if (!(match= s.match(/^\]/))) break ;
	    s= s.slice(match.index+match[0].length) ;
	    if (term_so_far) {
		_proxy_jslib_needs_jslib= true ;
		new_last_token= ')' ;
		if (prefix!='') {
		    term_so_far= "_proxy_jslib_assign('"+prefix+"', "+term_so_far+", ("+sub_expr+"), '', '')" ;
		    prefix= '' ;
		    div_ok= true ;
		} else if (match= s.match(RE.NEXTISINCDEC)) {
		    s= s.slice(match.index+match[0].length) ;
		    op= match[3] ;
		    term_so_far= "_proxy_jslib_assign('', "+term_so_far+", ("+sub_expr+"), '"+op+"', '')" ;
		    div_ok= true ;
		// use charAt() to avoid use of (?!...) construct in regex
		} else if ((match= s.match(RE.NEXTISASSIGN)) && (s.charAt(match[0].length)!='=')) {
		    s= s.slice(match.index+match[0].length) ;
		    op= match[3] ;
		    ex_s= _proxy_jslib_get_next_js_expr(s, 0) ;
		    s= ex_s[1] ;
		    new_val= _proxy_jslib_proxify_js(ex_s[0], 0, with_level) ;
		    term_so_far= "_proxy_jslib_assign('', "+term_so_far+", ("+sub_expr+"), '"+op+"', ("+new_val+"))" ;
		    div_ok= false ;
		} else {
		    term_so_far= "_proxy_jslib_handle("+term_so_far+", ("+sub_expr+"))" ;
		    if (last_token=='new') term_so_far= "("+term_so_far+")" ;
		    div_ok= true ;
		}
	    } else {
		term_so_far= '['+sub_expr+']' ;
		new_last_token= ']' ;
		div_ok= true ;
	    }


	} else if (RE.PUNCDIVPUNC.test(token)) {
	    out[out.length]= prefix + term_so_far + token ;
	    prefix= term_so_far= '' ;

	} else {
	    // shouldn't get here
	}

	if (token) {
	    last_token= new_last_token  ? new_last_token  : token ;
	    newline_since_last_token= false ;
	}

    }

    out[out.length]= prefix + term_so_far ;

    if (top_level && does_write) {
	out[out.length]= ' ;\n_proxy_jslib_flush_write_buffers() ;' ;
	_proxy_jslib_needs_jslib= true ;
    }

    return out.join('') ;



    // nesting the function lets us access and modify s
    function _proxy_jslib_get_next_js_term() {
	var o= '', p, ofrag, match, m2, ex_s ;

	if (!(match= s.match(RE.SKIPTOIDENTIFIER))) return [void 0, void 0] ;
	s= s.slice(match.index+match[0].length) ;
	p= "'" + match[3] + "'" ;
	ofrag= match[3] ;

	while (match= s.match(RE.SKIPTOOFRAG)) {
	    s= s.slice(match.index+match[0].length) ;
	    o+= ofrag ;
	    if (match[3]=='.') {
		if (!(m2= s.match(RE.SKIPTOIDENTIFIER))) return [void 0, void 0] ;
		s= s.slice(m2.index+m2[0].length) ;
		p= "'" + m2[3] + "'" ;
		ofrag= '.' + m2[3] ;
	    } else if (match[3]=='[') {
		ex_s= _proxy_jslib_get_next_js_expr(s, 1) ;
		s= ex_s[1] ;
		p= ex_s[0] ;
		ofrag= '[' + p + ']' ;
		if (!s.match(/^\]/)) return [void 0, void 0] ;
		s= s.slice(1) ;
	    } else if (match[3]=='(') {
		p= '' ;
		ex_s= _proxy_jslib_get_next_js_expr(s, 1) ;
		s= ex_s[1] ;
		ofrag= '(' + ex_s[0] + ')' ;
		if (!s.match(/^\)/)) return [void 0, void 0] ;
		s= s.slice(1) ;
	    }
	}
	return [o, p] ;
    }

}


// can't nest this because it's called from outside _proxy_jslib_proxify_js()
function _proxy_jslib_get_next_js_expr(s, allow_multiple) {
    var out= new Array(), p= new Array(), element, token, div_ok, last_token ;
    var RE= _proxy_jslib_RE ;

    while (1) {
	if (div_ok) {
	    if (!(match= s.match(RE.InputElementDiv))) break ;
	} else {
	    if (!(match= s.match(RE.InputElementRegExp))) break ;
	}
	s= s.slice(match.index+match[0].length) ;
	element= match[0] ;
	token= match[3] ;

	if (element==';' || element==',') {
	    if (!allow_multiple && p.length==0) {
		s= element+s ;
		return [out.join(''), s] ;
	    }

	} else if (/^[\x0a\x0d]$/.test(element)) {
	    if ( !allow_multiple && p.length==0
		 &&   /^(\)|\]|\+\+|\-\-)$|^([a-zA-Z\$\_\\\d'"]|\.\d|\/..)/.test(last_token)
		 && ! /^(case|delete|do|else|in|instanceof|new|typeof|void|function|var)$/.test(last_token)
		 &&   RE.SKIPTOIDENTIFIER.test(s) )
	    {
		s= element+s ;
		return [out.join(''), s] ;
	    }

	} else if (/^[\(\[\{\?]$/.test(element)) {
	    p[p.length]= element ;

	} else if (/^[\)\]\}\:]$/.test(element)) {
	    if (p.length==0) {
		s= element+s ;
		return [out.join(''), s] ;
	    }
	    if (p.length>0 && !(element==':' && p[p.length-1]!='?')) p.length-- ;
	    if (element=='}' && p.length==0 && !allow_multiple) {
		out[out.length]= element ;
		return [out.join(''), s] ;
	    }
	}

	out[out.length]= element ;

	if (token) {
	    div_ok= /^(\)|\]|\+\+|\-\-)$|^([a-zA-Z\$\_\\\d'"]|\.\d|\/..)/.test(token) ;
	    if (/^(case|delete|do|else|in|instanceof|new|return|throw|typeof|void)$/.test(token)) div_ok= false ;
	    last_token= token ;
	}
    }

    return p.length==0  ? [out.join(''), s]  : [void 0, s] ;
}



function _proxy_jslib_separate_last_js_statement(s) {
    var ex_s, rest= '', last= '' ;
    var RE= _proxy_jslib_RE ;

    for (ex_s= _proxy_jslib_get_next_js_expr(s, 0), s= ex_s[1] ;
	 ex_s[0] || s ;
	 ex_s= _proxy_jslib_get_next_js_expr(s, 0), s= ex_s[1] )
    {
	if (s.match(RE.GOTLASTSTATEMENT)) return [rest, last+ex_s[0]] ;
	if (match= s.match(RE.STATEMENTTERMINATOR)) {
	    s= s.slice(match[0].length) ;
	    rest+= last+ex_s[0]+';' ;
	    last= '' ;
	} else {
	    if (ex_s[0]=='') return [rest, last] ;
	    last+= ex_s[0] ;
	    if (s.match(/^,/)) {
		s= s.slice(1) ;
		last+= ',' ;
	    }
	}
    }
    return [rest, last] ;
}



function _proxy_jslib_set_RE() {
    if (!_proxy_jslib_RE) {  // saves time for multiple calls
	var RE= new Object() ;

	// count embedded parentheses carefully when using all these in matches!
	RE.WhiteSpace= '[\x09\x0b\x0c \xa0]' ;
	RE.LineTerminator= '[\x0a\x0d]' ;

	// messy without non-greedy matching
	RE.Comment= '\\/\\*\\/*([^\\*]\\/|[^\\*\\/]*|\\**[^\\/])*\\*\\/|\\/\\/[^\\x0a\\x0d]*|\\<\\!\\-\\-[^\\x0a\\x0d]*' ;

	RE.IdentifierStart= '[a-zA-Z\\$\\_]|\\\\u[\da-fA-F]{4}' ;
	RE.IdentifierPart= RE.IdentifierStart+'|\\d' ;
	RE.IdentifierName= '('+RE.IdentifierStart+')('+RE.IdentifierPart+')*' ;

	RE.Punctuator= '\\>\\>\\>\\=?|\\=\\=\\=|\\!\\=\\=|\\<\\<\\=|\\>\\>\\=|[\\<\\>\\=\\!\\+\\*\\%\\&\\|\\^\\-]\\=|\\+\\+|\\-\\-|\\<\\<|\\>\\>|\\&\\&|\\|\\||[\\{\\}\\(\\)\\[\\]\\.\\;\\,\\<\\>\\+\\*\\%\\&\\|\\^\\!\\~\\?\\:\\=\\-]' ;
	RE.DivPunctuator= '\\/\\=?' ;

	RE.NumericLiteral= '0[xX][\\da-fA-F]+|(0|[1-9]\\d*)(\\.\\d*)?([eE][\\+\\-]?\\d+)?|\\.\\d+([eE][\\+\\-]?\\d+)?' ;
	RE.EscapeSequence= 'x[\\da-fA-F]{2}|u[\\da-fA-F]{4}|0|[0-3]?[0-7]\D|[4-7][0-7]|[0-3][0-7][0-7]|[^\\dxu]' ;
	RE.StringLiteral= '"([^\\"\\\\\\x0a\\x0d]|\\\\('+RE.EscapeSequence+'))*"|'
			+ "'([^\\'\\\\\\x0a\\x0d]|\\\\("+RE.EscapeSequence+"))*'" ;
	RE.RegularExpressionLiteral= '\\/([^\\x0a\\x0d\\*\\\\\\/]|\\\\[^\\x0a\\x0d])([^\\x0a\\x0d\\\\\\/]|\\\\[^\\x0a\\x0d])*\\/('+RE.IdentifierPart+')*' ;

	RE.Token= RE.IdentifierName+'|'+RE.NumericLiteral+'|'+RE.Punctuator+'|'+RE.StringLiteral ;
	RE.InputElementDiv= '^('+RE.WhiteSpace+'+|'+RE.LineTerminator+'|'+RE.Comment+
			    '|('+RE.Token+'|'+RE.DivPunctuator+'|'+RE.RegularExpressionLiteral+'))' ;
	RE.InputElementRegExp= '^('+RE.WhiteSpace+'+|'+RE.LineTerminator+'|'+RE.Comment+
			       '|('+RE.Token+'|'+RE.RegularExpressionLiteral+'|'+RE.DivPunctuator+'))' ;

	RE.SKIP= RE.WhiteSpace+'+|'+RE.LineTerminator+'|'+RE.Comment ;
	RE.SKIP_NO_LT= RE.WhiteSpace+'+|'+RE.Comment ;

	// make RegExp objects out of the ones we'll use
	RE.InputElementDiv= new RegExp(RE.InputElementDiv) ;
	RE.InputElementRegExp= new RegExp(RE.InputElementRegExp) ;
	RE.N_S_RE= new RegExp('^('+RE.NumericLiteral+'|'+RE.StringLiteral+'|'+RE.RegularExpressionLiteral+')$') ;
	RE.DOTSKIPEND= new RegExp('\\.('+RE.SKIP+')*$') ;
	// avoid (?!...) construct for older compatibility; thus needs extra check when using it
//	RE.NEXTISASSIGN= new RegExp('^('+RE.SKIP+')*(\\>\\>\\>\\=|\\<\\<\\=|\\>\\>\\=|[\\+\\*\\/\\%\\&\\|\\^\\-]?\\=(?!\\=))') ;
	RE.NEXTISASSIGN= new RegExp('^('+RE.SKIP+')*(\\>\\>\\>\\=|\\<\\<\\=|\\>\\>\\=|[\\+\\*\\/\\%\\&\\|\\^\\-]?\\=)') ;
	RE.NEXTISINCDEC= new RegExp('^('+RE.SKIP_NO_LT+')*(\\+\\+|\\-\\-)') ;
	RE.SKIPTOPAREN= new RegExp('^(('+RE.SKIP+')*\\()') ;
	RE.SKIPTOCOLON= new RegExp('^(('+RE.SKIP+')*\\:)') ;
	RE.SKIPTOCOMMASKIP= new RegExp('^(('+RE.SKIP+')*\\,('+RE.SKIP+')*)') ;
	RE.PUNCDIVPUNC= new RegExp('^('+RE.Punctuator+'|'+RE.DivPunctuator+')$') ;
	RE.SKIPTOIDENTIFIER= new RegExp('^('+RE.SKIP+')*('+RE.IdentifierName+')') ;
	RE.SKIPTOOFRAG= new RegExp('^('+RE.SKIP+')*([\\.\\[\\(])') ;
	RE.GOTLASTSTATEMENT= new RegExp('^(;|'+RE.LineTerminator+'|'+RE.SKIP+')*$') ;
	RE.STATEMENTTERMINATOR= new RegExp('^(;|'+RE.LineTerminator+')') ;

	_proxy_jslib_RE= RE ;
    }
}




//---- utilities -------------------------------------------------------


// Determine type of an object (to the extent that we care), and return that as
//   a string.
// Use instanceof when possible; otherwise, take a heuristic guess at the type
//   based on existing properties of the object.
// This will only detect types that are specifically handled below.  For types
//   that are not, this returns ''.
// Properties are carefully selected to test correctly in both Mozilla and MSIE;
//   objects and properties vary slightly by browser.
// Unfortunately, Mozilla can't use instanceof with Link, Layer, or Form objects,
//   so the catch block will usually be called for that reason when using Mozilla.
// Unfortunately, Mozilla has a bug such that it dies when HTMLAreaElement.pathname
//   is accessed.  Thus, we wrap the inner heuristic block in a try/catch block too.
// typeof(), o.constructor, and o.toString() each have their problems.  :P
// Mozilla hangs on "o instanceof XMLHttpRequest", so avoid that.  :P
// jsm-- this still needs improvement and more testing....
function _proxy_jslib_object_type(o) {
    if ((o==null) || (typeof(o)!='object')) return null ;   // can't use instanceof yet

    try {
	if (o instanceof Window) return 'Window' ;
	if (o instanceof Document) return 'Document' ;
	if (o instanceof Location) return 'Location' ;
	if (o instanceof Image) return 'Image' ;
	if (o instanceof Attr) return 'Attr' ;
	if (o instanceof Node) return 'Node' ;
	if (o instanceof NamedNodeMap) return 'NamedNodeMap' ;
	if (o instanceof Range) return 'Range' ;
	if (o instanceof CSS2Properties) return 'CSS2Properties' ;
	if (o instanceof CSSPrimitiveValue) return 'CSSPrimitiveValue' ;
	if (o instanceof CSSStyleDeclaration) return 'CSSStyleDeclaration' ;
	if (o instanceof Link) return 'Link' ;
	if (o instanceof Layer) return 'Layer' ;
	if (o instanceof Form) return 'Form' ;
	// if (o instanceof XMLHttpRequest) return 'XMLHttpRequest' ;  // hangs
	if ((o.getAllResponseHeaders!==void 0) && (o.getResponseHeader!==void 0) && (o.setRequestHeader!==void 0))
	    return 'XMLHttpRequest' ;   // non-standard but usually supported

    } catch (e) {
//alert(e.toString()) ;
	try {

	    if ((o.navigator!==void 0) && (o.clearInterval!==void 0) && (o.moveBy!==void 0) && (o.self===o.window))
		return 'Window' ;
	    if ((o.alinkColor!==void 0) && (o.cookie!==void 0) && (o.writeln!==void 0))
		return 'Document' ;
	    if ((o.pathname!==void 0) && (o.protocol!==void 0) && (o.target!==void 0))
		return 'Link' ;   // must do before 'Location'
	    if ((o.pathname!==void 0) && (o.protocol!==void 0)  && (o.search!==void 0))
		return 'Location' ;
	    if ((o.background!==void 0) && (o.parentLayer!==void 0) && (o.moveAbove!==void 0))
		return 'Layer' ;
	    if ((o.hspace!==void 0) && (o.src!==void 0) && (o.border!==void 0))
		return 'Image' ;
	    if ((o.action!==void 0) && (o.encoding!==void 0) && (o.submit!==void 0))
		return 'Form' ;
	    if ((o.ownerElement!==void 0) && (o.specified!==void 0))
		return 'Attr' ;
	    if ((o.nodeName!==void 0) && (o.nodeType!==void 0) && (o.nodeValue!==void 0))
		return 'Node' ;  // must be here after descendents of Node
	    if ((o.getNamedItem!==void 0) && (o.removeNamedItem!==void 0) && (o.setNamedItem!==void 0))
		return 'NamedNodeMap' ;
	    if ((o.cloneRange!==void 0) && (o.compareBoundaryPoints!==void 0) && (o.surroundContents!==void 0))
		return 'Range' ;
	    if ((o.azimuth!==void 0) && (o.backgroundAttachment!==void 0) && (o.pageBreakInside!==void 0))
		return 'CSS2Properties' ;
	    if ((o.primitiveType!==void 0) && (o.getRectValue!==void 0) && (o.getCounterValue!==void 0))
		return 'CSSPrimitiveValue' ;
	    if ((o.getPropertyCSSValue!==void 0) && (o.getPropertyPriority!==void 0) && (o.removeProperty!==void 0))
		return 'CSSStyleDeclaration' ;
	    if ((o.getAllResponseHeaders!==void 0) && (o.getResponseHeader!==void 0) && (o.setRequestHeader!==void 0))
		return 'XMLHttpRequest' ;   // non-standard but usually supported
	} catch(e){
//alert(e.toString()) ;
	}
    }

    return '' ;
}



// Using JS (not RFC) terminology, this returns:
//   full_match, protocol, authentication, host, hostname, port, pathname, search, hash
function _proxy_jslib_parse_url(URL) {
    var u ;
    if (u= URL.match(/^(javascript\:|livescript\:)((.|\s)*)$/i))
	return [ URL, u[1].toLowerCase(), u[2] ] ;

    u= URL.match(/^([\w\+\.\-]+\:)\/\/([^\/\?\#\@]*\@)?(([^\:\/\?\#]*)(\:[^\/\?\#]*)?)([^\?\#]*)([^#]*)(.*)$/) ;
    if (u==null) return ;   // if pattern doesn't match
    for (var i= 0 ; i<u.length ; i++)  if (u[i]==void 0) u[i]= '' ;
    u[1]= u[1].toLowerCase() ;
    u[2]= u[2].replace(/\@$/, '') ;
    u[3]= u[3].toLowerCase() ;
    u[3]= u[3].replace(/\.+(:|$)/, '$1') ;  // close potential exploit
    u[4]= u[4].toLowerCase() ;
    u[4]= u[4].replace(/\.+$/, '') ;      // close potential exploit
    u[5]= u[5].replace(/^\:/, '') ;
    return u ;
}


// returns url_start (NOT including packed flags), packed flags, and decoded target URL.
// if URL is not a proxified URL, return undefined (and is legitimately used this way).
// jsm-- should clear up "return void 0" from "return [void 0, void 0, void 0]",
//   as this is called from elsewhere
function _proxy_jslib_parse_full_url(URL) {
    if (URL=='about:blank') return ['', '', 'about:blank'] ;
    if (URL.match(/^(javascript|livescript)\:/i)) return ['', '', URL] ;
    if (URL=='') return ['', '', ''] ;

    var cmp, path_cmp ;

    if (_proxy_jslib_PROXY_GROUP.length) {
	for (var i in _proxy_jslib_PROXY_GROUP) {
	    if (URL.substring(0,_proxy_jslib_PROXY_GROUP[i].length)==_proxy_jslib_PROXY_GROUP[i]) {
		path_cmp= URL.substring(_proxy_jslib_PROXY_GROUP[i].length).match(/\/([^\/\?]*)\/?([^\?]*)(\??.*)/) ;
//		if (path_cmp==null) alert("CGIProxy Error: Can't parse URL <"+URL+"> with PROXY_GROUP; not setting all variables correctly.") ;
		if (path_cmp==null) return void 0 ;
		return [_proxy_jslib_PROXY_GROUP[i],
			path_cmp[1],
			_proxy_jslib_wrap_proxy_decode(path_cmp[2])+path_cmp[3]] ;
	    }
	}
	return void 0 ;
    }

    cmp= URL.match(/^([\w\+\.\-]+)\:\/\/([^\/\?]*)([^\?]*)(\??.*)$/) ;
    if (cmp==null) return void 0 ;

    // hack to canonicalize "%7e" to "~"; should do other encoded chars too
    //   as long as replacing doesn't change semantics
    cmp[3]=cmp[3].replace(/\%7e/gi, '~') ;

    path_cmp= cmp[3].match(_proxy_jslib_RE_FULL_URL) ;
//    if (cmp==null || path_cmp==null) alert("CGIProxy Error: Can't parse URL <"+URL+">; not setting all variables correctly.") ;
    if (cmp==null || path_cmp==null) return void 0 ;

    return [cmp[1]+"://"+cmp[2]+path_cmp[1],
	    path_cmp[2],
	    _proxy_jslib_wrap_proxy_decode(path_cmp[3])+cmp[4]] ;
}


function _proxy_jslib_pack_flags(flags) {
    var pflags= new Array() ;
    for (var i= 0 ; i<6 ; i++) { pflags[i]= (flags[i]==1) ? '1' : '0' }
    pflags[6]= String.fromCharCode(_proxy_jslib_MIME_TYPE_ID[flags[6]]+65) ;  // only works through #26
    return pflags.join('') ;
}

function _proxy_jslib_unpack_flags(flagst) {
    var flags= flagst.split('') ;
    for (var i= 0 ; i<6 ; i++) { flags[i]= (flags[i]=='1') ? 1 : 0 }
    flags[6]= flags[6].charCodeAt(0)-65 ;     // only works through #26
    flags[6]= _proxy_jslib_ALL_TYPES[flags[6]] ;
    return flags ;
}



function _proxy_jslib_html_escape(s) {
    if (s==void 0) return '' ;
    s= s.replace(/\&/g, '&amp;') ;
    s= _proxy_jslib_global_replace(s, /([^\x00-\x7f])/,
		function (a) {
		    return '&#' + a[1].charCodeAt(0) + ';' ;
		} ) ;
    return s.replace(/\"/g, '&quot;')
	    .replace(/\</g, '&lt;')
	    .replace(/\>/g, '&gt;') ;
}

function _proxy_jslib_html_unescape(s) {
    if (s==void 0) return '' ;
    s= _proxy_jslib_global_replace(s, /\&\#(x)?(\w+);?/,
		function (a) { return a[1]
		    ? String.fromCharCode(eval('0x'+a[2]))
		    : String.fromCharCode(a[2])
		} ) ;
    return s.replace(/\&quot\b\;?/g, '"')
	    .replace(/\&lt\b\;?/g,   '<')
	    .replace(/\&gt\b\;?/g,   '>')
	    .replace(/\&amp\b\;?/g,  '&') ;
}



// The replace() method in Netscape is broken, :( :( so we have to implement
//   our own.  The bug is that if a function is used as the replacement pattern
//   (needed for anything complex), then *any* replace() or match() (and others?)
//   within that function (or in called functions) will cause its $' to
//   be used in place of the calling replace()'s $' .  :P
// Call this function with a string, a NON-GLOBAL (!) pattern with possible
//   parentheses, and a callback function that takes one argument that is the
//   array resulting from s.match(pattern), and returns a replacement string.
// Because of how this is implemented, ^ in pattern works much like Perl's \G.
function _proxy_jslib_global_replace(s, pattern, replace_function) {
    var out= '' ;
    var m1 ;
    while ((m1=s.match(pattern))!=null) {
	out+= s.substr(0,m1.index) + replace_function(m1) ;
	s= s.substr(m1.index+m1[0].length) ;
    }
    return out+s ;
}


//----------------------------------------------------------------------


