Thursday, November 15, 2012

little bit of javascirpt fun (also know as why this sucks)

A couple weeks ago I was working with a couple developers who didn't understand why I hated prototype in javasciprt.  It's not that I don't think it has uses it's just that if you are using prototype you are probably doing it wrong.  I created this little fiddle to show them where the problems start to happen.

http://jsfiddle.net/phlik/Uv3Sg/

Tuesday, September 18, 2012

Javascript string replacing

I spend a lot of time working in JavaScript.  I also find that I spend a lot of time replacing text in strings in this language.  Most of the time this can be done easily by using a good templating system. When you are working with localization systems, you can't rely on templating.

My first attempt at string replace was:
var stamp = function(template, tag, value){
    return template.replace('{'+ tag + '}', value);
};

This was a very simple attempt and wasn't very good.  It has a lot of problems. Top of the list is it will not get every instance of the tag in the string. You end up having to call stamp several times to replace the same thing.  So I set out to fix this problem.  I found you could use regular expressions to do this kind of thing.  I built out this simple function to do the work.
var stampValues = function (template, replacements) {
    for (var tag in replacements) {
        var reg = new RegExp('\{' + tag + '\}', 'g');
        template = template.replace(reg, replacements[tag]);
    }
    return template;
};

It's much better than the above one because it gets all the tags in the string. It's actually much better than any other code I have tried but more on that later.

The next version looked like this.  It uses underscore to do the flow control because each is better than "for" -- right?
var stampValuesEx0 = function (template, replacements) {
    _(replacements).each(function (value, tag) {
        var reg = new RegExp('\{' + tag + '\}', 'g');
        template = template.replace(reg, value);
    });
    return template;
};

It's not. It's slower.  Not noticeably slower but when you put a timer to it the stampValues is faster.

After looking at this I realized I was doing the Regular expression incorrectly. I could change the way I did it and probably get more speed out of it.  So I built this . . .
var stampValuesEx2 = function (template, replacements) {
    var setValues = (function () {
        var translateReg = /{\w+}/g;
        var cleanup = /[{}]/g;
        return function (s) {
            return (s.replace(translateReg, function (match) {
                return replacements[match.replace(cleanup, '')];
            }));
        };
    })();
    return setValues(template);
}

And It SUCKS.  It's slow; it takes double the time of the stampValues function.  There are a few things you can do to speed it up.  You can build out a closure with the regular expressions already in them this actually helped a lot. It cuts about 1/3 of the execution time.  That version looks like this:
var stampValuesEx3 = (function () {
    var translateReg = /{\w+}/g;
    var cleanup = /[{}]/g;
    return function (template, replacements) {
        return (template.replace(translateReg, function (match) {
            return replacements[match.replace(cleanup, '')];
        }));
    }
})();
It still not as fast as stampValues but it is faster than other attempts I have made.

In short I ended up using stampValues for my string replace function.

The code I used to test all these functions can be found at here take a look. If you have examples that you think are better or faster I would be interested in seeing them.


Thursday, March 22, 2012

String replace the better way.

This last week I have been working on making my team project at work run better on ie 7.  Usually that would mean that I spent all my time fixing styles, but there are better people then me at that.  So for me the project was getting rid of the scrpt is running two long errors.  The app I work on is very JavaScript heavy.  One of the worst offending functions I had found was the following:

function clean(word) {
        if (word) {
            
            return word.toLowerCase().
                replace(/\s/gi, "").                
                replace(/[àáâãäå]/gi, "a").
                replace(/æ/gi, "ae").
                replace(/ç/gi, "c").
                replace(/[èéêë]/gi, "e").
                replace(/[ìíîï]/gi, "i").
                replace(/ñ/gi, "n").
                replace(/[òóôõö]/gi, "o").
                replace(/œ/gi, "oe").
                replace(/[ùúûü]/gi, "u").
                replace(/[ýÿ]/gi, "y").
                replace(/\W/gi, "");
        } else {
            return word;
        }
    }

Which is a very brute force way of cleaning up strings for searching.  It was the most expensive call in our system.  With a little work it was changed to the following. 

