All pastes #155749 Raw Edit

New

public javascript v1 · immutable
#155749 ·published 2006-08-31 09:40 UTC
rendered paste body
// If you want to install this script, right-click <span class="plainlinks">[http://www.hrwiki.org/index.php?title=User:Phlip/Greasemonkey&action=raw&ctype=text/javascript&fakeextension=.user.js this link]</span> and chose "Install User Script".<br>// If that option is not there, then you need to install [http://www.mozilla.org/firefox/ Firefox] and [http://greasemonkey.mozdev.org/ Greasemonkey], and then restart Firefox and return to this page.<br>// To update the script, if you have an old version, Go to Tools&rarr;Manage&nbsp;User&nbsp;Scripts, click on "Homestar&nbsp;All&#8209;In&#8209;One" and click "Uninstall". Then re-install it from the link above. <pre>// Homestar All-In-One// version 3.0// 2006-08-29// Copyright (c) Phillip Bradbury, Loafing, T Rice, Jesse Ruderman//// A combination of several useful scripts for Homestar Runner cartoons://  Homestar-Fullon, a greasemonkey script for making H*R cartoons fullscreen.//  Seek Bar, a bookmarklet that adds a progress bar to flash cartoons//   (with modifications).//  Previous/Next buttons for Strong Bad Emails, TGS, Marzipan's//   Answering Machine, Biz Cas Fri, Puppet Jams and main pages.//  An HRWiki link on all pages.//  The ability, if you turn on the "fullscreen" option, to keep the actual//   stage the same size (so you can see "outside the frame").//  Turning everything upside-down, like on April Fools Day, 2006.//  A plain-HTML navbar, to replace the Flash one. This is mostly for me//   as the navbar doesn't work right on my computer (font problems).//   It could also be useful for others, letting you middle-click the navbar//   to open things in new tabs.//  Loading subtitles from the wiki and displaying them beneath the toon.// All of these can easily be turned on or off with the "Preferences" box//  in the top left.//// Released under the GPL.//// Homestar-Fullon written by T Rice <timgm@bcheck.net> and is//  released under the GPL.//  http://dana.ucc.nau.edu/~tsr22/apps/greasemonkey///// Seek bar written by Jesse Ruderman <jruderman@hmc.edu> and is//  distributed with permission ("You may modify and/or distribute//  up to three bookmarklets from this site in any way you want.")//  http://www.squarefree.com/bookmarklets///  Originally it was just the Pause button and the seek bar,//  I modified it to add a frame counter, frame step buttons and zoom buttons.//  I also modified it so the Pause button automatically updates when the flash//  movie pauses itself (eg at the end of the toon).//// Previous/Next buttons written by Phillip Bradbury, but inspired by//  StrongBad Emails: Prev & Next from http://userscripts.org/scripts/show/1015//// HRWiki link also written by Phillip Bradbury, but inspired by an attempt//  by Tom Preuss to do the same thing - except it did the translation from//  URL to Wiki page name in the script, this does it at the HRWiki server//  so that when a new toon comes out, the script doesn't need to be changed.//  http://www.hrwiki.org/index.php/User:Tom/Greasemonkey_Script//// Subtitles written in collaboration with "Loafing"//  http://www.hrwiki.org/index.php/User:Loafing//// Direct any comments to//  http://www.hrwiki.org/index.php/User_talk:Phlip/Greasemonkey//// --------------------------------------------------------------------//// WARNING: This script explicitly avoids use of one of Greasemonkey's security//  features. THIS SCRIPT SHOULD NOT BE USED on ANY page where you do not trust//  the page writer. Not that it would make sense to anyway, given it's rather//  Homestar-specific. Your use of this script is stating that you trust//  The Brothers Chaps to not insert malicious code into the Homstar Runner site,//  and the HRWiki admins to not put any on the mirror.//// One of the security features of Greasemonkey, used to plug its holes in//  previous versions, is Mozilla's XPCNativeWrapper, which is used to ensure//  that you're calling the real functions of objects on the page, and not//  weird and potentially hazardous ones written by the page designer. However//  this also blocks functions like flashmovie.CurrentFrame() which are needed//  by the seek bar. Thus to make the seek bar work, I needed to turn this off.//// --------------------------------------------------------------------//// This is a Greasemonkey user script.//// To install, you need Greasemonkey: http://greasemonkey.mozdev.org/// Then restart Firefox and revisit this script.// Under Tools, there will be a new menu item to "Install User Script".// Accept the default configuration and install.//// To uninstall, go to Tools/Manage User Scripts,// select "Homestar All-In-One", and click Uninstall.//// --------------------------------------------------------------------//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA//// --------------------------------------------------------------------//// ==UserScript==// @name          Homestar All-In-One// @namespace     http://www.hrwiki.org/// @description	  Combination of many Homestar Runner scripts. Version 3.0.// @include       http://homestarrunner.com/*// @include       http://www.homestarrunner.com/*// @include       http://podstar.homestarrunner.com/*// @include       http://videlectrix.com/*// @include       http://www.videlectrix.com/*// @include       http://hrwiki.org/mirror/*// @include       http://www.hrwiki.org/mirror/*// @include       https://secure.homestarrunner.com/heythanks.html*// ==/UserScript==// Podstar/Videlectrix and HRWiki error pages, respectively. Don't do anything on those pages.if (document.title != "The page cannot be found" && document.title != "Homestar Runner Wiki - 404 Not Found"){	var whichsite = 0;	if (location.hostname.indexOf("podstar") >= 0) whichsite = 1;	if (location.hostname.indexOf("videlectrix") >= 0) whichsite = 2;	if (location.pathname.indexOf("/mirror/") >= 0) whichsite = 3;		// icons, as Base64-encoded PNG files.	// the hrwiki one used to hotlink http://www.hrwiki.org/favicon.ico but now	// use "data:" to avoid bandwidth-leeching (even this minor)	var image_hrwiki = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQ" +		"CAMAAAAoLQ9TAAAAzFBMVEXsFQgrPqLjBgDQDw7yAwA8PrbBGhr/AABCRcLfHBvTIiHBKy5" +		"OVKvCNTj/HRS8S1T/MzPgR0b2Q0Rcf611d7jSWGG9Ynd6fc5fkdPpZW5mmcybhaekgqK2fJ" +		"SWlXF4lctlnt3/ZmbbdXqFlMWSkbi5kkqVnIN9ncvYfIeToaqhmrCApNaolruNoc/Ij53/f" +		"Xy1p2eFqty1qX+Tr8/0jpSgsteftdDCr8q4ud3Wtanqq6qtweLrtMDVwszsxb3M1eLu59j7" +		"9PT///8lJce4h/WNAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAs" +		"TAQCanBgAAAAHdElNRQfWBRkTLxz1P7v8AAAAyklEQVQY02XP23aCMBAF0DQaIxUjBrCjEi" +		"9oRIWotRUrWC/w//9kIssn5+GsOXvNyyD0NnI/MqnnBTaRcrH+WS92FUmPzCMV5XEs/KfIV" +		"VkSL73nS2Z9GpGjsvk1uxdF1k96T5Ckmdp/xc0KYGUgGrhEefZH2g1c10YIklMylgd1Gl90" +		"bEADdxSKz3x4zc/MB33CqYDDlvoDNcW6Iwgo/84Yrqsj6xhA4LB/3l7S7BcPKxDMwUIxp96" +		"G6htguAWTkNbEC0KzgtUw/QHI7xdXgqr/KgAAAABJRU5ErkJggg==";	var image_prefs = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQC" +		"AMAAAAoLQ9TAAAAllBMVEUAGQASEhIfHx8fJy8pKSk2NjZBQUFJR0ZQUE9RUVFSUlJNX3No" +		"aGhsaWdramlycG1meY98fHx+fn5wgpV0iqKKh4R4jaR9jJx8kad9kad/mbONmaWEnrmEnrq" +		"koZy3t7fIx8bKyMHT0c3S0dDU09DV1NPP1t3W1dXY2Njb2tfe29bf3tzj4uHr6+js6+r39/" +		"f5+PgAAABrL3yvAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTA" +		"QCanBgAAAAHdElNRQfWBRoFKh31UQ8DAAAAgUlEQVQY022OxxLCMAwFRSc4BEIPJZQQ08v+" +		"/8+RsTExDDpIe3ijfSJ/hx9g62Dt4GaAI+8YT0t27+BxxvvE/no5pYT10lGFrE34Ja40W3g" +		"1oMGmW7YZ6hnCYexKTPVkXivuvWe1Cz1aKqPNI3N0slI2TNYZiARJX30qERc7wBPKC4WRDz" +		"WdWHfmAAAAAElFTkSuQmCC";	var image_close = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQC" +		"AQAAAC1+jfqAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfW" +		"BRkTNhxuPxLkAAAAHXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBUaGUgR0lNUO9kJW4AAAE" +		"KSURBVCjPhdGxSgNBFAXQMzpgYWwsLEQUDBJBQgqFIChZEPR7/DA/QCGQTgQtJE1ENoWohY" +		"UgbGKQyFjErNv52nObe19wqGWg7z0l5YVgVdOu+wUt507tqIVQ4Zodp861ooELe15M5KFI6" +		"Zfr9u25MIj6Jl4cmSIPBWrq2o5cufO4aOJDYSozNTa2pK4t03PtwUdMKRRykAmW0dTRcyNX" +		"pBQpI8GJDTR050zkNzK0bMMZLvUNZ8yCfy6Wvbc1NVyi4dloXjqWvds6uvp41pFmpVOKJWd" +		"6bgwxkmTMIotWKpwrfBkZl7uMonUHf5wSlV2+fUZrjnXdzrmyy7djD8GWTW9e51z557o1Tz" +		"85FH/WkOkaHQAAAABJRU5ErkJggg==";		settingnames = new Array(		{name: 'resize',    title: 'Resize flash to full-screen',            tooltip: 'Resizes the toon so it fills the entire window',                              def: 1},		{name: 'noscale',   title: ' Show outside-the-frame action',         tooltip: 'Lets you see what\'s happening beyond the frames',                            def: 0},		{name: 'showmenu',  title: 'Enable right-click menu',                tooltip: 'Enables the right-click context menu',                                        def: 1},		{name: 'seekbar',   title: 'Show seek bar',                          tooltip: 'Lets you fast forward and rewind',                                            def: 1},		{name: 'frames',    title: ' Show frame counter on seek bar',        tooltip: 'Shows you exactly where you are',                                             def: 1},		{name: 'hrwiki',    title: 'Add HRWiki link',                        tooltip: 'Adds a link to the appropriate page on the Homestar Runner Wiki',             def: 1},		{name: 'prevnext',  title: 'Show previous/next buttons',             tooltip: 'Lets you easily move through SBEmails, TGS, etc',                             def: 1},		{name: 'checknext', title: ' Check if next exists',                  tooltip: 'Doesn\'t add a "next" link on the latest SBEmail, etc',                       def: 0},		{name: 'flipper',   title: 'Turn everything upside-down',            tooltip: 'Relive the mania of inverted April Fools Day Homestar Runner',                def: 0},		{name: 'navbar',    title: 'Plain HTML navbar',                      tooltip: 'Replaces the flash navbar with normal links... so you can open in tabs, etc', def: 0},		{name: 'randot',    title: ' Include Big Toons in rando',            tooltip: 'Limit the "rando" function to what you like to watch',                        def: 1},		{name: 'randosh',   title: ' Include Shorts in rando',               tooltip: 'Limit the "rando" function to what you like to watch',                        def: 1},		{name: 'randoho',   title: ' Include Holiday toons in rando',        tooltip: 'Limit the "rando" function to what you like to watch',                        def: 1},		{name: 'randop',    title: ' Include Puppet Stuff in rando',         tooltip: 'Limit the "rando" function to what you like to watch',                        def: 1},		{name: 'randoteh',  title: ' Include Powered by The Cheat in rando', tooltip: 'Limit the "rando" function to what you like to watch',                        def: 1},		{name: 'randosb',   title: ' Include Strong Bad Emails in rando',    tooltip: 'Limit the "rando" function to what you like to watch',                        def: 1},		{name: 'randoam',   title: ' Include Answering Machine in rando',    tooltip: 'Limit the "rando" function to what you like to watch',                        def: 1},		{name: 'randotgs',  title: ' Include Teen Girl Squad in rando',      tooltip: 'Limit the "rando" function to what you like to watch',                        def: 1},		{name: 'subtitles', title: 'Show subtitles',                         tooltip: 'Shows subtitles or captions below the toon, if any are available',            def: 0},		{name: 'captions',  title: ' Show captions',                         tooltip: 'Include sound effects in the subtitles',                                      def: 1},		{name: 'colours',   title: ' Use colours',                           tooltip: 'Distinguish characters by colour effects (turn off if colourblind)',          def: 1},		{name: 'voiceover', title: '  Show names on voiceovers',             tooltip: 'Show the speakers name if they aren\'t on the screen',                        def: 1},		{name: 'testsubs',  title: ' Test subtitles script',                 tooltip: 'Use this to test a subtitles script (copy/paste into a text box)',            def: 0}	);	settings = {};	for (i = 0; i < settingnames.length; i++)		settings[settingnames[i].name] = GM_getValue(settingnames[i].name, settingnames[i].def) != 0;	settings['language'] = GM_getValue('language', 'en');	defaultxmlfile = escape('<?xml version="1.0" encoding="utf-8"?>\n<transcript xml:lang="en-us">\n<line start="" end="" speaker=""></line>\n</transcript>');	settings['testsubsdata'] = unescape(GM_getValue('testsubsdata', defaultxmlfile));	extrasettings = new Array();		addsettingsbox();		document.body.style.margin = "0px";		// find flash objects	switch (whichsite)	{		case 0: // www.homestarrunner.com			var objs = document.getElementsByTagName("EMBED");			if (objs && objs.length >= 2)			{				var flashmovie = objs[0];				var navbar = objs[1];			}			else if (objs && objs.length >= 1)			{				var flashmovie = objs[0];				var navbar = false;			}			else			{				var flashmovie = false;				var navbar = false;			}			if (!flashmovie)			{				objs = document.getElementsByTagName("OBJECT");				if (objs && objs.length >= 1)					var flashmovie = objs[0];			}			break;		case 1: // podstar.homestarrunner.com			var objs = document.getElementsByTagName("EMBED");			var flashmovie = false;			if (objs && objs.length >= 1)				var navbar = objs[0];			else				var navbar = false;			break;		case 2: // videlectrix			var objs = document.getElementsByTagName("EMBED");			var navbar = false;			if (objs && objs.length >= 1)				var flashmovie = objs[0];			else				var flashmovie = false;			settings.navbar = false;			break;		case 3: // mirror			var objs = document.getElementsByTagName("EMBED");			var flashmovie = false;			if (objs && objs.length >= 1)				var flashmovie = objs[0];			if (!flashmovie)			{				objs = document.getElementsByTagName("OBJECT");				if (objs && objs.length >= 1)					var flashmovie = objs[0];			}			navbar = document.getElementById('navbar');			if (!navbar)				settings.navbar = false;			var flashcontainer = document.getElementById('flash');			if (flashcontainer)				flashcontainer.style.width = "auto";			break;	}	if (flashmovie)	{		//expose Flash plugin-added methods		flashmovie = flashmovie.wrappedJSObject;				// confirm that this is really a flash file		// and not (for example) the embedded background sound on SB's website		if (flashmovie.nodeName.toLowerCase() == "object")		{			var src = flashmovie.getAttribute('src');			if (src)			{				if (src.substring(src.length - 4).toLowerCase() != ".swf")					flashmovie = false;			}			else			{				a = flashmovie.getElementsByTagName('param').namedItem("movie");				if (!a || a.value.substring(a.value.length - 4).toLowerCase() != ".swf")					flashmovie = false;			}		}		else if (flashmovie.nodeName.toLowerCase() == "embed")		{			var src = flashmovie.getAttribute('src');			if (!src || src.substring(src.length - 4).toLowerCase() != ".swf")				flashmovie = false;		}	}		if (!flashmovie)		settings.resize = settings.seekbar = settings.frames = settings.flipper = settings.noscale = settings.showmenu = settings.subtitles = false;	if (settings.flipper)		settings.seekbar = settings.subtitles = false;		// globals	var settingsbox;	var seekbar;	var isPercentage = false;	var aspect = 1.0;	var randolink;	var randourls = new Array();	var subtitleholder;	var transcript = new Array();	var nosubtitles = document.createComment("");	var currentsubtitles = nosubtitles;	var characters = {		"sfx": {			"color": "#FFF",			"sfx": true,			"name": {"en": ""}		}	};	var transcriptErrors;		// used by wikilink, prevnext, flipper... put it out here.	var filename = location.pathname.toLowerCase();	i = filename.lastIndexOf('/');	if (i >= 0)		filename = filename.substr(i + 1);	i = filename.lastIndexOf('.');	if (i >= 0)		filename = filename.substr(0,i);		// pull puppet stuff out of its background	if ((settings.flipper || settings.seekbar || settings.subtitles) && flashmovie.src=="puppet_background.swf")	{		var flashvars = getFlashVars();		if (flashvars.videoName)			replaceFlash(flashvars.videoName);	}		if (settings.navbar)		replacenavbar();	if (settings.subtitles)		setupSubtitles();	if (settings.seekbar)		addFlashControls(flashmovie);	if (settings.resize)		resize();	if (settings.resize && settings.noscale)		noscale();	if (settings.showmenu)		showmenu();	if (settings.hrwiki)		wikilink();	if (settings.prevnext)		prevnext();	if (settings.flipper && whichsite == 0)		flipper();		// mess with popup windows - make them bigger and resizeable	var oldopen = unsafeWindow.open;	unsafeWindow.open = function(a,b,c)	{		c = c.split(/,/);		var opts = {};		for (var i = 0; i < c.length; i++)		{			var d = c[i].split(/=/);			if (d.length == 2)				opts[d[0]] = d[1];		}		opts["width"] = window.screen.width * 0.8;		opts["height"] = window.screen.height * 0.8;		opts["resizeable"] = "yes";		c = "";		for (var i in opts)		{			c += i + "=" + opts[i] + ",";		}		return oldopen(a,b,c);	}}function replaceFlash(url){	where = flashmovie;	while (where && where.parentNode && where.parentNode.nodeName.toLowerCase() == "object")		where = where.parentNode;	var newFlash=document.createElement("object");	newFlash.setAttribute("width",flashmovie.width);	newFlash.setAttribute("height",flashmovie.height);	newFlash.setAttribute("type","application/x-shockwave-flash");	newFlash.setAttribute("bgcolor",flashmovie.bgcolor ? flashmovie.bgcolor : "#FFFFFF");	newFlash.setAttribute("data",url);		where.parentNode.replaceChild(newFlash,flashmovie);		flashmovie=newFlash.wrappedJSObject;}function getSWFFilename(){	// try to find the filename	var a = flashmovie.src;	if (!a)		a = flashmovie.data;	if (!a)	{		a = flashmovie.getElementsByTagName('param').namedItem('movie');		if (a)			a = a.value;	}	return a;}function getFlashVars(){	var flashvars = new Object();	var flashvarsstring = flashmovie.getAttribute("FlashVars");	if (!flashvarsstring)	{		flashvarsstring = flashmovie.getElementsByTagName('param').namedItem('FlashVars');		if (flashvarsstring)			flashvarsstring = flashvarsstring.value;	}	// parse the string	if (flashvarsstring)	{		var flashvarsparts = flashvarsstring.split('&');		for (var i = 0; i < flashvarsparts.length; i++)		{			var a = flashvarsparts[i].split('=');			if (a.length == 2)				flashvars[unescape(a[0])] = unescape(a[1]);		}	}	var filename = getSWFFilename();	var i = filename.indexOf('?');	if (i >= 0)	var flashvarsstring = filename.substring(i + 1);	if (flashvarsstring)	{		var flashvarsparts = flashvarsstring.split('&');		for (var i = 0; i < flashvarsparts.length; i++)		{			var a = flashvarsparts[i].split('=');			if (a.length == 2)				flashvars[unescape(a[0])] = unescape(a[1]);		}	}	return flashvars;}function addsettingsbox(){	settingsbox = document.createElement('div');	settingsbox.style.borderRight = settingsbox.style.borderBottom = '1px solid #666';	settingsbox.style.background = '#EEE';	settingsbox.style.color = '#000';	settingsbox.style.position = 'fixed';	settingsbox.style.left = 0;	settingsbox.style.top = 0;	settingsbox.style.width = '350px';	settingsbox.style.font = '12px sans-serif';	settingsbox.style.textAlign = 'left';	settingsbox.style.display = 'none';	document.body.appendChild(settingsbox);	var titlebar = document.createElement('div');	titlebar.style.fontWeight = "bolder";	titlebar.style.background = "#CCC";	titlebar.style.borderBottom = "1px solid #666";	titlebar.style.padding = '3px';	settingsbox.appendChild(titlebar);	var closebutton = document.createElement('img');	closebutton.src = image_close;	closebutton.title = "Click to hide preferences";	closebutton.style.cssFloat = "right";	closebutton.style.verticalAlign = "text-bottom";	closebutton.style.cursor = "pointer";	closebutton.style.display = "block";	closebutton.addEventListener('click', function(){settingsbox.style.display = "none"; settingslink.style.display = "block";}, false);	titlebar.appendChild(closebutton);	var prefslogo = document.createElement('img');	prefslogo.src = image_prefs;	prefslogo.style.verticalAlign = "text-bottom";	titlebar.appendChild(prefslogo);	titlebar.appendChild(document.createTextNode(" Preferences"));	var settingsform = document.createElement('form');	settingsform.style.margin = 0;	settingsform.style.padding = '3px';	settingsbox.appendChild(settingsform);	var settingslist = document.createElement('ul');	settingslist.style.listStyle = "none";	var a = window.innerHeight - 75;	if (a < 40) a = 40;	settingslist.style.maxHeight = a + 'px';	settingslist.style.overflow = 'auto'; // vertical scrollbar if needed	window.addEventListener('resize', function()	{		var a = window.innerHeight - 75;		if (a < 40) a = 40;		settingslist.style.maxHeight = a + 'px';	}, false);	settingslist.style.padding = settingslist.style.margin = 0;	settingsform.appendChild(settingslist);	for (i = 0; i < settingnames.length; i++)	{		var settingrow = document.createElement('li');		settingnames[i].li = settingrow;		var settingcheckbox = document.createElement('input');		settingcheckbox.type = "checkbox";		settingcheckbox.checked = settings[settingnames[i].name];		settingcheckbox.title = settingnames[i].tooltip;		settingcheckbox.id = "setting_" + settingnames[i].name;		settingcheckbox.addEventListener('click', enabledisable, false);		settingrow.appendChild(settingcheckbox);		settingnames[i].checkbox = settingcheckbox;		var settinglabel = document.createElement('label');		settinglabel.htmlFor = "setting_" + settingnames[i].name;		settinglabel.appendChild(document.createTextNode(' ' + settingnames[i].title));		settinglabel.title = settingnames[i].tooltip;		settingrow.appendChild(settinglabel);		settingnames[i].label = settinglabel;				if (settingnames[i].title.charAt(0) == ' ')		{			// get number of spaces;			var numspaces = 1;			while (settingnames[i].title.charAt(numspaces) == ' ') numspaces++;			var previousindex = i - 1;			while (previousindex > 0 && settingnames[previousindex].title.substring(0, numspaces).match(/^ +$/))				previousindex--;			if (previousindex >= 0)			{				settingnames[i].parent = settingnames[previousindex];				if (!settingnames[previousindex].ul)				{					settingnames[previousindex].ul = document.createElement('ul');					settingnames[previousindex].ul.style.listStyle = "none";					settingnames[previousindex].ul.style.padding = settingnames[previousindex].ul.style.margin = 0;					settingnames[previousindex].ul.style.marginLeft = "2em";					settingnames[previousindex].li.appendChild(settingnames[previousindex].ul);				}				settingnames[previousindex].ul.appendChild(settingrow);			}			else				settingslist.appendChild(settingrow);		}		else			settingslist.appendChild(settingrow);	}	var savebutton = document.createElement('input');	savebutton.type = "submit";	savebutton.value = "Save and Apply";	savebutton.style.display = "block";	savebutton.style.margin = "0 auto";	settingsform.appendChild(savebutton);	settingsform.addEventListener("submit", savesettings, false);		var settingslink = document.createElement('div');	settingslink.style.borderRight = settingslink.style.borderBottom = '1px solid #666';	settingslink.style.background = '#EEE';	settingslink.style.display = "block";	settingslink.style.position = 'fixed';	settingslink.style.left = '0px';	settingslink.style.top = '0px';	settingslink.style.padding = '3px';	var settingslinkimage = document.createElement('img');	settingslinkimage.src = image_prefs;	settingslinkimage.title = "Click to show preferences";	settingslinkimage.style.cursor = "pointer";	settingslinkimage.style.display = "block";	settingslinkimage.addEventListener('click', function(){settingsbox.style.display = "block"; settingslink.style.display = "none";}, false);	settingslink.appendChild(settingslinkimage);	document.body.appendChild(settingslink);		// add some extra settings other than checkboxes that aren't handled in the structure above	extrasettings[0] = {'name': 'language'};	var settingrow = document.createElement('li');	extrasettings[0].li = settingrow;	var settinglabel = document.createElement('label');	settinglabel.htmlFor = "setting_language";	settinglabel.appendChild(document.createTextNode('Subtitle Language: '));	settinglabel.title = 'Display subtitles in this language, if any';	settingrow.appendChild(settinglabel);	extrasettings[0].label = settinglabel;	var settingselect = document.createElement('select');	settingselect.title = 'Display subtitles in this language, if any';	settingselect.id = "setting_language";	settingrow.appendChild(settingselect);	extrasettings[0].select = settingselect;	for (i = 0; i < settingnames.length; i++)	{		if (settingnames[i].name == "subtitles")		{			extrasettings[0].parent = settingnames[i];			settingnames[i].ul.insertBefore(settingrow, settingnames[i].ul.firstChild);		}	}	extrasettings[0].populated = false;		extrasettings[1] = {'name': 'testsubsdata'};	var settingtextarea = document.createElement('textarea');	settingtextarea.title = 'Paste your XML data here';	settingtextarea.id = "setting_testsubsdata";	settingtextarea.rows = 10;	settingtextarea.style.width = "100%";	settingtextarea.style.fontSize = "10px";	settingtextarea.appendChild(document.createTextNode(settings['testsubsdata']));	extrasettings[1].textarea = settingtextarea;	var div = document.createElement('div');	div.style.display = "block";	div.style.margin = "5px 10px 5px 2em";	div.appendChild(settingtextarea);	for (i = 0; i < settingnames.length; i++)	{		if (settingnames[i].name == "testsubs")		{			extrasettings[1].parent = settingnames[i];			settingnames[i].li.appendChild(div);		}	}	extrasettings[1].populated = false;		enabledisable();}function enabledisable(){	for (i = 0; i < settingnames.length; i++)	{		if (!settingnames[i].parent)			continue;		enabled = true;		p = settingnames[i].parent;		while(p)		{			if (!p.checkbox.checked)			{				enabled = false;				break;			}			p = p.parent;		}		settingnames[i].checkbox.disabled = !enabled;		settingnames[i].label.style.color = enabled ? "inherit" : "#666";	}		enabled = true;	p = extrasettings[0].parent;	while(p)	{		if (!p.checkbox.checked)		{			enabled = false;			break;		}		p = p.parent;	}	extrasettings[0].select.disabled = !enabled;	extrasettings[0].label.style.color = enabled ? "inherit" : "#666";	if (enabled && !extrasettings[0].populated)		downloadxmlfromwiki("Subtitles:Languages", populatelanguagelist);		enabled = true;	p = extrasettings[1].parent;	while(p)	{		if (!p.checkbox.checked)		{			enabled = false;			break;		}		p = p.parent;	}	extrasettings[1].textarea.disabled = !enabled;	// hide it entirely if immediate parent is disabled	extrasettings[1].textarea.style.display = extrasettings[1].parent.checkbox.checked ? "block" : "none";	settingsbox.style.width = extrasettings[1].parent.checkbox.checked ? "500px" : "350px";}function savesettings(e){	for (i = 0; i < settingnames.length; i++)	{		settingbox = settingnames[i].checkbox;		if (settingbox)			GM_setValue(settingnames[i].name, settingbox.checked ? 1 : 0);	}		if (extrasettings[0].populated)		GM_setValue('language', extrasettings[0].select.value);	GM_setValue('testsubsdata', escape(extrasettings[1].textarea.value));	location.reload();	// stop the form from actually being submitted	if (e && e.preventDefault)		e.preventDefault();}// modified from Homestar-Fullonfunction doResize(){	var dw = window.innerWidth;	var dh = window.innerHeight - 15; // things get weird sometimes... -15 to make sure we don't get scrollbars.	if (navbar)	{		// parseInt will take the number part at the start, turning eg "10px" into 10		a = document.defaultView.getComputedStyle(navbar, null);		dh -= parseInt(a.height,10);		dh -= parseInt(a.marginTop,10);		dh -= parseInt(a.marginBottom,10);	}	if (seekbar)	{		a = document.defaultView.getComputedStyle(seekbar, null)		dh -= parseInt(a.height,10);		dh -= parseInt(a.marginTop,10);		dh -= parseInt(a.marginBottom,10);	}	if (subtitleholder)	{		a = document.defaultView.getComputedStyle(subtitleholder, null)		dh -= parseInt(a.height,10);		dh -= parseInt(a.marginTop,10);		dh -= parseInt(a.marginBottom,10);	}	if (transcriptErrors)	{		a = document.defaultView.getComputedStyle(transcriptErrors, null)		dh -= parseInt(a.height,10);		dh -= parseInt(a.marginTop,10);		dh -= parseInt(a.marginBottom,10);	}	// enforce a (rather small) minimum size, regardless of how much crap is squeezed below the frame	if (dw < 100) dw = 100;	if (dh < 100) dh = 100;	// if it was a percentage size, or we're looking outside the frame, just fill the whole window.	// otherwise, keep the aspect ratio correct... "touch inside" style.	if (!isPercentage && !settings.noscale)	{		if(dw/aspect <= dh)			dh = Math.floor(dw / aspect);		else			dw = Math.floor(dh * aspect);	}	/* set embed's size */	flashmovie.width = dw;	flashmovie.height = dh;	if (seekbar)		seekbar.style.width = Math.max(dw, 450) + "px";}function resize(){	if (flashmovie.width.toString().indexOf('%') >= 0 || flashmovie.width.toString().indexOf('%') >= 0)		isPercentage = true;	else		aspect = flashmovie.width/flashmovie.height;	window.addEventListener('resize', doResize, false);	doResize();}// modified from the seek bar bookmarkletfunction addFlashControls(flash){	seekbar=document.createElement("div");	seekbar.style.width=Math.max(parseInt(flash.width)||0,450) + "px";	seekbar.style.margin = "0 auto";	var where=flash;	while(where.parentNode.tagName.toLowerCase()=="object")		where=where.parentNode;	where.parentNode.insertBefore(seekbar,where.nextSibling);	var table=document.createElement("table");	table.style.width="100%";	seekbar.appendChild(table);	var row=table.insertRow(-1);	var pauseButton=document.createElement("button");	pauseButton.appendChild(document.createTextNode("Pause"));	var buttonCell=row.insertCell(-1);	buttonCell.appendChild(pauseButton);	var prevCell=row.insertCell(-1);	var prevButton=document.createElement("button");	prevButton.appendChild(document.createTextNode("|<"));	prevCell.appendChild(prevButton);	var slider=row.insertCell(-1);	slider.width="100%";	var visibleSlider=document.createElement("div");	visibleSlider.style.position="relative";	visibleSlider.style.height="10px";	visibleSlider.style.width="100%";	visibleSlider.style.MozBorderRadius="4px";	visibleSlider.style.background="#aaa";	slider.appendChild(visibleSlider);	var thumb=document.createElement("div");	thumb.style.position="absolute";	thumb.style.height="20px";	thumb.style.width="10px";	thumb.style.top="-5px";	thumb.style.MozBorderRadius="4px";	thumb.style.background="#666";	visibleSlider.appendChild(thumb);	var nextCell=row.insertCell(-1);	var nextButton=document.createElement("button");	nextButton.appendChild(document.createTextNode(">|"));	nextCell.appendChild(nextButton);	if (settings.frames)	{		var frameCell=row.insertCell(-1);		var framecounter=document.createElement("div");		framecounter.style.background="#ccc";		framecounter.style.color="#000";		framecounter.style.fontWeight="bold";		frameCell.appendChild(framecounter);		framecountertext=document.createTextNode("");		framecounter.appendChild(framecountertext);	}	else		framecountertext = false;	if (!settings.noscale)	{		var zoomOutCell=row.insertCell(-1);		var zoomOutButton=document.createElement("button");		// \u2212 is &minus;		zoomOutButton.appendChild(document.createTextNode("\u2212"));		zoomOutCell.appendChild(zoomOutButton);		var zoomNormalCell=row.insertCell(-1);		var zoomNormalButton=document.createElement("button");		zoomNormalButton.appendChild(document.createTextNode("0"));		zoomNormalCell.appendChild(zoomNormalButton);		var zoomInCell=row.insertCell(-1);		var zoomInButton=document.createElement("button");		zoomInButton.appendChild(document.createTextNode("+"));		zoomInCell.appendChild(zoomInButton);	}	var sliderWidth;	var paused=false;	var dragging=false;	var lastframe=-1;	addEvent(pauseButton,"click",pauseUnpause);	addEvent(prevButton,"click",prevFrame);	addEvent(nextButton,"click",nextFrame);	if (!settings.noscale)	{		addEvent(zoomOutButton,"click",zoomOut);		addEvent(zoomNormalButton,"click",zoomNormal);		addEvent(zoomInButton,"click",zoomIn);	}	addEvent(slider,"mousedown",drag);	addEvent(slider,"drag",function(){return false;});	window.setInterval(update,50);	function pauseUnpause(){paused=flash.IsPlaying();pauseButton.style.borderStyle=paused?"inset":"";if(paused)flash.StopPlay();else flash.Play();}	function prevFrame(){flash.GotoFrame(flash.CurrentFrame()-1);}	function nextFrame(){flash.GotoFrame(flash.CurrentFrame()+1);}	function zoomIn(){flash.Zoom(67);}	function zoomOut(){flash.Zoom(150);}	function zoomNormal(){flash.Zoom(0);}	function update()	{		sliderWidth=parseInt(getWidth(slider)-getWidth(thumb));		frame=flash.CurrentFrame();		tot=totalFrames();		if (tot > 0)		{			if (framecountertext)				framecountertext.nodeValue="\xA0"+(frame+1)+"/"+tot+"\xA0";			if(!dragging)			{				thumb.style.left=parseInt(frame/tot*sliderWidth)+"px";				paused=!flash.IsPlaying();				pauseButton.style.borderStyle=paused?"inset":"";			}		}		else if (framecountertext)		{			framecountertext.nodeValue="\xA0Loading...\xA0";		}	}	function dragMousemove(e)	{		var pageX=e.clientX+document.body.scrollLeft;		var pos=bounds(0,pageX-getX(slider)-5,sliderWidth);		var frame=bounds(1,Math.ceil(totalFrames()*pos/sliderWidth),totalFrames()-2);		thumb.style.left=pos+"px";		flash.GotoFrame(frame);	}	function release(e){removeEvent(document,"mousemove",dragMousemove);removeEvent(document,"mouseup",release);if(!paused)flash.Play();dragging=false;}	function drag(e){addEvent(document,"mousemove",dragMousemove);addEvent(document,"mouseup",release);dragging=true;dragMousemove(e);}	function bounds(min,val,max){return Math.min(Math.max(min,val),max);}	function totalFrames(){if(typeof flash.TotalFrames=="number")return flash.TotalFrames;else if(typeof flash.TotalFrames=="function")return flash.TotalFrames();else return 1;}	function getWidth(elem){if(document.defaultView&&document.defaultView.getComputedStyle)return parseFloat(document.defaultView.getComputedStyle(elem,null).getPropertyValue("width"));else return parseFloat(elem.offsetWidth);}	function getX(elem){if(!elem) return 0;return(elem.offsetLeft)+getX(elem.offsetParent);}	function addEvent(elem,eventName,fun){if(elem.addEventListener)elem.addEventListener(eventName,fun,false);else elem.attachEvent("on"+eventName,fun);}	function removeEvent(elem,eventName,fun){if(elem.addEventListener)elem.removeEventListener(eventName,fun,false);else elem.detachEvent("on"+eventName,fun);}}function noscale(){	// have to wait until the Flash has loaded, otherwise SetVariable will fail.	// best way I have found to test this, is if the current frame is >= 0...	// before it's loaded, it's -1.	// Before Flash itself initialises, CurrentFrame doesn't exist, so check for that too.	var a = flashmovie.CurrentFrame;	if (typeof(a) == "function")		a = a();	if (typeof(a) == "number" && a >= 0 && flashmovie.SetVariable)		flashmovie.SetVariable("Stage.scaleMode", "noScale");	else		setTimeout(noscale, 10);}function showmenu(){	var a = flashmovie.CurrentFrame;	if (typeof(a) == "function")		a = a();	if (typeof(a) == "number" && a >= 0 && flashmovie.SetVariable)		flashmovie.SetVariable("Stage.showMenu", 1);	else		setTimeout(showmenu, 10);}function addHRWikiLink(pagename, isurl){	div = document.createElement("div")	div.style.borderLeft = div.style.borderBottom = '1px solid #666';	div.style.background = '#EEE';	div.style.position = "fixed";	div.style.right = "0px";	div.style.top = "0px";	div.style.padding = "3px";	link = document.createElement("a");	if (isurl)		link.href = pagename;	else		link.href = "http://www.hrwiki.org/index.php/" + escape(pagename.replace(/ /g, '_'));	link.title = "See the HRWiki article for this page";	link.style.display = "block";	link.style.textDecoration = "none"	div.appendChild(link);	img=document.createElement("img");	img.style.border="0px";	img.style.display="block";	img.src=image_hrwiki;	link.appendChild(img);	if (settings.subtitles)	{		link = document.createElement("a");		link.href = "http://www.hrwiki.org/index.php/Subtitles:" + escape(filename.replace(/ /g, '_')) + "/" + escape(settings.language);		link.title = "See the HRWiki article for this page's subtitles";		link.style.display = "block";		link.style.textDecoration = "none"		link.style.textAlign = "center";		link.style.fontSize = link.style.lineHeight = "16px";		link.style.marginTop = "3px";		div.appendChild(link);		link.appendChild(document.createTextNode('S'));	}	document.body.appendChild(div);}function wikilink(){	// many pages on the mirror have an "info" link in the navbar (thanks Tom!)... use that	if (whichsite == 3)	{		var a = document.getElementById("navbar");		if (a) a = a.getElementsByTagName("a");		if (a)		{			for (i = 0; i < a.length; i++)			{				if (a[i].firstChild.nodeType == 3 && a[i].firstChild.nodeValue == "info")				{					addHRWikiLink(a[i].href, true);					return;				}			}		}	}		// pull the filename from the url, use it as a link to HRWiki	// all the filenames except a couple of special-cases are	//  redirects to their articles	// don't link to certain pages, they aren't redirects, but already existing pages	// also detect a 404 error and special-case Strong Sad's Lament	     if (document.title == "Oops! You bwoke it.")		addHRWikiLink("404'd");	else if (document.title == "The page cannot be found")		;	else if (document.title == "Homestar Runner Wiki - 404 Not Found")		; // the Wiki's 404 page - do nothing.	else if (filename == "interview")		addHRWikiLink("The_Interview");	else if (filename == "fhqwhgads")		addHRWikiLink("Everybody_to_the_Limit");	else if (filename == "trogdor")		addHRWikiLink("TROGDOR%21");	else if (filename == "marshie")		addHRWikiLink("Meet_Marshie");	else if (location.pathname.substr(0, 12) == "/sadjournal/" && filename != "wonderyears" && filename != "super8")		addHRWikiLink("Strong_Sad%27s_Lament");	else if (filename == "")	{		     if (whichsite == 0)			addHRWikiLink("Index_Page");		else if (whichsite == 1)			addHRWikiLink("Podstar_Runner");		else if (whichsite == 2)			addHRWikiLink("Videlectrix");		else if (whichsite == 3)			; // this will be a 403 page - do nothing.	}	else		addHRWikiLink(filename);}// Prev/Next linksfunction addprevnextlinks(prefix,number){	if (number > 1)	{		var prevnum = (number - 1).toString();		var link = document.createElement("a");		if (prefix == "sbemail" && number == 101)			link.href="sbemailahundred.html";		else if (prefix == "sbemail" && number == 152)			link.href="kotpoptoon.html";		else			link.href=prefix+prevnum+".html";		link.style.position="fixed";		link.style.left="0px";		link.style.bottom="0px";		link.style.padding="3px";		link.style.background="white";		link.style.border="1px solid black";		link.style.textDecoration="none";		link.appendChild(document.createTextNode('<'));		document.body.appendChild(link);	}	var nextnum = (number + 1).toString();	var link = document.createElement("a");	if (prefix == "sbemail" && number == 99)		link.href="sbemailahundred.html";	else if (prefix == "sbemail" && number == 150)		link.href="kotpoptoon.html";	else		link.href=prefix+nextnum+".html";	link.style.position="fixed";	link.style.right="0px";	link.style.bottom="0px";	link.style.padding="3px";	link.style.background="white";	link.style.border="1px solid black";	link.style.textDecoration="none";	link.appendChild(document.createTextNode('>'));	if (settings['checknext'])	{		GM_xmlhttpRequest({			method: "HEAD",			url: link.href,			onload: function (results)			{				if (results.status == 200)					document.body.appendChild(link);			}		});	}	else		document.body.appendChild(link);}function prevnext(){	// this is coded like this instead of just looking for /(\d+)/ so that it	// doesn't find pages like commandos3 or xmas04	var result;	if ((result = filename.match(/^(sbemail|tgs|answer|bizcasfri|puppetjam|main)(\d+)$/)))	{		// sbemail100 isn't actually a sbemail		if (result[1] != "sbemail" || result[2] != "100")			addprevnextlinks(result[1],parseInt(result[2],10));	}	else if (filename == "sbemailahundred")		addprevnextlinks("sbemail", 100);	else if (filename == "kotpoptoon")		addprevnextlinks("sbemail", 151);	else if (filename == "dween_tgs")		addprevnextlinks("tgs", 6);}function flipper(){	a = getSWFFilename();	if (!a)		return;	     if (filename == "toons")		replaceFlash("theyCallHimFlipperToons.swf?contentURL=" + escape(a));	else if (filename == "games")		replaceFlash("theyCallHimFlipperGames.swf?contentURL=" + escape(a));	else if (filename == "payplus")		replaceFlash("theyCallHimFlipperPayPlus.swf?contentURL=" + escape(a));	else if (filename == "main22")		replaceFlash("theyCallHimFlipperVirusMain.swf?contentURL=" + escape(a));	else if (filename == "sbemail118")		// virus *wasn't* flipped correctly originally, but I think having it work is better than		// preserving the glitch.		replaceFlash("theyCallHimFlipperVirusMain.swf?contentURL=" + escape(a));	else if (filename == "sbemailahundred")		replaceFlash("theyCallHimFlipperHundred.swf?contentURL=" + escape(a));	else		replaceFlash("theyCallHimFlipper.swf?contentURL=" + escape(a));}function addnavbarlink(ul,href,title){	var li = document.createElement("li");	var link = document.createElement("a");	link.href = href;	link.appendChild(document.createTextNode(title));	li.appendChild(link);	ul.appendChild(li);	return link;}function replacenavbar(){	// need to add the styles as a stylesheet, rather than inline styles	// so that we can use :hover	GM_addStyle(		"#newnavbar { margin: 0; padding: 0; text-align: center; text-transform: lowercase; } " +		"#newnavbar li { margin: 0; padding: 0; display: inline; } " +		"#newnavbar :link, #newnavbar :visited { color: #666; font-family: sans-serif; text-decoration: none; padding: 0 1em; } " +		"#newnavbar :link:hover, #newnavbar :visited:hover { color: #CCC; } " +		// for overriding podstar's settings:		"#newnavbar :link, #newnavbar :visited { font-weight: normal; } " +		"#newnavbar :link:hover, #newnavbar :visited:hover { background: transparent; font-weight: normal; } "	);	var newnavbar = document.createElement("ul");	newnavbar.id = "newnavbar";	newnavbar.style.height = newnavbar.style.fontSize = newnavbar.style.lineHeight = "10px";	if (!settings.seekbar)		newnavbar.style.marginTop = "10px";	if (navbar)	{		var where = navbar;		while(where.parentNode.tagName.toLowerCase() == "object")			where = where.parentNode;		where.parentNode.insertBefore(newnavbar, where);		if (whichsite == 3)			where.style.display = "none";		else			where.parentNode.removeChild(where);	}	else		document.body.appendChild(newnavbar);	mainlink = addnavbarlink(newnavbar, "http://www.homestarrunner.com/main" + Math.floor(Math.random() * 23 + 1) + ".html", "Main");	// just for fun, re-randomise on each mouse-over (for the status bar)	mainlink.addEventListener("mouseover",function(){mainlink.href="http://www.homestarrunner.com/main" + Math.floor(Math.random() * 23 + 1) + ".html"}, false);	addnavbarlink(newnavbar, "http://www.homestarrunner.com/toons.html", "Toons");	addnavbarlink(newnavbar, "http://www.homestarrunner.com/games.html", "Games");	addnavbarlink(newnavbar, "http://www.homestarrunner.com/characters2.html", "Characters");	addnavbarlink(newnavbar, "http://www.homestarrunner.com/downloads.html", "Downloads");	addnavbarlink(newnavbar, "http://homestarrunner.stores.yahoo.net/", "Store");	addnavbarlink(newnavbar, "http://www.homestarrunner.com/sbemail.html", "SB Emails");	addnavbarlink(newnavbar, "http://www.homestarrunner.com/email.html", "Contact");	addnavbarlink(newnavbar, "http://www.homestarrunner.com/legal.html", "Legal");	randolink = addnavbarlink(newnavbar, "javascript:alert('rando.xml not loaded yet... be patient')", "Rando");	// load rando.xml and handle all that jazz	GM_xmlhttpRequest({		method: "GET",		url: "http://www.homestarrunner.com/rando.xml",		onload: randoxml_loaded	});		navbar = newnavbar;}function randoxml_loaded(results){	// info on DOMParser stole from http://www.webreference.com/programming/javascript/domwrapper/3.html	// Greasemonkey workaround from http://greaseblog.blogspot.com/2005/12/workarounds-for-missing-xmlhttprequest.html	// (oh noes! unsafeWindow!)	var parser = new unsafeWindow.DOMParser();	// fix invalid XML...	// add missing root element	doc = results.responseText.replace(/<\?xml.*?\?>/g, ""); // strip <?xml ?> tag	doc = "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n<rando>" + doc + "</rando>";	// fix bad ampersands	doc = doc.replace(/&(?!\w*;)/g, "&amp;");	doc = parser.parseFromString(doc, "application/xml");	var sbemailcounter = 0;	for (i = 0; i < doc.documentElement.childNodes.length; i++)	{		if (doc.documentElement.childNodes[i].nodeType == 1)		{			var type = doc.documentElement.childNodes[i].nodeName.toLowerCase();			if (settings['rando' + type] == false) // == false so that it's considered "true" for undefined... if they add a new toon type				continue;			u = doc.documentElement.childNodes[i].getAttribute('u');			n = doc.documentElement.childNodes[i].getAttribute('n');			if (!n) n = "Untitled";			if (type == "sb")			{				sbemailcounter++;				n = "SBEmail: " + n;			}			if (u)				randourls[randourls.length] = {u: "http://www.homestarrunner.com/" + u, n: n};			else				randourls[randourls.length] = {u: "http://www.homestarrunner.com/sbemail" + sbemailcounter + ".html", n: n};		}	}	newrandolink()	// just for fun, re-randomise on each mouse-over (for the status bar)	randolink.addEventListener('mouseover', newrandolink, false);}function newrandolink(){	if (randourls.length > 0)	{		r = randourls[Math.floor(Math.random() * randourls.length)];		randolink.href = r.u;		randolink.title = r.n;	}	else	{		randolink.href = "javascript:alert('Nothing to choose from')";		randolink.title = "Nothing to choose from";	}}function downloadxmlfromwiki(url, callback){	url = escape(url.replace(/ /g, '_'));	GM_xmlhttpRequest({		method: "GET",		url: "http://www.hrwiki.org/index.php?title=" + url + "&action=raw",		onload: function(x) { xmldownloaded(x, callback, false, false); }	});}function xmldownloaded(results, callback, redirected, showerrors){	var text = results.responseText;	text = text.replace(/{{.*?}}/g, "");	text = text.replace(/<\/?pre[^>]*>/g, "");	text = text.replace(/^\s+/g, "");	// check for redirects	var matches = text.match(/^#REDIRECT\s*\[\[(.*)\]\]/i);	if (matches)	{		if (redirected) // trap double-redirects		{				removeSubtitles();			return;		}		text = matches[1];		if (matches = text.match(/^(.*)\|/))			text = matches[1];		if (matches = text.match(/^(.*)\#/))			text = matches[1];		text = text.replace(/^\s+|\s+$/g, '');		text = text.replace(/ /g, '_');		GM_xmlhttpRequest({			method: "GET",			url: "http://www.hrwiki.org/index.php?title=" + escape(text) + "&action=raw",			onload: function(x) { xmldownloaded(x, callback, true, showerrors); }		});		return;	}	var parser = new unsafeWindow.DOMParser();	try	{		var doc = parser.parseFromString(text, "application/xml");	}	catch (e)	{		if (showerrors)		{			transcriptError("Error in test subtitles:");			var pre = document.createElement("pre");			pre.style.font = "inherit";			pre.style.margin = "0.5em 0 0";			pre.appendChild(document.createTextNode(e.toString()))			transcriptErrors.appendChild(pre);		}		removeSubtitles();		return;	}	// check if returned document is an error message	if (doc.documentElement.lastChild && doc.documentElement.lastChild.nodeName == 'sourcetext')	{		// the xml document looks like		// <parsererror>Error details<sourcetext>Source text</sourcetext></parsererror>		if (showerrors)		{			transcriptError("Error in test subtitles:");			var pre = document.createElement("pre");			pre.style.font = "inherit";			pre.style.margin = "0.5em 0 0";			pre.appendChild(document.createTextNode(doc.documentElement.firstChild.nodeValue.replace(/Location: .*\n/, "")))			transcriptErrors.appendChild(pre);			pre = document.createElement("pre");			pre.style.margin = "0.5em 0 0";			pre.appendChild(document.createTextNode(doc.documentElement.lastChild.firstChild.nodeValue))			transcriptErrors.appendChild(pre);		}		removeSubtitles();		return;	}	callback(doc);}function populatelanguagelist(xml){	while (extrasettings[0].select.firstChild)		extrasettings[0].select.removeChild(extrasettings[0].select.firstChild);	a = xml.getElementsByTagName('language');	for (i = 0; i < a.length; i++)	{		// sanity-check the node		if (a[i].hasAttribute('xml:lang') && a[i].firstChild && (a[i].firstChild.nodeType == xml.TEXT_NODE || a[i].firstChild.nodeType == xml.CDATA_SECTION_NODE))		{			option = document.createElement('option');			option.appendChild(document.createTextNode(a[i].firstChild.nodeValue));			option.lang = option.value = a[i].getAttribute('xml:lang');			if (option.lang == settings['language'])				option.selected = true;			option.dir = "ltr";			if (a[i].hasAttribute('dir'))				option.dir = a[i].getAttribute('dir');			extrasettings[0].select.appendChild(option);		}	}	extrasettings[0].populated = true;}function setupSubtitles(){	subtitleholder = document.createElement('div');	subtitleholder.style.color = "white";	subtitleholder.style.font = "20px/25px sans-serif";	subtitleholder.style.backgroundColor = "black";	subtitleholder.style.height = "100px";	//subtitleholder.style.marginTop = "10px";	subtitleholder.style.textAlign = "center";	where = flashmovie;	while(where.parentNode.tagName.toLowerCase() == "object")		where = where.parentNode;	where.parentNode.insertBefore(subtitleholder, where.nextSibling);		GM_addStyle(		'.italic { font-style: italic; } ' +		'.italic em, .italic cite, .italic i { font-style: normal; }'	);		subtitleholder.appendChild(currentsubtitles = document.createTextNode("Loading subtitles..."));		downloadxmlfromwiki('Subtitles:Characters', charactersLoaded);}function removeSubtitles(){	subtitleholder.parentNode.removeChild(subtitleholder);	subtitleholder = false;	if (settings.resize)		doResize();}function charactersLoaded(doc){	var speakers = doc.getElementsByTagName("speaker");	for (var i = 0; i < speakers.length; i++)	{		var speakername = speakers[i].getAttribute("id");		characters[speakername] = {"color": speakers[i].getAttribute("color"), "sfx": speakers[i].hasAttribute("sfx"), "name": {"en": ""}};		var names = speakers[i].getElementsByTagName("name");		for (var j = 0; j < names.length; j++)		{			var lang = names[j].getAttribute("xml:lang");			if (names[j].firstChild && (names[j].firstChild.nodeType == doc.TEXT_NODE || names[j].firstChild.nodeType == doc.CDATA_SECTION_NODE))				characters[speakername].name[lang] = names[j].firstChild.nodeValue;		}	}	if (!settings.testsubs)		downloadxmlfromwiki('Subtitles:' + filename + '/' + settings.language, transcriptLoaded);	else		xmldownloaded({'responseText': settings.testsubsdata}, transcriptLoaded, false, true);}function transcriptLoaded(doc){	// set some defaults	if (!doc.documentElement.getAttribute("xml:lang")) doc.documentElement.setAttribute("xml:lang", "en");	if (!doc.documentElement.getAttribute("dir"))      doc.documentElement.setAttribute("dir",      "ltr");	// inherit languages to all subnodes	inheritLanguages(doc.documentElement);	// now parse the lines into divs and get start and end frames	var lines = doc.getElementsByTagName("line");	var previousEnd = NaN;	for (var i = 0; i < lines.length; i++)	{		var line = new Object();		line.start = parseInt(lines[i].getAttribute("start"), 10);		line.end = parseInt(lines[i].getAttribute("end"), 10);		if (settings.testsubs)		{			if (isNaN(line.start))				transcriptError("Start value \"" + lines[i].getAttribute("start") + "\" is not a number");			if (isNaN(line.end))				transcriptError("End value \"" + lines[i].getAttribute("end") + "\" is not a number");			if (line.end < line.start)				transcriptError("Line beginning frame " + line.start + " ends before it begins.");			if (line.start < previousEnd)				transcriptError("Line beginning frame " + line.start + " starts before the previous frame ends.");			previousEnd = line.end;		}		line.text = importNodes(lines[i]);		transcript.push(line);	}			if (settings.resize)		doResize();		setInterval(refreshSubtitles, 50);}function inheritLanguages(node){	for (var i = node.firstChild; i; i = i.nextSibling)	{		if (i.nodeType == i.ELEMENT_NODE)		{			if (!i.hasAttribute("xml:lang")) i.setAttribute("xml:lang", node.getAttribute("xml:lang"));			if (!i.hasAttribute("dir"))      i.setAttribute("dir",      node.getAttribute("dir"));			inheritLanguages(i);		}	}}// replacement for document.importNode() that actually works properly// turning eg <span> into an HTML span element, rather than an unknown element// that happens to be called "span".function importNodes(node){	var name = node.nodeName.toLowerCase();	if (characters[name])	{		node.setAttribute("speaker", name);		name = "speaker";	}	if (name == "line" || name == "speaker")	{		// format the speaker appropriately as a div		var speaker = node.getAttribute("speaker");		if (!settings.captions && (speaker == "sfx" || node.hasAttribute("sfx")))			return document.createComment(""); // return nothing		newNode = document.createElement("div");		var char = characters[speaker];		if (!char)		{			if (settings.testsubs && speaker)			{				line = node;				while (line && line.nodeName != "line")					line = line.parentNode;				if (line)					transcriptError("Line beginning frame " + line.getAttribute("start") + " has an unrecognised speaker name \"" + speaker + '"');			}			char = {"color": "#FFF", "name": {"en": ""}};		}		if (settings.colours)			newNode.style.color = char.color;		if (node.hasAttribute("voiceover"))			newNode.className = "italic";		if (node.hasAttribute("volume"))			newNode.style.fontSize = (node.getAttribute("volume") * 100) + "%";		newNode.lang = node.getAttribute("xml:lang");		newNode.dir = node.getAttribute("dir");		var hasSpeakerChildren = false;		for (var i = node.firstChild; i; i = i.nextSibling)		{			if (i.nodeType == i.ELEMENT_NODE)			{				newNode.appendChild(importNodes(i));				var a = i.nodeName.toLowerCase();				if (i == "line" || i == "speaker" || characters[i])					hasSpeakerChildren = true;			}			else if (i.nodeType == i.TEXT_NODE || i.nodeType == i.CDATA_SECTION_NODE)				newNode.appendChild(document.importNode(i, true));		}		if (!hasSpeakerChildren)		{			// this is a normal text node - do some extra text stuff			if (char.sfx || node.hasAttribute("sfx"))			{				newNode.insertBefore(document.createTextNode('('), newNode.firstChild);				newNode.appendChild(document.createTextNode(')'))				newNode.className = "italic";			}			if (!settings.colours || (node.hasAttribute("voiceover") && settings.voiceover))			{				// find the language with the longest prefix match				// fall back to "en" if none found				var bestmatch = "en";				var langbits = node.getAttribute("xml:lang").split("-");				for (i = langbits.length; i >= 1; i--)				{					var lang = langbits.slice(0, i).join("-");					if (char.name[lang])					{						bestmatch = lang;						break;					}				}				if (char.name[bestmatch] != '')					newNode.insertBefore(document.createTextNode(char.name[bestmatch] + ": "), newNode.firstChild);			}		}		return newNode;	}	else	{		// check element blacklist		if (name == "script" ||		    name == "style"  ||		    name == "object" ||		    name == "param"  ||		    name == "embed"  ||		    name == "a"      ||		    name == "img"    ||		    name == "applet" ||		    name == "map"    ||		    name == "frame"  ||		    name == "iframe" ||		    name == "meta"   ||		    name == "link"   ||		    name == "form"   ||		    name == "input")		{			if (settings.testsubs)				transcriptError("Blacklisted element \"" + name + "\" stripped.");			return document.createComment(""); // return nothing		}		var newNode = document.createElement(name);		// copy across attributes		for (var i = 0; i < node.attributes.length; i++)		{			name = node.attributes[i].nodeName.toLowerCase();			// check attribute blacklist			// javascript, and anything that might load stuff from offsite			if (name != "href" && name != "src" && name.substring(0, 2) != "on")			{				if (name == "style")				{					// regex taken from MediaWiki Sanitizer.php					if (!node.attributes[i].nodeValue.match(/(expression|tps*:\/\/|url\\s*\().*/i))						newNode.setAttribute("style", node.attributes[i].nodeValue);				}				else if (name == "xml:lang")				{					newNode.lang = node.attributes[i].nodeValue;				}				else					newNode.setAttribute(node.attributes[i].nodeName, node.attributes[i].nodeValue);			}			else if (settings.testsubs)				transcriptError("Blacklisted attribute \"" + name + "\" stripped.");		}		// copy across children		for (var i = node.firstChild; i; i = i.nextSibling)		{			if (i.nodeType == i.ELEMENT_NODE)				newNode.appendChild(importNodes(i));			else if (i.nodeType == i.TEXT_NODE || i.nodeType == i.CDATA_SECTION_NODE)				newNode.appendChild(document.importNode(i, true));		}		return newNode;	}	document.createComment(""); // fallthrough}function setSubtitles(node){	if (!node)		node = nosubtitles;	if (currentsubtitles != node)	{		subtitleholder.replaceChild(node, subtitleholder.firstChild);		currentsubtitles = node;	}}function refreshSubtitles(){	var frame = false;	if (!flashmovie)		return;	if (typeof(flashmovie.CurrentFrame) == "function")		frame = flashmovie.CurrentFrame();	if (typeof(frame) == "number" && frame >= 0)	{		// change from native 0-based to more friendly 1-based		frame++;		// binary search to find the right transcript line		var first = 0;		var last = transcript.length;		while(first < (last - 1))		{			var mid = (first + last) >> 1;			if (frame >= transcript[mid].start)				first = mid;			else				last = mid;		}		// should we actually show the line?		if(transcript[first].start <= frame && transcript[first].end >= frame)			setSubtitles(transcript[first].text);		else			setSubtitles(false);	}}function transcriptError(str){	if (!transcriptErrors)	{		transcriptErrors = document.createElement('div')		transcriptErrors.style.color = "red";		transcriptErrors.style.background = "black";		transcriptErrors.style.font = "12pt sans-serif";		transcriptErrors.style.textAlign = "left";		transcriptErrors.style.margin = "0.5em";		document.body.appendChild(transcriptErrors);	}	else		transcriptErrors.appendChild(document.createElement('br'));	transcriptErrors.appendChild(document.createTextNode(str));}//</pre>