Note: This is not the complete source code--just the main source file.
You can download the full source (with include files) from our sample code archive by clicking on the diskette icons.

BrowserMirror.inc.vbs.asp

<%
'// Browser Mirror engine
'// version 2002-02-16
'// 
'// Displays information that your browser reveals to servers.
'//
'// Inputs (form variables):
'//   none
'//
'// HexGadgets (components) required:
'//   none
'//
'// Other dependencies:
'//   - VBScript 5.0 or later
'//     Get the latest at http://msdn.microsoft.com/scripting/
'//
'// History:
'// 2002-02-16  Created
'//
'// Copyright 2002 Hexillion Technologies. All rights reserved.
'// 
'// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
'// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
'// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND/OR
'// FITNESS FOR A PARTICULAR PURPOSE.


const sBrowserMirrorSession = "BrowserMirrorSession"
const sBrowserMirrorPersistent = "BrowserMirrorPersistent"
const sHexUtilityVars = "HexUtilityVars"
const sAspSession = "ASPSESSIONID"


class BrowserMirror

	private m_dtCookie

	property Get Name()
		Name = "Browser Mirror"
	end property
	
	property Get Desc()
		Desc = "See what your browser reveals"
	end property
	
	property Get ViewSourceURL()
		ViewSourceURL = "http://www.hexillion.com/samples/view_src.asp?name=BrowserMirror.inc.vbs.asp"
	end property
	
	property Get DownloadSourceURL()
		DownloadSourceURL = "http://www.hexillion.com/samples/#BrowserMirror"
	end property

	
	Private Sub Class_Initialize()
		
		'// Get date for designating current cookies
		m_dtCookie = now()
	end sub


	Private Sub Class_Terminate()
	end sub
	
	
	public function GetHead()
		'// Returns a string to put between the <head></head> tags
		
		'// Build cookie strings
		dim sSession, sPersist
		sPersist = "BrowserMirrorPersistent=" & _
		           server.URLEncode( m_dtCookie ) & _
		           "; expires=" & FormatGMT( DateAdd( "yyyy", 1, m_dtCookie ) ) & _
		           "; path=/"
		sSession = "BrowserMirrorSession=" & _
		           server.URLEncode( m_dtCookie ) & _
		           "; path=/"
		
		'// Set cookies with meta tags and JavaScript to try to circumvent HTTP header filtering
		GetHead = "<meta http-equiv=""Set-Cookie"" content=""" & sPersist & """>" & vbcrlf & _
		          "<meta http-equiv=""Set-Cookie"" content=""" & sSession & """>" & vbcrlf & _
		          "<SCRIPT LANGUAGE=""JavaScript"" TYPE=""text/javascript""><!--" & vbcrlf & _
		          "    // Intentional obfuscation to evade JavaScript ""sanitizers""" & vbcrlf & _
		          "    var d1 = document;" & vbcrlf & _
		          "    var c1 = 'c' + 'o' + 'o' + 'k' + 'i' + 'e';" & vbcrlf & _
		          "    d1[c1] = '" & sPersist & "';" & vbcrlf & _
		          "    d1[c1] = '" & sSession & "';" & vbcrlf & _
		          "//--></SCRIPT>"
		
	end function
	
	
	private function FormatGMT( dt )
		'// Put date into string format appropriate for cookie expiration dates
		FormatGMT = WeekdayName( Weekday( dt ), true ) & ", " & _
		            Format00( Day( dt ) ) & "-" & _
		            MonthName( Month( dt ), true ) & "-" & _
		            cstr( Year( dt ) ) & " " & _
					Format00( Hour( dt ) ) & ":" & _
					Format00( Minute( dt ) ) & ":" & _
					Format00( Second( dt ) ) & " GMT"
	end function
	
	
	private function Format00( i )
		if i < 10 then
			Format00 = "0" + cstr( i )
		else
			Format00 = cstr( i )
		end if
	end function


	Sub WriteForm()
		'// No input form needed
	end sub
	
	
	sub WriteOutput()
	
		'// Grab incoming test cookies first because setting them in 
		'// the response will change them in the request. (ASP bug?)
		dim sCookieSession, sCookiePersistent
		sCookieSession = Request.Cookies( sBrowserMirrorSession )
		sCookiePersistent = Request.Cookies( sBrowserMirrorPersistent )
	
		'// Set test cookies before flushing output
		Response.Cookies( sBrowserMirrorSession ) = m_dtCookie
		Response.Cookies( sBrowserMirrorSession ).Path = "/"
		Response.Cookies( sBrowserMirrorPersistent ) = m_dtCookie
		Response.Cookies( sBrowserMirrorPersistent ).Expires = DateAdd( "yyyy", 1, m_dtCookie )
		Response.Cookies( sBrowserMirrorPersistent ).Path = "/"

		'// Display any output so far
		Response.Flush
	
		ShowConnectionInfo
		ShowHeaders
		ShowCookies m_dtCookie, sCookieSession, sCookiePersistent
		ShowScripting
	end sub
	
	
	private sub ShowConnectionInfo
		'// Write heading
		WriteLn "<h3>Connection</h3>"
		
		dim sRequest
		sRequest = request( "REQUEST_METHOD" ) & " " & request( "URL" )
		if "" <> request( "QUERY_STRING" ) then sRequest = sRequest & "?" & request( "QUERY_STRING" )
		sRequest = sRequest & " " & request( "SERVER_PROTOCOL" )
		
		dim sCrypto
		if "on" = request( "HTTPS" ) then
			sCrypto = request( "HTTPS_KEYSIZE" ) & "-bit session key"
		else
			sCrypto = "none"
		end if
		
		dim sDomDoss
		sDomDoss = "DomainDossier.vbs.asp?dom_whois=1&net_whois=1&dom_dns=1&addr=" & request( "REMOTE_ADDR" )
		
		'// Write connection info
		WriteLn "<table border=""0"" cellpadding=""5"" cellspacing=""0"">"
		WriteLn "	<tr>"
		WriteLn "		<td valign=""baseline"" align=""right"">client IP address:</td>"
		WriteLn "		<td valign=""baseline"">"
		WriteLn "			<span class=""ipaddr"">" & request( "REMOTE_ADDR" ) & "</span>&nbsp; "
		WriteLn "			<a href=""" & sDomDoss & """>[see what this reveals]</a>"
		WriteLn "		</td>"
		WriteLn "	</tr>"
		WriteLn "	<tr>"
		WriteLn "		<td valign=""baseline"" align=""right"">server port:</td>"
		WriteLn "		<td valign=""baseline""><b>" & request( "SERVER_PORT" ) & "</b></td>"
		WriteLn "	</tr>"
		WriteLn "	<tr>"
		WriteLn "		<td valign=""baseline"" align=""right"">request:</td>"
		WriteLn "		<td valign=""baseline""><b>" & sRequest &  "</b></td>"
		WriteLn "	</tr>"
		WriteLn "	<tr>"
		WriteLn "		<td valign=""baseline"" align=""right"">encryption:</td>"
		WriteLn "		<td valign=""baseline""><b>" & sCrypto & "</b></td>"
		WriteLn "	</tr>"
		
		if "" <> request( "AUTH_TYPE" ) then
			WriteLn "	<tr>"
			WriteLn "		<td valign=""baseline"" align=""right"">authentication:</td>"
			WriteLn "		<td valign=""baseline""><b>" & request( "AUTH_TYPE" ) & "</b></td>"
			WriteLn "	</tr>"
			WriteLn "	<tr>"
			WriteLn "		<td valign=""baseline"" align=""right"">username:</td>"
			WriteLn "		<td valign=""baseline""><b>" & request( "AUTH_USER" ) & "</b></td>"
			WriteLn "	</tr>"
			
			if "basic" = lcase( request( "AUTH_TYPE" ) ) then
				WriteLn "	<tr>"
				WriteLn "		<td valign=""baseline"" align=""right"">password:</td>"
				WriteLn "		<td valign=""baseline""><b>" & request( "AUTH_PASSWORD" ) & "</b></td>"
				WriteLn "	</tr>"
			end if
		else
			WriteLn "	<tr>"
			WriteLn "		<td valign=""baseline"" align=""right"">authentication:</td>"
			WriteLn "		<td valign=""baseline""><b>none</b></td>"
			WriteLn "	</tr>"
		end if
				
		WriteLn "</table>"
		
		Response.Flush
	end sub
	
	
	private sub ShowHeaders
		'// Write heading
		WriteLn "<h3>HTTP headers</h3>"
		
		'// Write HTTP headers
		WriteLn "<pre>" & server.HTMLEncode( Request.ServerVariables( "ALL_RAW" ) ) & "</pre>"
		
		Response.Flush
	end sub
	
	
	private sub ShowCookies( dtNew, sCookieSession, sCookiePersistent )
		'// Write heading
		WriteLn "<h3>Cookies</h3>"
		
		dim sAcceptSession, sAcceptPersist, sSendSession, sSendPersist, sAspSession
		dim sButton
		sAcceptSession = "?"
		sAcceptPersist = "?"
		sSendSession = "?"
		sSendPersist = "?"
		sButton = "complete test"
		
		'// If this is a postback...
		if "" <> Request.Form( "key" ) then
			
			dim sDate
			sDate = Request.Form( "key" )
			
			'// If we got the session cookie we just set...
			if sDate = sCookieSession then
				sAcceptSession = "yes"
				sSendSession = "yes"
			
			'// Else if we at least got an old session cookie...
			elseif 0 <> len( sCookieSession ) then
				sAcceptSession = "no"
				sSendSession = "yes"
			
			else
				'// Cookie was neither received nor sent
				sAcceptSession = "no"
				sSendSession = "no"
			end if
			
			'// If we got the persistent cookie we just set...
			if sDate = sCookiePersistent then
				sAcceptPersist = "yes"
				sSendPersist = "yes"
				
			'// Else if we at least got an old persistent cookie...
			elseif 0 <> len( sCookiePersistent ) then
				sAcceptPersist = "no"
				sSendPersist = "yes"
			
			else
				'// Cookie was neither received nor sent
				sAcceptPersist = "no"
				sSendPersist = "no"
			end if
			
			sButton = "test again"
		end if
		
		'// Search for known cookies
		dim s, aCookies
			
		'// Use HTTP_Cookie because we've already set the Response
		'// cookies and ASP has put them in the Request.Cookies
		aCookies = split( request( "HTTP_Cookie" ), " " )
			
		for each s in aCookies
			
			if left( s, len( sBrowserMirrorSession ) ) = sBrowserMirrorSession then
				sSendSession = "yes"
					
			elseif left( s, len( sBrowserMirrorPersistent ) ) = sBrowserMirrorPersistent then
				sSendPersist = "yes"
					
			elseif left( s, len( sHexUtilityVars ) ) = sHexUtilityVars then
				sSendSession = "yes"
					
			elseif left( s, len( sAspSession ) ) = sAspSession then
				sSendSession = "yes"
			end if
		next

		WriteLn "<table border=""0"" cellpadding=""5"" cellspacing=""0"">"
		WriteLn "	<tr>"
		WriteLn "		<td valign=""baseline"" align=""right"">&nbsp;</td>"
		WriteLn "		<td valign=""baseline"" align=""center"">accepting</td>"
		WriteLn "		<td valign=""baseline"" align=""center"">sending</td>"
		WriteLn "	</tr>"
		WriteLn "	<tr>"
		WriteLn "		<td valign=""baseline"" align=""right"">session</td>"
		WriteLn "		<td valign=""baseline"" align=""center""><b>" & sAcceptSession & "</b></td>"
		WriteLn "		<td valign=""baseline"" align=""center""><b>" & sSendSession & "</b></td>"
		WriteLn "	</tr>"
		WriteLn "	<tr>"
		WriteLn "		<td valign=""baseline"" align=""right"">persistent</td>"
		WriteLn "		<td valign=""baseline"" align=""center""><b>" & sAcceptPersist & "</b></td>"
		WriteLn "		<td valign=""baseline"" align=""center""><b>" & sSendPersist & "</b></td>"
		WriteLn "	</tr>"
		WriteLn "</table>"
		
		WriteLn "<form name=""cookieform"" method=""POST"" action=""" & request( "SCRIPT_NAME" ) & """>"
		WriteLn "	<input type=""hidden"" name=""key"" value=""" & dtNew & """>"
		WriteLn "	<input id=""cookietest"" type=""submit"" value=""" & sButton & """>"
		WriteLn "</form>"
		
		Response.Flush
	end sub
	
	
	private sub ShowScripting
		'// This isn't meant to be an exhaustive list of all that can
		'// be obtained via client-side scripting. It just samples some
		'// of the more interesting items.
		
		'// Notice the obfuscation. The SafeWeb.com anonymizing service
		'// (which PrivaSec.com licenses) tries to "sanitize" JavaScript
		'// instead of stripping it out entirely. It breaks blocks of JS
		'// that it finds suspicious. The obfuscation tries to circumvent
		'// the sanitizing, though in some cases it's overkill--the sanitizing
		'// just doesn't work very well. It's also quite erratic, breaking
		'// innocent code while letting evil stuff slip right by.
		
		'// Observations about the SafeWeb sanitizing:
		'//
		'// - Suspicious assignments are flagged with extra semicolons on the end:
		'//       var suspect = 'suspicious';;
		'//
		'// - In the vicinity of suspicious code, any function calls get broken
		'//   with extra parentheses:
		'//       document.writeln()('My innocent text');
		'//
		'// - Javascript comments are stripped out everywhere *except* suspicious blocks.
		'//
		'// - For all the effort that the SafeWeb people apparently put into the
		'//   sanitizer, they missed a number of obvious security holes. For example,
		'//   Netscape browsers can still reveal the user's true IP address via
		'//       java.net.InetAddress.getLocalHost().getHostAddress();
		'//   Duh.
		'//
		'// - SafeWeb's "paranoid" mode does little more than modify all document.write
		'//   and document.writeln calls to write blanks. This will break a lot of
		'//   innocent code but is easily circumvented. And Netscape will still display
		'//   the true IP address. So much for paranoia.
		'//
		'// More about SafeWeb:
		'//   http://www.safeweb.com/
		'//   http://www.privasec.com/
		'//   http://www.wired.com/news/politics/0,1283,50371,00.html
		'//   http://www.cs.bu.edu/techreports/pdf/2002-003-deanonymizing-safeweb.pdf
	
	%>
<h3>Client-side scripting</h3>

<script language="JavaScript"><!--
	var version = '1.0';

	var d = document;
	var n = navigator;
	var w = 'w' + 'r' + 'i' + 't' + 'e' + 'l' + 'n';
	
	// SafeWeb's paranoid mode makes *any* VBScript
	// method called write or writeln shoot blanks, so
	// we've made this handy little function that
	// VBScript can call to display its output.
	function jsdw( s )
		{
		d[w]( s );
		}
	
//--></script>

<script language="JavaScript1.1"><!--
	var version = '1.1';
	
	// Turn off error reporting
	window.onerror = null;
//--></SCRIPT>

<script language="JavaScript1.2"><!--
	var version = '1.2';
//--></script>

<script language="JavaScript1.3"><!--
	var version = '1.3';
//--></script>

<script language="JavaScript1.4"><!--
	var version = '1.4';
//--></script>

<script language="JavaScript1.5"><!--
	var version = '1.5';
//--></script>

<script language="JavaScript1.6"><!--
	var version = '1.6';
//--></script>

<script language="JavaScript2.0"><!--
	var version = '2.0';
//--></script>

<table border="0" cellpadding="5" cellspacing="0">
	<tr>
		<td valign="baseline" align="right">JavaScript:</td>
		<td valign="baseline">
			<b>
				<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--
					d[w]( 'version ' + version );
				//--></SCRIPT>
				<noscript>disabled/not supported</noscript>
			</b>
		</td>
	</tr>
	<tr>
		<td valign="baseline" align="right">VBScript:</td>
		<td valign="baseline"><b ID="vbs">disabled/not supported</b></td>
		<SCRIPT LANGUAGE="VBScript" TYPE="text/vbscript"><!--
			'// This technique won't work for IE 3.
			document.all( "vbs" ).firstChild.nodeValue = "version " & ScriptEngineMajorVersion & "." & ScriptEngineMinorVersion & "." & ScriptEngineBuildVersion
		'--></SCRIPT>
	</tr>
	<tr>
		<td valign="baseline" align="right">Java:</td>
		<td valign="baseline">
			<b>
				<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--
					// SafeWeb/PrivaSec is suspicious of this block and breaks it.
					// By leaving this block in, however, the next block escapes breakage.
					document.writeln( '' );  
				//--></SCRIPT>
				<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--
					var je = 'j' + 'a' + 'v' + 'a' + 'E' + 'n' + 'a' + 'b' + 'l' + 'e' + 'd';
					if( n[je]() )
						{
						d[w]( 'enabled' );
						}
				//--></SCRIPT>
				<applet height="0" width="0">disabled/not supported</applet>
			</b>
		</td>
	</tr>
	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--
	
		// Personal profile
/*
		var n = navigator;
		if( "undefined" != typeof( n['userProfile'] ) )
			{
			var profile = n['userProfile'];

			profile.clearRequest();
			profile.addReadRequest("Vcard.FirstName");
			profile.addReadRequest("Vcard.LastName");
			profile.addReadRequest("Vcard.Email");
			profile.addReadRequest("Vcard.Home.Phone");
			profile.doReadRequest(1,"Browser Mirror");
			
			var name = profile.getAttribute("Vcard.FirstName") + ' ' + profile.getAttribute("Vcard.LastName" );
			var email = profile.getAttribute("Vcard.Email");
			var phone = profile.getAttribute("Vcard.Home.Phone");

			if( ' ' != name )
				{
				d[w]( '<tr>' );
				d[w]( '<td valign="baseline" align="right">name:</td>' );
				d[w]( '<td valign="baseline"><b>' + name + '</b></td>' );
				d[w]( '</tr>' );
				}
				
			if( '' != email )
				{
				d[w]( '<tr>' );
				d[w]( '<td valign="baseline" align="right">email:</td>' );
				d[w]( '<td valign="baseline"><b>' + email + '</b></td>' );
				d[w]( '</tr>' );
				}

			if( '' != phone )
				{
				d[w]( '<tr>' );
				d[w]( '<td valign="baseline" align="right">home phone:</td>' );
				d[w]( '<td valign="baseline"><b>' + phone + '</b></td>' );
				d[w]( '</tr>' );
				}
			}
*/
	//--></SCRIPT>
	
	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--
		
		// Try to get IP address
		if( "undefined" != typeof( java ) )
			{
			var j = java;
			var IPAddress = j.net.InetAddress.getLocalHost().getHostAddress();
			}
		
		// Close and reopen script block--a Java exception could kill this block
	//--></SCRIPT>
	
	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--

		// IP Address
		if( IPAddress )
			{
			d[w]( '<tr>' );
			d[w]( '<td valign="baseline" align="right">IP address:</td>' );
			d[w](   '<td valign="baseline"><span class="ipaddr">' + IPAddress + '</span>' );
			d[w]( '<a href="DomainDossier.vbs.asp?dom_whois=1&net_whois=1&dom_dns=1&addr=' + IPAddress + '">&nbsp; [see what this reveals]</a></td>' );
			d[w]( '</tr>' );
			}
		
	//--></SCRIPT>
	
	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--
	
		// Cookies
		// SafeWeb/PrivaSec and other services aggregate cookies from *all* sites
		// you visit into one master cookie, which the following will reveal.
		var c = 'c' + 'o' + 'o' + 'k' + 'i' + 'e';
		var gotcha = d[c];
		if( gotcha )
			{
			d[w]( '<tr>' );
			d[w]( '<td valign="baseline" align="right">cookies:</td>' );
			d[w]( '<td valign="baseline"><b>' + gotcha + '</b></td>' );
			d[w]( '</tr>' );
			}
			
	//--></SCRIPT>
	
	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--
	
		// Referrer
		if( d['referrer'] )
			{	
			d[w]( '<tr>' );
			d[w]( '<td valign="baseline" align="right">referrer:</td>' );
			d[w]( '<td valign="baseline"><b>' + d['referrer'] + '</b></td>' );
			d[w]( '</tr>' );
			}
		
	//--></SCRIPT>
	
	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--
	
		// Browser
		var n = navigator;
		var ua = 'u' + 's' + 'e' + 'r' + 'A' + 'g' + 'e' + 'n' + 't';
		var browser = n[ua];
		d[w]( '<tr>' );
		d[w]( '<td valign="baseline" align="right">browser:</td>' );
		d[w]( '<td valign="baseline"><b>' + browser + '</b></td>' );
		d[w]( '</tr>' );
		
	//--></SCRIPT>
	
	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--
	
		// Plugins - Netscape
		var pi = 'p' + 'l' + 'u' + 'g' + 'i' + 'n' + 's';
		if( "undefined" != typeof( n[pi] ) )
			{
			var ps = n[pi];
			
			if( ps.length > 0 )
				{
				d[w]( '<tr>' );
				d[w]( '<td valign="top" align="right">plugins:</td>' );
				d[w]( '<td valign="top">' );
				d[w]( '<table border="0" cellpadding="5" cellspacing="0">' );

				for( var i=0; i<ps.length; i++ )
					{
					d[w]( '<tr>' );
					d[w]( '<td valign="baseline"><b>' + ps[i].name + '</b></td>' );
					d[w]( '<td valign="baseline"><b>' + ps[i].description + '</b></td>' );
					d[w]( '<td valign="baseline"><b>' );
					
					for( var i2=0; i2<ps[i].length; i2++ )
						{
						d[w]( ps[i][i2].type + '<br>' );
						}
					
					d[w]( '</b></td>' );
					d[w]( '<td valign="baseline"><b>' + ps[i].filename + '</b></td>' );
					d[w]( '</tr>' );
					}
			
				d[w]( '</table>' );
				d[w]( '</td></tr>' );
				}
			}
	//--></SCRIPT>

	<SCRIPT LANGUAGE="VBScript" TYPE="text/vbscript"><!--
	
		'// ActiveX plugins - IE
		sub Detect( ProgID, Description )
			On Error resume next
			dim o
			if ScriptEngineMajorVersion() >= 2 then
				set o = CreateObject( ProgID )
				if Err = 0 then jsdw Description & "<br>"
			end if
		end sub
		
		jsdw "<tr>"
		jsdw "<td valign=""baseline"" align=""right"">ActiveX:</td>"
		jsdw "<td valign=""baseline""><b>"
		
		Detect "ShockwaveFlash.ShockwaveFlash", "Macromedia Flash Player"
		Detect "SWCtl.SWCtl", "Macromedia Shockwave Player"
		Detect "Macromedia.ActiveShockwave.1", "Active Shockwave"
		Detect "RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)", "RealPlayer"
		Detect "rmocx.RealPlayer G2 Control", "RealPlayer G2"
		Detect "IERJCtl.IERJCtl.1", "RealJukebox"
		Detect "MediaPlayer.MediaPlayer.1", "MediaPlayer"
		Detect "PDF.PdfCtrl.1", "Adobe Acrobat 1.0 Reader"
		Detect "PDF.PdfCtrl.2", "Adobe Acrobat 2.0 Reader"
		Detect "PDF.PdfCtrl.3", "Adobe Acrobat 3.0 Reader"
		Detect "PDF.PdfCtrl.4", "Adobe Acrobat 4.0 Reader"
		Detect "PDF.PdfCtrl.5", "Adobe Acrobat 5.0 Reader"
		Detect "Agent.Control.1", "MS Agent 1.5"
		Detect "Agent.Control.2", "MS Agent 2.0"
		Detect "MSComCtl2.Animation", "MS Animation"
		Detect "DirectAnimation.DirectAnimationIntegratedMediaControl.1", "MS DirectAnimation"
		Detect "MSVRML2C.VRMLBrowserCtl.1", "MS VRML 2.0 Viewer"
		
		jsdw "</b></td>"
		jsdw "</tr>"
		
	'--></SCRIPT>
		
	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--
			// SafeWeb/PrivaSec is suspicious of this block and breaks it.
			// By leaving this block in, however, the next block escapes breakage.
			document.writeln( '' );
	//--></SCRIPT>
		
	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--
		
		// Clipboard
		var ec = 'e' + 'x' + 'e' + 'c' + 'C' + 'o' + 'm' + 'm' + 'a' + 'n' + 'd';
		var pste = 'p' + 'a' + 's' + 't' + 'e';
		var ctr = 'c' + 'r' + 'e' + 'a' + 't' + 'e' + 'T' + 'e' + 'x' + 't' + 'R' + 'a' + 'n' + 'g' + 'e';
		
		if( "undefined" != typeof( d[ec] ) )
			{
			d[w]( '<tr>' );
			d[w]( '<td valign="top" align="right">clipboard:</td>' );
			d[w]( '<td><form name="clipform">' );
			d[w]( '<textarea id="cliptext" rows="5" cols="50"></textarea>' );
			d[w]( '</form></td>' );
			d[w]( '</tr>' );
			
			d['clipform']['cliptext']['focus']();
			d['clipform']['cliptext'][ctr]()[ec]( pste );
			window['scroll']( 0, 0 );
			}
	//--></SCRIPT>

	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--

		// Local time
		d[w]( '<tr>' );
		d[w]( '<td valign="baseline" align="right">local time:</td>' );
		d[w]( '<td valign="baseline"><b>' + (new Date()) + '</b></td>' );
		d[w]( '</tr>' );

	//--></SCRIPT>

	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--

		// Screen dimensions
		if( "undefined" != typeof( screen ) )
			{
			d[w]( '<tr>' );
			d[w]( '<td valign="baseline" align="right">screen:</td>' );
			d[w]( '<td valign="baseline"><b>' + screen.width + 'x' + screen.height + '&nbsp; ' + screen.colorDepth + ' bits/pixel</b></td>' );
			d[w]( '</tr>' );
			}

	//--></SCRIPT>

	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--

		// Browser window dimensions
		if( "undefined" != typeof( window.screenX ) &&
		    "undefined" != typeof( window.screenY ) &&
		    "undefined" != typeof( window.outerWidth ) &&
		    "undefined" != typeof( window.outerHeight ) )
			{
			d[w]( '<tr>' );
			d[w]( '<td valign="baseline" align="right">window:</td>' );
			d[w]( '<td valign="baseline"><b>' + window.outerWidth + 'x' + window.outerHeight + '&nbsp; (' + window.screenX + ',' + window.screenY + ')</b></td>' );
			d[w]( '</tr>' );
			}

	//--></SCRIPT>

	<SCRIPT LANGUAGE="JavaScript" TYPE="text/javascript"><!--

		// Web page dimensions			
		if( "undefined" != typeof( window.innerWidth ) &&
			"undefined" != typeof( window.innerHeight ) )
			{
			d[w]( '<tr>' );
			d[w]( '<td valign="baseline" align="right">page:</td>' );
			d[w]( '<td valign="baseline"><b>' + window.innerWidth + 'x' + window.innerHeight + '</b></td>' );
			d[w]( '</tr>' );
			}
		else if( "undefined" != typeof( document.body ) )
			{
			if( "undefined" != typeof( document.body.clientWidth ) &&
			    "undefined" != typeof( document.body.clientHeight ) )
				{
				d[w]( '<tr>' );
				d[w]( '<td valign="baseline" align="right">page:</td>' );
				d[w]( '<td valign="baseline"><b>' + document.body.clientWidth + 'x' + document.body.clientHeight + '</b></td>' );
				d[w]( '</tr>' );
				}
			}
	//--></SCRIPT>
	
</table>
	<%
	end sub
	
	
	private sub WriteLn( s )
		Response.Write s & vbcrlf
	end sub
	
end class
%>