var removeAccents = (function () {
        var translateReg = /[àáâãäåæçèéêëìíîïñòóôõöœùúûüýÿ]/g;
        var translate = {
            "à""a""á""a""â""a""ã""a""ä""a",
            "å""a""æ""ae""ç""ç""è""e""é""e",
            "ê""e""ë""e""ì""i""í""i""î""i",
            "ï""i""ñ""n""ò""o""ó""o""ô""o",
            "õ""o""ö""o""œ""oe""ù""u""ú""u",
            "û""u""ü""u""ý""y""ÿ""y"
        };
        return function(s) {
            return (s.replace(translateReg, function(match) {
                return translate[match];
            }));
        };
    })();
 
    function clean(word) {
        if (word) {
            return removeAccents(word.toLowerCase().replace(/\s/gi, "").replace(/\W/gi, ""));
        } else {
            return word;
        }
    }

For a massive boost in performance.




Thursday, January 19, 2012

Failings of the Unix Commodity

Imagine if you will a city with an array of transportation systems.  The most popular transportation system is a personal helicopter.  A home can have dozens of automated helicopters, each built to go fly to a single place and back.  Very little knowledge is needed to operate these helicopters and traveling with them is rather convenient: You don't have to wait for traffic lights or wind around with a road.  You just hop in, the helicopter takes the absolutely most direct route to your destination, and you hop out.

People have grown quite accustomed to having large garages in this city where they keep little armadas of these specialized aircraft; one for going to the supermarket, one for going to the mall, one for going to work, one for going to school, one for going to night clubs, one to cruise around town, and so on.  Hop in, push the "Start" button and you're on your way!

In order to keep selling these helicopters to consumers, manufacturers have been adding luxurious features.  It began with cup holders and grew into hot tubs, projector screens, and all other sorts of amenities to make the flight more pleasant.  While these luxuries do add weight that slows the helicopters down, people don't really notice because of all the fun they're having.

Because these helicopters blindly take the most direct routes to their destinations, crashes are not unheard of.  Some manufacturers try to avoid crashes between two of their own helicopters but that doesn't really do much for the overall aviation safety.

Earlier-on in their history, these helicopters were infamous for their propensity to have mid-air collisions, landing mishaps, and the like.  In spite of all the damage this incoherent method of transportation has caused, you can't argue with the billions of dollars the flying hot tubs have raked in.

While it is true that these helicopters can only travel to certain places, this is largely mitigated by the fact that people are willing to make many varieties of helicopters.  Most helicopter riders only really care to go to the most popular shopping centers and movie theaters anyway so they're quite content with the selection.

The other major mode of transportation is the local subway system.  This series of subterranean tracks is dark, damp and noisy.  It's inconvenient -- requiring you to know a schedule and how trains connect in order to really get anywhere.  It usually involves a lot of indirection as you connect to various stations and hop between different lines to get to your destination.

Those who prefer the subway system are proud of how low their expenses are and how few people actually get hurt by their transit system.  They have experts dedicated to maintaining and fine-tuning the whole transit system to make sure that every train arrives on time with as few surprises as possible.

Subway workers and users get along well.  They have a thriving subculture in their subway.  They all know each other and were always eager to exchange ideas about anything but especially about how they could make their subway better.

Many of the riders are also share-holders in the subway.  They take the money they save from having such an inexpensive transit system and invest it into expanding and refining it.  As a result, there is no part of the city that is more than a mile from the nearest subway station.  While walking to the subway station is a little bit of work, it is manageable and subway drivers tend to be fit and capable of the trek.

With a subway pass (that costs less than a tenth of the insurance premiums that most pay for their helicopters) and a good understanding of the subway system, subway passengers can get anywhere they'd like to go.  They see parts of the city that may be beneath the notice of helicopter riders because nobody makes aircraft that fly there.  These subway riders are totally content to trade some convenience for this kind of freedom; there are no prescribed ways or places to travel.  There is only a system that helps you get anywhere.

Helicopter riders feel like fish out of water when they enter the subway.  They enter the train and start looking for the massaging recliner seats but they find only stiff benches.  They get confused by the unspoken need to pay attention and know whether or not a stop is at the destination.  They are absolutely horrified about the idea of having to walk anywhere -- thinking that when the vehicle stops, the journey should be totally over.  When buried in a tunnel, they feel incapable of knowing where they are or what direction they want to be going.  In fact, they feel annoyed that they have to even know anything about direction.

