I awoke one day last week with this comic idea percolating in my brain. Too bad I'm lousy at drawing.
My old blog - come see my new one
$('input#user_email').focus();
$('#sign-in-modal-form').find('input:not(:hidden):first').focus();
someobject.methods.
irb(main):001:0> a = Array.new
=> []
irb(main):002:0> a.methods.sort.collect {|m| puts "#{m} defined by #{a.method(m).owner}"}
& defined by Array
* defined by Array
+ defined by Array
- defined by Array
<< defined by Array
<=> defined by Array
== defined by Array
=== defined by Kernel
=~ defined by Kernel
[] defined by Array
[]= defined by Array
__id__ defined by Kernel
__send__ defined by Kernel
all? defined by Enumerable
any? defined by Enumerable
assoc defined by Array
at defined by Array
choice defined by Array
class defined by Kernel
clear defined by Array
clone defined by Kernel
collect defined by Array
collect! defined by Array
combination defined by Array
compact defined by Array
compact! defined by Array
concat defined by Array
count defined by Array
cycle defined by Array
delete defined by Array
delete_at defined by Array
delete_if defined by Array
detect defined by Enumerable
display defined by Kernel
drop defined by Array
drop_while defined by Array
dup defined by Kernel
each defined by Array
each_cons defined by Enumerable
each_index defined by Array
each_slice defined by Enumerable
each_with_index defined by Enumerable
empty? defined by Array
entries defined by Enumerable
enum_cons defined by Enumerable
enum_for defined by Kernel
enum_slice defined by Enumerable
enum_with_index defined by Enumerable
eql? defined by Array
equal? defined by Kernel
extend defined by Kernel
fetch defined by Array
fill defined by Array
find defined by Enumerable
find_all defined by Enumerable
find_index defined by Array
first defined by Array
flatten defined by Array
flatten! defined by Array
freeze defined by Kernel
frozen? defined by Array
grep defined by Enumerable
group_by defined by Enumerable
hash defined by Array
id defined by Kernel
include? defined by Array
index defined by Array
indexes defined by Array
indices defined by Array
inject defined by Enumerable
insert defined by Array
inspect defined by Array
instance_eval defined by Kernel
instance_exec defined by Kernel
instance_of? defined by Kernel
instance_variable_defined? defined by Kernel
instance_variable_get defined by Kernel
instance_variable_set defined by Kernel
instance_variables defined by Kernel
is_a? defined by Kernel
join defined by Array
kind_of? defined by Kernel
last defined by Array
length defined by Array
map defined by Array
map! defined by Array
max defined by Enumerable
max_by defined by Enumerable
member? defined by Enumerable
method defined by Kernel
methods defined by Kernel
min defined by Enumerable
min_by defined by Enumerable
minmax defined by Enumerable
minmax_by defined by Enumerable
nil? defined by Kernel
nitems defined by Array
none? defined by Enumerable
object_id defined by Kernel
one? defined by Enumerable
pack defined by Array
partition defined by Enumerable
permutation defined by Array
pop defined by Array
private_methods defined by Kernel
product defined by Array
protected_methods defined by Kernel
public_methods defined by Kernel
push defined by Array
rassoc defined by Array
reduce defined by Enumerable
reject defined by Array
reject! defined by Array
replace defined by Array
respond_to? defined by Kernel
reverse defined by Array
reverse! defined by Array
reverse_each defined by Array
rindex defined by Array
select defined by Array
send defined by Kernel
shift defined by Array
shuffle defined by Array
shuffle! defined by Array
singleton_methods defined by Kernel
size defined by Array
slice defined by Array
slice! defined by Array
sort defined by Array
sort! defined by Array
sort_by defined by Enumerable
taint defined by Kernel
tainted? defined by Kernel
take defined by Array
take_while defined by Array
tap defined by Kernel
to_a defined by Array
to_ary defined by Array
to_enum defined by Kernel
to_s defined by Array
transpose defined by Array
type defined by Kernel
uniq defined by Array
uniq! defined by Array
unshift defined by Array
untaint defined by Kernel
values_at defined by Array
zip defined by Array
| defined by Array
Class.ancestors # [Class, Module, Object, Kernel] Module.ancestors # [Module, Object, Kernel] Object.ancestors # [Object, Kernel] Kernel.ancestors # uninitialized constant Kernel
So she asked this kid who knew everything. Irwin. “Irwin, what’s the plural for ox?”
“Ox. Oxen. The farmer used his oxen.”
“Brian?”
“What?”
“Brian, what’s the plural for box?”
“Boxen. I bought 2 boxen of doughnuts.”
“No, Brian, no. Let’s try another one. Irwin, what’s the plural for goose?”
“Geese. I saw a flock of geese.”
“Brian?”
[Exasperated laughing]“Wha-a-at?”
“What’s the plural for moose?”
“Moosen! I saw a flock of MOOSEN! There were many of ‘em. Many much moosen. Out in the woods…in the wood-es…in the woodsen. The meese want the food in the woodesen…food is the eatenesen…the meese want the food in the woodesenes…food in the woodesenes.”
Every noun has a gender, and there is no sense or system in the distribution; so the gender of each must be learned separately and by heart. There is no other way. To do this one has to have a memory like a memorandum-book. In German, a young lady has no sex, while a turnip has. Think what overwrought reverence that shows for the turnip, and what callous disrespect for the girl. See how it looks in print -- I translate this from a conversation in one of the best of the German Sunday-school books:
Gretchen: "Wilhelm, where is the turnip?"
Wilhelm: "She has gone to the kitchen."
Gretchen: "Where is the accomplished and beautiful English maiden?"
Wilhelm: "It has gone to the opera."
Esperanto is much easier to learn than other languages because:
- The different letters are always pronounced in the same way and every letter in a word is pronounced. Therefore there are no difficulties with spelling and pronunciation, as one knows that the penultimate syllable is always stressed.
- The grammar is simple, logical and without exceptions. The grammatical exceptions are often what make it so difficult to learn a new language.
- Most of the words in Esperanto are international and are found in languages around the world.
- It is easy to make new words with prefixes or suffixes. Thus, if one learns one word, ten or more usually come as part of the package.
...Programming languages are ways to express human thought... Machines do not care whether programs are structured well; they just execute them bit by bit. Structured programming is not for machines, but for humans... So to design a human-oriented langauge, Ruby, I followed the Principle of Least Surprise. I consider that everything that surprises me less is good. As a result I feel a natural feeling, even a kind of joy, when programming in Ruby.
cachedFile('foo.png');
cachedFile('subdirectory/bar.png','class="buz"')
$GLOBAL_cachedFile_cache = null;
function cachedFile($name, $attr=null){
global $GLOBAL_cachedFile_cache;
if (!isset($GLOBAL_cachedFile_cache[$name])){
$root = $_SERVER['DOCUMENT_ROOT'];
$filetype = substr($name,strripos($name,'.')+1);
/* Configuration options */
$imgpath = '/images/';
$csspath = '/stylesheets/';
$jspath = '/scripts/';
switch ($filetype){
case 'css':
$output = '<link rel="stylesheet" type="text/css" href="/includes/';
$output .= $name;
$output .= '?' . filemtime($root . $csspath . $name) . '" ';
if($attr){
$output .= $attr . ' ';
}
$output .= '/>' . "\n";
break;
case 'js':
$output = '<script type="text/javascript" src="/includes/';
$output .= $name;
$output .= '?' . filemtime($root . $jspath . $name) . '"';
$output .= '</script>' . "\n";
break;
case 'jpg':
case 'gif':
case 'png':
//This code will get run in any of the three cases above
$output = '<img src="' . $imgpath . $name;
$output .= '?' . filemtime($root . $imgpath . $name) . '"';
$imgsize = getimagesize($root . $imgpath . $name);
$output .= ' ' . $imgsize[3];
if($attr){
$output .= ' ' . $attr;
}
$output .= ' />';
break;
}
$GLOBAL_cachedFile_cache[$name] = $output;
}
echo $GLOBAL_cachedFile_cache[$name];
}
Using asset timestamps
By default, Rails appends asset‘s timestamps to all asset paths[1]. This allows you to set a cache-expiration date for the asset far into the future, but still be able to instantly invalidate it by simply updating the file (and hence updating the timestamp, which then updates the URL as the timestamp is part of that, which in turn busts the cache).
It‘s the responsibility of the web server you use to set the far-future expiration date on cache assets that you need to take advantage of this feature. Here‘s an example for Apache:
# Asset Expiration
ExpiresActive On
<filesmatch "\.(ico|gif|jpe?g|png|js|css)$">
ExpiresDefault "access plus 1 year"
</FilesMatch>
If you look at a the source for a Rails page, you'll see what they mean: the path to a stylesheet might be "/stylesheets/scaffold.css?1268228124", where the numbers at the end are the timestamp when the file was last updated.
So it should work like this:
1. The browser says 'give me this page'
2. The server says 'here, and by the way, this stylesheet called scaffold.css?1268228124 can be cached for a year - it's not gonna change.'
3. On reloads, the browser says 'I'm not asking for that css file, because my local copy is still good.'
4. A month later, you edit and save the file, which changes the timestamp, which means that the file is no longer called scaffold.css?1268228124 because the numbers change.
5. When the browser sees that, it says 'I've never seen that file! Give me a copy, please.' The cache is 'busted.'

