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

on synchronizeFolder (baseFolder, directoryOpmlUrl, flDeleteFiles=false, flTolerateDownloadErrors=true) {
		<<8/31/02; 2:11:04 AM by JES
			<<Fixed a bonehead bug in the last change.
		<<8/31/02; 1:58:05 AM by JES
			<<Small modification to prevent files which should not be downloaded from being downloaded: Lwarence found that sometimes the file modification dates were off by a second in the filesystem, as compared to the date in the OPML file. Instead of an absolute timestamp comparison, we now provide a couple of seconds of leeway in the modification date, since we can't be 100% certain that the operating system will keep up when setting the mod date of files we've downloaded.
		<<3/20/02; 11:23:37 PM by JES
			<<Fixed a bug which would cause files which should be downloaded, not to be.
		<<3/12/02; 1:28:56 AM by JES
			<<Download the file if its mod-date is different than, rather than greater than, the file that exists on disk.
		<<3/12/02; 1:17:54 AM by JES
			<<If the <outline> element has a url attribute, load the file from the url specified by the url attribute, instead of from the relative path as determined by the outline structure.
		<<3/11/02; 11:13:34 PM by JES
			<<Call tcp.httpClient instead of tcp.httpReadUrl, passing flAcceptOpml as true, so that if requesting the OPML from a Radio server, we get back OPML, instead of rendered HTML.
		<<12/30/01; 11:44:13 PM by JES
			<<Synchronize the contents of a folder on disk, with a folder accessible over the Internet, based on the contents of the directory.opml file specified at directoryOpmlUrl.
			<<flDeleteFiles specifies whether to delete files from disk, which don't appear in the directory-opml.
			<<flTolerateDownloadErrors specifies whether an error downloading a file is a scriptError, or is ignored.
			<<Cribbed from workspace.userlandSamples.clonePublicRadioFiles.
	local (baseUrl = string.popSuffix (directoryOpmlUrl, "/") + "/");
	<<local (xmltext = tcp.httpReadUrl (directoryOpmlUrl))
	local (xmltext);
	bundle { //read xmltext from the URL
		local (urlparts = string.urlSplit (directoryOpmlUrl));
		local (server = urlparts[2], port = 80);
		if server contains ":" {
			port = string.nthField (server, ":", 2);
			server = string.nthField (server, ":", 1)};
		xmltext = string.httpResultSplit (tcp.httpClient (server:server, port:port, path:urlparts[3], flAcceptOpml:true))};
	xml.compile (xmltext, @xstruct);
	on dolevel (adrtable, folder) {
		local (adrsub, text, type);
		for adrsub in adrtable {
			if nameof (adrsub^) endswith "\toutline" {
				text = adrsub^.["/atts"].text;
				type = adrsub^.["/atts"].type;
				if type == "folder" {
					local (innerfolder = folder + text + "/");
					dolevel (adrsub, innerfolder)}
				else {
					local (modified = date (adrsub^.["/atts"].whenLastUploaded));
					local (created = date (adrsub^.["/atts"].whenCreated));
					local (url = baseurl + folder + text); //default
					if defined (adrsub^.["/atts"].url) {
						url = adrsub^.["/atts"].url};
					local (f = basefolder + string.replaceall (folder, "/", file.getpathchar ()) + text);
					local (flread = false);
					if file.exists (f) {
						if abs (number (file.modified (f) - modified)) > 3 { //give +/- 3 sec leeway (explanation below)
							<<8/31/02; 1:54:58 AM by JES
								<<Lawrence found that sometimes local mod-dates were off by a second. Adding a +/- 3 second tolerance will prevent, for example, theme files from being repeatedly downloaded. Almost nothing will ever be modified more frequently than every 5 seconds, and even if it were, it's very unlikely that there were significant changes.
							flread = true}}
					else { //file doesn't exist -- we must download it
						flread = true};
					if flread {
						try {
							local (filetext = tcp.httpReadUrl (url));
							file.surefilepath (f);
							file.writewholefile (f, filetext, creationdate:created);
							file.setmodified (f, modified)}
						else {
							if not flTolerateDownloadErrors {
								scriptError (tryError)}}}}}}};
	local (adrdoc = xml.getaddress (@xstruct, "opml"));
	dolevel (xml.getaddress (adrdoc, "body"), "")}

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.