When I was still in diapers, there were two kinds of computers around: The home desktop and the mainframe.  Home desktops were like a garage full of the Helicopters above: Emphasizing personal convenience and mass-marketability at the cost of stability and long-term maintainability.  Mainframes were like the Subway described above:  Sacrificing personal convenience and ease-of-use in exchange for having a robust, reliable, versatile system that can service the needs of many people at once.

I know I'm going to get crap if I don't mention Linux so...

As the years went by in this city, helicopter manufacturers got adventurous.  They tried to emulate admirable traits of the subway system; sometimes consciously, sometimes not.  They started making helicopters that could fly to multiple destinations.  They started making hybrid airplane-helicopter craft that could take you greater distances than just a helicopter could.  They introduced parachutes to keep helicopters from crashing into the ground in a massive conflagration of doom, and they started teaching riders to jump out of one helicopter and into another in a highly dangerous attempt at getting people places faster without having to buy more helicopters.

Meanwhile, others who admired the solid engineering of the subway system tried to emulate its strengths.  A group of volunteers paved an expansive road system on the ground that roughly resembled the subway tunnels beneath them.  Other volunteers built custom cars to drive on this road that had some of the conveniences you find in personal helicopters.  

These automobile drivers included crazy hippies that believed that asphalt was implicitly morally superior to flying as well as some entrepreneurs who hoped there would be a rising car market like there had been a helicopter market.  Some still just liked the penguin logo that was painted onto the cars.

While driver neglect could cause crashes on these roads and they were still more common than in the subway, the consequences of these crashes weren't quite as catastrophic as the airborne equivalents and so it was generally believed to be better.

This is a story that many are familiar with.  But there's actually a lot more to it than that.  Years before the automobile was introduced, there emerged another subway imitation in town.  

Some entrepreneurial souls looked at the great efficiency and usefulness of the subway and decided to try making rail travel a tradable commodity.  They prefabricated railways that could be flown in and dropped on top of a neighborhood for an instant railway transit system.  This process was naturally expensive so only the wealthiest districts could afford such a thing.

The enormous template of rail tried hard to look like the layout of the subway system.  But building such a system in such a different circumstance is hard.  When transporting this massive pretzel of track, it would often bend and warp under its own weight and had to be reshaped to fit the terrain.  After the track was finally set in place, it usually didn't resemble the subway it was intended to emulate.

Three major companies rose as providers of trolley networks.  Each had their own ideas as to what a track system should look like and how the trolley cars should behave.  Each track would be just similar enough that a passenger could make a few safe assumptions about the schedules and directions of certain lines.  And each would have its own "gotchas" that made expertise in one neighborhood's track not fully transferable to another.

The lack of standardization between all trolley systems made it incredibly difficult for some to navigate -- even those who had grown accustomed to the subway system were not quite at home on this surface railway.  

Because the companies that made these tracks were more interested in manufacturing efficiency than in usage efficiency, trolleys were eventually written off as a cute anachronism rather than a real transit system.  The purported savings of using such a system simply weren't there.  What's more, because these trolleys purported themselves to be the same as the subway system, whatever bad reputation they'd accrued was shared with the subways.

Those who had sunk the great amounts of money into buying trolley systems were stuck with them and tried to make do with what they had but no new buyers were lining up.

Trolley companies eventually got to the point where they made all their money selling repair and maintenance services to people who'd previously purchased trolley systems from them.

Some tried to add propeller blades to their trolley cars; thinking this could attract some helicopter-style revenue.  Other companies tried making their cars bigger or faster to see if that would attract neighborhoods to their wares.  

In spite of all their efforts, the trolley companies weren't getting the kind of money they wanted.  Their attempts at mutating with market demands only made whatever rail templates they did sell even less cohesive than before.

