So bluesmoon wrote a blog entry on function currying in javascript. Read it first, if you've got no idea what I'm talking about.
But the example given there is hardly the *nice* one - you don't need a makeAdder(), you can sprinkle a little bit more magical pixie dust to make a maker. I remembered that I had a better sample lying around from early 2005, but unfortunately it wasn't quoted in my journal entry.
I couldn't find the exact code I wrote back then, but here's a re-do of the same idea.
function curried(f, args, arity) { return function() { var fullargs = args.concat(toArray(arguments)); if(fullargs.length < arity) { /* recurse */ return curry(f).apply(null, fullargs); } else { return f.apply(null, fullargs); } }; } function curry(f, arity) { if(!arity) arity = f.length; return function() { var args = toArray(arguments); if(args.length < arity) { return curried(f, args, arity); } else { /* boring */ return f.apply(null, args); } }; }
Basically with the help of two closures (the two function() calls without names), I created a generic currying mechanism which can be used as follows.
function add(a,b) { return a+b;} add = curry(add); var add1 = add(1); var c = add1(2);
Now, the hack works because of the arguments object available for use in every javascript function. Also every function, being an object as well, lets you look up the number of arguments (arity) it accepts by default. You can even make a full-class decorator, if you pay more attention to the scope (null, in my examples) passed to the function apply().
Here's the full code example.
--Things are are rarely simple. The function of good software is to make the complex appear to be simple.
-- Grady Booch.
A few months back I bought myself a cycle - a Firefox ATB. For nearly two months before heading out to Ladakh, I cycled to work. One of those days, I carried yathin's GPS along with me. So yesterday night, I dug up the GPX files, out of sheer boredom (and inspired by one of shivku's tech talks). After merging the tracks and waypoints, I managed to plot the track on a map with the help of some javascript. Here's how it looks.
I have similar tracklogs from Ladakh, but they have upwards of 2000 points in each day, which do not play nicely with the maps rendering - not to mention the lack of maps at that zoom level. I need to probably try the Google maps api to see if they automatically remove nodes which resolve to the same pixel position at a zoom level.
I've put up the working code as well as the gpx parser. To massage my data into the way I want it to be, I also have a python gpx parser. And just for the record, I'm addicted to map/reduce/filter, lambdas and bisect.
--If you want to put yourself on the map, publish your own map.
I've sort of been toying around with AttackAPI over the weekend and interestingly, I figured out that I was vulnerable to a lot of the attack vectors that were present. But what javascript causes, javascript can fix too. So here's a quick fix to prevent an intruder from portscanning your local network for ftp or other ports.
FindProxyForURL: The proxy autoconfig file can be used to filter out requests to the naughty port scanners. The aim is to detect a bad URL, redirect it to a proxy which will log the referrer and raise the corresponding alarms. And to parse out the URL properly, I use the following regex.
var urlRegex = new RegExp( "^(([^:/?#]+):)?"+ // scheme "(" + "(//)?"+ // delim "(([^@]+)@)?" + // userinfo "([^/?#:]*)?" + // host "(:([^/?#]+))?"+ // port ")"+ "([^?#]*)"+ // path "(\\?([^#]*))?"+ // query "(#(.*))?$" // fragment );
After parsing out the URL, my very simple filter checks for a port value which is suspicious (i.e below 1024 and not 80) and redirects it to my local logging proxy which eats the request. I still haven't figured out a way of leaving a honeypot for attackers to ensure there's a human at the other end.
function FindProxyForURL(url, host) { var m = url.match(urlRegex); if(m) { var port = m[7]; if(port != "" && port != "80" && port.length < 4) return "PROXY 127.0.0.1:4242"; } else { return "PROXY 127.0.0.1:4242"; } return "DIRECT"; }
It should be perfectly possible for this technique to be extended to prevent XSS exploits with javascript land checking for common XSS attack vectors. But the essential problem is that this particular function cannot maintain context easily. The previous request cannot affect the current one, nor the current one affect the next request. Having minimal ability to learn does cause a large number of problems for a really practical solution - but if there is already such a hook, it might be possible to hook an extension into it.
--Too many people are thinking of security instead of opportunity.
-- James F. Byrnes
posted at: 01:23 | path: /insecurity | permalink |
Flockr generates digraphs out of your flickr contacts. This is what has triggered me to go off the straight & narrow path of low level programming into hacks with Graph networks and x-mixed-replace. Anyway, what is done is done - take a look at a canned demo if you are on Firefox 1.5 and above (can't host cgi scripts).
The really hard part of the above code comes out of the simple fact that HTML Canvas is totally pixel based. You cannot attach an event to a small circle drawn as lines & figures. The code inside graph.js has a class called NodeHandler which sort of implements event masks and handlers for a node I've drawn on canvas. The code uses a hashed bucket to determine which all nodes it needs to iterate over, rather than loop over every node in the graph for every mouse move - harsh lessons learnt from dotgnu's winforms. It works better than I'd expected of Javascript and certainly seems snappy enough.
Now, I'm off hacks for a while ... time to vent some energy on real code.
--An empty canvas has more potential for greatness than any painting.
One of the first cool things I saw in flickr was notes. They're those small boxes which you can drag across a picture to mark off a region or add some more context to something. When I recently started linking in flickr photos to my blog, these were some things I missed. Without a small box saying "That thin line is the road", a few of the more impressive photographs I'd got were quite ordinary landscapes.
While looking at the new flickr apis - especially the JSON apis, something clicked somewhere. Finally, there seemed to be a very nice way to do cross-domain requests from my blog (or literally any web-page) to flickr to read notes, tags and other information. Minimilastically, this is what my code does :
function myMethod(data) { alert(data["stat"]); } var photos_get_info = "http://api.flickr.com/services/rest/?" + "method=flickr.photos.getInfo&api_key="+api_key + "&format=json&jsoncallback=myMethod" + "&photo_id=" + photo_id + "&secret="+secret; /* cross-domain request */ (function(url) { var _s = document.createElement("script"); _s.src = url; document.body.appendChild(_s); })(photos_get_info);
The photo_id and secret are the two parts in a flickr image url, the first part is the id and the second the secret. Provided you've given valid data there, flickr will respond to your data load with something like the following data.
myMethod({"photo" : .... , "stat" : "ok" });
Which when interpreted by the browser, magically seems to call your callback myMethod. Isn't that beautiful or what ? Of course, this workaround is not necessarily new information for me - but pretty damn convenient. Either way, once you've got the cross-domain data, it is only a few steps away from taking that data and displaying it.
Take a closer look at the ugly javascript if you want, or just look at the pretty pictures or funny pictures or even your own pictures.
Actually, more than being able to embed notes in my blog, this has brought along an unexpected advantage. With this script, the flickr notes are scaled according to the picture, so that you can have notes for a large or original size picture. Maybe I should make this a GM script so that I can do the same in flickr's zoom.gne pages.
Either way, the fun ends here.
--It's difficult to see the picture when you are inside the frame.
Since I do not run any server side code, I'm always playing around with new client side tricks. For example, the XSL in my RSS or the sudoku solver. But recently I was playing with the HTML Canvas and was wondering whether there was some other way I could generate images client side with javascript. And it turns out that you can.
Tool of choice for moving image data from a javascript variable into a real image is a data: URI. And it also helps that windows bitmaps are so easy to generate, after all it was designed with simplicity in mind. Here's a chunk of code which should in most ways be self explanatory.
function Bitmap(width, height, background) { this.height = height; this.width = width; this.frame = new Array(height * width); } Bitmap.prototype.setPixel = function setPixel(x,y, c) { var offset = (y * this.width) + x; /* remember that they are integers and not bytes :) */ this.frame[offset] = c; }; Bitmap.prototype.render = function render() { var s = new StringStream(); s.writeString("BM"); s.writeInt32(14 + 40 + (this.height * this.width * 3)); /* 24bpp */ s.writeInt32(0); s.writeInt32(14+40); /* 14 bytes done, now writing the 40 byte BITMAPINFOHEADER */ s.writeInt32(40); /* biSize == sizeof(BITMAPINFOHEADER) */ s.writeInt32(this.width); s.writeInt32(this.height); s.writeUInt16(1); /* biPlanes */ s.writeUInt16(24); /* bitcount 24 bpp RGB */ s.writeInt32(0); /* biCompression */ s.writeInt32(this.width * this.height * 3); /* size */ s.writeInt32(3780); /* biXPelsPerMeter */ s.writeInt32(3780); /* biYPelsPerMeter */ s.writeInt32(0); /* biClrUsed */ s.writeInt32(0); /* biClrImportant */ /* 54 bytes done and we can start writing the data */ for(var y = this.height - 1; y >=0 ; y--) { for(var x = 0; x < this.width; x++) { var offset = (y * this.width) + x; s.writePixel(this.frame[offset] ? this.frame[offset] : 0); } } return s; };
Well, that was easy. Now all you have to do is generate a base64 stream from the string and put in a data: URL. All in all it took a few hours of coding to get Javascript to churn out proper Endian binary data for int32 and uint16s. And then it takes a huge chunk of memory while running because I concatenate a large number of strings. Ideally StringStream should have just kept an array of strings and finally concatenated them all into one string to avoid the few hundred allocs the code currently does. But why optimize something when you could sleep instead.
Anyway, if you want a closer look at the complete code, here's a pretty decent demo.
--Curiousity is pointless.