Sometimes you can get in the zone just enough to be productive on a plane. On my flight to Mexico City yesterday, I created Endpoint a project that contains a server proxy, JavaScript client, and Greasemonkey Script with a mission. The mission is to take a URL, work out if it is a redirect (via a Location: header), and then return the final endpoint for it.
Why did I do this?
I was brainstorming functionality for a Twitter client with James Strachan (he is working on gtwit) and we talked about how annoying tinyurl / is.gd / snurl / you name it URLs are. They don't tell you where you are going, and you could get Rick Rolled (if you are lucky) or much much worse.
So, I wanted to create a library, and one client (Greasemonkey) to test it out. Then anyone else could use it too to resolve directly from their Web pages.
How does it work
You load up the JavaScript via script src and then you can call resolve, passing the URL and a callback that will get the result. A few examples:
Under the hood, a bunch of stuff is happening. I would love to be able to just use XMLHttpRequest to dynamically hit the URL and look at the headers, but the same-origin policy stops me.
This is why I have the server proxy, which returns a JSONP callback.
When you call resolve(url, callback) the script tag is created on the fly and added to the DOM. The callback function is all handled to allow multiple calls, and then the chain unravels.
Here you can see it all in action, showing how my Twitter stream will go through and the URLs will dynamically change from their tinyurl versions to whereyouaregoing.com:
I wanted to use App Engine to host the server proxy, but unfortunately I can't work out how to do that yet. You have access to the URLFetch API to access resources from App Engine. Unfortunately for me, one of the features is that it understands redirects and just goes on through to the full resource itself, with no way to get the endpoint from the headers in the response.
Also, Simon Willison just put up a simple service on App Engine, json-time, that "exposes Python’s pytz timezone library over JSON." I think that we will see a lot of these types of mini-Web services hosted on App Engine. Taking Python utility and making services from its goodness is an obvious choice.
An open source set of tools for persistence and distributed computing using intuitive standards-based JSON interfaces of HTTP REST, JSON-RPC, JSONPath, and HTTP Channels. The core of the Persevere project is the Persevere Server. The Persevere server includes a Persevere JavaScript client, but the standards-based interface is intended to be used with any framework or client.
The Persevere Server is an object storage engine and application server
(running on Java/Rhino) that provides persistent data storage of dynamic
JSON data in an interactive server side JavaScript environment. It is
currently in beta, and boasts a very solid feature set that should
interest JavaScript, Dojo and Ajax developers:
Create, read, update, and delete access to persistent data through
a standard JSON HTTP/REST web interface
Dynamic object persistence - expando objects, arrays, and
JavaScript functions can be stored, for extensive JavaScript persistence
support
Remote execution of JavaScript methods on the server through
JSON-RPC for a consistent client/server language platform
Flexible and fast indexed query capability through JSONPath
Comet-based data monitoring capabilities through HTTP Channels
with Bayeux transport plugin/negotiation support
Data-centric capability-based object level security with user
management, Persevere is designed to be accessed securely through Ajax
with public-facing sites
Comprehensive referencing capabilities using JSON referencing,
including circular, multiple, lazy, non-lazy, cross-data source, and
cross-site referencing for a wide variety of object structures
Data integrity and validation through JSON Schema
Class-based data hierarchy - typed objects can have methods,
inheritance, class-based querying
Pluggable data source architectures - SQL tables, XML files,
remote web services can be used as data stores
Service discovery through Service Mapping Description
There are terms of use that you should abide by, and some other comments:
An area to pay special attention to relates to correctly identifying
yourself in your requests. Applications MUST always include a valid and accurate http referer header in their requests. In addition, we ask, but do not require, that each request contains a valid API Key. By providing a key, your application provides us with a secondary identification mechanism that is useful should we need to contact you in order to correct any problems.
Check out the updated documentation for more details on each API:
Jacob Seidelin went on a ( crazy :) ) mission to create a pure JavaScript video player that didn't use Flash:
My first thought was to read binary video files using a technique like the Andy Na posted about here, figuring that there must be some really simple to parse video formats around, but I soon changed directions and decided to make up a whole new video format. Enter.. JSONVid. Using a player like mplayer, it is easy to export all frames in a movie clip to individual jpeg files, and using whichever language you prefer it is also fairly trivial to collect these files, base64 encode the bunch of them and throw them all together in a nice JSON file (I used this PHP script).
The format uses good ole data: URLs, which are finally supported in IE with version 8:
{
frm : "JSVID", // format id tag
ver : 1, // version number of format
width : 320, // width of video
height : 240, // height of video
rate : 15, // framerate (frames per second)
frames : 495, // number of frames in file
data : {
video : [ // here comes 495 data:uris containing base64 encoded jpeg image frames
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASABIAAD/7gAOQWRv ... ",
"data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEASABIAAD/7gAOQWRv ... ",
...
]
}
}
Then he created the player:
First strategy was to create an Image object for each frame and render it on a canvas element using drawImage(). That worked fine and performance was nice (although Opera used a lot of CPU), but I figured I'd try just using a regular image tag and just change the src property to another data:uri each frame. The change was barely noticeably in Firefox and Safari and it ran a bit better in Opera, so I lost the canvas and stuck with plain old images.
Now, it seems that Firefox will eat up all the memory in the world if you keep throwing new data:uris at the same image tag, which led to another change, so for each frame a new Image object was created and saved for later and as the video played, the previous frame Image was replaced by the new Image object. That seemed to work, but introduced an annoying delay as all these Image objects were created before playing, so I ended up moving the Image creation to actual render cycle where it simply checks if the frame Image has already been created, and if not, creates it.
There are a couple of tests to play with. It was also pointed out that maybe an animated gif/png would be a choice (without controls), and of course, Flash is still the best choice here, until we get video support in most browsers.
Oliver Steele is doing great work, and he has just released a gem called JCON which stands for JavaScript Conformance. It tests JSON values to make sure that they are valid for the new world of ECMAScript 4 type definitions (e.g. new { x:int, y:string }( 3, "foo" ) ).
// with JavaScript Fu
# this will succeed if e.g. response contains a script tag that includes
# fn("id", {x:1, y:2}, true)
response.should call_js(‘fn’) do |args|
args[0].should conform_to_js(‘string’)
args[1].should conform_to_js(‘{x:int, y:int}’)
args[2].should conform_to_js(‘boolean’)
# or:
args.should conform_to_js(‘[string, {x:int, y:int}, boolean]’)
end
In other JSON news, it appears that new ECMAScript standard will no longer reserve the words:
abstract boolean byte char double final float implements int interface
long native package private protected public short static synchronized
throws transient volatile
And Douglas Crockford says that no browsers reserve them, and thus he is unreserving them from jsLint.
var services = new dojox.rpc.Service("http://mydomain.com/mySMD");
var newsDeferred = services.getNews({query:"dojo"});
newsDeferred.addCallback(function(returnValue){
alert("A news item: " + returnValue[0]);
});
Neil Roberts asked about cross domain SMDs and Kris said:
Yes, we will use JSONP, although we use a special form, where the callback function will be derived directly from the name of the SMD, in order to allow for static creation of SMDs that can be accessed cross-domain.