ryanbridges.org
7Oct/140

PhantomJS with Flash support OSX Binary available

Posted by ryan bridges

You can grab the OSX binary here. There is a known issue where the rendered plugin is not visible in screen captures. I will post an update when a solution is found.

Filed under: Uncategorized No Comments
14Jul/140

PhantomJS with Flash support win32 binaries available

Posted by ryan bridges

You can now use PhantomJS with flash on Windows again. The binary is available for download here. *NOTE: To insure that Phantom can rasterize the plugin, all Flash objects are forced to use transparent wmode. This overrides the wmode parameter of the object tag.

Filed under: Uncategorized No Comments
21May/1315

Putting the Flash back in PhantomJS

Posted by ryan

I think PhantomJS has reached a point where it no longer needs an introduction. I've been using it more and more in recent months for a variety of tasks. Everything from automating web page snapshots to page performance analysis.  The value of this tool is immeasurable and it's headless design makes it convenient to use on the desktop or server.

But there was one place where it wasn't convenient.

In my day job, I manage a highly instrumented RIA with several Flash components. As of version 1.5, plugin support was removed from PhantomJS. This was actually a brilliant move, as this allowed it to run without dependencies on X11, which meant it could run on almost any build server out of the box without additional dependencies.

But I really, REALLY wanted to perform headless testing of the callbacks from my flash plugins.

So on a rainy Atlanta Sunday, after reading blog post after blog post lamenting the lack of plugin support in current versions of PhantomJS, I forked the repo and added it back. You can grab my fork on github. The build process is still identical to the REAL PhantomJS :-)

https://github.com/r3b/phantomjs

The --load-plugins command line option returns, and the X11 dependencies along with it.  As a test, I used the page rendering example script to make a PNG of http://www.dhs.state.il.us/accessibility/tests/flash/video.html.

The 'snap.js' script. The 3-second delay should give the flash object enough time to load.

var page = require('webpage').create();
page.open('http://www.dhs.state.il.us/accessibility/tests/flash/video.html', function () {
	window.setTimeout(function(){
        page.render('video.png');
        phantom.exit();
    },3000);
});

Run from the command line
./bin/phantomjs --load-plugins=true snap.js

Creates video.png in the current directory

video

Feel free to open a ticket on github if you find a bug that is specific to this fork.  If you have any comments, good ideas, or if you just found this useful, drop me a line. I'd love to hear about it.

Stay lucky,

ryan

UPDATE:

You will need a few extra dependencies to build and run this version.  Also note that you will need to build from the master branch, as the version tags were created on the main project before I forked.

This is the script I used to provision my build servers

apt-get -y update
apt-get --no-install-recommends -y install build-essential git-core g++
apt-get --no-install-recommends -y install openssl chrpath libssl-dev libfontconfig1-dev libglib2.0-dev libx11-dev libxext-dev libfreetype6-dev libxcursor-dev libxrandr-dev libxv-dev libxi-dev libgstreamermm-0.10-dev xvfb

For those having issues, Here are 32- and 64-bit x86 binaries built on Ubuntu 10.04 (specifically for use with the Lucid boxes from Vagrant)

http://www.ryanbridges.org/downloads/phantomjs/phantomjs--linux-i686.tar.bz2

http://www.ryanbridges.org/downloads/phantomjs/phantomjs--linux-x86_64.tar.bz2

UPDATE 2: Build information for CentOS
Commenter julian writes:

We recently built a 64 bit version for Centos. It took a long time to get it working, which in the end hinged on getting the installation in the right order.

We built from source. At the compilation stage we found that we needed to do the following:

export LIBXCB_ALLOW_SLOPPY_LOCK=1

Having built the executable it was hard to get Flash working with it. Flash needed to be installed last for this to work successfully.

The version that finally worked was:

yum install -y xorg-x11-server-Xvfb xorg-x11-server-Xorg xorg-x11-fonts* dbus-x11 xulrunner.x86_64 nspr.x86_64 nss.x86_64
yum install -y phantomjs flash-plugin nspluginwrapper libcurl

The RPM (version 1.10.0 development) is downloadable here here:
http://www.botsphere.com/rpms/phantomjs-1.9-1.x86_64.rpm

Filed under: Uncategorized 15 Comments
10Apr/130

Where do the Teenage Mutant Ninja Turtles find their information online?

Posted by ryan

CNN.com/video It's not everyday that you can say you've influenced pop culture.

Selection_003

TMNT, S01E07

 

 

Filed under: Uncategorized No Comments
17Jan/130

Ball pit: first demo using the HTML5 Device Orientation and Motion APIs

Posted by ryan

