Monday, November 08, 2010 at 12:05 AM.

	<<12/29/02; 12:18:28 PM by JES
		<<Added support for serial number renewals.
	<<11/10/02; 1:47:29 PM by JES
		<<Instead of a startDate parameter in the url, use a days parameter to get the number of days worth of updates specified in the url.
	<<11/10/02; 1:16:44 PM by JES
		<<If a startDate is present in the getArgs, set the lastUpdate for Radio.root to that date before getting the update.
	<<4/16/02; 3:14:32 PM by JES
		<<Fixed a bug which would cause a macro error when there's a timeout updating Radio.root.
	<<1/21/02; 7:04:14 PM by JES
		<<Use more explanatory confirmation messages, when the page refreshes. Improved the intro text. Added some padding below the text.
	<<1/21/02; 6:27:35 PM by JES
		<<Added some white-space between the intro text and the confirmation message.
	<<1/21/02; 2:58:10 PM by JES
		<<Created. Render the Update Radio.root page.
local (pta = html.getPageTableAddress ());
pta^.title = radio.string.getlocalizedstring ("updateRadioRoot.title");

local (htmltext, indentlevel=0);
on add (s) {
	htmltext = htmltext + string.filledstring ("\t", indentlevel) + s + "\r"};
on daysBeforeToday (ctdays) {
	local (d, day, month, year, hour, minute, second);
	date.get ( (), @day, @month, @year, @hour, @minute, @second);
	d = date.set (day, month, year, 0, 0, 0);
	local (oneday = 60 * 60 * 24);
	d = d - (oneday * ctdays);
	return (d)};

local (confirmText = "");
if pta^.method == "POST" { //handle a POST
	local (adrargs = @pta^.radioResponder.postArgs);
	if defined (adrargs^.updateRadioRoot) {
		if defined (adrargs^.days) { //get the updates from this date
			local (d = daysBeforeToday (number (adrargs^.days)));
			d = date.yesterday (d);
			user.rootUpdates.servers.Radio.lastUpdate = date.netStandardString (d)};
		local (scriptText);
		scriptText = "local (params = {@root, true,});\r";
		scriptText = scriptText + "thread.callScript (@rootUpdates.update, params)";
		local (adr =;
		new (scriptType, adr);
		local (oldtarget = target.set (adr));
		op.setLineText (scriptText);
		try {target.set (oldtarget)};
		script.getcode (adr, adr); //use script.getcode to avoid dialogs asking if you want to compile before closing
		adr^ ();
		local (now = (), flTimeout = false);
		while not defined ( { //loop until the update is complete, or we time out
			thread.sleepTicks (6); //0.1 seconds
			if () - now > 300 { //5 minute timeout
				flTimeout = true;
		if flTimeout {
			confirmText = "<div style=\"font-weight:bold; color:maroon;\">" + radio.string.getlocalizedstring ("updateRadioRoot.timeoutMessage") + "</div>"}
		else { //udpate completed -- set confirmation message, delete temporary objects
			local (t); new (tableType, @t);
			t.server =;
			t.ctNewParts =;
			delete (;
			delete (adr); //delete the script
			msg (""); //clear the update message from the About window
			if t.ctNewParts > 0 {
				confirmText = "<div style=\"padding-bottom:30px;\">" + radio.string.getlocalizedstring ("updateRadioRoot.confirmMessage", @t) + "</div>"}
			else { //already up-to-date
				confirmText = "<div style=\"padding-bottom:30px;\">" + radio.string.getlocalizedstring ("updateRadioRoot.confirmNoNewParts", @t) + "</div>"}}}};

if confirmText != "" { //render the confirm text
	add ("<p>" + confirmText + "</p>")}
else { //redner the form
	local (flExpired = false);
	if defined ( {
		local (whenExpires = date (;
		flExpired = whenExpires < ()};
	if flExpired {
		local (t); new (tableType, @t);
		t.purchaseRenewalUrl = string.replace (, "<%serialNumber%>",;
		t.renewLicenseUrl =;
		add (radio.string.getLocalizedString ("updateRadioRoot.expired", @t))}
	else {
		bundle { //intro text
			local (since);
			if defined (pta^.radioResponder.getArgs.days) {
				local (t); new (tableType, @t);
				local (d = daysBeforeToday (number (pta^.radioResponder.getArgs.days))); = date.shortString (d);
				since = radio.string.getlocalizedstring ("updateRadioRoot.sinceDate", @t)}
			else {
				since = radio.string.getlocalizedstring ("updateRadioRoot.sinceTheLastUpdate")};
			local (t); new (tableType, @t);
			t.since = since;
			add (radio.string.getlocalizedstring ("updateRadioRoot.introText", @t))};
		bundle { //add the form with the Update Radio.root button
			add ("<br><br><br>");
			local (buttonName = radio.string.getlocalizedstring ("updateRadioRoot.buttonName"));
			add ("<form method=\"POST\">");
			if defined (pta^.radioResponder.getArgs.days) {
				add ("<input type=\"hidden\" name=\"days\" value=\"" + pta^.radioResponder.getArgs.days + "\">")};
			add ("<input type=\"submit\" name=\"updateRadioRoot\" value=\"" + buttonName + "\">");
			add ("</form>")};
		add ("<div style=\"padding-bottom:25px\">"); //adds some space before the <hr> at the bottom of the page
		add ("</div>")}};

return (htmltext)

This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.