Home Page
Archive > Posts > Tags > Web browsers
Search:

Installing KeePassXC & a Flatpak sandboxed browser

Since I have been moving my primary workstation to Linux, I have been in need of finding a new password manager after Roboform failed me. I decided to try out KeePassXC but was having trouble since my Ungoogled Chromium browser was sandboxed in Flatpak. The instructions for this on Unix Stack Exchange were no longer working so I had to dig into it myself.


The 2 primary problems were that:
1) The browsers’ sandboxes did not have the QT libs.
2) The interprocess communication pipe socket had been renamed from kpxc_server to org.keepassxc.KeePassXC.BrowserServer.


The following are the instructions to get KeePassXC running in Flatpak versions of both Chrome and Firefox. This was tested on Linux Mint 21.3 with both Ungoogled Chromium and Firefox. You will need to change the KP_FLATPAK_PACKAGE if you use other versions of Chrome.


  1. Run the relevant below environment variables in your command shell before running the commands in the following steps:
    #Shared environment variables:
    KP_CUSTOM=/home/$USER/keepass-browser
    KP_JSON_NAME=org.keepassxc.keepassxc_browser.json
    
    #Chrome environment variables:
    KP_FLATPAK_PACKAGE=io.github.ungoogled_software.ungoogled_chromium
    KP_JSON_START=~/.config/chromium/NativeMessagingHosts
    KP_JSON_END=~/.var/app/$KP_FLATPAK_PACKAGE/config/chromium/NativeMessagingHosts
    
    #Firefox environment variables:
    KP_FLATPAK_PACKAGE=org.mozilla.firefox
    KP_JSON_START=~/.mozilla/native-messaging-hosts
    KP_JSON_END=~/.var/app/$KP_FLATPAK_PACKAGE/.mozilla/native-messaging-hosts
    		
  2. Install and enable the browser extension:
    KeePassXD > Tools > Settings > Browser Integration:
    • Check “Enable Browser Integration”
    • Check “Chromium” and/or “Firefox”
    • Download the plugin listed on this screen in your browser
    • Click "OK"
    Note: This creates $KP_JSON_START/$KP_JSON_NAME

  3. Set up the needed files in the sandbox:
    #Put KeePass proxy and needed library files in user directory
    mkdir -p $KP_CUSTOM/lib
    mkdir -p $KP_JSON_END #Needed for firefox
    cp /usr/bin/keepassxc-proxy $KP_CUSTOM/
    rsync -a /usr/lib/x86_64-linux-gnu/libicudata* /usr/lib/x86_64-linux-gnu/libicuuc* /usr/lib/x86_64-linux-gnu/libicui* /usr/lib/x86_64-linux-gnu/libdouble* /usr/lib/x86_64-linux-gnu/libsodium* /usr/lib/x86_64-linux-gnu/libQt5* $KP_CUSTOM/lib
    
    #Copy the JSON file to the Flatpak app directory and change the executable path in the file
    cp $KP_JSON_START/$KP_JSON_NAME $KP_JSON_END/
    sed -i "s/\/usr\/bin\//"$(echo $KP_CUSTOM | sed 's_/_\\/_g')"\//" $KP_JSON_END/$KP_JSON_NAME
    		
  4. Add permissions to the Flatpak:
    flatpak override --user --filesystem=$KP_CUSTOM:ro $KP_FLATPAK_PACKAGE #Only required if home directory is not shared to the Flatpak
    flatpak override --user --filesystem=xdg-run/org.keepassxc.KeePassXC.BrowserServer:ro $KP_FLATPAK_PACKAGE
    flatpak override --user --env=LD_LIBRARY_PATH=$(flatpak info --show-permissions $KP_FLATPAK_PACKAGE | grep -oP '(?<=LD_LIBRARY_PATH=).*')";$KP_CUSTOM/lib" $KP_FLATPAK_PACKAGE
    		
Roboform (offline mode) on Linux with Wine
Part 0: Installation

I’ve been moving from Windows to Linux recently and my latest software move attempt is Roboform, a password manager that I use in offline mode. Just running it under Wine works fine for the primary software interaction, but I was unable to get it fully integrated with its chrome extension. Below is the information for my attempt to get it working, in case someone could use the information or wanted to try continuing my attempts.

To move your RoboForm profile to Linux, copy the data from C:\Users\USERNAME\AppData\Local\RoboForm\Profiles\Default Profile to ~/.wine/drive_c/users/USERNAME/Local Settings/Application Data/RoboForm/Profiles/Default Profile.


Part 1: Redirect the extension to the executable

The chrome extension talks to its parent, rf-chrome-nm-host.exe, through the native messaging API. To direct the extension to talk to the windows executable you have to edit ~/.config/chromium/NativeMessagingHosts/com.siber.roboform.json and change the path inside it to /home/USERNAME/chrome-robo.sh, a script file that you will create. You can’t link directly to the rf-chrome-nm-host.exe because it has to be run through Wine, and the path cannot contain arguments.

Create a file with executable permissions at ~/chrome-robo.sh and set its contents to:

cd "/home/USERNAME/.wine/drive_c/Program Files (x86)/Siber Systems/AI RoboForm/9.6.1.1/";
/usr/bin/wine ./rf-chrome-nm-host.exe chrome-extension://pnlccmojcmeohlpggmfnbbiapkmbliob/ --parent-window=0

Part 2: Debugging why it isn’t working

It should have worked at this point, but it still wasn’t, so I had to go further into debug mode. The full copy of the C source code can be found at the bottom of this post. Make sure to replace USERNAME in the source (and instructions in this post) with your username, as using “~” to specify your home directory often doesn’t work in this setup. You may also need to replace version numbers (9.6.1.1 for this post).

First, I created a simple C program to sit in between the chrome extension and the rf-chrome-nm-host.exe. All it did was forward the stdin/stdout between both programs (left=chromium, right=rf-chrome-nm-host.exe) and output their crosstalk to a log file (./log) that I monitored with tail -f. I pointed to the generated executable in the ~/chrome-robo.sh file.

All that was generated on the Linux config was: left=ping, right=confirm ping, left=get product info, END.

I then modified the program to specifically handle chrome native messaging packets, which are always a 4 byte number specifying the packet length, followed by the packet data (IsChrome=1). If this variable is turned off there is a place in the code where you can set a different executable with parameters to run.

Next, I ran the program in Windows with a working left+right config so I could see what packets were expected.

I then added a hack to the program (AddRoboformAnswerHacks=1) to respond to the 2nd-4th packets sent from the left (get-product-info, get-product-info, Initialize2) with what was expected from the right. rf-chrome-nm-host.exe crashed on the 5th packet, and debugging further from there would have taken too more time than I was willing to put in, so at that point I gave up.


Part 3: Trying with windows

I next decided to see if I could get the chromium extension to play nicely by talking directly to the rf-chrome-nm-host.exe on my Windows machine via an SSH tunnel. To do this, I changed the char *cmd[]= line to:

char *cmd[]={
  "/usr/bin/ssh",
  "USERNAME@HOSTNAME",
  "cd c:/Program\\ Files\\ \\(x86\\)/Siber\\ Systems/AI\\ RoboForm/9.6.1.1; ./rf-chrome-nm-host.exe chrome-extension://pnlccmojcmeohlpggmfnbbiapkmbliob/ --parent-window=0",
  NULL
};

While the first 4 packets succeeded in this setup, the following packets (rf-api-request) were all met with: pipe open error: The system cannot find the file specified. (error 2).

This was another stopping point because debugging this would also have taken too long. Though I did do some initial testing using Process Monitor and handle lookups in Process Explorer.


Part 4: The C source code
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

FILE *SideLog; //This logs all events to the file "log"
FILE *RecordLeft; //This logs the exact packets that the left side sends to the file "left"
int IsChrome=1; //True for roboform chrome compatibility, false to just pass through data as is
int DisplayStatus=1; //Whether to show the "Status: x" updates
int AddRoboformAnswerHacks=0; //Whether to force send fake responses that the rf-chrome server is not responding to
const char* HomePath="/home/USERNAME/.wine/drive_c/Program Files (x86)/Siber Systems/AI RoboForm/9.6.1.1/"; //This must be set.
const char* ExePath="/home/USERNAME/.wine/drive_c/Program Files (x86)/Siber Systems/AI RoboForm/9.6.1.1/rf-chrome-nm-host.exe"; //This must be set. You can make sure rf-chrome-nm-host.exe is running with a 'ps'

//Send back a custom packet to the left. This will show in the log file BEFORE the packet it is responding to.
void SendLeft(char *str)
{
	char Buffer[255];
	int StrSize=strlen(str);
	*(int*)Buffer=StrSize;
	strcpy(Buffer+4, str);

	write(STDOUT_FILENO, Buffer, StrSize+4);
	fprintf(SideLog, "OVERRIDE REQUEST: %s\n\n", Buffer+4);
	fflush(SideLog);
}

//Forward data from left to right or vice versa. Also saves to logs and "left" file
void ForwardSide(int InFileHandle, int OutFileHandle, fd_set* ReadFDS, int IsLeft)
{
	//Exit here if no data
	if(!FD_ISSET(InFileHandle, ReadFDS))
		return;

	//Create a static 1MB+1K buffer - Max packet with chrome is 1MB
	const int BufferLen=1024*(1024+1);
	static char* Buffer=0;
	if(!Buffer)
		Buffer=malloc(BufferLen);

	//If not chrome, just pass the data as is
	char* Side=(IsLeft ? "left" : "right");
	if(!IsChrome) {
		int ReadSize=read(InFileHandle, Buffer, BufferLen);
		write(OutFileHandle, Buffer, ReadSize);
		if(IsLeft)
			fwrite(Buffer, ReadSize, 1, RecordLeft);
		Buffer[ReadSize]=0;
		fprintf(SideLog, "%s (%d): %s\n\n", Side, ReadSize, Buffer);
		fflush(SideLog);
		return;
	}

	//Read the 4 byte packet size and store it at the beginning of the buffer
	unsigned int PacketSize;
	read(InFileHandle, &PacketSize, 4);
	*(unsigned int*)Buffer=PacketSize;

	//Read in the packet and zero it out at the end for the string functions
	read(InFileHandle, Buffer+4, PacketSize);
	Buffer[PacketSize+4]=0;

	//Send fake product-info packet since rf-chrome-nm-host.exe was not responding to it
	if(AddRoboformAnswerHacks && IsLeft && strstr(Buffer+4, "\"name\":\"getProp\"") && strstr(Buffer+4, "\"args\":\"product-info\"")) {
		//The return packet with header at the front
		char VersionInfo[]="{\"callbackId\":\"2\",\"result\":\"{\\\"version\\\":\\\"9-6-1-1\\\",\\\"haveReportAnIssue\\\":true,\\\"haveBreachMon\\\":true,\\\"haveLoginIntoAccount\\\":true}\"}";

		//Simplistic version counter hack since chrome always sends 2 version info requests at the beginning
		static int VersionCount=2;
		VersionInfo[15]='0'+VersionCount;
		VersionCount++;

		SendLeft(VersionInfo);
	//Send fake initialization info packet since rf-chrome-nm-host.exe was not responding to it
	} else if(AddRoboformAnswerHacks && IsLeft && strstr(Buffer+4, "\"name\":\"Initialize2\"")) {
		SendLeft("{\"callbackId\":\"4\",\"result\":\"rf-api\"}");
	//Forward the packet to the other side and store in the "left" file if left side
	} else {
		write(OutFileHandle, Buffer, PacketSize+4);
		if(IsLeft)
			fwrite(Buffer, PacketSize+4, 1, RecordLeft);
	}

	//Output the packet to the log
	fprintf(SideLog, "%s (%d): %s\n\n", Side, PacketSize, Buffer+4);
	fflush(SideLog);
}