I made this little demo as an attempt to familiarize myself with the HTML5 Device Orientation and Device Motion APIs.  With a little javascript (and a LOT of physics/math help from http://www.flashmonkey.co.uk/simple-javascript-physics/), I made some balls roll around the screen based on device orientation.  Enjoy!  *Note: it's a lot more interesting when viewed on a capable mobile device.

20130117_002748

Filed under: Uncategorized No Comments
16Jan/130

Build a better Javascript timer

Posted by ryan bridges

JavaScript timers are old. I couldn't tell you the first time I used one. Or when I realized they weren't all that reliable. The subject came up at the water cooler recently and I decided to try a few techniques I had learned over the years to see if I could get a little more accuracy.  You can get a little more background on timers and why they are unreliable in this article from John Resig. The punchline is: JavaScript is asynchronous, so it can only add the specified function to the stack when the time comes. There is no guarantee that the function will execute immediately, as there could be any number of things in queue waiting to be executed ahead of it.  So, what can we do?

First, the setup.  We are going to create a timer that keeps track of the difference in milliseconds from its initial start time to its execution time.  The function will then insert that time in an LI element and append it to a given UL element.  The first example is a simple page layout.

		<style>
			body:{
				width:100%;
			}
			#container{
				position:relative;
				width:960px;
				margin:0 auto;
			}
			h1{
				text-align:center;
			}
			ul{
				position:relative;
				width:30%;
				float:left;
				margin:0 3px;
				background:#cecece;
			}
		</style>
		<div id="container">
			<h1>A better JavaScript Timer, Example 1</h1>
			<ul id="outputTimer1">
				<li>This is the output from our first timer.</li>
			</ul>
		</div>

Next up, we'll write our initial javascript timer the old-fasioned way.

		<script>
			var interval=5000; //5-second interval (in millis)
			(function(window){ //we'll use a closure so our examples don't conflict
				var list=document.getElementById('outputTimer1'), //get a handle to our UL element
					start=Date.now(); //set our start time
				setInterval(function(){
					var elapsed=Date.now()-start,//get the elapsed time as soon as the function is called
						li=document.createElement('LI'); //create our list item.
					li.innerText="elapsed time is: "+elapsed; //set the text
					list.appendChild(li); //and append it to the list
				}, interval)
			}(window));
		</script>

For most of you, this probably ran just fine.  The code showed perfect 5000ms intervals and I must be crazy.  If we add some entropy to the page, you'll begin to see what I mean. In example #3, I added a simple animation loop.  Now you should start to see some erratic behavior. When I ran the example, it took only 2 iterations to throw the timer off by 41ms!  If only we had a separate thread where the timer could run without interference from the rest of the page...

Web Workers to the rescue?

The first optimization is to rework our timer as a recursive function using setTimeout.  This allows the timer to have a little bit of intelligence. Rather that merely executing 5000ms from the current execution, compensate for the overcrowded call stack by computing the time the next interval would have fired, had it not been late.

Function.prototype.interval = function (ms) {
	var func = this;
	function interval() {
		var obj = this, args = arguments, nextInterval=now()+ms;
		func.apply(obj, args);
		setTimeout(function(){interval.apply(obj, args);},nextInterval-now());
	}
	return interval;
}

Then we can apply this concept in a webworker

function now(){return (new Date()).getTime()};
var interval=5000, //5-second interval (in millis)
	start=now(); //set our start time
(function(){
	var elapsed=now()-start;
	self.postMessage(elapsed);
}.interval(interval)())

And catch it in our main page

//new hotness
(function(window){ //we'll use a closure so our examples don't conflict
	var list=document.getElementById('outputTimer2'),//get a handle to our UL element
		worker = new Worker('worker.js');//create a web worker with a script containing our new timer code
	worker.addEventListener('message', function(event) {//listen for messages from the worker
		if(!event.data)return;//ignore that initial execution to kick off the timer for the sake of consistency
		var li=document.createElement('LI'); //create our list item.
		li.innerText="elapsed time is: "+event.data; //set the text to the data passed back from the worker
		list.appendChild(li); //and append it to the list
	}, false);
	worker.postMessage(""); // start the worker.
}(window));

We can see in the finished product that, though the message handler is still at the mercy of the congestion in the main page thread, it is able to heal itself and stay a bit closer to the goal.

26Oct/110

About the author

Posted by ryan

I'm a 30-something parent and aging punk who has spent a dozen or so years in the computer industry. This is my attempt to document the little annoyances I come across so I have somewhere to look for them when they pop up again.

Thanks for stopping by,

ryan

Filed under: Uncategorized No Comments