One trolley manufacturer decided to shift efforts toward building accessories for helicopters.  Another transformed its trolleys into industrial freight trains.  The last fumbled around for a while until the penguin cars showed up.  They eagerly jumped on the bandwagon and have been trying to transform their own track into paved roads since.  As soon as they saw the cars weren't just a fad, they started pulling parts out of their disheveled trolley cars and plugging them into the automobiles, hoping more than anything that they could turn it into a solid business plan.

This last company still has lingering segments of track with disheveled cars sputtering about it.  This slow energy hog of a transit system is a glorious testament of the hubris of the trolley industry which presumed they could prefabricate the emergent brilliance of a peer-reviewed, actively used, actively maintained transit system.

Some took this lesson from the trolley industry as evidence that rail travel was all together flawed or that the mistakes of the trolley were the mistakes of the subway as well.  Some even believed that the pitfalls of the trolley model were a problem with all non-aeronautic travel --- making it easy to dismiss the cars and their pavement when those started cropping up.

Today, the trolley is one of the more clumsy, unreliable forms of transportation there is.  Even the messy helicopter industry has managed to fumble their way into some best practices that mitigate their system's shortcomings.  As helicopters grow to more closely resemble the subway system beneath them, they brag about how novel and illustrious their inventions are and they mock the rails that they see beneath them.

Their mockery is not entirely unfounded.  If your only exposure to computing systems were the home desktop and the commercial Unix system, it makes perfect sense why you would prefer your squadron of helicopters.

Wednesday, January 18, 2012

jQuery how I love you.

So I had a problem today where I needed to be able to tell if a JavaScript object was empty.  I spent 10 minuets  Googleing for a consice soluction then I went to jQuery util page on a whim and the answer was there.

http://api.jquery.com/jQuery.isEmptyObject/

With just one call the library will tell me if it has data.  Thanks to the people that build such cool tools for me to use.

Friday, January 13, 2012

Benchmarking arithmetic

Got curious so I decided to see how quickly and accurately some arithmetic gets done in various environments. Results below.

[ishpeck@slcatedjamu ~]$ time dc -e "16384d^p"
113837518811535904250072068341232590877598871955010488951192642300792\
621302625312821980719831387362324936714246794526258573039676337010858\
828763430793585922853616976807646165532533059489556150449708988141578\
442943112023447213983043116092849446398990980402342632274314814328953\
404819192156219054837263740293206244418473178404516135133213244063518\
784562296023799090475839668510215390134010117698262576769574042814029\
529033278052184274508131740701273566100706819850632337113494857562098\
320151217292158833266370707127916108421901433177514694034750917722728
... ....
218238270074739736264157780272832032578594361150434678340392480113080\
089703735801591153586235927851796939292373259062814173277075113674401\
829043044144045490928371875112748010711233174142910835089303346849145\
895484745236306027347877637526426501080516036812222087305078640639225\
541848209795509140539016236258676383295890570846220185368800472374864\
023572119859359115185919085597104610288583655001397080304511835993974\
191673243089264458895016889710034575213135566915400700972672256581021\
999134594756634350940758242683390117111624193719460587302044176159214\
609746781781933047509937334480699072619539011846151062186574802048674\
92382202923258637344388123757033376532121188827136

real 0m1.167s
user 0m0.283s
sys 0m0.003s



dc surprised me with its slowness until I realized it was throwing those backslashes in there. That can eat up some time.