int main(void) {
	//Create pipes
	int pipe1[2]; //Parent writes to child
	int pipe2[2]; //Child writes to parent
	if(pipe(pipe1)==-1 || pipe(pipe2)==-1) {
		perror("pipe");
		exit(EXIT_FAILURE);
	}

	//Fork the current process
	pid_t pid = fork();
	if(pid==-1) {
		perror("fork");
		exit(EXIT_FAILURE);
	}

	//New (child) process
	if(pid == 0) {
		//Close unused ends of the pipes
		close(pipe1[1]); // Close write end of pipe1
		close(pipe2[0]); // Close read end of pipe2

		//Redirect stdin to the read end of pipe1
		dup2(pipe1[0], STDIN_FILENO);
		close(pipe1[0]);

		//Redirect stdout to the write end of pipe2
		dup2(pipe2[1], STDOUT_FILENO);
		close(pipe2[1]);

		//Move to the roboform home directory
		if(IsChrome) {
			if(chdir(HomePath) == -1) {
				perror("chdir");
				exit(EXIT_FAILURE);
			}
		}

		//Execute a command that reads from stdin and writes to stdout. The default is the chrome command. If not in chrome, you can fill in the exe and parameter you wish to use
		char *cmd[] = {"/usr/bin/wine", (char*)ExePath, "chrome-extension://pnlccmojcmeohlpggmfnbbiapkmbliob/", "--parent-window=0", NULL};
		if(!IsChrome) {
			cmd[0]="/usr/bin/php";
			cmd[1]="echo.php";
		}
		execvp(cmd[0], cmd);
		perror("execlp");
		exit(EXIT_FAILURE);
	}

	//---Parent process - forwards both sides---
	//Close unused ends of the pipes
	close(pipe1[0]); // Close read end of pipe1
	close(pipe2[1]); // Close write end of pipe2

	//Open the log files
	SideLog = fopen("./log", "w+");
	RecordLeft = fopen("./left", "w+");

	//Run the main loop
	int max_fd=pipe2[0]+1; //Other pipe is STDIN which is 0
	while(1) {
		//Create the structures needed for select
		fd_set read_fds;
		FD_ZERO(&read_fds);
		FD_SET(STDIN_FILENO, &read_fds);
		FD_SET(pipe2[0], &read_fds);

		struct timeval timeout;
		timeout.tv_sec = 10;
		timeout.tv_usec = 0;
	
		//Listen for an update
		int status = select(max_fd, &read_fds, NULL, NULL, &timeout);

		//Display "Status: x" if its setting is true
		if(DisplayStatus) {
			fprintf(SideLog, "Status: %d\n", status);
			if(status==0)
				fflush(SideLog);
		}

		//Exit on bad status
		if (status==-1) {
			perror("select");
			break;
		}

		//Check both sides to see if they need to forward a packet
		ForwardSide(STDIN_FILENO, pipe1[1], &read_fds, 1);
		ForwardSide(pipe2[0], STDOUT_FILENO, &read_fds, 0);
	}

	//Close pipes
	close(pipe1[1]);
	close(pipe2[0]);

	//Wait for the child process to finish
	wait(NULL);

	return EXIT_SUCCESS;
}
Opening IntelliJ via the Symfony ide setting
Nasty Escaping Problems

I wanted a simple setup in Symfony where the programmer could define their ide in the parameters file. Sounds simple, right? Just add something like ide_url: 'phpstorm' to parameters.yml->parameters and ide: '%ide_url%' to config.yml->framework. And it worked great, however, my problem was much more convoluted.

I am actually running the Symfony server on another machine and am accessing the files via NFS on Windows. So, it would try to open PHPStorm with the incorrect path. Symfony suggests the solution to this is writing your own custom URL handler with %f and %l to fill in the filename and line, and use some weird formatting to do string replaces. So I wrote in 'idea://%%f:%%l&/PROJECT_PATH_ON_SERVER/>DRIVE_LETTER:/PATH_ON_WINDOWS/' (note the double parenthesis for escaping) directly in the config.yml and that worked, kind of. The URL was perfect, but IntelliJ does not seem to register the idea:// protocol handler like PHPStorm theoretically does (according to some online threads) with phpstorm://. So I had to write my own solution.

This answer on stackoverflow has the answer on how to register a protocol handler in Windows. But the problem now was that the first parameter passed to IntelliJ started with the idea:// which broke the command-line file-open. So I ended up writing a script to fix this, which is at the bottom.

OK, so we’re almost there; I just had to paste the string I came up with back into the parameters.yml, right? I wish. While this was now working properly in a Symfony error page, a new problem arose. The Symfony bin/console debug:config framework command was failing with You have requested a non-existent parameter "f:". The darn thing was reading the unescaped string as 'idea://%f:%l&...' and it thought %f:% was supposed to be a variable. Sigh.

So the final part was to double escape the strings with 4 percent signs. 'idea://%%%%f:%%%%l&...'. Except now the URL on the error pages gave me idea://%THE_PATH:%THE_LINE_NUMBER. It was adding an extra parenthesis before both values. This was simple to resolve in the script I wrote, so I was finally able to open scripts directly from the error page. Yay.



So here is the final set of data that has to be added to make this work:
Registry: HKCR/idea/(default) = URL:idea Protocol HKCR/idea/URL Protocol = "" HKCR/idea/shell/open/command = "PATH_TO_PHP" -f "PATH_TO_SCRIPT" "%1" "%2" "%3" "%4" "%5" "%6" "%7" "%8" "%9" parameters.yml: parameters: ide_url: 'idea://%%%%f:%%%%l&/PROJECT_PATH_ON_SERVER/>DRIVE_LETTER:/PATH_ON_WINDOWS/' config.yml: framework: ide: '%ide_url%' PHP_SCRIPT_FILE:
<?php
function DoOutput($S)
{
	//You might want to do something like output the error to a file or do an alert here
	print $S;
}

if(!isset($argv[1]))
	return DoOutput('File not given');
if(!preg_match('~^idea://(?:%25|%)?([a-z]:[/\\\\][^:]+):%?(\d+)/?$~i', $argv[1], $MatchData))
	return DoOutput('Invalid format: '.$argv[1]);

$FilePath=$MatchData[1];
if(!file_exists($FilePath))
	return DoOutput('Cannot find file: '.$FilePath);

$String='"C:\Program Files\JetBrains\IntelliJ IDEA 2018.1.6\bin\idea64.exe" --line '.$MatchData[2].' '.escapeshellarg($FilePath);
DoOutput($String);
shell_exec($String);
?>
Download all of an author’s fictionpress stories

I was surprised in my failure to find a script online to download all of an author’s stories from Fiction Press or Fan Fiction.Net, so I threw together the below.

If you go to an author’s page in a browser (only tested in Chrome) it should have all of their stories, and you can run the following script in the console (F12) to grab them all. Their save name format is STORY_NAME_LINK_FORMAT - CHAPTER_NUMBER.html. It works as follows:

  1. Gathers all of the names, chapter 1 links, and chapter counts for each story.
  2. Converts this information into a list of links it needs to download. The links are formed by using the chapter 1 link, and just replacing the chapter number.
  3. It then downloads all of the links to your current browser’s download folder.

Do note that chrome should prompt you to answer “This site is attempting to download multiple files”. So of course, say yes. The script is also designed to detect problems, which would happen if fictionpress changes their html formatting.

//Gather the story information
const Stories=[];
$('.mystories .stitle').each((Index, El) =>
	Stories[Index]={Link:$(El).attr('href'), Name:$(El).text()}
);
$('.mystories .xgray').each((Index, El) =>
	Stories[Index].NumChapters=/ - Chapters: (\d+) - /.exec($(El).text())[1]
);

//Get links to all stories
const LinkStart=document.location.protocol+'//'+document.location.host;
const AllLinks=[];
$.each(Stories, (_, Story) => {
	if(typeof(Story.NumChapters)!=='string' || !/^\d+$/.test(Story.NumChapters))
		return console.log('Bad number of chapters for: '+Story.Name);
	const StoryParts=/^\/s\/(\d+)\/1\/(.*)$/.exec(Story.Link);
	if(!StoryParts)
		return console.log('Bad link format for stories: '+Story.Name);
	for(let i=1; i<=Story.NumChapters; i++)
		AllLinks.push([LinkStart+'/s/'+StoryParts[1]+'/'+i+'/'+StoryParts[2], StoryParts[2]+' - '+i+'.html']);
});

//Download all the links
$.each(AllLinks, (_, LinkInfo) =>
	$('a').attr('download', LinkInfo[1]).attr('href', LinkInfo[0])[0].click()
);

jQuery('.blurb.group .heading a[href^="/works"]').map((_, El) => jQuery(El).text()).toArray().join('\n');
Sending URLs as a file in an HTML form using AJAX
It is common knowledge that you can use the FormData class to send a file via AJAX as follows:
var DataToSend=new FormData();
DataToSend.append(PostVariableName, VariableData); //Send a normal variable
DataToSend.append(PostFileVariableName, FileElement.files[0], PostFileName); //Send a file
var xhr=new XMLHttpRequest();
xhr.open("POST", YOUR_URL, true);
xhr.send(DataToSend);

Something that is much less known, which doesn't have any really good full-process examples online (that I could find), is sending a URL's file as the posted file.
This is doable by downloading the file as a Blob, and then directly passing that blob to the FormData. The 3rd parameter to the FormData.append should be the file name.

The following code demonstrates downloading the file. I did not worry about adding error checking.
function DownloadFile(
    FileURL,     //http://...
    Callback,    //The function to call back when the file download is complete. It receives the file Blob.
    ContentType) //The output Content-Type for the file. Example=image/jpeg
{
    var Req=new XMLHttpRequest();
    Req.responseType='arraybuffer';
    Req.onload=function() {
        Callback(new Blob([this.response], {type:ContentType}));
    };
    Req.open("GET", FileURL, true);
    Req.send();
}

And the following code demonstrates submitting that file
//User Variables
var DownloadURL="https://www.castledragmire.com/layout/PopupBG.png";
var PostURL="https://www.castledragmire.com/ProjectContent/WebScripts/Default_PHP_Variables.php";
var PostFileVariableName="MyFile";
var OutputFileName="Example.jpg";
//End of User Variables

DownloadFile(DownloadURL, function(DownloadedFileBlob) {
    //Get the data to send
    var Data=new FormData();
    Data.append(PostFileVariableName, DownloadedFileBlob, OutputFileName);

    //Function to run on completion
    var CompleteFunction=function(ReturnData) {
        //Add your code in this function to handle the ajax result
        var ReturnText=(ReturnData.responseText ? ReturnData : this).responseText;
        console.log(ReturnText);
    }

    //Normal AJAX example
    var Req=new XMLHttpRequest();
    Req.onload=CompleteFunction; //You can also use "onreadystatechange", which is required for some older browsers
    Req.open("POST", PostURL, true);
    Req.send(Data);

    //jQuery example
    $.ajax({type:'POST', url:PostURL, data:Data, contentType:false, processData:false, cache:false, complete:CompleteFunction});
});

Unfortunately, due to cross site scripting (XSS) security settings, you can generally only use ajax to query URLs on the same domain. I use my Cross site scripting solutions and HTTP Forwarders for this. Stackoverflow also has a good thread about it.

Cross site scripting solutions
When you are forced to break the security model

So I was recently hired to set up a go-between system that would allow two independent websites to directly communicate and transfer/copy data between each other via a web browser. This is obviously normally not possible due to cross-site browser security settings (XSS), so I gave the client 2 possible solutions. Both of these solutions are written with the assumption that there is a go-between intermediary iframe/window, on a domain that they control, between the 2 independent site iframes/window. This would also work fine for one site you control against a site you do not control.

  1. Tell the browser to ignore this security requirement:
    • For example, if you add to the chrome command line arguments “--disable-web-security”, cross-site security checks will be removed. However, chrome will prominently display on the very first tab (which can be closed) at the top of the browser “You are using an unsupported command-line flag: —disable-web-security. Stability and security will suffer”. This can be scary to the user, and could also allow security breaches if the user utilizes that browser [session] for anything except the application page.
  2. The more appropriate way to do it, which requires a bit of work on the administrative end, is having all 3 sites pretend to run off of the same domain. To do this:
    1. You must have a domain that you control, which we will call UnifyingDomain.com (This top level domain can contain subdomains)
    2. The 2 sites that YOU control would need a JavaScript line of  “document.domain='UnifyingDomain.com';” somewhere in them. These 2 sites must also be run off of a subdomain of UnifyingDomain.com, (which can also be done through apache redirect directives).
    3. The site that you do not control would need to be forwarded through your UnifyingDomain.com (not a subdomain) via an apache permanent redirect.
      • This may not work, if their site programmer is dumb and does not use proper relative links for everything (absolute links are the devil :-) ). If this is the case:
        • You can use a [http] proxy to pull in their site through your domain (in which case, if you wanted, you could inject a “domain=”)
        • You can use the domain that you do not control as the top level UnifyingDomain.com, and add rules into your computer’s hostname files to redirect its subdomains to your IPs.