In addition, Microsoft is requiring phone makers to keep basic elements of its user interface, including a physical button to start Web searches on Bing.


"Agile development keeps you focused on the task, and helps you always have something usable for the user so you get feedback."
What are some of the decisions you made that helped you move quickly?
"I knew it needed to have filter subscriptions, but at first it was simpler to just copy and past the entire Easylist into a file and use Unix regex tools to turn that into Javascript code [an array]… I didn't have any updating, but that was a quick and dirty way to have something that covered lots of websites at once. The next week, I had people reported ads that weren’t being blocked because I wasn’t updating Easylist, so I had to patch manually while I was trying to get filter subscriptions written.”
"When I put new features in, I tried to put them as opt-in experiments, using the Google Labs approach, where users that are geeky enough can try it out and give me feedback... Before that, I updated one night and went to bed, and the next morning I found people complaining in my comments that I blocked all images on all web sites. I kept getting those complaints for three days until everybody’s browser had gotten the version that fixed it, even though I had released 10 updates in that time. So now I do stuff in experiments first.”
Many developers feel like we can't publish something unless it's perfect. But clearly that attitude would have stopped you from succeeding here. How do you decide if something is "good enough for now?"

"It's a balance, but I think the idea that if I put something in there that's not perfect, it will hurt my reputation, that’s false, because that's what Microsoft has been doing forever. If you can put something out that's not perfect and get feedback, you're ahead of the person who hasn't released anything at all… I just look for the absolute simplest thing I can do that adds some functionality, then do that and release it… There are still a lot of things I want to do with AdBlock, but it's been useful for thousands of people even thought it's not perfect."
What did you learn during this process?
"This project has 500 times more users than anything I've ever built personally. I'm seeing how successful Agile can be if I just listen to users and do the thing that people are shouting for most. So I've validated the agile approach... combined with not ever sleeping."
"Also, I need to weigh how loud the user is with what percentage of the user base they represent. People were clamoring for a long time that I get a change log up and post my source code. I could have spent 4-5 hours doing that, but that would have been time I wasn’t blocking ads and fixing bugs, and most people don’t care about a change log. I actually wrote a priority list down – responding to user requests quickly was first, because people liked my fast customer service, then fixing ad reports, then fixing bug reports, then feature requests, and way down the list was administrative stuff like a change log. The list got more formalized when I finally got some breathing room, when the ads were being blocked and most of the bugs were fixed, so I created a Google Code project, where I can mark bugs with low or high priority and people can see my change log."
You used object orientation pretty heavily in your Javascript on this project. How did that help you?
"What makes it most useful for me in Javascript is that it simplifies the code; it's one level of complexity that's hidden. If an object has two methods exposed, I only have to remember those two methods, where with procedural code there are a bunch of methods in the global namespace that I have to keep up with. It's harder to do in Javascript because the syntax isn't as friendly as in something like Ruby, but once you learn the syntax, it's fine, and it makes your JS feel SO much nicer."
I had the chance to actually see you working for a bit, and the main thing that stood out to me was your fluid use of vim. It's almost like you're playing an instrument: you don't seem to think about the commands. You're just typing at a thousand miles an hour, and fully formatted code flows out and morphs on the screen, while split windows appear and disappear as needed. How did you attain such editor mastery, and how important is that to your career?
It's freaking wonderful to be fluent in one editor... I just think ‘I want an IF statement’ and the braces appear.
