[ishpeck@slcatedjamu ~]$ time python -c "print 16384 ** 16384"
1138375188115359042500720683412325908775988719550104889511926423007926213026253128219807198313873623249367142467945262585730396763370108588287634307935859228536169768076461655325330594895561504497089881415784429431120234472139830431160928494463989909804023426322743148143289534048191921562190548372637402932062444184731784045161351332132440635187845622960237990904758396685102153901340101176982625767695740428140295290332780521842745081317407012735661007068198506323371134948575620983201512172921588332663707071279161084219014331775146940347509177227281385333933210897869224188603686168680892745382927717262582865116798735382574696365796311299351046728260094290719606736072012259117111400667629363151930588541659099143747134721613089069740776235687657534765557725361993289329394049820885278902800491606809630123223601804037635379024208423418856532333180705506732367579643586252181430162147604245508970283612154605179099342622822975114534462339240221466716903857275803280366341678962977346051289393798425922859136969165217554566247811263669128403448140287396494805411846462566580026934215636853835525602451004242548897751439534340759663617153864418706583169642432738589331305934295186834298433853228606541975022545265261045793253180106547809428350799194427853647105017781506127477182293624210259930919849611849204841346064260162960557828534199134070897721151924
... ...
703704366990068353216089737426366069381491347684599380093222610835917961800770781409200926729603012036399122612354223297965849193568220166221823827007473973626415778027283203257859436115043467834039248011308008970373580159115358623592785179693929237325906281417327707511367440182904304414404549092837187511274801071123317414291083508930334684914589548474523630602734787763752642650108051603681222208730507864063922554184820979550914053901623625867638329589057084622018536880047237486402357211985935911518591908559710461028858365500139708030451183599397419167324308926445889501688971003457521313556691540070097267225658102199913459475663435094075824268339011711162419371946058730204417615921460974678178193304750993733448069907261953901184615106218657480204867492382202923258637344388123757033376532121188827136

real 0m0.789s
user 0m0.203s
sys 0m0.010s


Intrepid old Python has some nice optimization to help eek out those fractions of a second.

