Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Friday, December 30, 2011

Flash Sucks

But everything else sucks more.

Where is the alternative to the write-once run-anywhere platform that has a rich UI toolkit, is installed on almost all machines ... what? Java you say? Really, come now; Loading anything in Java in the browser feels like I'm booting up a Virtual Machine. What about Silverlight? No, not that either.
Standards you say? Ok, let's roll. You can do most of what Flash does with:
  1. CSS3
  2. HTML Video
  3. WebGL
  4. Adaptive Bitrate Streaming (progress)
  5. HTML Canvas
  6. Imaginary Partial Loading Support That Doesn't Exist (maybe the partially supported <script defer="defer">)
  7. SVG
  8. The Imaginary Sandboxing for Separation of Applications standard
  9. HTML Audio
  10. HTTPS
  11. WebSockets
  12. Imaginary Crossdomain.xml Equivalent That Doesn't Exist
  13. LocalStorage
  14. ECMAScript 5
  15. IndexedDB
And even if you got the imaginary things working and the drafts finalized you still need a solution that
  • Works on all major platforms
  • Works on all major browsers
  • Has no nuanced implementation details
  • Has non-conflicting, non-ambiguous standards
  • Is well understood
  • Has a usable IDE for graphic designers
  • Has a wide, cheap, coder base.
Flash does this. In fact, I had streaming, synchronized, animation and audio in 1996, on Netscape 2.0, on a Pentium 1 @ 120Mhz with 16MB of RAM, on a 28.8Kbps connection, on Windows 95. All I had to do was download a 160KB add-on and restart my browser; back before DOM 0, and when the W3C was moving from SGML to the fancy new "XML" standard.
A decade and a half later, going to the CSS3 equivalent I have to carefully choose the browser, then see my cpu hosed and still have frame drop, have audio sync problems, and have to load ALL of it before seeing ANY of it.
The Flash hate is totally misplaced. What they have done is absolutely phenomenal. I'm sorry that you see teeth whitening ads and porno site popups with it, but don't blame the technologists; that's like blaming Honda Of Japan because some asshole cut you off on the Freeway.
And besides, what will the ad-haters use in this future world of 2022? Some amalgamated FlashBlock equivalent that can easily just turn off all the annoying stuff? This line will be blurred and it won't be possible.
Adobe has done, and continues to do what Microsoft Failed at, what Apple Failed at, what Sun Failed at, and what Google is almost, but not quite, succeeding in, decades later.

Friday, November 11, 2011

The winners are: Opera, IE, Firefox, Chrome, Safari; in that order.

This is a response to a contentious blog entry I wrote two days ago.

In under 36 hours, a lot has changed:
  • ECMAscript.org has updated their tests
  • Opera 12 Alpha is out.
  • Firefox 10 Alpha is out.
Also, many said I didn't give Opera a fair shake. So now the beta and alpha builds have been included.

Here's the updated (2011-11-11) results. Each browser's data is compressed with bzip2.
BrowserFailsThe photoThe dataRelease Status
Opera 11.60 beta 11471ScreenshotXML ResultsBeta
IE 10 10.0.8102.06ScreenshotXML ResultsAlpha
Opera 12.00 alpha 111611ScreenshotXML ResultsAlpha
Firefox 10.0a2 2011-11-11160ScreenshotXML ResultsAlpha
Firefox 9.0164ScreenshotXML ResultsBeta
Firefox 8.0164ScreenshotXML ResultsRelease
IE 9 9.0.8112.16421322ScreenshotXML ResultsRelease
Chrome 17 17.0.932.0 dev-m415ScreenshotXML ResultsAlpha
Chrome 16 16.0.912.36 beta-m415ScreenshotXML ResultsBeta
Chrome 15 15.0.874.120 m416ScreenshotXML ResultsRelease
Safari 5.1.1 6534.51.22772ScreenshotXML ResultsRelease
Opera 11.52 11003751ScreenshotXML ResultsRelease
IE 8 8.0.6001.18702N/A[1]ScreenshotN/ARelease
1The test fails to run in IE8, much like the last time. But after the error is hit, the status bar quickly goes back to saying "done". The developers tools, however, shows the error in the same place.