This project is why I ended up making my HTTP Forwarders client in go (coming soon).

Debugging AJAX in Chrome

It has always really bugged me that in Chrome, when you want to view the response and form data for an AJAX request listed in the console, you have to go through multiple annoying clicks to view these two pieces of data, which are also on separate tabs. There is a great Chrome extension though called AJAX-Debugger that gets you all the info you need on the console. However, it also suffered from the having-to-click-through problem for the request data (5th object deep in an object nest), and it did not support JSONP. I’ve gone ahead and fixed these 2 problems :-).


Now to get around to making the other Chrome plugin I’ve been needing for a while ... (Automatic devtool window focus when focusing its parent window)


[Edit on 2015-08-20 @ 8:10am] I added another patch to the Chrome extension to atomically run the group calls (otherwise, they sometimes showed out of order).

Also, the auto focusing thing is not possible as a pure extension due to chrome API inadequacies. While it would be simple to implement using an interval poll via something like Auto Hot Key, I really hate [the hack of] making things constantly poll to watch for something. I’m thinking of a hybrid chrome extension+AHK script as a solution.

Font size hack for Mac Web Browsers

Mac renders fonts differently than windows, which is a problem when trying to make cross-system compatible web pages. I've read in many places that using "em" instead of pixels fixes this problem, but sometimes using pixel based measurements is required for a project.

I found when testing a recent project's web page out on Apple's OSX that no matter what browser I used, the fonts were always 2px bigger than on windows, which threw off my layouts. So I used the simple JavaScript solution below (jQuery required). Note that this assumes all font sizes are in pixels. It might not hurt to add a check for that if you mix font size types.