[ishpeck@slcatedjamu ~]$ time clisp -x "(expt 16384 16384)"
i i i i i i i ooooo o ooooooo ooooo ooooo
I I I I I I I 8 8 8 8 8 o 8 8
I \ `+' / I 8 8 8 8 8 8
\ `-+-' / 8 8 8 ooooo 8oooo
`-__|__-' 8 8 8 8 8
| 8 o 8 8 o 8 8
------+------ ooooo 8oooooo ooo8ooo ooooo 8

Welcome to GNU CLISP 2.49 (2010-07-07)

Copyright (c) Bruno Haible, Michael Stoll 1992, 1993
Copyright (c) Bruno Haible, Marcus Daniels 1994-1997
Copyright (c) Bruno Haible, Pierpaolo Bernardi, Sam Steingold 1998
Copyright (c) Bruno Haible, Sam Steingold 1999-2000
Copyright (c) Sam Steingold, Bruno Haible 2001-2010

Type :h and hit Enter for context help.

1138375188115359042500720683412325908775988719550104889511926423007926213026253128219807198313873623249367142467945262585730396763370108588287634307935859228536169768076461655325330594895561504497089881415784429431120234472139830431160928494463989909804023426322743148143289534048191921562190548372637402932062444184731784045161351332132440635187845622960237990904758396685102153901340101176982625767
... ...
7414291083508930334684914589548474523630602734787763752642650108051603681222208730507864063922554184820979550914053901623625867638329589057084622018536880047237486402357211985935911518591908559710461028858365500139708030451183599397419167324308926445889501688971003457521313556691540070097267225658102199913459475663435094075824268339011711162419371946058730204417615921460974678178193304750993733448069907261953901184615106218657480204867492382202923258637344388123757033376532121188827136
Bye.

real 0m1.262s
user 0m0.393s
sys 0m0.007s


It surprised me how much slower Common was here. Doesn't help that it clutters the display with all that junk, either.

[ishpeck@slcatedjamu random_scripts]$ time csharp -e "Console.WriteLine(Math.Pow(16384, 16384));"
Infinity

real 0m0.282s
user 0m0.257s
sys 0m0.033s


I don't know what I did wrong here... I mean, besides trusting a statically typed language to know what to do with so huge a number.

[ishpeck@slcatedjamu ~]$ time newlisp -e "(pow 16384 16384)"
inf

real 0m0.003s
user 0m0.000s
sys 0m0.000s


LAWL! Infinity!

[ishpeck@slcatedjamu ~]$ time echo "16384 ^ 16384" | ghci
GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package ffi-1.0 ... linking ... done.
Prelude> 11383751881153590425007206834123259087759887195501048895119264230079262130262531282198071983138736232493671424679452625857303967633701085882876343079358592285361697680764616553253305948955615044970898814157844294311202344721398304311609284944639899098040234263227431481432895340481919215621905483726374029320624441847317840451613513321324406351878456229602379909047583966851021539013401011769826257676957404281402952903327805218427450813174070127356610070681985063233711349485756209832015121729215883326637070712791610842190143317751469403475091772272813853339332108978692241886036861686808927453829277172625828651167987353825746963657963112993510467282600942907196067360720122591171114006676293631519305885416590991437471347216130890697407762356876575347655577253619932893293940498208852789028004916068096301232236018040376353790242084234188565323331807055067323675796435862521814301621476042455089702836121546051790993426228229751145344623392402214667169038572758032803663416789629773460512893937984259228591369691652175545662478112636691284034481402873964948054118464625665800269342156368538355256024510042425488977514395343407596636171538644187065831696424327385893313059342951868342984338532286065419750225452652610457932531801065478094283507991944278536471050177815
......
1800770781409200926729603012036399122612354223297965849193568220166221823827007473973626415778027283203257859436115043467834039248011308008970373580159115358623592785179693929237325906281417327707511367440182904304414404549092837187511274801071123317414291083508930334684914589548474523630602734787763752642650108051603681222208730507864063922554184820979550914053901623625867638329589057084622018536880047237486402357211985935911518591908559710461028858365500139708030451183599397419167324308926445889501688971003457521313556691540070097267225658102199913459475663435094075824268339011711162419371946058730204417615921460974678178193304750993733448069907261953901184615106218657480204867492382202923258637344388123757033376532121188827136
Prelude> Leaving GHCi.

real 0m1.060s
user 0m0.250s
sys 0m0.173s


And for more LOL's!

[ishpeck@slcatedjamu ~]$ time lynx -dump http://www.wolframalpha.com/input/?i=16384%5E16384
#[1]Wolfram|Alpha

* [2]Home
* [3]Examples
* [4]Products
* [5]Blog
* [6]About

*
+ [7]Wolfram Research
+
+ [8]Wolfram Mathematica
+ [9]Wolfram Demonstrations
+ [10]Wolfram MathWorld
+ [11]Wolfram Science
+ [12]WolframTones
+
+ [13]More

Experimental Feature

You have the Wolfram CDF Player installed and can now enable
Wolfram|Alpha Interactive to:
* Interact with your results using sliders and controls
* Rotate and zoom 3D graphics and visualizations
* Manipulate results directly in your browser

[14]Learn more [15]Remind me later

Experimental Feature


Thanks for helping us test Wolfram|Alpha with CDF!
Try these interactive examples:
* Interactively manipulate parameters
____________________ Submit
* Rotate 3D graphics
____________________ Submit
* Read plot values
____________________ Submit
* Animate dynamic processes
____________________ Submit
* Instantly build interactive interfaces
____________________ Submit


Experimental Feature


Thanks for helping us test Wolfram|Alpha with CDF!
Please tell us what you think:[16]Take a survey

Experimental Feature


[17]Learn more [18]Take a survey

[19]Wolfram|Alpha Computational Knowledge EngineEnter what you want to
calculate or know about:

____________________

Submit

[20]Examples[21]Random

To see full output on this page you need to enable JavaScript in your
browser. [22]More info
Computing
Computing...
__________________________________________________________________

Input:

16384^16384
[23]Save as image [24]Copyable plaintext [25]Mathematica form
__________________________________________________________________
__________________________________________________________________

Decimal approximation:

* [26]More digits

[27]1.13837518811535904250072068341232590877598871955010... 10^69049
__________________________________________________________________
__________________________________________________________________

Power of 10 representation:

10^(10^4.839157747319649)
__________________________________________________________________
__________________________________________________________________

Number length:

69050 decimal digits
__________________________________________________________________
__________________________________________________________________

Last few digits:

...1188827136
__________________________________________________________________

[28]Computed by Wolfram MathematicaDownload as: PDFLive Mathematica

... ...

real 0m1.025s
user 0m0.017s
sys 0m0.010s


Of course, this is all very far from scientific but it was amusing to try. I've noticed that clisp tends to out-perform Python on smaller numbers (I assume because Python's cache is helpind it out when there's a lot of repitition). Nobody who actually _tried_ to compute the desired value botched anything up (the way Python is wont to in some arithmetic situations).

I know Haskell tended to be much faster if you subtracted start-up time (which this test does not).