nextNumber(); //returns 1 nextNumber(); //returns 2 nextNumber(); //returns 3
var nextNumber = (function(){var i=1; return function() {return i++;}})();
<label for="helmet1color">Helmet 1 Color</label> <input id="helmet1color" name="helmet[1][color]"/> <label for="helmet1size">helmet 1 Size</label> <input id="helmet1size" name="helmet[1][size]"/>
function newHelmetInputs(i){
var inputSet = '';
inputSet += '<label for="helmet'+ i +'color">Helmet '+ i +' Color</label>'
inputSet += '<input id="helmet'+ i +'color" name="helmet['+ i +'][color]"/>'
inputSet += '<label for="helmet'+ i +'size">Helmet '+ i +' Size</label>'
inputSet += '<input id="helmet'+ i +'size" name="helmet['+ i +'][size]"/>'
return inputSet;
}
i = nextNumber(); newInputs = newHelmetInputs(i);
$('#addhelmet').click(function(){
var i = nextNumber();
var newInputs = newHelmetInputs(i);
$(this).before(newInputs);
$('#helmet' + i + 'size').rules('add', {digits: true});
});
foreach ($_POST['helmet'] as $key=>$val){
$emailbody .= 'Helmet ' . $key . ' Color: ' . $val['color'];
$emailbody .= 'Helmet ' . $key . ' Size: ' . $val['size'];
$emailbody .= '
"
}