$(document).ready(function() {
	if(/Macintosh/.test(navigator.userAgent))
		$.each(document.styleSheets, function(Indx, SS) {
			var rules=SS.cssRules || SS.rules;
			for(var i=0;i<rules.length;i++)
				if(rules[i].style && rules[i].style.fontSize!='')
					rules[i].style.fontSize=(parseInt(rules[i].style.fontSize, 10)-2)+'px';
});
HTML5 Video in Chrome for Android
It never ends when programming for browsers

Due to the facts of life and economic demand, a majority of the work I’ve been doing over the past 10 years has been web work (PHP, JavaScript, SQL, HTML, CSS). When I first started in this field, browser incompatibilities were a MAJOR problem, but nowadays, it’s incredibly rare for me to write a piece of code in one browser that doesn’t automatically work in all the others without bugs. Maybe it’s just the fact I’ve been doing this for so long that I know what to avoid, but I’d like to think it’s mostly because the browser makers have gotten their acts together and subscribe to making everything compatible by following [W3C] guidelines.

Browser incompatibilities still creep up from time to time though, and I’ll be writing up about a few of them in some of my upcoming posts. The majority and biggest problems I seem to run into nowadays revolve around mobiles.


So in Google Chrome for Android, when trying to include an HTML5 video, the “autoplay” HTML5 attribute seems to be ignored. The obvious less-than-optimal hack would be to just include a “.play()” call in JavaScript, but this seems to only work if the action is triggered by the user (like when trying to create a popup window). So as far as I can see right now, there is no way to autoplay a video in Google Chrome for Android.

UTF8 fix for iOS mail
Thanks apple</sarcasm>

Nowadays, it just makes sense to do everything in utf8 from the start. Most everything of consequence now supports it, it keeps byte count down for most anyone using an alphabet that is primarily latin, it is compatible with a old of older software, and can help lead to some useful shortcuts in programming. A very good number of libraries and languages even assume it as the default character encoding now.

It’s especially nice for html and web pages, so content can just be pasted in as-is, except of course for single and double quotes (which I always replace with ’ “ ” anyways) and < > &. However, I was recently thrown for a loop when my utf8 encoding was not being read correctly in Apple’s iOS mail client. After lots of testing and research, I came to the conclusion that it just plain doesn’t support utf-8 by default! I think I read somewhere you have to install foreign language packs to make it available, but that doesn’t help our normal latin-based-alphabet users.


The simple solution for diacritic (and other html encodable) characters is to just encode them as html: (only supported for php>=5.3.4)
function EncodeForIOS($String) //This assumes the following characters are already encoded (line 2): & < >
{
	$MailHTMLConvertArray=get_html_translation_table(HTML_ENTITIES, ENT_NOQUOTES, 'UTF-8');
	unset($MailHTMLConvertArray['&'], $MailHTMLConvertArray['<'], $MailHTMLConvertArray['>']);
	return strtr($String, $MailHTMLConvertArray);
}
iGoogle Security Problems
For a company that stresses security...

I’ve recently been having problems using the Google Reader widget in iGoogle. Normally, when I clicked on an RSS Title, a “bubble” popped up with the post’s content. However recently when clicking on the titles, the original post’s source opened up in a new tab. I confirmed the settings for the widget were correct, so I tried to remember the last change I made in Firefox that could have triggered this problem, as it seems the problem was not widespread, and only occurred to a few other people with no solution found. I realized a little bit back that I had installed the HTTPS Everywhere Firefox plugin. As described on the EFF’s site “HTTPS Everywhere is a Firefox extension ... [that] encrypts your communications with a number of major websites”.

Once I disabled the plugin and found the problem went away, I started digging through Google’s JavaScript code with FireBug. It turns out the start of the problem was that the widgets in iGoogle are run in their own IFrames (which is a very secure way of doing a widget system like this). However, the Google Reader contents was being pulled in through HTTPS secure channels (as it should thanks to HTTPS Everywhere), while the iGoogle page itself was pulled in through a normal HTTP channel! Separate windows/frames/tabs cannot interact with each other through JavaScript if they are not part of the same domain and protocol (HTTP/HTTPS) to prevent Cross-site scripting hacks.

I was wondering why HTTPS Everywhere was not running iGoogle through an HTTPS channel, so I tried it myself and found out Google automatically redirects HTTPS iGoogle requests to non secure HTTP channels! So much for having a proper security model in place...

So I did a lot more digging and modifying of Google’s code to see if I couldn’t find out exactly where the problem was occurring and if it couldn’t be fixed with a hack. It seems the code to handle the RSS Title clicking is injected during the “onload” event of the widget’s IFrame. I believe this was the code that was hitting the security privilege error to make things not work. I attempted to hijack the Google Reader widget’s onload function and add special privileges using “netscape.security.PrivilegeManager.enablePrivilege”, but it didn’t seem to help the problem. I think with some more prodding I could have gotten it working, but I didn’t want to waste any more time than I already had on the problem.

The code that would normally be loaded into the widget’s IFrame window hooks the “onclick” event of all RSS Title links to both perform the bubble action and cancel the normal “click” action. Since the normal click action for the anchor links was not being canceled, the browser action of following the link occurred. In this case, the links also had a “target” set to open a new window/tab.


There is however a “fix” for this problem, though I don’t find it ideal. If you edit the “extensions\https-everywhere@eff.org\chrome\content\rules\GoogleServices.xml” file in your Firefox profile directory (most likely at “C:\Users\USERNAME\AppData\Roaming\Mozilla\Firefox\Profiles\PROFILENAME\” if running Windows 7), you can comment out or delete the following rule so Google Reader is no longer run through secure HTTPS channels:

<rule from="^http://(www\.)?google\.com/reader/" 
to="https://www.google.com/reader/"/>

That being said, I’ve been having a plethora of problems with Facebook and HTTPS Everywhere too :-\ (which it actually mentions might happen in its options dialog). You’d think the largest sites on the Internet could figure out how to get their security right, but either they don’t care (the more likely option), or they don’t want the encryption overhead. Alas.

UTF8 BOM
When a good idea is still considered too much by some

While UTF-8 has almost universally been accepted as the de-facto standard for Unicode character encoding in most non-Windows systems (mmmmmm Plan 9 ^_^), the BOM (Byte Order Marker) still has large adoption problems. While I have been allowing my text editors to add the UTF8 BOM to the beginning of all my text files for years, I have finally decided to rescind this practice for compatibility reasons.

While the UTF8 BOM is useful so that editors know for sure what the character encoding of a file is, and don’t have to guess, they are not really supported, for their reasons, in Unixland. Having to code solutions around this was becoming cumbersome. Programs like vi and pico/nano seem to ignore a file’s character encoding anyways and adopt the character encoding of the current terminal session.

The main culprit in which I was running into this problem a lot with is PHP. The funny thing about it too was that I had a solution for it working properly in Linux, but not Windows :-).

Web browsers do not expect to receive the BOM marker at the beginning of files, and if they encounter it, may have serious problems. For example, in a certain browser (*cough*IE*cough*) having a BOM on a file will cause the browser to not properly read the DOCTYPE, which can cause all sorts of nasty compatibility issues.

Something in my LAMP setup on my cPanel systems was removing the initial BOM at the beginning of outputted PHP contents, but through some preliminary research I could not find out why this was not occurring in Windows. However, both systems were receiving multiple BOMs at the beginning of the output due to PHP’s include/require functions not stripping the BOM from those included files. My solution to this was a simple overload of these include functions as follows (only required when called from any directly opened [non-included] PHP file):

<?
/*Safe include/require functions that make sure UTF8 BOM is not output
Use like: eval(safe_INCLUDETYPE($INCLUDE_FILE_NAME));
where INCLUDETYPE is one of the following: include, require, include_once, require_once
An eval statement is used to maintain current scope
*/

//The different include type functions
function safe_include($FileName)	{ return real_safe_include($FileName, 'include'); }
function safe_require($FileName)	{ return real_safe_include($FileName, 'require'); }
function safe_include_once($FileName)	{ return real_safe_include($FileName, 'include_once'); }
function safe_require_once($FileName)	{ return real_safe_include($FileName, 'require_once'); }

//Start the processing and return the eval statement
function real_safe_include($FileName, $IncludeType)
{
	ob_start();
	return "$IncludeType('".strtr($FileName, Array("\\"=>"\\\\", "'", "\\'"))."'); safe_output_handler();";
}

//Do the actual processing and return the include data
function safe_output_handler()
{
	$Output=ob_get_clean();
	while(substr($Output, 0, 3)=='?') //Remove all instances of UTF8 BOM at the beginning of the output
		$Output=substr($Output, 3);
	print $Output;
}
?>

I would have like to have used PHP’s output_handler ini setting to catch even the root file’s BOM and not require include function overloads, but, as php.net puts it “Only built-in functions can be used with this directive. For user defined functions, use ob_start().”.

As a bonus, the following bash command can be used to find all PHP files in the current directory tree with a UTF8 BOM:

grep -rlP "^\xef\xbb\xbf" . | grep -iP "\.php\$"

[Edit on 2015-11-27]
Better UTF8 BOM file find code (Cygwin compatible):
 find . -name '*.php' -print0 | xargs -0 -n1000 grep -l $'^\xef\xbb\xbf'
And to remove the BOMs (Cygwin compatible):
find . -name '*.php' -print0 | xargs -0 -n1000 grep -l $'^\xef\xbb\xbf' | xargs -i perl -i.bak -pe 'BEGIN{ @d=@ARGV } s/^\xef\xbb\xbf//; END{ unlink map "$_$^I", @d }' "{}"
Simpler remove BOMs (not Cygwin/Windows compatible):
find . -name '*.php' -print0 | xargs -0 -n1000 grep -l $'^\xef\xbb\xbf' | xargs -i perl -i -pe 's/^\xef\xbb\xbf//' "{}"
Realtime StdOut pass through to Web Browser
Tying it all together

I had the need to pass a program’s [standard] output to a web browser in real time. The best solution for this is to use a combination of programs made in different languages. The following are all of these individual components to accomplish this task.

Please note the C components are only compatible with gcc and bash (cygwin required for Windows), as MSVC and Windows command prompt are missing vital functionality for this to work.




The first component is a server made in C that receives stdin (as a pipe, or typed by the user after line breaks) and sends that data out to a connected client (buffering the output until the client connects).

PassThruServer source, PassThruServer compiled Windows executable.


Compilation notes:
  • This compiles as C99 under gcc:
    gcc PassThruServer.c -o PassThruServer
  • Define “WINDOWS” when compiling in Windows (pass “-DWINDOWS”)

Source Code:
#include <stdio.h>
#include <malloc.h>
#include <fcntl.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>

//The server socket and options
int ServerSocket=0;
const int PortNumber=1234; //The port number to listen in on

//If an error occurs, exit cleanly
int error(char *msg)
{
	//Close the socket if it is still open
	if(ServerSocket)
		close(ServerSocket);
	ServerSocket=0;

	//Output the error message, and return the exit status
	fprintf(stderr, "%s\n", msg);
	return 1;
}

//Termination signals
void TerminationSignal(int sig)
{
	error("SIGNAL causing end of process");
	_exit(sig);
}

int main(int argc, char *argv[])
{
	//Listen for termination signals
	signal(SIGINT, TerminationSignal);
	signal(SIGTERM, TerminationSignal);
	signal(SIGHUP, SIG_IGN); //We want the server to continue running if the environment is closed, so SIGHUP is ignored -- This doesn't work in Windows
	
	//Create the server
	struct sockaddr_in ServerAddr={AF_INET, htons(PortNumber), INADDR_ANY, 0}; //Address/port to listen on
	if((ServerSocket=socket(AF_INET, SOCK_STREAM, 0))<0) //Attempt to create the socket
		return error("ERROR on 'socket' call");
	if(bind(ServerSocket, (struct sockaddr*)&ServerAddr, sizeof(ServerAddr))<0) //Bind the socket to the requested address/port
		return error("ERROR on 'bind' call");
	if(listen(ServerSocket,5)<0) //Attempt to listen on the requested address/port
		return error("ERROR on 'listen' call");

	//Accept a connection from a client
	struct sockaddr_in ClientAddr;
	int ClientAddrLen=sizeof(ClientAddr);
	int ClientSocket=accept(ServerSocket, (struct sockaddr*)&ClientAddr, &ClientAddrLen);
	if(ClientSocket<0) 
		return error("ERROR on 'accept' call");

	//Prepare to receive info from STDIN
		//Create the buffer
		const int BufferSize=1024*10;
		char *Buffer=malloc(BufferSize); //Allocate a 10k buffer
		//STDIN only needs to be set to binary mode in windows
		const int STDINno=fileno(stdin);
		#ifdef WINDOWS
			_setmode(STDINno, _O_BINARY);
		#endif
		//Prepare for blocked listening (select function)
		fcntl(STDINno, F_SETFL, fcntl(STDINno, F_GETFL, 0)|O_NONBLOCK); //Set STDIN as blocking
		fd_set WaitForSTDIN;
		FD_ZERO(&WaitForSTDIN);
		FD_SET(STDINno, &WaitForSTDIN);

	//Receive information from STDIN, and pass directly to the client
	int RetVal=0;
	while(1)
	{
		//Get the next block of data from STDIN
		select(STDINno+1, &WaitForSTDIN, NULL, NULL, NULL); //Wait for data
		size_t AmountRead=fread(Buffer, 1, BufferSize, stdin); //Read the data
		if(feof(stdin) || AmountRead==0) //If input is closed, process is complete
			break;
		
		//Send the data to the client
		if(write(ClientSocket,Buffer,AmountRead)<0) //If error in network connection occurred
		{
			RetVal=error("ERROR on 'write' call");
			break;
		}
	}
	
	//Cleanup
	if(ServerSocket)
		close(ServerSocket);
	free(Buffer);
	
	return RetVal;
}



The next component is a Flash applet as the client to receive data. Flash is needed as it can keep a socket open for realtime communication. The applet receives the data and then passes it through to JavaScript for final processing.

Compiled Flash Client Applet


ActionScript 3.0 Code (This goes in frame 1)
import flash.external.ExternalInterface;
import flash.events.Event;
ExternalInterface.addCallback("OpenSocket", OpenSocket);

function OpenSocket(IP:String, Port:Number):void
{
	SendInfoToJS("Trying to connect");
	var TheSocket:Socket = new Socket();
	TheSocket.addEventListener(Event.CONNECT, function(Success) { SendInfoToJS(Success ? "Connected!" : "Could not connect"); });
	TheSocket.addEventListener(Event.CLOSE, function() { SendInfoToJS("Connection Closed"); });
	TheSocket.addEventListener(IOErrorEvent.IO_ERROR, function() {SendInfoToJS("Could not connect");});
	TheSocket.addEventListener(ProgressEvent.SOCKET_DATA, function(event:ProgressEvent):void { ExternalInterface.call("GetPacket", TheSocket.readUTFBytes(TheSocket.bytesAvailable)); });
	TheSocket.connect(IP, Port);
}
function SendInfoToJS(str:String) { ExternalInterface.call("GetInfoFromFlash", str); }
stop();

Flash sockets can also be implemented in ActionScript 1.0 Code (I did not include hooking up ActionScript 1.0 with JavaScript in this example. “GetPacket” and “SendInfoToJS” need to be implemented separately. “IP” and “Port” need to also be received separately).
var NewSock=new XMLSocket();
NewSock.onData=function(msg) { GetPacket(msg); }
NewSock.onConnect=function(Success) { SendInfoToJS(Success ? "Connected!" : "Could not connect"); }
SendInfoToJS(NewSock.connect(IP, Port) ? "Trying to Connect" : "Could not start connecting");



JavaScript can then receive (and send) information from (and to) the Flash applet through the following functions.

  • FLASH.OpenSocket(String IP, Number Port): Call this from JavaScript to open a connection to a server. Note the IP MIGHT have to be the domain the script is running on for security errors to not be thrown.
  • JAVASCRIPT.GetInfoFromFlash(String): This is called from Flash whenever connection information is updated. I have it giving arbitrary strings ATM.
  • JAVASCRIPT.GetPacket(String): This is called from Flash whenever data is received through the connection.

This example allows the user to input the IP to connect to that is streaming the output. Connection information is shown in the “ConnectionInfo” DOM object. Received data packets are appended to the document in separate DOM objects.

JavaScript+HTML Source


Source Code: (See JavaScript+HTML Source file for all code)
var isIE=navigator.appName.indexOf("Microsoft")!=-1;
function getFlashMovie(movieName) { return (isIE ? window[movieName] : document[movieName]);  }
function $(s) { return document.getElementById(s); }

function Connect()
{
	getFlashMovie("client").OpenSocket($('IP').value, 1234);
}

function GetInfoFromFlash(Str)
{
	$('ConnectionInfo').firstChild.data=Str;
}

function GetPacket(Str)
{
	var NewDiv=document.createElement('DIV');
	NewDiv.appendChild(document.createTextNode(Str));
	$('Info').appendChild(NewDiv);
}



Next is an example application that outputs to stdout. It is important that it flushes stdout after every output or the communication may not be real time.

inc source, inc compiled Windows executable.


inc counts from 0 to one less than a number (parameter #1 [default=50]) after a certain millisecond interval (parameter #2 [default=500]).

[Bash] Example:
./inc 10 #Counts from 0-9 every half a second

Source Code:
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
	int NumLoops=(argc>1 ? atoi(argv[1]) : 50); //Number of loops to run from passed argument 1. Default is 50 if not specified.
	int LoopWait=(argc>2 ? atoi(argv[2]) : 500); //Number of milliseconds to wait in between each loop from passed argument 2. Default is 500ms if not specified.
	LoopWait*=1000; //Convert to microseconds for usleep

	//Output an incremented number every half a second
	int i=0;
	while(i<NumLoops)
	{
		printf("%u\n", i++);
		fflush(stdout); //Force stdout flush
		usleep(LoopWait); //Wait for half a second
	};
	
	return 0;
}



This final component is needed so the Flash applet can connect to a server. Unfortunately, new versions of Flash (at least version 10, might have been before that though) started requiring policies for socket connections >:-(. I don’t think this is a problem if you compile your applet to target an older version of Flash with the ActionScript v1.0 code.

This Perl script creates a server on port 843 to respond to Flash policy requests, telling any Flash applet from any domain to allow connections to go through to any port on the computer (IP). It requires Perl, and root privileges on Linux to bind to a port <1024 (su to root or run with sudo).

Flash Socket Policy Server (Rename extension to .pl)


Source Code:
#!/usr/bin/perl
use warnings;
use strict;

#Listen for kill signals
$SIG{'QUIT'}=$SIG{'INT'}=$SIG{__DIE__} = sub
{
	close Server;
	print "Socket Policy Server Ended: $_[0]\n";
	exit;
};

#Start the server:
use Socket;
use IO::Handle;
my $FlashPolicyPort=843;
socket(Server, PF_INET, SOCK_STREAM, getprotobyname('tcp')) or die "'socket' call: $!"; #Open the socket
setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, 1) or die "'setsockopt' call: $!"; #Allow reusing of port/address if in TIME_WAIT state
bind(Server, sockaddr_in($FlashPolicyPort,INADDR_ANY)) or die "'bind' call: $!"; #Listen on port $FlashPolicyPort for connections from any INET adapter
listen(Server,SOMAXCONN) or die "'listen' call: $!"; #Start listening for connections
Server->autoflush(1); #Do not buffer output

#Infinite loop that accepts connections
$/ = "\0"; #Reset terminator from new line to null char
while(my $paddr=accept(Client,Server))
{
	Client->autoflush(1); #Do not buffer IO
	if(<Client> =~ /.*policy\-file.*/i) { #If client requests policy file...
		print Client '<cross-domain-policy><allow-access-from domain="*" to-ports="*" /></cross-domain-policy>'.$/; #Output policy info: Allow any flash applets from any domain to connect
	}
	close Client; #Close the client
}
This could very easily be converted to another better [less resource intensive] language too.


How to tie all of this together
  1. Start the servers
    • In your [bash] command shell, execute the following
      Server/FlashSocketPolicy.pl & #Run the Flash Policy Server as a daemon. Don't forget sudo in Linux
      ./inc | ./PassThruServer #Pipe inc out to the PassThruServer
    • Note that this will immediately start the PassThruServer receiving information from “inc”, so if you don’t get the client up in time, it may already be done counting and send you all the info at once (25 seconds).
    • The PassThruServer will not end until one of the following conditions has been met:
      • The client has connected and the piped process is completed
      • The client has connected and disconnected and the disconnect has been detected (when a packet send failed)
      • It is manually killed through a signal
    • The Flash Policy Server daemon should probably just be left on indefinitely in the background (it only needs to be run once).
  2. To run the client, open client.html through a web server [i.e. Apache’s httpd] in your web browser. Don’t open the local file straight through your file system, it needs to be run through a web server for Flash to work correctly.
  3. Click “connect” (assuming you are running the PassThruServer already on localhost [the same computer]). You can click “connect” again every time a new PassThruServer is ran.
JavaScript problems when crossing windows Part 2
IE being a pain in the butt like usual

To continue the subject in my last post, these next cross-window bugs also derive from objects not being recognized properly when being passed between windows in JavaScript.

I needed the ability to dynamically run functions in the secondary window form the primary window where the parameters are taken from an array. Since a “function” from a secondary window is not seen as a function object from the primary window in IE, the apply member was not working.

I have included a fix for this below in the “RunFunctionInRemoteWindow” function, which is just a wrapper function in the second window that calls the apply function. This function manually copies the array through a for loop, instead of using slice, because in IE7 (but not IE8), the passed arrays were not seen as valid JSObjects, so the slice method (which is a standard method used for copying arrays by value) was not working.


LocalWindow.html [run this one]
<html><body>
<input type=button onclick="RunTest();" value='Click me when the second window has opened to run the test'>
<script type="text/javascript">

//Spawn the second window
var NewWindow=window.open('RemoteWindow.html');

//Run the test
function RunTest()
{
	LocalAlertString('This is an alert generated from the local window');
	NewWindow.RemoteAlertString('This is an alert generated from the remote window');
	alert('The local window alert function is of type function: '+(LocalAlertString instanceof Function));
	alert('The remote window alert function is of type function: '+(NewWindow.RemoteAlertString instanceof Function));
	LocalAlertString.apply(window, ['This is an alert generated from the local window through the APPLY member']);

	try {
	NewWindow.RemoteAlertString.apply(NewWindow.window, ['This is an alert generated from the remote window through the APPLY member. This will not work in IE because the remote window\'s function is not actually a function.']);
	} catch(e) { alert('The REMOTE APPLY failed: '+e.message); }

	NewWindow.RunFunctionInRemoteWindow('RemoteAlertString', ['This is an alert generated from the remote window through the FIXED APPLY function.']);
}

//Generate an alert in the local window
function LocalAlertString(TheString)
{
	alert('Local String: '+TheString);
}

</script></body></html>

RemoteWindow.html [do not run this one, it is opened as a popup from LocalWindow.html]
<html><body><script type="text/javascript">
//Generate an alert in the remote window
function RemoteAlertString(TheString)
{
	alert('Remote String: '+TheString);
}

//Call functions in this window remotely through the "apply" member
function RunFunctionInRemoteWindow(FunctionName, Parameters)
{
	//Manually copy the passed Parameters since "Parameters" may not be a valid JSObject anymore (this could be detected and array.slice used if it is still valid)
	var ParametersCopy=[];
	for(var i=0;i<Parameters.length;i++)
		ParametersCopy[i]=Parameters[i];
	
	window[FunctionName].apply(window, ParametersCopy);
}
</script></body></html>
JavaScript problems when crossing tabs or windows
Too tired to think of a subtitle today

I was doing some research around April of 2009 on JavaScript interaction between web browser windows. I was doing this because web browsers are starting to split off each tab/window into separate processes/threads (Firefox is lagging in this), which can lead to some useful new implementations in the browser world, including multithreading. I wanted to explore the interaction between these windows to make sure there were no caveats that might creep up if I decided to take advantage of this.

The first one I found was that each browser window has its own instance of all of the base object classes, so prototypes do not carry over, and instanceof will not work as expected.

For example, if in WindowOne, you add a prototype to the Array class called IsArray, it is only accessible by arrays created in WindowOne. If you pass an array created in WindowOne into a second window, the prototype is still available on that one array (IIRC this was not true of some of the browsers at the time, but I tested again today, and it worked for IE8, Firefox3, and Google Chrome). Also, since the base object class in Window1 and other windows are not the same, an object created in Window1 and passed to another window will return false in a instanceof Object operation in that other window.


Here is some example code to help show what I’m talking about.

LocalWindow.html [run this one]
<html><body>
<input type=button onclick="RunTest();" value='Click me when the second window has opened to run the test'>
<script type="text/javascript">
Array.prototype.IsArray=true;
var NewWindow=window.open('RemoteWindow.html'); //Spawn the second window
function RunTest() { NewWindow.RunTest({}, [], new ExampleObject()); }; //Send the test data to remote window
function ExampleObject() { } //An example class
</script></body></html>

RemoteWindow.html [do not run this one, it is opened as a popup from LocalWindow.html]
<html><body><script type="text/javascript">
function RunTest(AnObject, AnArray, AnExampleObject)
{
   var MyTests=[
      'AnObject instanceof Object',
      'AnObject.IsArray',                               //Object.prototype does not have this (Array.prototype does)
      'AnArray instanceof Object',
      'AnArray instanceof Array',
      'AnArray.IsArray',                                //This was added to the Array.prototype in the parent window
      'AnArray instanceof opener.Array',                //This example does not work in IE7 because opener.x cannot be properly accessed
      'AnExampleObject instanceof opener.ExampleObject',//This example does not work in IE7 because opener.x cannot be properly accessed
      'AnExampleObject instanceof ExampleObject'        //This test should error because "ExampleObject" does not exist in this window
   ];
   
   for(var i=0;i<MyTests.length;i++) //This runs each test like the following: alert("TEST: "+(TEST));
      try {
         eval('alert("'+MyTests[i]+': "+('+MyTests[i]+'));');
      } catch(e) {
         alert('Error on test "'+MyTests[i]+'": '+(e.hasOwnProperty('message') ? e.message : e.toString()));
      }
}
</script></body></html>
Cross Domain AJAX Requests
Bypassing the pesky browser security model

Since I just released my AJAX Library, I thought I’d post a useful script that uses it. The function CrossDomainGetURL below uses the AJAX Library to make requests across domains in Firefox. It takes one more parameter (not in order) than the AJAX Library's GetURL function, which is an array of domains to pull cookies from for the AJAX request.


function GetCookiesFromURL(Domains) //Return all the cookies for Domains specified in the Domains array
{
	var cookieManager = Components.classes["@mozilla.org/cookiemanager;1"].getService(Components.interfaces.nsICookieManager); //Requires privileges, which is granted in CrossDomainGetURL
	var iter=cookieManager.enumerator, CookieList=[], cookie; //The object used to find all cookies, the final list of cookies, and a temporary object
	while(iter.hasMoreElements()) //Loop through all cookies
		if(((cookie=iter.getNext()) instanceof Components.interfaces.nsICookie) && Domains.indexOf(cookie.host)!=-1) //If a cookie whose host matches one of our domains
			CookieList.push(cookie.name+'='+cookie.value); //Add it to our final list
	return CookieList.join("; "); //Return the cookie list for the specified domains
}

function CrossDomainGetURL(URL, Data, CookieDomains, ExtraOptions) //See AJAX Library GetURL function. CookieDomains is an array specifying what domains cookies are pulled from for the AJAX call. 
{
	//Access universal privileges in Firefox (Required to get cookies for other domains, and to use AJAX with other domains). This functionality is lost as soon as this function loses scope.
	try { netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect"); }
	catch(e) { return alert('Cannot access browser privileges'); }

	if(CookieDomains instanceof Array) //If an array of domains is passed to get cookies from...
	{	
		ExtraOptions=((ExtraOptions instanceof Object) ? ExtraOptions : {}); //Make sure extra options is an object
		ExtraOptions.AdditionalHeaders=((ExtraOptions.AdditionalHeaders instanceof Object) ? ExtraOptions.AdditionalHeaders : {}); //Make sure extra options has an additional headers object
		ExtraOptions.AdditionalHeaders.Cookie=GetCookiesFromURL(CookieDomains); //Get cookies for the domains
	}
	
	return GetURL(URL, Data, ExtraOptions); //Do the AJAX Call
}
More Browser Bugs
I really hate web browser scripting due to the multitude of interoperability problems

I’ve been incredibly busy lately, especially with work, but I finally have some time for personal stuff like posting again, yay. I’m currently stuck at the airport, and am leaving at 7AM this morning on vacation for 10 days on a tour of the west coast (Los Angeles, Disney World, Hollywood, Las Vegas, Grand Canyon, etc). The main reason for this get away is I’ll be meeting up with a good friend and his fiancée for their vacation and will be attending his wedding in Las Vegas ^_^.

I am currently on one of those open network connections at the airport that you have to pay to use, tunneled through one of my SSH servers, so I can bypassing their pay service and get online for free to post this :-). Hey, it’s their own fault for not securing it properly lol. I periodically kept getting dropped connections due to a weak signal, so I had to get back up after finding the connection and walk around, using my iPod to detect signal strengths until I found a better area with a stronger signal because. The thing is proving to be very useful ^_^. Anywho, on to the content of the post.


I’ve recently run into a number of new bugs [new to me at least] in both IE (version 7) and Firefox (version 3) that I have not encountered before and, as usual, have to program around to accomplish my tasks. I thought I’d discuss 3 of these bugs.

  • Relative (non absolute) base URL paths do not work in either Firefox or Internet Explorer.

    Setting a base path for a website is often a necessity for websites that have web pages that are in subdirectories beyond the websites’s root directory. The reason for this is that the page-common layout of a web page usually refers to all images and content in a relative path. This is done for multiple reasons including:

    • Ease of moving the site between addresses like for test stages, or if the site is served from multiple domain names.
    • It’s easier to read source code URLs this way
    • It makes the HTML files smaller; though this isn’t a problem for most users these days because internet connection speeds are much faster.

    An example of W3C valid code that produces this error is as follows:
    <head><base href="/MySite/">
    
    The code, unfortunately, has to be an absolute URL like the following for current versions of IE and Firefox.
    <head><base href="http://domain.com/MySite/">
    

    One simple method to solve this problem is to use JavaScript to set an absolute base URL. Unfortunately, this then requires web browsers to have JavaScript enabled to work :-\. For this reason, this is really a quick fix for internal use that shouldn’t be put into production use unless JavaScript is required anyways.

    The following code will set a base of “http://domain.com/MySite/” for “http://domain.com/MySite/Posts/Post1.html”.

    <head>
    	<script type="text/javascript">
    		function GetBase() //Get the directory above the current path’s URL
    		{
    			return document.location.protocol+	//The protocol ("http:" or "https:")
    				'//'+				//End the protocol section with a //
    				document.location.hostname+	//The host (domain)
    				document.location.pathname.replace(/(\/[^/]*){2}$/,'')+ //This moves up 1 directory from the current path. To move up more directories, set the "2" in this line to NumberOfDirectoriesToMoveUp+1
    				'/';				//Add a '/' to set the end of the path as a directory
    		}
    		document.write('<base href="'+GetBase()+'">'); //Write a BASE object to set the current web page’s base URL to GetBase()
    	</script>
    </head>
    

    A simpler solution is to just have your parsing language (PHP for example) detect the server you are running on and set the proper base URL accordingly. This method assumes you know all the possible places/addresses your website will run on.

    <head><base href="<?=($_SERVER['HTTP_HOST']=='domain.com' ? 'http://domain.com/MySite/' : 'http://domain2.com/')?>"></head>
    
  • Reserved keywords in IE cannot be used as object members
    Example (JavaScript):
    var MyObject={};
    MyObject.return=function() { return true; }
    
    Solution: Instances of this must be encoded in strings
    var MyObject={};
    MyObject['return']=function() { return true; }
    
    This also occurs for other reserved keywords like “debugger” and “for”.
  • IE’s window does not have the “hasOwnProperty” member function like ALL OTHER OBJECTS

    This is a major nuisance because trying to find out if a variable exists and is not a prototype in the global scope is an important function. *sighs*

    The fix for this is using “window.VARIABLE!==undefined”, though this won’t tell you if the variable is actually instanced or [again] if it is part of the prototype; only if it is defined.


One more JavaScript engine difference between IE and Firefox is that in IE you can’t end a hash with an empty member. For example, the following works in Firefox, but not IE:

var b={a:1, b:2, c:3, d:4, };

This shouldn’t really be done anyways, so it’s not really a problem IMO. I ran across this when converting some bad Perl code (generated by YACC) which coincidentally allows this.


It’s really hard making everything compatible across all web browser platforms when they all contain so many nuances and bugs :-\.

Managing Firefox History
Software likes hiding sensitive information and keeping it persistent :-(

Since version 3 of Firefox, the browser has moved over from using flat files for keeping track of browsing history (history.dat) and bookmarks (bookmarks.html) to using SQLite databases (places.sqlite). This change over was required because the old flat file formats were badly implemented, clunky, and not able to handle the new demands of the location bar and browser history. Using a SQL database was the perfect solution for the complexity brought in with the new location bar and its dynamic searching of previous URLS, as SQL is easy to implement, is mostly compatible against multiple SQL application implementations (removing dependency on a single product), and powerful for cross referencing lookups. As a matter of fact, most of the data Firefox keeps now is stored in SQLite databases.

SQLite was also a good choice for the SQL solution because it can be implemented minimally straight into a product without needing a large install and a lot of bloat. While I like SQLite for this purpose and its ease of implementation, it lacks a lot of base SQL functionality that would be nice, like TABLE JOINS inside of DELETE statements, among many other language abilities. I wouldn’t suggest using it for large database driven products that require high optimization, which I believe it can’t handle. It’s meant as a simpler SQL implementation.


Anyways, I was very happy to see that when you delete URLs from the history in the newest version of Firefox that it actually deletes them out of the database as opposed to just hiding them, like it used to. The history manager actual seems to do its job quite well now, but I noticed one big problem. After attempting to delete all the URLs from a specific site out of the Firefox history manager, I noticed there were still some entries from that site in the SQLite database, which is a privacy problem.

After some digging, I realized that there are “hidden” entries inside of the history manager. A hidden entry is created when a URL is loaded in a frame or IFrame that you do not directly navigate too. These entries cannot be viewed through the history manager, and because of this, cannot be easily deleted outside of the history database without wiping the whole history.

At this point, I decided to go ahead and look at all the table structures for the history manager and figure out how they interact. Hidden entries are marked in places.sqlite::moz_places.history with the value “1”. According to a Firefox wiki “A hidden URL is one that the user did not specifically navigate to. These are commonly embedded pages, i-frames, RSS bookmarks and javascript calls.” So after figuring all of this out, I came up with some SQL commands to delete all hidden entries, which don’t really do anything anyways inside the database. Do note that Firefox has to be closed to work on the database so it is not locked.

sqlite3 places.sqlite
DELETE FROM moz_annos WHERE place_id IN (SELECT ID FROM moz_places WHERE hidden=1);
DELETE FROM moz_inputhistory WHERE place_id IN (SELECT ID FROM moz_places WHERE hidden=1);
DELETE FROM moz_historyvisits WHERE place_id IN (SELECT ID FROM moz_places WHERE hidden=1);
DELETE FROM moz_places WHERE hidden=1;
.exit

This could all be done in 1 SQL statement in MySQL, but again, SQLite is not as robust :-\. There is also a “Favorite’s Icon” table in the database that might keep an icon stored as long as a hidden entry for the domain still exists, but I didn’t really look into it.

The IPod Touch
And IPhones

So I decided to go over to the evil side recently and get an IPod Touch. I originally wanted to just try it out in The Apple Store, but I just couldn’t find out all I wanted to about it there, and was getting highly annoyed by the completely ignorant sale reps, who couldn’t answer any of my questions anyways, hovering over my shoulder. And, yes, I asked them a few questions and neither they nor their managers had a clue. >:-(

However, all the sales reps I’ve been talking to lately at different stores about the IPod Touch and other electronic products I’ve been interested in buying have been pushing me to just buy them, and return them if I’m not satisfied. This sales tactic is a bit new to me, and I don’t like buying something and returning it needlessly, but they suggest it, so I decided what the heck! I guess it’s assumed most people will buy it and either decide they like it, forget to return it, or are too lazy to return it! So I decided to go to Fry’s to grab one (IPod Touch 2G v2.2) for testing and possibly keeping if I liked it because The Apple Store were really uncool about a lot of things, and also charged a hefty restocking fee on return... jerks. The jury is still out on if I’ll be keeping it or not, but I decided to share some of my findings.

When I talk about the IPod Touch here, I am also talking about the IPhone, because they are basically the exact same product. The IPhone just has the camera and the phone features, but the rest of the software is all the same (they run on the same OS). I also have a few IPhone specific comments below, as a good friend of mine got one for XMas and I helped him out with setting it up and found out a few things about it at the same time. Whenever I refer to the IPod Touch from here on out, I am referring to both IPod Touches and IPhones.


First of all, as is advertised and highly touted, The IPod Touch has style. The design is wonderful, it has a lot of nifty features, and has lots of useful applications in the App Store, many of them free. The product itself is by far better than anything else I’ve tried on the market for music playing and general PDA (personal digital assistant) purposes.

The Blackberrys I’ve tried out at a Verizon store (the Storm and Curve IIRC) weren’t even in the same league as the IPod Touch. I also tried out a G1 (Google phone) at a TMobile store, and initial impressions were not spectacular. However, I can’t make a solid judgment on the G1 because I didn’t spend as much time with it as I could have, as I knew I couldn’t use it anyways. This is because I refuse to switch from the Verizon network because the signal quality and customer support I have received from them are worlds better than what I had ever received from Cingular (now AT&T), AT&T, and Sprint.


Now that I’ve gotten the initial information out of the way including why the IPod Touch is nice; on to all of the problems I’ve found with it.

  • Apple has horrible draconian policies regarding what can be put on an IPod Touch. Applications can only (legally) be put on the IPod Touch from the App Store, and Apple specifically regulates what is in the store, only allowing in it what is “best for their interests”. This, of course, includes denying any application in the App Store that “duplicates functionality” of an Apple product. This is bad for many reasons.
    • First and foremost, it’s not Apple’s place (though they argue that it is) to say who can develop and what can be developed for the IPod Touch, as long as it is not malicious in any way.
    • Apply very specifically blocks, quite often, products that would be excellent with great functionality because it “competes” with their generally inferior applications. Of course, one can unlock older IPod Touches, and I’m sure newer ones will be unlockable soon enough, so this problem can be bypassed. When a phone is unlocked, it can be theoretically used on a compatible network (not AT&T), and you can install any application you want to on it for free (as long as you can find it). The legality of this is questionable, but it’s not really risky.
    • This can force developers who have spent their time and effort to build a good product to not be accessible to the market, thereby completely screwing them after the fact. Apple is not specific on what can be put on the store, and is very subjective about the whole matter. Unfortunately, many developers have found themselves in this position after submitting their application to Apple for inclusion in the store.
    • Apple can decide to block a product after it has been released and people have bought it, deleting it from their phones without refund. I believe (but have no proof) that this has already happened when a product “duplicated the functionality” of a new application or feature in an application of theirs that was added after the fact.
  • The SMS (texting) interface on the IPhone is horrible. It only allows you to see part of the message that you are typing at any time (40 characters as a hazy guess). This could easily be fixed through a third party application, but Apple blocks any application that has SMS as it is “duplicating” the functionality of something they built. See the above bullet for more information.
  • The keyboard correction on the IPod touches leaves much to be desired, and there is no text prediction (suggesting words you are typing).
  • The virtual keyboard itself, while far ahead of any other virtual keyboard on a cell phone I have tried as far as usability goes, also leaves a lot to be desired, and can be quite annoying. I did get used to it pretty fast, but mistakes were very often and easily made, and I do not believe one could ever type as fast on a virtual keyboard, like the IPod Touch’s, as a physical keyboard, though I haven’t spent near enough time practicing on it to confirm this. The Google phones (at least the G1) solves this problem with its flip-out keyboard interface.
  • No multitasking. Period. The IPod Touch can do a few things at the same time (mainly play music), but 2 applications cannot run at the same time, and trying is against their developer agreement. Apple did this to control the user experience, so that a user doesn’t try running too many things at once, creating a bad user experience on the product from lag, which they would blame on Apple. Granted, the IPod Touch isn’t that powerful and it would be easy to bog down the system if too many things were running, but some things need to continue running in the background, with minimal processor time, to create a good experience.
    One of many examples of this is AIM (AOL Instant Messenger). When you start the application, it signs you on, and it keeps you online AIM until you specifically sign off (or perhaps if you turn off the phone, but I doubt it). This means that if you exit the AIM application after signing on, it shows other people that you are still online and receiving messages, even if you aren’t getting them. When you open the application back up, it retrieves all of the queued messages that were sent to you while the application was not opened. How hard and taxing would it be on the system to pop up a message informing the user a new message has come in while they are in other applications? Apparently too much, as Apple has to be black and white about the multitasking issue instead of allowing developers to petition for the right. Further, this queued AIM message system also tips one off to the fact that ALL AIM messages are sent through their servers to get to your IPod Touch, instead of your system directly connecting to the AIM servers, which is essentially an invasion on your private conversations.
  • Crashing. The IPod Touch itself has crashed on me twice within the first 2 hours I used it. When this occurred, I could not even start most all of the applications, even after turning the IPod Touch on and off (all the way, not standby mode). The only way I found to fix this was installing a new application from the App Store, or updating an application that had a new version ready. Go figure.
  • The IPhone can only take pictures, and not video. While there are products that allow taking video on the IPhone, they can only be installed by unlocking the phone, as Apple will not allow them on the App Store (see the top bullet for more information).
  • No searching for text on the current page in the web browser (Safari). This really bugs me as it is an essential feature I need in my web browser :-(.
  • I don’t trust installing Apple applications on my computers. I actually ended up using VMWare to use ITunes for this reason >:-(. ITunes likes embedding itself in your system in lots of places it shouldn’t, much like AOL since version 5.0. I do not believe it uninstalls itself completely either if you try. Also, when I tried uninstalling bonjour (an Apple communication protocol, which the program that runs it is also named, It used to be called Rendezvous) it didn’t even TRY to uninstall itself from my system. It just took the program off of a few lists and left all the files there. Even worse, I noticed that Bonjour was hooking a bunch of other processes it shouldn’t have been *sighs*.
  • I’ve saved my biggest complaint for last. All music on the IPod Touches (all IPods actually, and Zunes and Zens too) organize music by the MP3’s ID3 tags into genre/album/artist/etc, and do not allow organizing the music in folder based structures. While for most people this is not a problem, it is a big one for me. This is not a problem for people “new” to the MP3 player scene that buy their music straight from the ITunes Store, as that music is already organized for them with proper tags how they want it. My, and many other peoples collections, that have been being built for well over a decade (from CDs myself or friends have ripped ourselves for the most part), are not all tagged very well, as it never mattered. While I could go through my whole directory and tag everything properly, this would take upwards of hundreds of hours to do, and would be a waste of my time. Even so, I feel being able to organize by directory can be easier to navigate and organize then straight up genre/album/artist listings. This is a very basic functionality of all MP3 players I have had up until this point.
  • The above problem is actually solvable by playlist folder structures. Unfortunately, these are only available on some of the IPod types (for example, the Classic and Nano, IIRC) but not on IPod Touches or IPhones :-(. Further, building these nested folder playlist structures is also a minor pain. I started writing a script to do it for my music collection until I realized it didn’t work on my IPod Touch. ITunes transfers each folder to the IPod Touch as a flat playlist of all the songs in the playlists under it, but again, this is not a problem on some of the other IPod Systems. Unfortunately, if I was to spend the money on an IPod, I would like it to be a PDA too with much more functionality, which the IPod Touch satisfies, and the others do not.

As previously mentioned, I might not be keeping the IPod Touch, as I cannot justify the cost of it mainly as an MP3 player while I’ve already had other solutions that are almost as good for a number of years. I was one of the first adopters of MP3 players (of the MP3s on CD variety) back in 1998, I believe, and they still work great. However, I would probably get an IPhone were I able to use it on the Verizon network because it combines all the features I like on the IPod Touch with a phone. I would love to be able to use its excellent web browser (as far as cell phone browsers go) anywhere, not just when an accessible WiFi network was handy. The cost of an IPhone is more proportionate to what I’d like to spend since I’d be getting a phone and a music player out of it. Unfortunately, when unlocked, IPhones (and G1s) cannot work on Verizon, like it can the other networks, because Verizon uses a different kind of technology for its carrier signals (CDMA instead of GSM). Alas :-\.


Oh, yes, one more thing I wanted to mention. Apple was originally turning a blind eye to the unlocking IPhone market because most of them were going oversees to markets untapped by Apple, which is good for business for them. However, when Apple started expanding into other countries and this practice no longer served their needs, they added on a section to the AT&T contract you are forced to sign up for when buying the phone. It basically stipulates that if you cancel the AT&T contract (which incurs a fee after the first 30 days anyways) that you have to return the IPhone too. This way Apple is guaranteeing people can’t use the phone outside of AT&T.

Chrome no longer doing separate processes
Google broke Chrome :-(

There were at least 3 really neat things about Google Chrome when it made its spectacular entrance onto the web browser market a few months ago that made it a really viable option compared to its competitors. These features were [“are”, going to write it in present tense as they are still true]:

  1. It is fast, especially with JavaScript.
    • I have done speed tests on the JavaScript engines between browsers (which unfortunately I can’t post), and function calls, especially recursion, in the JavaScript engine in Chrome are incredibly faster when compared to the other Web Browsers.
    • However, SpiderMonkey, the new JavaScript engine being used in Firefox, seriously kicks all the other browsers in the butt in speed optimizations when it comes to loop iterations and some other areas. SpiderMonkey is available in the newest non-stable builds of Firefox (v3.1), but is not turned on by default.
  2. Different tabs run in different processes; which was very heavily advertised during Chrome’s launch. This carries with it two great advantages.
    1. A locked or crashed tab/window (usually through JavaScript) won’t affect the other tabs/windows.
    2. Since each tab is in a separate OS process, meaning they are also being run on separate OS threads, they can be run on separate logical operating cores (CPUs). This means that browser tabs can be run in parallel and not slow each other down (depending on the number of logical CPUs you have).

    Unfortunately, this is not as completely true as is widely advertised. New processes are only opened when the user manually opens a new window or tab. If a new window or tab is opened by JavaScript or by clicking a link, it still runs in the same process!

    Google has a FAQ Entry on this as follows:

    16. How can my web page open a new tab in a separate process?

    Google Chrome has a multi-process architecture, meaning tabs can run in separate processes from each other, and from the main browser process. New tabs spawned from a web page, however, are usually opened in the same process, so that the original page can access the new tab using JavaScript.

    If you’d like a new tab to open in a separate process:

    • Open the new tab with about:blank as its target.
    • Set the newly opened tab’s opener variable to null, so that it can’t access the original page.
    • Redirect from about:blank to any URL on a different domain, port, or protocol than that of the page spawning the pop-up. For example, if the page spawning the pop-up is on http://www.example.com/:
      • a different domain would be http://www.example.org
      • a different port would be http://www.example.com:8080
      • a different protocol would be https://www.example.com

    Google Chrome will recognize these actions as a hint that the new and old pages should be isolated from each other, and will attempt to load the new page in a separate process.

    The following code snippet can be used to accomplish all of these steps:

    var w = window.open();
    w.opener = null;
    w.document.location = "http://different.example.com/index.html";
    			

    The only problem is... THIS NO LONGER WORKS! Google recently (within the last 7 days) broke this FAQ recommendation with an automatic update to Chrome, so new tabs that are not manually opened by the user cannot be forced to new processes even with their little code snippet. Personally, I think this behavior is really lame and every tab should be able to open in separate processes every time no matter what, and still be able to talk to each other through process message passing. It may slow things down a little, but it’s a much more powerful model, IMO. An option for this in the window.open’s options parameter would be really nice...

  3. And of course, it’s Google, who, in general, “does no evil”. :-)
    • I can’t find the original article I was looking for on this “don’t do evil” topic :’( ... it basically said something to the extent that the “don’t be evil” motto only applies to business inside the USA, or something like that.
    • I have been a long time fan of Google though, and I still think that pretty much everything they’ve done, in general, has been for the good of everyone. There are always going to be blemishes on a company that size, and for how big they are and all they do, they’ve done a pretty damn good job, IMO. Just my two cents.
Erasing Website Cookies
A quick useful code snippet because it takes way too long to do this through normal browser means
This erases all cookies on the current domain (in the “ / ” path)

JavaScript:
function ClearCookies() //Clear all the cookies on the current website
{
	var MyCookies=document.cookie; //Remember the original cookie string since it will be changing soon
	var StartAt=0; //The current string pointer in MyCookies
	do //Loop through all cookies
	{
		var CookieName=MyCookies.substring(StartAt, MyCookies.indexOf('=', StartAt)).replace(/^ /,''); //Get the next cookie name in the list, and strip off leading white space
		document.cookie=CookieName+"=;expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/"; //Erase the cookie
		StartAt=MyCookies.indexOf(';', StartAt)+1; //Move the string pointer to the end of the current cookie
	} while(StartAt!=0)
}

I went a little further with the script after finishing this to add a bit of a visual aspect.
The following adds a textarea box which displays the current cookies for the site, and also displays the cookie names when they are erased.
<input type=button value="Clear Cookies" onclick="ClearCookies()">
<input type=button value="View Cookies" onclick="ViewCookies()">
<textarea id=CookieBox style="width:100%;height:100%"></textarea>
<script type="text/javascript">
function ViewCookies() //Output the current cookies in the textbox
{
	document.getElementById('CookieBox').value=document.cookie.replace(/;/g,';\n\n');
}

function ClearCookies() //Clear all the cookies on the current website
{
	var CookieNames=[]; //Remember the cookie names as we erase them for later output
	var MyCookies=document.cookie; //Remember the original cookie string since it will be changing soon
	var StartAt=0; //The current string pointer in MyCookies
	do //Loop through all cookies
	{
		var CookieName=MyCookies.substring(StartAt, MyCookies.indexOf('=', StartAt)).replace(/^ /,''); //Get the next cookie name in the list, and strip off leading white space
		CookieNames.push(CookieName); //Remember the cookie name
		document.cookie=CookieName+"=;expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/"; //Erase the cookie
		StartAt=MyCookies.indexOf(';', StartAt)+1; //Move the string pointer to the end of the current cookie
	} while(StartAt!=0)
	document.getElementById('CookieBox').value='Clearing: '+CookieNames.join("\nClearing: "); //Output the erased cookie names
}
</script>

Live Example:
Google Chrome - Bug?
And other browser layout bugs

To start off, sorry I haven’t been posting much the last couple of months. First, I got kind of burnt out from all the posting in August. More recently however, I’ve been looking for a J-O-B which has been taking a lot of my time. Now that I’ve found some work, I’m more in the mood to post again, yay. Hopefully, this coming month will be a bit more productive in the web site :-). Now on to the content.


Browser rendering [and other] bugs have been a bane of the web industry for years, particularly in the old days when IE was especially non-standards-compliant, so people had to add hacks to their pages to make them display properly. IE has gotten much better since then, but there are still lots of bugs in it, especially because Microsoft wants to not break old web sites that had to add hacks to make them work in the outdated versions of IE. Other modern browsers still have rendering problems too [see the acid tests], but again, these days it’s not so bad.


I just ran into one of these problems in a very unexpected place: Google Chrome. I kind of ignored the browser’s launch, as I’m mostly happy with Firefox (there’s a few major bugs that have popped up in Firefox 3.0 that are a super annoyance, but I try to ignore them), but needed to install Chrome recently. When I went to my web page in it, I noticed a major glitch in the primary layout, so I immediately researched it.


What it currently looks like
Rendered in Firefox v3.0.3
Chrome Error - What I wanted it to look like
What it looks like in Chrome v0.2.149.30
Which is apparently correct according to the CSS guidelines
Chrome Error - What it looks like in Chrome

So I researched what was causing the layout glitch, assuming it was my code, and discovered it is actually a rendering bug in Firefox and IE, not Chrome (I think)! Basically, DIV’s with top margins transfer their margins to their parent DIVs, as is explained here:

Note that adjoining vertical margins are collapsed to use the maximum of the margin values. Horizontal margins are not collapsed.
The text there isn’t exactly clear cut, but it seems to support my suggestion that Chrome has it right. Here is an example, which renders properly in Chrome, but not IE and Firefox.

<div style="background-color:blue;width:100px;height:100px;">
    <div style="margin-top:25px;width:25px;height:25px;background-color:green;">
</div>
 

In the above example, the green box’s top should be directly against the blue box, and the blue box inherits the margin and is pushed away from the top of the red box.


Honestly, I think this little margin-top caveat is quite silly and doesn’t make sense. Why collapse the margins when it would make more sense to just use the box model so the child has a margin against its parent. Go figure.

So to fix the problem, I ended up using “padding-top” on the parent instead of “margin-top” on the child. Blargh.



This isn’t the first bug I’ve discovered in Firefox either (which I usually submit to Firefox’s bugzilla).

At least one of the worst ones bugs I’ve submitted (which had already been submitted in the past, I found out) has been fixed. “Address bar should show path/query %-unescaped so non-ASCII URLs are readable” was a major internationalization problem, which I believe was a deal breaker for Firefox for anyone using any language that isn’t English. Basically any non-ASCII character in the address bar was escaped with %HEXVALUE instead of showing the actual character. Before Firefox got out an official bug fix, I had been fixing this with a nifty Firefox add-on, Locationbar2, which I still use as it has a lot of other nifty options.

One bug that has not yet been fixed that I submitted almost 2 years ago (it has been around for almost 4 years) is “overflow:auto gets scrollbar on focused link outline ”. I wrote up the following document on this when I submitted it to Mozilla:


I put this in an IFRAME because for some reason the bug didn’t show up when I inlined this HTML, go figure. The font size on the anchor link also seems to matter now... I do not recall it mattering before.

At least Firefox (and Chrome) are still way WAY more on the ball than IE.


Edit on 2009-7-26: The margin-top bug has been fixed on Firefox (not sure which version it happened on, but I’m running version 3.0.12 currently).

Custom Fonts in Web Browsers
Solutions for a strict medium

A very important part of the design world is fonts, but it is an unfortunately annoying part of web browser land. There are very few fonts that come by default with OSs and even less default ones that match each other across all OSs, so your website won’t look the same across all platforms unless you use the right combinations. It’s much pretty guaranteed that if you want anything even remotely special in terms of a font somewhere on your website, you will be out of luck to match it across all platforms.

The commonplace solution for this is, of course, creating images for whenever you need special fonts displayed. While this is the most elegant solution, it is only appropriate for special circumstances, and not normal site content, as image file sizes can get ridiculous, and you lose plain text advantages like searchability and search engine recognition. Another solution is to request the user to download the font, like here. While this is a valid solution, the vast majority of users would not download the font because, mostly, they don’t care enough, and secondly, people generally know not to go download unfamiliar files on the internet when they don’t have to, for security reasons.

This has actually been a problem for me recently as I realized some of the default fonts I use for my site, which have always come with Windows, do not have default equivalents that come with most Linux distributions, as I had assumed. That’s a topic for a different day though.


So I had a customer recently request the ability to dynamically display some text in a certain font, so I told him there are 2 solutions. The first would be to use JavaScript to load translucent PNG images, the second would be to embed a Flash applet, as Flash can store font files internally for use. So here are instructions and examples of both:


JavaScript + PNG Translucency (alpha blending) Method
There are 2 ways to create the PNG translucency in Photoshop; one easier but less effective way that doesn’t maintain quality, and a slightly more complex path with better results.
  • To start off for both paths, a screenshot (ALT+PRINT SCREEN to take only the current window) will need to be taken of the font rendered in black against a white background. This can be done in your favorite word processor as long as it properly renders with translucency, or (for Windows) by just going to the font file in “c:\windows\fonts” and opening it, which uses “fontview.exe”.
  • After you have the screenshot, open a new file in Photoshop (File > New OR CTRL+N) and paste the screenshot into a new layer (Edit > Paste OR CTRL+V)
  • Delete the background layer, which requires the layer window is open (Window > Layers OR F7 to toggle its display). Right click the text portion “Background” of the background layer, and choose “Delete Layer”.
  • Select the region that contains your font’s alphabet (M for selection tool) and crop it (Image > Crop).
  • You might want to zoom in at this point for easier viewing (CTRL++ for in, CTRL+- for out).
  • The easy way from there:
    • Deselect the area (Select > Deselect OR CTRL+D).
    • Select the Magic Wand tool (W), set Tolerance to 0, check Anti-Aliased, and uncheck Contiguous
    • Select a pure white pixel and then delete the selection (DELETE)
    • You now have a translucent image that you can save and use, but the translucency isn’t that of the original font, as that is not how the magic wand tool works.
    Example using “Aeolus True Type Font” (Set against a green background via HTML for example sake)
    Translucent Aeolus True Type Font Easy Method
  • The better way:
    • Add a mask to your current layer (Layer > Add Layer Mask > Reveal All)
    • Go to the channels window (Window > Channels to toggle its display, it should be in the same window as Layers, in a separate tab) and select either the red, green, or blue layer. It doesn’t matter which as they should all hold the exact same values (grayscale [white-black colors] have the same red, green, and blue values), so red channel (CTRL+1) is fine.
    • Copy the channel (CTRL+C) (the entire workspace should still be selected after the crop)
    • Select the mask channel (CTRL+\), and you also need to make it visible (toggle the little eyeball icon besides it)
    • Paste into the mask channel (CTRL+V), invert it (Image > Adjustments > Invert OR CTRL+I), and then make it invisible again (untoggle little eyeball icon besides it)
    • Reselect the RGB contents (CTRL+~) and flood fill it with black [or your color of choice]: Paint Bucket Tool (G), 255 tolerance, no antialias
    • You now have a translucent image of the font that you can save and use that has the original font quality. You can test it by adding a white layer below it.
    Example using “Aeolus True Type Font” (Set against a green background via HTML for example sake)
    Translucent Aeolus True Type Font Good Method
From there the image file can be split up into individual images called “a.png”, “b.png”, etc, and a simple JavaScript string could be used to convert a string to display the picture text like “'MyString'.replace(/(.)/g, '<img src="$1.png">')”.
Example (this is produced by JavaScript):

Internet Explorer 6 also has the added problem of not allowing translucent images, so a hack is needed for this. Basically, an element (like a blank image) needs to have its filter style set like the following (JavaScript DirectX hack...)
style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='IMAGELOCATION', sizingMethod='scale')";


Flash Method
While this method is much quicker to complete and easier to pull off than the previous method, it is also more prone to problems and browser incompatibility. Flash and JavaScript never got along well enough in my book. Anywho, here’s the process. (Source file here)
  • In a new Flash document (v5.0+), create a text box with the following properties:
    • Type: “Dynamic Text”
    • var: MyText
    • Font: YOURFONTCHOICE
    • Embed (button): Select the set of characters the dynamic text box might display. The less glyphs you select, the smaller the output file will be. I included all alpha-numeric+punctuation in the below example (24.3KB).
  • That’s all you need for the Flash file, so all that’s left now is the JavaScript. The following function will set the text for you inside the movie. Also, you should set the embed (for normal browsers) and object (for IE) tags as different “id”s. The wmode is an important parameter here too, in that it makes the background invisible and the Flash applet more a part of the web page (not a “separate window”).
    <object width="300" height="40" id="CustomFontIE" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000">
    	<param name="movie" value="OtherContent/CustomFonts/CustomFont.swf">
    	<param wmode="transparent">
    	<embed src="OtherContent/CustomFonts/CustomFont.swf" wmode="transparent" width="300" height="40" id="CustomFont" type="application/x-shockwave-flash">
    </object>
    <script type="text/javascript">
    	var IsIE=(navigator.appName.indexOf('Microsoft')!=-1);
    	function SetFlashText(NewText) { document.getElementById('CustomFont'+(IsIE ? 'IE' : '')).SetVariable('MyText', NewText); }
    </script>
    		
Example: (Set against a green background via HTML for example sake)
Enter text here:
Flash applet:



Firefox Extensions
Creating this list took way too long x.x;
So I jumped on the bandwagon and switched over to Firefox 3.0 when it came out a week or two ago, and was pleasantly surprised after some forced addon (used to be called extension) updates that everything worked brilliantly, including my favorite plugin, Firebug. I meant to write this post containing the addons I use and recommend a long time ago (once again, jumping on the bandwagon as everyone else and their dog that has a blog has done this topic too...), but now is as good as ever, especially since there are some updates for Firefox’s new version.

  • Adblock plus:
    • Block unwanted ads, images, and other multimedia.
    • Notes: Had to upgrade to this from just “Adblock”.
  • Adblock Filterset.G Updater:
    • A good set of ads to block for Adblock.
    • Notes: This doesn’t seem to be updated much anymore, and never checked to see if it worked with Adblock plus.
  • AI Roboform Toolbar for Firefox:
    • This is a software suite that always you to store passwords and personal information in encrypted (against AES) container files against a master password, so it’s pretty darn secure. It interfaces well with both IE and Firefox, and really helps with the filling out of personal info on those long tedious credit card forms and such.
    • Notes: I just wish it worked better outside of web browsers in the Windows environment... maybe one day I’ll make something for that, it would be fun.
  • BugMeNot:
    • Bypass web registration by checking the bugmenot.com database for free user-provided accounts.
  • Cache View:
    • Allows you to go to a cache for the page you are currently on from one of the many caching services like Google Cache, Coral Cache, and archive.org’s Wayback Machine.
    • Notes: I modified this to allow you to open all cache sites at once and to work for Firefox 3... maybe one of these days I’ll release the additions.
  • Download Statusbar:
    • “View and manage downloads from a tidy statusbar”
  • Firebug:
    • Required for [web] programmers, and still very useful for [web] developers. Some main features include:
      • JavaScript console for debug output and real-time JavaScript injection
      • JavaScript debugging
      • Realtime HTML DOM view
      • Realtime editing of DOM object information and positioning
      • DOM object CSS styles and where they came from
      • Downloaded files with their acquisition time
    • Notes: This is by far my favorite Firefox extension.
  • FireFTP:
    • Fully featured FTP manager.
    • Notes: You’ll never need to find a component FTP manager again once you’ve got this great Firefox integrated one.
  • Greasemonkey:
    • Insertion of JavaScript scripts on specified web pages.
  • Html Validator:
    • Realtime HTML validation of viewed web pages without having to go through w3c.org (web standards committee).
  • IE Tab:
    • “Embedding Internet Explorer in tabs of Mozilla/Firefox”
    • Notes: Since IE is sometimes a necessity when people refuse to conform to standards; and for developers to make sure things look right in the (unfortunately) most used web browser.
  • keyconfig [functions for] [Original?]:
    • (Re)bind keyboard shortcuts in Firefox.
    • Notes: I heavily rely on this since I’m a bit of a shortcut nut.
  • Locationbar2:
    • Adds options to the location bar like:
      • Highlighting the domain
      • Go to parent directories of your current URL by clicking
      • Hide the protocol (ex: “http://”).
    • Notes: I originally used this because it fixed a major problem that plagued Firefox and still plagues IE in which the address bars show escaped URLs (like “Firefox%20Extensions” instead of “Firefox Extensions”), so foreign URLs, which used lots of non-ASCII characters were next to impossible to read. I submitted this to Mozilla a ways back, and fortunately it was fixed for Firefox 3. This, IMO, is one of the most important fixes for Firefox 3, and it wasn’t even really advertised.
  • OpenDownload:
    • “Allows you to open ANY file (executables, etc.) from the internet into the default program assigned by your operating system, without needing to save it first.”
    • Notes: This is not marked as compatible with Firefox 3, but works fine. Firefox has added an “applications” tab to its options dialog that kind of takes care of this, but this still does at least allow direct opening of all file extensions without also mapping them in Firefox.
  • Tab Mix Plus:
    • “Tab browsing with an added boost.”
    • Notes: This is becoming less needed with each Firefox version upgrade, but it still has a lot of options in it that make it worthwhile.
  • User Agent Switcher:
    • Switch the “User Agent” of Firefox to fool pages into thinking you are using a different web browser or crawler.
    • Notes: There are many uses for this, one being to see how pages change for web crawlers.
  • View Cookies:
    • “View cookies of the current web page.”
    • Notes: Firefox 3 has added a feature to make this no longer needed, but I still much prefer the way this extension handles cookie viewing.
  • Web Developer:
    • A plethora of very useful web developer tools.
Other addons I no longer use but can still be useful
  • Answers:
    • Alt+Click on any word or term for quick info from answers.com.
  • ChatZilla:
    • An IRC (it’s a kind of chat room protocol) interface through Firefox.
    • Notes: I’m sure I’d use this a lot more... if I actually used IRC.
  • DownThemAll! & FlashGot:
    • Ability to download lots of content and/or links from web pages.
  • Morning Coffee:
    • “Keep track of daily routine websites and opens them in tabs.” You can set websites to load by individual day, weekday/weekend, or every day.
    • Notes: No longer really needed since RSS has become so commonplace.
  • Page Update Checker:
    • “Automatically checks to see if a web page has changed.”
    • Notes: No longer really needed since RSS has become so commonplace.
  • Referrer History:
    • Viewing how you browsed to pages through a referrer tree.
    • Notes: This is not compatible with Firefox 3, hasn’t been updated for ages, and is extremely slow as it uses a brute force method to build the referrer tree. I might see if I can find a better version of something like this (or make it) if the need ever arises again.
  • Torbutton:
    • Toggle completely anonymous web browsing at the push of a button.
    • Notes: I found using the tor network way too slow, so I have since abandoned it for faster methods, which I will post about some day. Tor still remains an excellent “full-proof” way to stay anonymous on the internet though.
  • VideoDownloader:
    • Download videos from many popular sites.
    • Notes: I prefer just using Firebug and a download manager now...
Addons I no longer use and are (I think) pretty much obsolete as of Firefox 3
  • Enhanced History Manager:
    • Lots of neat history managing features...
    • Notes: This addon hasn’t been updated in a long time... I’m not sure if it works with Firefox 3. To be honest, I don’t even remember what it does completely.
  • Image Zoom:
    • “Adds zoom functionality for images...”
    • Notes: Firefox 3 now has full page zoom, as opposed to just text, so this is no longer really needed.

And as a Bonus, MozBackup is a simple utility for creating backups of Mozilla products’ profiles.
An easier way to exchange style sheets in HTML
Simple JavaScripting

I have seen rather complex code out there for style sheet swapping in web browsers through JavaScript, and just found out a much simpler way works.

I could have sworn I tried to do real-time style sheet swapping a very long while back and none of my tests turned out satisfactorily, but a friend was just asking me about it, and I was redoing the tests, and it all worked out perfectly in an incredibly easy fashion in IE 6 & 7 and Firefox 2.5 & 3. All that needs to be done is swap the href of the link object pointing to the external style sheet file.

<link href="OLDSTYLESHEET.css" rel=stylesheet type="text/css" id=MyScriptSheet>
<input type=button onclick="document.getElementById('MyScriptSheet').href='NEWSTYLESHEET.css'">

Adding style sheets by dynamically inserting HTML via JavaScript seemed to work just fine too.

document.body.innerHTML+='<link href="NEWSTYLESHEET.css" rel=stylesheet type="text/css">';
Internet Explorer Identity Crisis
It just wants to think it’s Firefox
Does anyone else find it odd that IE reports itself as ‘Mozilla’ if you access the navigator.appCodeName variable? You can test this out by putting the following in your browser as the URL javascript:alert(navigator.appCodeName), or you could check out this script, where I noticed this, which reports all information that can be found out about you through going to a web page, and accessible via JavaScript/PHP.
W3C and web standards
And steps backwards in software evolution

It’s great to have standards so everything can play together nicely.  I’ve even heard IE8 should pass the Acid2 test with “Web Standard Compatibility” mode turned on, and it has been confirmed for a long time that FireFox3 will (finally) pass it.  Microsoft, of course, has a bit of a problem with backwards compatibility when everyone had to use hacks in the past to “conform” to their old IE software, which was, and still is, filled with bugs and errors; and with IE version upgrades, they need to not break those old websites.  This really technically shouldn’t be a problem if people properly mark their web pages with compatible versions of HTML, XHTML, etc, but who wants to deal with that? Compatibility testing and marking, especially in the web world, is a serious pain in the ass, which I can attest to after working with web site creation for many years, something I am not very proud of :-).  I am a C++ advocate, and Java/.NET hater, and yes, I’ve worked heavily in all of them.


Anyways, some new web standards even break old ones, for example:
<font><center></font></center>
is no longer allowed.  Non nested (ending child elements before the parent) is no longer possible in certain circumstances in HTML4, and definitely not allowed in XHTML, as that would be specifically against what XML was designed for.  This was one of my favorite parts of original HTML too, in that you could easily combine formatting elements in different sections and orders without having to redefine all previous formats each time.  Though CSS does help with this, it has its own quirks too that I consider to be a rather large failing in its design.  I should be expanding more on that later on.

And then there’s this one other oddity that has always bugged me.  Two standard HTML colors are “gray” and “lightgrey”... if that’s not a little confusing... and for the record, “grey” and “lightgray” do not work in IE.

Further, XML, while it has its place and reasons, really really bugs me.  Just the fact that it really slows things up and is overused where it’s not needed because it is the “popular” thing to do.  Come on people, is it that hard to create and use interfaces for binary compiled data?  Or even ini-type files for crying out loud... Until we have specific hardware designed and implemented to parse XML, or better text parsing in general, I will continue to consider XML a step backwards, a very unfortunate reoccurring reality in the software world.

GreaseMonkey, FireBug, and JavaScripting
Keeping up with the webmasters
A few days ago I threw together a script for a friend in GreaseMonkey (a FireFox extension) that removes the side banner from Demonoid. It was as follows (JavaScript).
var O1=document.getElementById('navtower').parentNode;
O1.parentNode.removeChild(O1);

This simple snippet is a useful example that is used for a lot of webpage operations. Most web page scripting just involves finding objects and then manipulating them and their parent objects. There are two common ways to get the reference to objects on a web page. One is document.getElementById, and another is through form objects in the DOM.
With the first getElementById, you can get any object by passing it’s id tag, for example,
<div id=example>
<script language=JavaScript>
	var MyObject=document.getElementById('example');
</script>
This function is used so often, many frameworks also abbreviate it with a function:
function GE(Name) { return document.getElementById(Name); }
I know of at least one framework that actually names the function as just a dollar sign $.

The second way is through the name tag on objects, which both the form and any of its form elements require. Only form elements like input, textarea, and select can use this.
<body>
	<form name=MyForm>
		<input type=text name=ExampleText value=Example>
	</form>
	<script language=JavaScript>
		document.MyForm.ExampleText.value='New Example'; //Must use format document.FormName.ObjectName
	</script>
</body>
This is the very basis of all JavaScript/web page (client side only) programming. The rest is just learning all the types of objects with their functions and properties.

So, anyways, yesterday, Demonoid changed their page so it no longer worked. All that needed to be done was change the 'navtower' to 'smn' because they renamed the object (and made it an IFrame). This kind of information is very easy to find and edit using a very nice and useful FireFox extension called FireBug. I have been using this for a while to develop web pages and do editing (for both designing and JavaScript coding) and highly recommend it.
FireBug in Action