Well, Opera wins. and the old becomes new again. IE10 still takes the number 2 slot with everything else staying nearly the same.

about:
Tests were done on Windows 8, XP, and Vista; to try to main consistency. If you want to contact the author, reply here below. The author is Chris McKenzie; a programmer dedicated to truth, no matter how crazy it gets. Check out his projects on github.

Wednesday, November 9, 2011

The Acid3 of JS has a few surprises.

Edit: Updated Results Are Available Here

Wikipedia has an article on a Javascript conformance test called sputnik from Google.

It has the results from various Desktop browsers on how standards-compliant they are. Now I know what you are thinking, probably #1 is Chrome because the test is from Google, followed by Opera, Safari, and Firefox; with IE trailing behind in a pitiful display of brokenness.

But that's not what Wikipedia shows. In fact, it shows IE as the most standards-compliant browser.

Microsoft has quite brilliant engineers and recently they've began to take their browser seriously again, but to say that Internet Explorer has the most standards compliant JS engine? This would be quite a departure from history.

I needed to verify these results, for my own sanity.

According to Wikipedia, the test has changed hands and is now hosted at test262.ecmascript.org. You can go there now, it's on a domain registered by Mozilla Corporation. So this doesn't look like some wonky unfair comparison that almost looks to be designed to make Microsoft look good. Let's get questions of legitimacy out of the way.

Here's the updated (2011-11-09) results. Each browser's data is compressed with bzip2.
BrowserFailsThe photoThe data
IE 10 10.0.8102.06ScreenshotXML Results
Firefox 8.0164ScreenshotXML Results
Firefox 9.0 (2011-11-08)164ScreenshotXML Results
IE 9 9.0.8112.16421322ScreenshotXML Results
Chrome 16.0.912.32 beta-m415ScreenshotXML Results
Chrome 15.0.874.106 m416ScreenshotXML Results
Opera 11.523750ScreenshotXML Results
IE 8 8.0.6001.18702N/A[1]ScreenshotN/A
1The test fails to run in IE8 and hits a Javascript error fairly early on.

IE 10 did the best by far. Surprised? Me too. The next up was Firefox. Also surprised? Yeah, here too. Then IE 9 ... IE 9? The world is crazy sometimes. Chrome comes in right above Opera, which basically eats shit ... that's a new one. What has this world come to?

One of the important things to note is that failures seem to happen in batches. That is to say it's successful for a few hundred (or a few thousand) tests, then a bunch of tests fail consecutively. Almost makes me think of that math exam you once got where questions 2-8 depended on you getting question 1 right.

These tests also don't speak to how performant the browsers are on, well, anything. Their are more factors than compliance-to-standards when it comes to providing the best web experience. Regardless, these results certainly support the on-going notion that IE is finally back in the running.

Further Work

I just looked at the number of failed tests; not focusing on the content of what tests failed. I'm not familiar enough (and just plain not smart enough) with the internals of ECMAScript to know whether the results warrant further investigation or concern. I do know from my own experience that I've fallen victim to many more IE Javascript bugs then other browsers. And perhaps, that's the important thing; not whether a feature is implemented, or passes a smoke screen test, but whether the feature has problems. It would be great to hear what some of the browser developers have to say about these results.

about:
Tests were done on Windows 8, XP, and Vista; to try to main consistency. If you want to contact the author, reply here below. The author is Chris McKenzie; a programmer dedicated to truth, no matter how crazy it gets. Check out his projects on github.

Friday, April 8, 2011

Javascript Database

Throwing my hat into this one: A Generic Javascript Database for all.

Thursday, December 17, 2009

JS Array to object

So I wanted to be able to use an object in JSON but transfer it as an array.

The issue is that the syntax of el.name is nice, but the {name:"joe"} is longer then just ["joe"].

The way around it is very simple actually.

We'll start with a normal object
{
firstname: "Joe",
lastname: "Shmoe",
address: "123 Twiddledeedoo Lane",
}

Now we do this in javacript:

var keys = ["firstname", "lastname", "address"], obj = {};

And we transfer ["Joe","Shmoe","123 Twiddledeedoo Lane"] as the payload.

Now the code is fairly straight forward. Assuming:

var values = ["Joe","Shmoe","123 Twiddledeedoo Lane"];

To efficiently get back to the object we do the following:

do{
obj[keys.pop()] = values.pop();
} while (keys.length);

And that's it. It's so straight forward ... I don't know why it was a mystery for so long...

Wednesday, December 9, 2009

adding exclusionary search to craigslist

So I'm looking for a car, but craigslist doesn't support the - sign in search

Try doing -salvage in the car search ... doesn't work.

So I made a filter bar to exclude things from a craigslist search:

Get it here

Use it to type in obvious things...
Screen shot

Tuesday, December 8, 2009

Simplifying libpcap filter creation

Making a capture filter for tcpdump from wireshark has always been a pain in my mind. Maybe there is a nice tool out there to do it for me --- but I really don't know. So the useful syntax for tcpdump is basically:
(network protocol)[offset] == (decimal value)
For instance:
ether[100] == 123 and ether[102] == 124
I mean sure, some wankers probably want to do more with their packets but I'm not one of them. I simply have a typical packet like this:
 0000  02 00 00 00 45 00 02 8a  db 46 40 00 40 06 b0 6c   ....E... .F@.@..l
0010 43 7f e9 5a 4a 7d 35 64 fa 4c 00 50 a0 b6 33 f4 C..ZJ}5d .L.P..3.
0020 6b 36 b9 97 80 18 20 8a ca 1e 00 00 01 01 08 0a k6.... . ........
0030 5b 11 94 89 ca d6 48 ed 47 45 54 20 2f 20 48 54 [.....H. GET / HT
0040 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a 20 67 6f TP/1.1.. Host: go
0050 6f 67 6c 65 2e 63 6f 6d 0d 0a 55 73 65 72 2d 41 ogle.com ..User-A
0060 67 65 6e 74 3a 20 4c 69 6e 6b 73 20 28 32 2e 31 gent: Li nks (2.1
0070 70 72 65 33 37 3b 20 46 72 65 65 42 53 44 20 37 pre37; F reeBSD 7
0080 2e 30 2d 52 45 4c 45 41 53 45 20 69 33 38 36 3b .0-RELEA SE i386;
0090 20 38 30 78 32 34 29 0d 0a 41 63 63 65 70 74 3a 80x24). .Accept:
00a0 20 2a 2f 2a 0d 0a 41 63 63 65 70 74 2d 45 6e 63 */*..Ac cept-Enc
00b0 6f 64 69 6e 67 3a 20 67 7a 69 70 2c 20 64 65 66 oding: g zip, def
00c0 6c 61 74 65 2c 20 62 7a 69 70 32 0d 0a 41 63 63 late, bz ip2..Acc
00d0 65 70 74 2d 43 68 61 72 73 65 74 3a 20 75 73 2d ept-Char set: us-
00e0 61 73 63 69 69 2c 20 49 53 4f 2d 38 38 35 39 2d ascii, I SO-8859-
00f0 31 2c 20 49 53 4f 2d 38 38 35 39 2d 32 2c 20 49 1, ISO-8 859-2, I
0100 53 4f 2d 38 38 35 39 2d 33 2c 20 49 53 4f 2d 38 SO-8859- 3, ISO-8
0110 38 35 39 2d 34 2c 20 49 53 4f 2d 38 38 35 39 2d 859-4, I SO-8859-
0120 35 2c 20 49 53 4f 2d 38 38 35 39 2d 36 2c 20 49 5, ISO-8 859-6, I
0130 53 4f 2d 38 38 35 39 2d 37 2c 20 49 53 4f 2d 38 SO-8859- 7, ISO-8
0140 38 35 39 2d 38 2c 20 49 53 4f 2d 38 38 35 39 2d 859-8, I SO-8859-
0150 39 2c 20 49 53 4f 2d 38 38 35 39 2d 31 30 2c 20 9, ISO-8 859-10,
0160 49 53 4f 2d 38 38 35 39 2d 31 33 2c 20 49 53 4f ISO-8859 -13, ISO
0170 2d 38 38 35 39 2d 31 34 2c 20 49 53 4f 2d 38 38 -8859-14 , ISO-88
0180 35 39 2d 31 35 2c 20 49 53 4f 2d 38 38 35 39 2d 59-15, I SO-8859-
0190 31 36 2c 20 77 69 6e 64 6f 77 73 2d 31 32 35 30 16, wind ows-1250
01a0 2c 20 77 69 6e 64 6f 77 73 2d 31 32 35 31 2c 20 , window s-1251,
01b0 77 69 6e 64 6f 77 73 2d 31 32 35 32 2c 20 77 69 windows- 1252, wi
01c0 6e 64 6f 77 73 2d 31 32 35 36 2c 20 77 69 6e 64 ndows-12 56, wind
01d0 6f 77 73 2d 31 32 35 37 2c 20 63 70 34 33 37 2c ows-1257 , cp437,
01e0 20 63 70 37 33 37 2c 20 63 70 38 35 30 2c 20 63 cp737, cp850, c
01f0 70 38 35 32 2c 20 63 70 38 36 36 2c 20 78 2d 63 p852, cp 866, x-c
0200 70 38 36 36 2d 75 2c 20 78 2d 6d 61 63 2c 20 78 p866-u, x-mac, x
0210 2d 6d 61 63 2d 63 65 2c 20 78 2d 6b 61 6d 2d 63 -mac-ce, x-kam-c
0220 73 2c 20 6b 6f 69 38 2d 72 2c 20 6b 6f 69 38 2d s, koi8- r, koi8-
0230 75 2c 20 6b 6f 69 38 2d 72 75 2c 20 54 43 56 4e u, koi8- ru, TCVN
0240 2d 35 37 31 32 2c 20 56 49 53 43 49 49 2c 20 75 -5712, V ISCII, u
0250 74 66 2d 38 0d 0a 41 63 63 65 70 74 2d 4c 61 6e tf-8..Ac cept-Lan
0260 67 75 61 67 65 3a 20 65 6e 2c 20 2a 3b 71 3d 30 guage: e n, *;q=0
0270 2e 31 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 .1..Conn ection:
0280 4b 65 65 70 2d 41 6c 69 76 65 0d 0a 0d 0a Keep-Ali ve....

And now I want to like, create a libpcap filter on the "GET" to detect whether it's a GET request.

Now I know what the wankers are saying:
"Well, what if this was some crazy ass packet over here with the boundary of one layer of the network stack just happening to translate into the ASCII character 'G' and then say, the signature or magic number of the next layer down translating into 'ET'. THEN WHAT? Then what?"

Um, then, I get those packets too; all zero of them. Really. I mean, get a life. That shit doesn't happen.

So let's go back to the real problem. I want to use wireshark and figure out how to write this ...

So I fire up wireshark and then go to the three pane view. I expand the "Hypertext Transfer Protocol" node, then the "GET" node and right click on "Request Method: GET". I go up to apply as filter then click "selected":

This seems quite reasonable. After clicking on it I do indeed get something in the filter syntax:

Absolutely stunning. I get this:
http.request.method == "GET"
That's not libpcap. Totally not it. You totally lose. I cannot pass that string to tcpdump. Luckily, the wireshark people have a command line capture form of wireshark, called tshark. Fantastic, let's see how to use it! :-)

$ tshark -h
TShark 1.0.3
Dump and analyze network traffic.
See http://www.wireshark.org for more information.

Copyright 1998-2008 Gerald Combs (email withheld by me) and contributors.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Usage: tshark [options] ...

Capture interface:
-i <interface> name or idx of interface (def: first non-loopback)
-f <capture filter> packet filter in libpcap filter syntax
-s <snaplen> packet snapshot length (def: 65535)
-p don't capture in promiscuous mode
-y <link type> link layer type (def: first appropriate)
-D print list of interfaces and exit
-L print list of link-layer types of iface and exit


Great, just great. You can't even accept your own syntax as a capture filter, just as a display one. I'm trying to reduce file size here...

What's the point?


So anyway, to make life easy I did a nice javascript app, as I love to do sooooo much and you can use it here.

So we go back to my initial packet and copy and paste it in the gargantuan textarea and click the only button there 'process'.

After you click on the obvious blue links, something magical starts to happen:


The filter syntax shows up for you. You don't have to play CSI Miami and count the bytes with VB by hand or something any more. Welcome to the 1980s ... you can use a mouse and construct a filter with ease. Enjoy.

It's worth mentioning that there is actually no protocol level analysis being done. If you have a radiotap header, the silly javascript app won't know. If you are listening on a device without an ethernet layer, such as tun0 or tun1, it will also not know. You basically need to be listening on wired ethernet. But that isn't hard now, is it!

Friday, December 4, 2009

Trimming JSON

JSON is a fairly succinct markup language. For instance, say I have two people Bob and Alice, and I have very private records on them:

{
"Bob":
{
"SSN": "502-80-2012",
"CCNumber": "3842-4234-1023",
"Mother's Maiden Name": "Swanson"
},

"Alice":
{
"SSN": "312-45-1231",
"CCNumber": "8481-3231-2234",
"Mother's Maiden Name": "Swathmore"
}
}

Now say I wanted to put this imaginary pseudo structure in "JSON format". Conveniently enough, it already is. No really. I'm not kidding. That's it. We are actually done. Or, in a more compact form:

{"Bob":{"SSN": "502-80-2012","CCNumber": "3842-4234-1023","Mother's Maiden Name": "Swanson"},"Alice":{"SSN": "312-45-1231","CCNumber": "8481-3231-2234","Mother's Maiden Name": "Swathmore"}}

Unnecessary Syntax
Now that's all gravy and really useful, but wait; did you know that there are only a few reserved words in Javascript and that everything else can safely be used as labels; as long as it doesn't have a space or some other reserved character. The stuff above then could be:

Before: (188b)
{"Bob":{"SSN": "502-80-2012","CCNumber": "3842-4234-1023","Mother's Maiden Name": "Swanson"},"Alice":{"SSN": "312-45-1231",CCNumber": "8481-3231-2234","Mother's Maiden Name": "Swathmore"}}

After: (173b)
{Bob:{SSN:"502-80-2012",CCNumber:"3842-4234-1023","Mother's Maiden Name": "Swanson"},Alice:{SSN:"312-45-1231",CCNumber:"8481-3231-2234","Mother's Maiden Name": "Swathmore"}}

Those extra bytes don't need to be transferred, really. So don't do it.

Zero-information data
Some information above offers Zero information. I could, for example, specify that I will always get the fields in this order:
  1. SSN
  2. CCNumber
  3. Mother's Maiden Name
As I did above. Given this then, those labels contain Zero information and ought to be eliminated if you care about space. The datastructures then, could be converted into arrays as follows:

Before: (173b)
{Bob:{SSN:"502-80-2012",CCNumber:"3842-4234-1023","Mother's Maiden Name": "Swanson"},Alice:{SSN:"312-45-1231",CCNumber:"8481-3231-2234","Mother's Maiden Name": "Swathmore"}}

After: (101b)
{Bob:["502-80-2012","3842-4234-1023","Swanson"],Alice:["312-45-1231","8481-3231-2234","Swathmore"]}

There! Removing Zero-information data is quite a space saver - as long as you are competent enough to know how to keep your code and your data separate.

Conceptual Run-time Analysis

The above optimizations will cost you a few regular expressions on the server side before emitting it to the client but this will be saved on the client side a few ways
  1. Less data on the wire
  2. Smaller string to parse
  3. Array indexes are faster then hashmap lookups --- they just are.
So it's the cumulative time of (server) and (client):
extra regex - data transfer - parsing - hash overhead
And seeing as the server side environment is much more diverse and gives you much more options then clientside (where it's javascript) - there's probably more reason to believe that this is a feasible net gain then not.

Questionable Optimizations
There are further steps that you can do for byte-count reduction --- but it is fairly questionable whether there will be a cumulative performance gain. I've broken the further steps down to a few methods:

Data Structure Flattening
Some background
In C, when you declare a multi-dimensional array, say 50x50, you can either index the array as you defined it, say using something like [4][20]; or you could just ignore it and treat the datastructure as it exists in memory, just a sequence of 250 units. You can cast the datastructure to the generic pointer type and then index it at [4 * 50 + 20] - sometimes it's easier, sometimes it isn't.

Flattening JSON
Let's revisit our previous datastructure and the principles of Zero Information. If we know that the structure will be something like this:

{ name: [3 fields], name: [3 fields], ... name: [3 fields] }


Then we could utilize a trick very similar to the C one discussed above. That is to say, just make the datastructure one gigantic array:

Before: (101b)
{Bob:["502-80-2012","3842-4234-1023","Swanson"],Alice:["312-45-1231","8481-3231-2234","Swathmore"]}

After: (99b)
["Bob","502-80-2012","3842-4234-1023","Swanson","Alice",
"312-45-1231","8481-3231-2234","Swathmore"]

There's a few important things we have to give up: First we no longer have 'labels' so the quotes have to go back in, adding a few bytes. But as a result, we can simplify the syntax a bit. Iterating through this can be done in many ways and the optimal one depends largely on the context of the data usage. It is however questionable, whether having to do additional math overhead is worth the extra 2 bytes. But there is, however, one more optimization we can do in this field

Stringifying
If we are willing to take the math overhead in stride, why don't we just go all the way then and simply make the data CSV - wherein you only need to quote things that have the reserved characters:

Before: (99b)
["Bob","502-80-2012","3842-4234-1023","Swanson","Alice",
"312-45-1231","8481-3231-2234","Swathmore"]


After: (83b)
"Bob,502-80-2012,3842-4234-1023,Swanson,Alice,312-45-1231,8481-3231-2234,Swathmore"

Transferring the output into a place usable for Javascript is debatable. You can't just split on the ',' since you need to accommodate for the escaped \'.

So you make yourself a nice regex to do the split and come up with an array at the end. But this is foolish. What you really ought to do is use the exec method and work your way through the string. This is of course, quite a bit more work then the code above.

This more work means more javascript code, more lines to execute, more lines to compile, etc. Is it worth it? Eh, don't know ... really, I don't.

Tables
Another thing we could do is to have substitution tables. For instance, let's say that when you analyze your data-structure after you've done the Zero-information removal techniques above, you still see a lot of redundancy; simply because there is a user that is very active, or something else of that nature. You can then make a static lookup table and implement it in JS and your server side scripting language of choice. During the JSON generation you simply swap things out. For instance, pretend we have this data set:

{Alice:["Marina Del Rey","California"],Bob:["Marina Del Rey","California"],Eve:["Playa Del Rey", "California"],Doug:["Playa Del Rey","California"]}


This would be likely say, if you are a local company and have local clients in these areas. You already have the fancy gzip compression and decompression on the server and client side, so you think you are good there, but not really:
  1. gzip still needs to pass over the strings on both sides; parse them, create the tables, allocate the memory - etc. It's real CPU time that you don't need to spend
  2. Javascript needs to do the same stuff.
So you just make a simple table:

var C = {
MDR:"Marina Del Rey",
CA:"California",
PDR:"Playa Del Rey"
};

Expose this on both ends and put it in your JSON encoder on the server side:

Before: (149b)
{Alice:["Marina Del Rey","California"],Bob:["Marina Del Rey","California"],Eve:["Playa Del Rey", "California"],Doug:["Playa Del Rey","California"]}

After: (74b)
{Alice:[C.MDR,C.CA],Bob:[C.MDR,C.CA],Eve:[C.PDR,C.CA],Doug:[C.PDR,C.CA]}

Not only have you saved significant bytes, but now those entries are just pointers to pre-existing strings in a table, so JS doesn't have to allocate new memory for it.

Dynamic Tables

If you really enjoy hitting your server CPU hard, you could create dynamic tables:

Before: (149b)
{Alice:["Marina Del Rey","California"],Bob:["Marina Del Rey","California"],Eve:["Playa Del Rey", "California"],Doug:["Playa Del Rey","California"]}

After: (136b)
{C:{MDR:"Marina Del Rey",CA:"California",PDR:"Playa Del Rey"}
,
Alice:[C.MDR,C.CA],Bob:[C.MDR,C.CA],Eve:[C.PDR,C.CA],Doug:[C.PDR,C.CA]}

But this is not recommended. Because you aren't doing the zero-information principle which is to remove, not just rearrange. What you have done above is just complicate things for a what may actually work out to be no byte gain at all, and will certainly be more CPU intensive to generate and parse on both the client and the server side.

Followers